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

Roblox开发:如何在服务器端而非客户端执行Raycast射线检测?

Roblox FPS游戏服务器端Raycast实现方案

问题概述

开发Roblox第一人称射击游戏时,常规客户端Raycast后通知服务器扣血的模式存在作弊风险(客户端可伪造命中信息)。需要改为服务器端执行Raycast,仅让客户端传递必要的相机数据,服务器自行判定命中,同时实现类似客户端测试代码的功能(获取相机指向对象的材质)。

核心思路

服务器无法直接访问客户端的相机视口数据,因此需要:

  1. 客户端定期(或触发射击时)将相机的原点位置和射线方向发送给服务器
  2. 服务器先校验数据合法性(防止客户端伪造位置)
  3. 服务器用合法数据构建射线,执行Raycast并处理结果

完整代码实现

客户端代码(StarterPlayerScripts)

替换你的测试代码,负责收集相机数据并发送给服务器:

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- 创建RemoteEvent用于客户端-服务器通信
local CameraRaycastRequest = Instance.new("RemoteEvent")
CameraRaycastRequest.Name = "CameraRaycastRequest"
CameraRaycastRequest.Parent = ReplicatedStorage

local camera = workspace.CurrentCamera
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.IgnoreWater = true

-- 每秒发送一次相机数据(可改为射击触发时发送)
while task.wait(1) do
    -- 动态更新过滤列表,避免角色移动后失效
    raycastParams.FilterDescendantsInstances = {LocalPlayer.Character or {}}
    
    -- 获取屏幕中心对应的射线数据
    local viewportCenter = Vector2.new(camera.ViewportSize.X/2, camera.ViewportSize.Y/2)
    local viewportRay = camera:ViewportPointToRay(viewportCenter.X, viewportCenter.Y)
    
    -- 向服务器发送射线原点和方向
    CameraRaycastRequest:FireServer(viewportRay.Origin, viewportRay.Direction)
end

服务器代码(ServerScriptService)

负责接收数据、校验合法性、执行Raycast并处理结果:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local CameraRaycastRequest = ReplicatedStorage:WaitForChild("CameraRaycastRequest")
-- 相机与角色的最大允许距离(第一人称下通常不超过5 studs)
local MAX_CAMERA_DISTANCE = 5

-- 处理客户端的射线请求
CameraRaycastRequest.OnServerEvent:Connect(function(player, cameraOrigin, cameraDirection)
    -- 校验玩家角色是否存在
    local character = player.Character
    if not character then return end
    local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
    if not humanoidRootPart then return end
    
    -- 校验相机位置是否合法:防止客户端伪造射线原点
    local distance = (cameraOrigin - humanoidRootPart.Position).Magnitude
    if distance > MAX_CAMERA_DISTANCE then
        warn(player.Name .. " 发送异常相机位置,疑似作弊")
        return
    end
    
    -- 配置服务器端Raycast参数(与客户端保持一致)
    local raycastParams = RaycastParams.new()
    raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
    raycastParams.FilterDescendantsInstances = {character}
    raycastParams.IgnoreWater = true
    
    -- 执行服务器端Raycast
    local raycastResult = workspace:Raycast(cameraOrigin, cameraDirection * 1000, raycastParams)
    
    -- 处理结果:示例为打印命中材质,可扩展为扣血逻辑
    if raycastResult then
        local hitMaterial = raycastResult.Material
        print(player.Name .. " 当前指向的材质:" .. hitMaterial.Name)
        
        -- 若命中其他玩家,执行扣血逻辑(需额外校验攻击合法性)
        local hitPlayer = Players:GetPlayerFromCharacter(raycastResult.Instance.Parent)
        if hitPlayer then
            -- 示例:扣减10点生命值
            local hitHumanoid = hitPlayer.Character:FindFirstChild("Humanoid")
            if hitHumanoid and hitHumanoid.Health > 0 then
                hitHumanoid.Health -= 10
                print(player.Name .. " 命中玩家 " .. hitPlayer.Name .. ",扣减10点生命值")
            end
        end
    else
        print(player.Name .. " 未命中任何物体")
    end
end)

关键注意事项

  • 数据校验是核心:必须限制相机与角色的距离,防止客户端伪造射线到地图任意位置
  • 性能优化:建议改为射击触发时发送数据,而非每秒定时发送,减少服务器负载
  • 防作弊局限性:仍可能存在瞄准类作弊,但客户端无法直接指令服务器扣血,大幅降低作弊风险
  • 参数一致性:服务器与客户端的Raycast参数(过滤规则、忽略水等)需保持一致,避免判定结果差异

内容的提问来源于stack exchange,提问作者Prof. Falken

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:27:42