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

Roblox项目脚本偶现“无法将值转换为对象”错误求助

Roblox僵尸项目问题排查与修复

项目需求

  • 玩家加入时创建leaderstats文件夹及points数值,从DataStore加载历史数据;玩家离开时保存当前points数据
  • 僵尸通过Magnitude计算与玩家的距离,在agroDistance范围内自动追踪玩家
  • 玩家触碰僵尸躯干时,points数值+1

现有脚本

数据存储脚本

local DatastoreService=game:GetService("DataStoreService")
local zombiePointIncrease=DatastoreService:GetDataStore("zombiePointIncrease")


game.Players.PlayerAdded:Connect(function(player)
    
    local leaderstats=Instance.new("Folder", player)
    leaderstats.Name="leaderstats"
    
    local points=Instance.new("IntValue", leaderstats)
    points.Name="points"
    local data
    local success, errormessage=pcall(function()
        data=zombiePointIncrease:GetAsync(player.UserId.. "-cash")
    end)    
    
    if success then
        points.Value=data
    else
        print("there was a error, getting your data")
    end
end)

game.Players.PlayerRemoving:Connect(function(player)
    local success, errormessage=pcall(function()
        zombiePointIncrease:SetAsync(player.UserId.. "-cash", player.leaderstats.points.Value)
    end)    
    
    if success then
        
        print("Data Successfully saved")
    else
        print("There was a error while saving your data")
        warn(errormessage)
    end
end)

僵尸追踪脚本

local zombieHumanoid=script.Parent:WaitForChild("Humanoid")
local zombieTorso=script.Parent:WaitForChild("HumanoidRootPart")

local function findTarget()
    local agroDistance=100
    local target

    for i, v in pairs(game.Workspace:GetChildren()) do
        local human=v:FindFirstChild("Humanoid")
        local torso=v:FindFirstChild("HumanoidRootPart")

        if human and torso and v~=script.Parent then
            --check distance
            if (torso.Position-zombieTorso.Position).magnitude<agroDistance then
                agroDistance=(torso.Position-zombieTorso.Position).magnitude
                target=torso
                return target
            end
        end
    end
end

while wait(1) do
    local torso=findTarget()
    if torso then
        zombieHumanoid:MoveTo(torso.Position)
    else
        zombieHumanoid:MoveTo(zombieTorso.Position + Vector3.new(-50, 50),0,Vector3.new(-50,50))
    end
end

触碰加分脚本

local zombietorso=script.Parent.HumanoidRootPart
local Players=game:GetService("Players")

local function findHuman()
    for i,v in pairs(game.Workspace:GetChildren()) do
        local human=v:FindFirstChild("Humanoid")
        local torso=v:FindFirstChild("HumanoidRootPart")
        if human and torso and v~=script.Parent then
            local player=game.Players:GetPlayerFromCharacter(v)
            local points=player.leaderstats.points
            points.Value=points.Value+1
        end
    end 
end

zombietorso.Touched:Connect(findHuman())

问题现象

  • 项目偶发报错,错误指向僵尸追踪脚本中的zombieHumanoid:MoveTo(zombieTorso.Position + Vector3.new(-50, 50),0,Vector3.new(-50,50))语句,提示无法将值转换为对象
  • 移除触碰加分脚本后,项目运行恢复正常

问题根源与修复方案

1. 触碰加分脚本的核心错误

  • 事件绑定错误:zombietorso.Touched:Connect(findHuman())是直接调用findHuman()并将返回值(nil)传给Connect,而非绑定函数本身,导致脚本逻辑混乱
  • 逻辑错误:每次触碰都会遍历所有Workspace对象给所有玩家加分,未判断触碰对象是否为当前玩家,且无防重复触发机制,还可能因player为nil导致报错

修复后的触碰加分脚本:

local zombietorso = script.Parent.HumanoidRootPart
local Players = game:GetService("Players")
local debounce = false -- 防重复触发

local function onTorsoTouched(hit)
    if debounce then return end
    debounce = true

    -- 获取触碰对象所属角色与玩家
    local character = hit.Parent
    local player = Players:GetPlayerFromCharacter(character)
    if not player then
        debounce = false
        return
    end

    -- 确保leaderstats和points存在后加分
    local leaderstats = player:FindFirstChild("leaderstats")
    local points = leaderstats and leaderstats:FindFirstChild("points")
    if points then
        points.Value = points.Value + 1
    end

    task.wait(1) -- 1秒冷却,避免连续触发
    debounce = false
end

-- 绑定函数引用而非调用函数
zombietorso.Touched:Connect(onTorsoTouched)

2. 僵尸追踪脚本的参数错误

  • MoveTo用法错误:Humanoid:MoveTo()的正确参数为(targetPosition: Vector3, [endPoint: Instance]),原代码传入了三个参数,第二个参数0不是Instance类型,触发类型转换错误
  • 寻敌逻辑缺陷:原findTarget函数找到第一个符合距离的玩家就直接返回,未遍历所有玩家找到最近目标

修复后的僵尸追踪脚本:

local zombieHumanoid = script.Parent:WaitForChild("Humanoid")
local zombieTorso = script.Parent:WaitForChild("HumanoidRootPart")

local function findTarget()
    local agroDistance = 100
    local target = nil

    for _, v in pairs(game.Workspace:GetChildren()) do
        local human = v:FindFirstChild("Humanoid")
        local torso = v:FindFirstChild("HumanoidRootPart")

        -- 仅追踪存活玩家
        if human and torso and v ~= script.Parent and human.Health > 0 then
            local distance = (torso.Position - zombieTorso.Position).Magnitude
            if distance < agroDistance then
                agroDistance = distance
                target = torso
            end
        end
    end
    return target -- 遍历完所有对象后返回最近目标
end

while task.wait(1) do
    local torso = findTarget()
    if torso then
        zombieHumanoid:MoveTo(torso.Position)
    else
        -- 生成随机游荡位置,避免参数错误
        local randomOffset = Vector3.new(math.random(-50, 50), 0, math.random(-50, 50))
        zombieHumanoid:MoveTo(zombieTorso.Position + randomOffset)
    end
end

3. 数据存储脚本的优化(可选)

  • 补充数据默认值,避免数据不存在时points为空
  • 绑定BindToClose事件,确保服务器关闭时保存所有玩家数据
  • 统一键名,避免-cash与功能不符的命名混乱

优化后的数据存储脚本:

local DatastoreService = game:GetService("DataStoreService")
local zombiePointIncrease = DatastoreService:GetDataStore("zombiePointIncrease")

game.Players.PlayerAdded:Connect(function(player)
    -- 分步创建对象,避免Parent参数潜在问题
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local points = Instance.new("IntValue")
    points.Name = "points"
    points.Parent = leaderstats
    points.Value = 0 -- 设置默认值

    local success, errormessage = pcall(function()
        local data = zombiePointIncrease:GetAsync(player.UserId .. "-points")
        if data then
            points.Value = data
        end
    end)    

    if not success then
        warn("加载玩家 " .. player.Name .. " 数据失败:" .. errormessage)
    end
end)

game.Players.PlayerRemoving:Connect(function(player)
    local leaderstats = player:FindFirstChild("leaderstats")
    if not leaderstats then return end
    local points = leaderstats:FindFirstChild("points")
    if not points then return end

    local success, errormessage = pcall(function()
        zombiePointIncrease:SetAsync(player.UserId .. "-points", points.Value)
    end)    

    if success then
        print("玩家 " .. player.Name .. " 数据保存成功")
    else
        warn("玩家 " .. player.Name .. " 数据保存失败:" .. errormessage)
    end
end)

-- 服务器关闭时批量保存数据
game:BindToClose(function()
    for _, player in pairs(game.Players:GetPlayers()) do
        local leaderstats = player:FindFirstChild("leaderstats")
        if not leaderstats then continue end
        local points = leaderstats:FindFirstChild("points")
        if not points then continue end

        local success, errormessage = pcall(function()
            zombiePointIncrease:SetAsync(player.UserId .. "-points", points.Value)
        end)    

        if success then
            print("服务器关闭:玩家 " .. player.Name .. " 数据保存成功")
        else
            warn("服务器关闭:玩家 " .. player.Name .. " 数据保存失败:" .. errormessage)
        end
    end
    task.wait(2) -- 等待异步保存完成
end)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:44:53