Roblox开发问题:Object触碰Orb后调用destroy()无法销毁
问题:Roblox中Object与Orb碰撞后无法销毁
我正在开发一款Roblox游戏,核心需求如下:
- 点击「AttractButton」时,Object会向玩家位置移动并停在距离玩家4 studs的位置;
- 点击「RepelButton」时,Object会被推开一段距离。
上述移动功能运行正常,但当Object与名为Orb的部件碰撞后,调用destroy()函数始终无法让Object消失,多次调试无果,寻求解决帮助。
StarterGui中的脚本
local Players = game:GetService("Players") local TweenService = game:GetService("TweenService") local CollectionService = game:GetService("CollectionService") local RunService = game:GetService("RunService") local player = Players.LocalPlayer local mouse = player:GetMouse() local controlGui = player:WaitForChild("PlayerGui"):WaitForChild("ControlGui") local attractButton = controlGui:WaitForChild("AttractButton") local repelButton = controlGui:WaitForChild("RepelButton") local attractMode = false local repelMode = false local cooldownTime = 2 local lastInteractionTime = {} local velocity = 10 -- studs per second -- Function to handle the attract button click local function onAttractButtonClick() attractMode = true repelMode = false print("Attract mode enabled") -- Visual feedback for button click attractButton.BackgroundColor3 = Color3.fromRGB(200, 200, 200) -- Change to a different color wait(0.1) -- Wait for a short delay attractButton.BackgroundColor3 = Color3.fromRGB(255, 255, 255) -- Revert to original color end -- Function to handle the repel button click local function onRepelButtonClick() attractMode = false repelMode = true print("Repel mode enabled") -- Visual feedback for button click repelButton.BackgroundColor3 = Color3.fromRGB(200, 200, 200) -- Change to a different color wait(0.1) -- Wait for a short delay repelButton.BackgroundColor3 = Color3.fromRGB(255, 255, 255) -- Revert to original color end attractButton.MouseButton1Click:Connect(onAttractButtonClick) repelButton.MouseButton1Click:Connect(onRepelButtonClick) -- Function to perform raycast check local function raycastCheck(startPos, endPos) local direction = (endPos - startPos).Unit * (endPos - startPos).Magnitude local raycastParams = RaycastParams.new() raycastParams.FilterType = Enum.RaycastFilterType.Blacklist raycastParams.FilterDescendantsInstances = {player.Character} local result = workspace:Raycast(startPos, direction, raycastParams) return result end -- Function to move object to final position with collision checking local function moveObject(target, finalPosition) local connection local function onHeartbeat() local currentPosition = target.Position local direction = (finalPosition - currentPosition).Unit local deltaTime = RunService.Heartbeat:Wait() local newPosition = currentPosition + direction * velocity * deltaTime local result = raycastCheck(currentPosition, newPosition) if result then target.Position = result.Position - direction * 1 -- Stop just before the obstacle connection:Disconnect() return elseif (currentPosition - finalPosition).Magnitude < 1 then target.Position = finalPosition connection:Disconnect() return end target.Position = newPosition end connection = RunService.Heartbeat:Connect(onHeartbeat) end -- Function to handle mouse button click mouse.Button1Down:Connect(function() local target = mouse.Target if target and target:IsA("BasePart") and CollectionService:HasTag(target, "attractable") then local currentTime = tick() local lastTime = lastInteractionTime[target] if lastTime and (currentTime - lastTime) < cooldownTime then print("Cooldown active. Please wait.") return end lastInteractionTime[target] = currentTime local character = player.Character or player.CharacterAdded:Wait() local humanoidRootPart = character:WaitForChild("HumanoidRootPart") local targetPosition = humanoidRootPart.Position local offset, finalPosition if attractMode then offset = (target.Position - targetPosition).Unit * 4 finalPosition = targetPosition + offset elseif repelMode then offset = (target.Position - targetPosition).Unit * 20 finalPosition = target.Position + offset end finalPosition = Vector3.new(finalPosition.X, target.Position.Y, finalPosition.Z) -- Keep Y the same moveObject(target, finalPosition) print(attractMode and "Object attracted" or "Object repelled") end end)
Object部件中的脚本
local object = script.Parent -- Assuming the script is directly inside the Object part local orb = game.Workspace:WaitForChild("Orb") -- Assuming the orb is named "Orb" and is a separate part in the Workspace local function onHit(otherPart) if otherPart == orb then object:Destroy() end end object.Touched:Connect(onHit)
排查与修复方案
1. 确保Touched事件正常触发
- 检查Orb和Object的
CanCollide属性是否为true,Touched事件依赖碰撞体开启碰撞才能触发; - 替换
otherPart == orb为otherPart.Name == "Orb",避免因碰撞到Orb的子部件导致匹配失败; - 增加调试输出确认事件触发状态:
local function onHit(otherPart) print("碰撞到的部件:", otherPart.Name) if otherPart.Name == "Orb" then print("执行销毁操作") object:Destroy() end end
2. 解决客户端脚本权限问题
如果Object中的脚本是本地脚本,仅在客户端销毁对象会导致服务器端Object依然存在,其他玩家无法看到销毁效果。需改为服务器脚本,或通过RemoteEvent通知服务器处理:
- 将Object内的脚本改为
ServerScript; - 若需客户端触发,创建RemoteEvent实现跨端通信:
- 在ReplicatedStorage中创建RemoteEvent,命名为
DestroyObject; - Object的本地脚本修改为:
local object = script.Parent local orb = game.Workspace:WaitForChild("Orb") local ReplicatedStorage = game:GetService("ReplicatedStorage") local destroyEvent = ReplicatedStorage:WaitForChild("DestroyObject") local function onHit(otherPart) if otherPart.Name == "Orb" then destroyEvent:FireServer(object) end end object.Touched:Connect(onHit) - 在ServerScriptService中添加服务器处理脚本:
local ReplicatedStorage = game:GetService("ReplicatedStorage") local destroyEvent = ReplicatedStorage:WaitForChild("DestroyObject") destroyEvent.OnServerEvent:Connect(function(player, object) if object and object:IsDescendantOf(game.Workspace) then object:Destroy() end end)
- 在ReplicatedStorage中创建RemoteEvent,命名为
3. 断开移动脚本的Heartbeat连接
Object销毁时,moveObject函数中的Heartbeat连接可能仍在运行,尝试修改已销毁对象的Position导致报错。需在Object销毁时自动断开连接:
local function moveObject(target, finalPosition) local connection = RunService.Heartbeat:Connect(function() local currentPosition = target.Position local direction = (finalPosition - currentPosition).Unit local deltaTime = RunService.Heartbeat:Wait() local newPosition = currentPosition + direction * velocity * deltaTime local result = raycastCheck(currentPosition, newPosition) if result then target.Position = result.Position - direction * 1 connection:Disconnect() return elseif (currentPosition - finalPosition).Magnitude < 1 then target.Position = finalPosition connection:Disconnect() return end target.Position = newPosition end) -- 监听对象销毁事件,自动断开连接 target.AncestryChanged:Connect(function(_, parent) if not parent then connection:Disconnect() end end) end
内容的提问来源于stack exchange,提问作者vinny9592
相关产品推荐
相关产品推荐

