Lua脚本报错:new函数参数错误(期望Vector3,得到Vector2)求解
Skriblio类游戏Lua错误修复:Vector3/Vector2类型不匹配
错误详情
运行脚本时触发错误:Lua error : invalid argument #1 to 'new' (Vector3 expected, got Vector2),错误位于第12行。
原代码
local UserInputService = game:GetService("UserInputService") local currentTool = "Line" -- Ganti dengan alat default Anda local currentColor = Color3.new(0, 0, 0) -- Ganti dengan warna default Anda local canvas = script.Parent -- Ganti dengan objek "canvas" yang sesuai local function drawLine(startPoint, endPoint) local line = Instance.new("Part") line.Anchored = true line.Material = Enum.Material.SmoothPlastic line.BrickColor = BrickColor.new(currentColor) line.Size = Vector3.new((startPoint - endPoint).Magnitude, 0.2, 0.2) line.CFrame = CFrame.new((startPoint + endPoint) / 2, Vector3.new(endPoint.X, endPoint.Y, 0)) line.Parent = canvas end local function drawCircle(center, radius) local circle = Instance.new("Part") circle.Anchored = true circle.Material = Enum.Material.SmoothPlastic circle.BrickColor = BrickColor.new(currentColor) circle.Shape = Enum.PartType.Cylinder circle.Size = Vector3.new(radius * 2, 0.2, radius * 2) circle.CFrame = CFrame.new(center) + Vector3.new(0, 0.1, 0) circle.Parent = canvas end local function drawFreehand(startPoint, endPoint) local line = Instance.new("Part") line.Anchored = true line.Material = Enum.Material.SmoothPlastic line.BrickColor = BrickColor.new(currentColor) line.Size = Vector3.new(0.2, 0.2, (startPoint - endPoint).Magnitude) line.CFrame = CFrame.new((startPoint + endPoint) / 2, Vector3.new(endPoint.X, endPoint.Y, 0)) line.Parent = canvas end local function erase(startPoint, endPoint) -- Dapatkan semua objek anak di dalam "canvas" local canvasChildren = canvas:GetChildren() -- Iterasi melalui semua objek anak dan periksa apakah mereka berada dalam wilayah yang ditentukan for _, child in ipairs(canvasChildren) do if child:IsA("BasePart") then local position = child.Position if position.X >= startPoint.X and position.X <= endPoint.X and position.Y >= startPoint.Y and position.Y <= endPoint.Y then child:Destroy() end end end end UserInputService.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then local startPoint = UserInputService:GetMouseLocation() if currentTool == "Line" then -- Menggambar garis UserInputService.InputEnded:Wait() local endPoint = UserInputService:GetMouseLocation() drawLine(startPoint, endPoint) elseif currentTool == "Circle" then -- Menggambar lingkaran UserInputService.InputEnded:Wait() local endPoint = UserInputService:GetMouseLocation() local radius = (startPoint - endPoint).Magnitude drawCircle(startPoint, radius) elseif currentTool == "Pen" then -- Menggambar secara bebas local prevPoint = startPoint repeat local currentPoint = UserInputService:GetMouseLocation() drawFreehand(prevPoint, currentPoint) prevPoint = currentPoint wait() until not UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) elseif currentTool == "Eraser" then -- Menghapus UserInputService.InputEnded:Wait() local endPoint = UserInputService:GetMouseLocation() erase(startPoint, endPoint) end end end)
问题根源
UserInputService:GetMouseLocation()返回的是Vector2类型(仅包含屏幕X/Y坐标),但Roblox中Part的CFrame、Position等属性需要Vector3类型(3D空间坐标,含X/Y/Z)。- 第12行的
CFrame.new((startPoint + endPoint)/2, ...)中,(startPoint + endPoint)/2是Vector2,不符合CFrame构造函数的参数要求,直接触发类型错误。 - 其他函数(如
drawCircle、erase)也存在同样的Vector2/Vector3不兼容问题。
修改方案
步骤1:添加屏幕坐标转3D世界坐标的函数
首先获取当前相机,并实现转换逻辑(假设Canvas位于Z=0的平面,可根据实际场景调整Z值):
local Camera = game.Workspace.CurrentCamera -- 将屏幕坐标转换为Canvas所在平面的3D坐标 local function screenToWorld(screenPos) -- 从相机发射射线到屏幕位置 local ray = Camera:ViewportPointToRay(screenPos.X, screenPos.Y) -- 计算射线与Z=0平面的交点(Canvas所在平面) local distance = -ray.Origin.Z / ray.Direction.Z return ray.Origin + ray.Direction * distance end
步骤2:替换所有鼠标位置的获取逻辑
将所有UserInputService:GetMouseLocation()替换为screenToWorld(UserInputService:GetMouseLocation()),确保传入函数的是Vector3类型的坐标。
步骤3:修复函数中的Vector3使用问题
drawLine和drawFreehand中,CFrame.new的第二个参数直接使用转换后的endPoint(已经是Vector3),无需手动构造Vector3。drawCircle中CFrame.new(center)的center现在是Vector3,无需额外处理。
修改后的完整代码
local UserInputService = game:GetService("UserInputService") local Camera = game.Workspace.CurrentCamera local currentTool = "Line" -- Ganti dengan alat default Anda local currentColor = Color3.new(0, 0, 0) -- Ganti dengan warna default Anda local canvas = script.Parent -- Ganti dengan objek "canvas" yang sesuai -- 将屏幕坐标转换为Canvas所在平面的3D坐标(假设Canvas在Z=0平面) local function screenToWorld(screenPos) local ray = Camera:ViewportPointToRay(screenPos.X, screenPos.Y) local distance = -ray.Origin.Z / ray.Direction.Z return ray.Origin + ray.Direction * distance end local function drawLine(startPoint, endPoint) local line = Instance.new("Part") line.Anchored = true line.Material = Enum.Material.SmoothPlastic line.BrickColor = BrickColor.new(currentColor) line.Size = Vector3.new((startPoint - endPoint).Magnitude, 0.2, 0.2) -- 直接使用Vector3类型的坐标构造CFrame line.CFrame = CFrame.new((startPoint + endPoint) / 2, endPoint) line.Parent = canvas end local function drawCircle(center, radius) local circle = Instance.new("Part") circle.Anchored = true circle.Material = Enum.Material.SmoothPlastic circle.BrickColor = BrickColor.new(currentColor) circle.Shape = Enum.PartType.Cylinder circle.Size = Vector3.new(radius * 2, 0.2, radius * 2) -- center已经是Vector3,直接使用 circle.CFrame = CFrame.new(center) + Vector3.new(0, 0.1, 0) circle.Parent = canvas end local function drawFreehand(startPoint, endPoint) local line = Instance.new("Part") line.Anchored = true line.Material = Enum.Material.SmoothPlastic line.BrickColor = BrickColor.new(currentColor) line.Size = Vector3.new(0.2, 0.2, (startPoint - endPoint).Magnitude) -- 直接使用Vector3类型的坐标构造CFrame line.CFrame = CFrame.new((startPoint + endPoint) / 2, endPoint) line.Parent = canvas end local function erase(startPoint, endPoint) local canvasChildren = canvas:GetChildren() for _, child in ipairs(canvasChildren) do if child:IsA("BasePart") then local position = child.Position -- 现在startPoint和endPoint都是Vector3,直接比较X/Y即可 if position.X >= math.min(startPoint.X, endPoint.X) and position.X <= math.max(startPoint.X, endPoint.X) and position.Y >= math.min(startPoint.Y, endPoint.Y) and position.Y <= math.max(startPoint.Y, endPoint.Y) then child:Destroy() end end end end UserInputService.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then -- 转换鼠标位置为3D坐标 local startPoint = screenToWorld(UserInputService:GetMouseLocation()) if currentTool == "Line" then UserInputService.InputEnded:Wait() local endPoint = screenToWorld(UserInputService:GetMouseLocation()) drawLine(startPoint, endPoint) elseif currentTool == "Circle" then UserInputService.InputEnded:Wait() local endPoint = screenToWorld(UserInputService:GetMouseLocation()) local radius = (startPoint - endPoint).Magnitude drawCircle(startPoint, radius) elseif currentTool == "Pen" then local prevPoint = startPoint repeat local currentPoint = screenToWorld(UserInputService:GetMouseLocation()) drawFreehand(prevPoint, currentPoint) prevPoint = currentPoint task.wait() until not UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) elseif currentTool == "Eraser" then UserInputService.InputEnded:Wait() local endPoint = screenToWorld(UserInputService:GetMouseLocation()) erase(startPoint, endPoint) end end end)
额外优化说明
- 将
wait()替换为task.wait(),这是Roblox推荐的现代等待方式。 - 在
erase函数中增加math.min/math.max处理,确保不管鼠标拖拽方向如何,区域判断都正确。
内容的提问来源于stack exchange,提问作者Adrian Nugroho
相关产品推荐
相关产品推荐

