You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Roblox Studio插件克隆树木旋转异常问题求助

Roblox Studio插件树木无法直立放置问题解决

问题描述

我编写了一款Roblox Studio插件脚本,功能是从ReplicatedStorage/Trees中随机选择树木模型,克隆后放置在编辑器内3D世界的点击位置。目前遇到的问题是:即使在平坦地形上,克隆出的树木也无法直立。

已尝试的方法

  • 设置固定CFrame角度(所有轴都试过0/90/180等),代码如下:
local rotation = CFrame.Angles(math.rad(0), math.rad(0), math.rad(0))
SpawnedTree:PivotTo(position * rotation)
  • 直接使用点击位置设置模型位置:
SpawnedTree:PivotTo(position)

使用的树木模型为Pine Tree,其枢轴位置正确,Orientation和Position均设为(0, 0, 0)。

原脚本代码

local NO_TREES_FOUND_ERROR = "No trees found!"
local NO_TREES_FOLDER_FOUND_ERROR = "No 'Trees' folder found!"

-- Tag Log
local TAG = "TPlace: "

-- Spawn tree
local function spawnTree(position)
    local treeToSpawn = nil -- Final Tree Model to spawn
    local randomInt -- Number of model to pick
    local storage = game:GetService("ReplicatedStorage") -- Obvious

    if not storage:FindFirstChild("Trees") then -- Just check if 'Trees' folder exist
        showError(NO_TREES_FOUND_ERROR) -- In GUI
        warn(TAG .. "No 'Trees' folder found! Create this folder in ReplicatedStorage and place trees there!")
    else
        local children = storage.Trees:GetChildren()
        
        if #children == 0 then -- If 'Trees' folder exist, check if there is tree models
            showError(NO_TREES_FOUND_ERROR) -- In GUI
            warn(TAG .. "No trees found! They need to be in ReplicatedStorage/Trees")
        else
            if #children == 1 then -- If there is only one model, select '1'
                randomInt = 1
            else
                local randomInt = math.random(1, #children)
            end

            treeToSpawn = children[randomInt]

            local SpawnedTree = treeToSpawn:Clone() -- Clone Tree
            SpawnedTree.Parent = workspace -- Add to workspace

            local rotation = CFrame.Angles(math.rad(0), math.rad(0), math.rad(0)) 
-- Set rotation (does'nt work)

            SpawnedTree:PivotTo(position * rotation) -- Transform
        end
    end
end

-- Get Mouse click positions
local Mouse = plugin:GetMouse()

local target = nil

local function button1Down()
    target = Mouse.Target
end

local function button1Up()
    if target == Mouse.Target and target.Name == "Terrain" then
        spawnTree(Mouse.Hit)
    end
end

local ClickEventDown
local ClickEventUp
ClickEventDown = Mouse.Button1Down:Connect(button1Down)
ClickEventUp = Mouse.Button1Up:Connect(button1Up)
plugin:Activate(isConnected)

问题分析与修复方案

核心问题

  1. Mouse.Hit的CFrame特性:Mouse.Hit返回的CFrame包含了地形表面的法线朝向,直接用它设置模型Pivot会让模型贴合地面倾斜,哪怕地形平坦也会继承错误的旋转信息。
  2. 变量作用域错误:在多树木分支中重新声明了local randomInt,导致外层变量未被赋值,会出现nil错误。

修复后的完整代码

local NO_TREES_FOUND_ERROR = "No trees found!"
local NO_TREES_FOLDER_FOUND_ERROR = "No 'Trees' folder found!"

-- Tag Log
local TAG = "TPlace: "

-- Spawn tree
local function spawnTree(hitCFrame)
    local treeToSpawn = nil
    local randomInt
    local storage = game:GetService("ReplicatedStorage")

    if not storage:FindFirstChild("Trees") then
        showError(NO_TREES_FOLDER_FOUND_ERROR)
        warn(TAG .. "No 'Trees' folder found! Create this folder in ReplicatedStorage and place trees there!")
        return
    end

    local children = storage.Trees:GetChildren()
    if #children == 0 then
        showError(NO_TREES_FOUND_ERROR)
        warn(TAG .. "No trees found! They need to be in ReplicatedStorage/Trees")
        return
    end

    -- 修正变量作用域问题
    randomInt = #children == 1 and 1 or math.random(1, #children)
    treeToSpawn = children[randomInt]

    local SpawnedTree = treeToSpawn:Clone()
    SpawnedTree.Parent = workspace

    -- 构建直立CFrame:保留点击位置,重置旋转为直立(可添加Y轴随机旋转让树木朝向自然)
    local spawnPosition = hitCFrame.Position
    -- 如需随机朝向,将math.rad(0)替换为math.rad(math.random(0, 360))
    local uprightCFrame = CFrame.new(spawnPosition) * CFrame.Angles(0, math.rad(0), 0)
    SpawnedTree:PivotTo(uprightCFrame)
end

-- Get Mouse click positions
local Mouse = plugin:GetMouse()
local target = nil

local function button1Down()
    target = Mouse.Target
end

local function button1Up()
    if target == Mouse.Target and target.Name == "Terrain" then
        spawnTree(Mouse.Hit)
    end
end

local ClickEventDown = Mouse.Button1Down:Connect(button1Down)
local ClickEventUp = Mouse.Button1Up:Connect(button1Up)
plugin:Activate(true) -- 激活插件

修复点说明

  • 修正randomInt变量作用域,避免nil错误。
  • 提取Mouse.Hit的位置信息,重新构建直立状态的CFrame,确保树木垂直于地面。
  • 添加return语句,错误发生后直接退出函数,避免无效代码执行。
  • 修正plugin:Activate的参数,直接传入true激活插件。

内容的提问来源于stack exchange,提问作者thewolf1119

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 13:37:57