Gun System Hitscan help: How do other games overcome client-server time delays?

Hello everyone.

For the past few days I’ve been reworking my gun system and decided it would be a good opportunity to test it out, so me and my friends got in a testing game and tried it. The issue we had most of the time was the fact that it didn’t feel like hitscan.

I made the gun system using Raycasting, where like every other system I get the origin and the mouse position and shoot a raycast. Raycasting is of course done on the server, which has led to some issues. One issue being that when I shot directly at my opponent, the shot didn’t register.

This differs heavily from other games I’ve played like Frontlines or Rivals where they’re bullets feel exactly like how hitscan should. How do these games handle their hitscan fast enough? What can I do to make my hitscan feel better and less delayed?

2 Likes

The client sees the world as it was in the past, since the data of where another player is takes time to be received. This is worsened when you send back a request to shoot from Player A’s position to Player B’s position at the time Player A was told about it, which has already moved plenty since the server got the request. Ugh!

In most shooters like Rivals, Overwatch, Valorant, etc, they subscribe to the idea of a “shooter-first” design. As you describe, the shooter should feel like their shots connect when their cursor is over another person. For this reason, raycasts and hit detection is usually done on the client. The client then sends the shot (and what it hit) to the server. The server will usually perform some sort of sanity check on the hit (within a certain distance, rewind known positions, make sure there was no obstructions, etc).

2 Likes

I do my shot raycasts from the players camera position to the mouse position, so I send over Mouse.Hit.Position and Camera.CFrame.Position, as I want my shots to be on the crosshair of course, but mainly because I’m not too experienced in this stuff.

However you bringing up the raycast on the client does give me the idea of using the ViewportToRay or whatever the method is, then sending over the ray and doing a sanity check with another ray to see if thats fine.

You do bring up rewind known positions, and I have to ask how can that be implemented and could you maybe explain that some more?

2 Likes

Sure!

Your raycast logic is probably fine, the main thing is that the actual raycast and the hit result should be done on the client. You’ll have to create some sort of remote event to then tell the server about the raycast result. The server can then apply the effects of the hit (damage).

The hard part is the sanity check on the server. IIRC, Overwatch uses it’s sophisticated replay system to be able to “rewind time” to when the player actually shot the bullet to see where the other player was to confirm that it should hit (within some margin of error).

This could probably be done in roblox, but would require more in-depth explanation. For your use case you could probably get away with just seeing if the current position of the hit player is within a certain number of studs of the hit position, and then doing a second raycast and making sure it isn’t obstructed early.

If you did want to implement rewinding, you’d need to store player’s previous positions up to a certain amount of time, then compare that with the hit and when the client made the raycast, but I’d need to sit down and think about it more.

2 Likes

Thank you so much for the response, this was actually very insightful! Never trust the client logic has been toying with me when it comes to making a gun systen. First it was Ammo, now its this. The hit detection in other games like the new game Wanted that released, and like Madcity is pretty good aswell. I’ll definitely try out the Client sided Raycast and do a sanity check with Magnitudes. I never knew hitscan can be this deep in video games!

1 Like