It’s me again lol. This time, I’m here with a possible enhancement for the Laser pistol to improve accuracy when fired while travelling at high speed.
Let’s start with a video from my upcoming game, WormHole Rider
As you can see, I need to travel at very high speeds, this is just a Class 2 Training Worm, even higher speeds are still in development and present special challenges. Speed portrayed in the HUD is mathematically accurate, based upon figures obtained here
Anyway, as you might imagine, when the character is travelling at such high velocity, we must take care to fire the projectile from the correct location, which can be substantially different between the client and the server.
Our Sensei @EtiTheSpirit has left us a breadcrumb to start us down the journey. On line 192 of Server
script we find the comment:
To do: It may be better to get this value on the clientside since the server will see this value differently due to ping and such.
Indeed. Let us proceed to do precisely that. It turns out to be fairly straightforward. Tracing the code we see that a MouseEvent is fired from client to server with a payload of the mouse’s Hit. Let’s enhance this payload with a bit more information. On the sending side, in the script file Client
we’ll change the RunService stepped handler to include a packet of data instead of just the Mouse.Hit.p. Here’s the necessary data points from my WormHole copy:
local packet = {
velocity = humanoidRootPart.Velocity.Magnitude,
cframe = CFrame.new(FirePointObject.WorldCFrame.p, Mouse.Hit.p),
ostick = tick(),
}
MouseEvent:FireServer(packet)
Now let’s modify the receiving side in Server
script as follows:
When receiving the event on line 261, let’s remove line 267 which computes a direction, since that is provided by the packet. And, instead of passing this computed direction to Fire()
we pass the whole packet.
Now, let’s update Fire()
to utilize the packet of information from the client. First, we’ll slightly modify the directionalCF initialization based on the packet’s CFrame’s LookVector:
local directionalCF = CFrame.new(Vector3.new(), packet.cframe.LookVector)
Let’s remove the sketch that our Sensei left for us on lines 191-193 and we will compute a modifiedBulletSpeed using the packet’s velocity as follows:
local modifiedBulletSpeed = (direction * (BULLET_SPEED + packet.velocity))
The velocity we received from the client was accurate at the time the weapon was fired. Now, let’s predict where the client has moved to, during the time that has elapsed since the packet was transmitted. To do that, we’ll need to diff the server’s tick with the one from the packet, and we’ll actually need to double it, since approximately this amount of time will again elapse on the return trip when server sync’s the projectile’s position back to client. Here’s my computation for the interpolated position using this doubled ping difference:
local pingOffset = (tick() - packet.ostick) * 2
local interpolatedPosition = packet.cframe.Position + (direction * packet.velocity * pingOffset)
And now we feed these inputs to the Caster:Fire as follows
local simBullet = Caster:Fire(interpolatedPosition, direction, modifiedBulletSpeed, CastBehavior)
With this, we predict where the gun’s muzzle has moved to, based upon it’s last known position and velocity, and the time difference between when it was fired and now.
I hope this mod might be useful to some other folks in the Roblox community
FirstVertex