Raycasting Problems[Solved]

So I have pretty much finished my testing with raycasting and have concluded that even the most optimized form of visualizing projectiles and beams on Roblox are not even smooth. I truly don’t understand how some games on Roblox do it. Keys pistols and gunfight arena to mention two obvious ones. It is baffling how they managed to make their tracers completely smooth looking. There’s nothing optimized about it. While it may not seem any different to the average person, if you test both the client and the server for raycasting you will clearly notice the difference. And while people might say “use fireallclients fixes it” … it’s not true at all. You can’t account for damage and hitmarkers unless you draw a seperate ray for the player who fired it, which becomes delayed and not sychronized with the rest of the clients. So my question is… what are you guys doing to make it smooth? I genuinely don’t get it and I’ve tried many different ways of doing it.

So if I understand your issue with raycasting right, it does not work smoothly because it’s delayed.

How I do it is just a normal raycast on the server. It’s important you use the server here, as if you don’t your function will be easy exploitable. I’ve never had the issue of lag/delayed raycasts.

If this is how you already do it, could you please show me your script? And perhaps the issue could be that your game is laggy, so I’d recommend using a baseplat with solely your weapon.

I hope this post helps you in any sort of way.

Kevin.

1 Like

I’m not sure about your specific game examples or how they do it, but there are some fairly technical ways of mitigating against these problems.

For example, one option is to ping the server and measure the time taken to receive a response. Assuming T1 is when it’s sent, and T2 is when it’s received: Server is (T2-T1)/2 seconds ahead of the client. Once you have the ping, you can track player positions/velocities and account for their ‘real’ position relative to the observed position. This can be done on the server or the client. Again this is relatively advanced and probably not required for the majority of cases/games on Roblox, but it’s one example of how you can account for latency.

I’d recommend reading how Valve does it with their Source engine:
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

Edit: Ah, apologies, I thought you were referring to discrepancies between Raycasts on the server vs client rather than just the visualisation of tracers.

2 Likes
local function Rocket(char)

if char:FindFirstChild("HumanoidRootPart") then

local root = char.HumanoidRootPart

local Rocket = Projectiles.Rocket:Clone()
Rocket.Parent = workspace.Projectiles
Rocket.Anchored = true
Rocket.CanCollide = false
Rocket.Transparency = 0
Rocket.Name = "Rocket_All"
Rocket.CFrame = root.CFrame * CFrame.new(0, 1, -6) * CFrame.Angles(math.rad(-90), 0, 0)

local function fireRay() 

local filter_table = {}
local rayOrigin = Rocket.Position
local rayDirection = Rocket.CFrame:VectorToWorldSpace(Vector3.new(0, 1, 0)) * 500
local param = RaycastParams.new()
param.FilterType = Enum.RaycastFilterType.Exclude
for _, i in pairs(workspace:GetDescendants()) do
if i and i:IsDescendantOf(workspace.Projectiles) or i.Parent:isA("Accessory") then
table.insert(filter_table, i)
end
end

param.FilterDescendantsInstances = filter_table

local rayResult = workspace:Raycast(rayOrigin, rayDirection, param)

local TweenService = game:GetService("TweenService")

local function VisualizeWithoutTarget()
local rayOrigin = Rocket.Position
local rayDirection = Rocket.CFrame:VectorToWorldSpace(Vector3.new(0, 1, 0)) * 500
local endpoint = rayOrigin + rayDirection
Rocket.CFrame = CFrame.new(rayOrigin, endpoint) * CFrame.Angles(math.rad(-90), 0, 0)

local duration = (rayOrigin - endpoint).Magnitude / 100
local tweenInfo = TweenInfo.new(duration, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
local goal = {Position = endpoint}
local tween = TweenService:Create(Rocket, tweenInfo, goal)
tween:Play()

task.delay(1, function()
Rocket:Destroy()
end)

end

local function VisualizeWithTarget(target, endpoint)

local velocity = 100
local stopDistance = 1
task.spawn(function()
local SteppedDebounce = false
game:GetService("RunService").Stepped:Connect(function(_, step)
local rayOrigin = Rocket.Position
local goal = target.Position
local distance = (rayOrigin - goal).Magnitude
if distance > stopDistance then
local alpha = step * velocity / distance
Rocket.CFrame = Rocket.CFrame:Lerp(CFrame.new(goal), alpha)
Rocket.CFrame = CFrame.new(Rocket.Position, goal) * CFrame.Angles(math.rad(-90), 0, 0)
else
if not SteppedDebounce then
SteppedDebounce = true
if Rocket then
print("Hi")
Rocket:Destroy()
game:GetService("ReplicatedStorage").Remotes.Damage:FireServer(target.Parent)
updateCrossHairGUI(char)
end
end
end
end)
end)

end

if rayResult and rayResult.Instance then
VisualizeWithTarget(rayResult.Instance, rayResult.Instance.Position)
else
VisualizeWithoutTarget()
end

end

fireRay()

end

end

Also don’t worry about exploits. I don’t care at all about exploits. All I care about is performance.

  1. This forum is made for help, not to have people making your scripts.
  2. You are using functions wrong.

Let me get a little more in depth on 2. The way you are currently using your functions is basically just to group your code. I assume that the function Rocket is used every time a shot has been fired. Then it gets pretty messy. You have an event connected to a function which is in a thread, which is in a function, which is in a function, which is in a function. Structure your code more like this:

local function SendRay(From : Postion, To : Position) -- if you would need a to argument you can use that here.
-- Use this function to return whether you got a hit. So do all the raycasting in here.
   return hit -- Just imagine this being the hit that you get from the raycast.
end

local function Effects() --Any other function like effects or whatever, place them in a function like this

end


Remote.OnServerEvent:Connect(function(Player) -- First argument is ALWAYS a player on server events.
    local HumanoidRootPart = Player.Character.HumanoidRootPart -- Perhaps you would first want to check if they are alive (so if Player.Character exists).
    local Hit = SendRay(HumanoidRootPart.Position)

    if Hit then
        -- And this is where you add your damage etc.
    end
end)

It actually is very possible, although advanced and not recommended in most games. I’m actively developing such a system in my game. Here’s a post that might help.

It’s simple: they use client-sided hitboxes (trusting the shooter), with server sanity checks. It’s not the most secure, but most exploiters in roblox aren’t advanced enough to take advantage of it, so it works well enough.

2 Likes