Let's talk hitscan systems

Started by
7 comments, last by Thaumaturge 3 years, 3 months ago

I'm currently working on an FPS engine where I'm attempting to mimic the mechanics of CS:GO as closely as possible. I've just recently started on weapon mechanics and have been attempting to figure out exactly (well not EXACTLY…but you know what I mean) how the hitscan system in csgo works. For example csgo incorporates recoil and weapon spread, so where exactly is the ray used for hitscanning cast from? My initial thought was that it was coming from the center of the users screen, with the weapon spread value added to the screen center value before being cast.

However, after I thought about this some more and analyzed some screen capture footage, when you fire, your screen jerks to simulate recoil. Therefore on the next weapon fire (either on mouse click or immediately after the last shot for automatic weapons), would recoil not be dictated by how much your screen jerked, since you'd be casting from the center of screen?

I suppose what my goal of this post really is is to start a conversation about ways to create an FPS hitscan system which takes into account recoil and weapon spread similar to games such as counter strike, with some talking points being:

  1. Calculating spread based off weapon properties and ray cast from center of screen
    1. My thoughts on this were to store an array of offset vectors for the spread of each weapon, then use these values depending on weapon rate of fire
  2. Weapon recoil screen jerk/movement and whether or not this should affect weapon spread. If it should not affect spread, how would one then obtain an accurate raycast from center of screen if center of screen has been modified to show this movement?
  3. How to show a bullet in flight coming from the barrel of a player's weapon?
    1. My idea for this is to include a dummy bone on the end of each weapon's muzzle, then create a bullet object at the point of the muzzle bone and translate it to the contact point of the raycast (translated very quickly)
  4. How to go about delaying the hit for enough time to show a bullet in flight? Occasionally in cs you'll see a bullet in flight, but if the hitscan were accounted for immediately AND THEN you saw the bullet in flight that wouldn't make sense, so I'm guessing there is some logic that accounts for this?
    1. This may just be as simple as saving the hit notification, then kicking off a fast bullet translation, then registering the hit…maybe…? That may lead to some oddities where you run behind a wall but still die because you actually were shot, just before you moved behind the wall. Which happens in CS all the time but this would be due to networking/client predication.
Advertisement

Not on-topic in the Game Design forum. Moving thread to a more appropriate forum.

-- Tom Sloper -- sloperama.com

As to the generation of weapon-spread, I think that I would likely just calculate spread-vectors on the fly; I'd only look to storing vectors beforehand if the former approach proved too slow.

Regarding the raycasts, as an alternative to casting from the centre of the screen, I could see a system that instead casts from the muzzle of the gun. (Adjusted to line up with the closest point under the centre of the screen, as I think was done in the old Mechwarrior games.) This would result in recoil animations “naturally” affecting accuracy.

If bullets can take appreciable time to travel, then I might be inclined to simulate this: instead of a straightforward "infinite" hitscan, I might limit the maximum length of the hitscan segment (with that maximum being calculated based on the delta-time in the current frame). Then, should the segment not find a hit, I would move it forward so that its tail-position is at its previous head-position, and try again on the next frame.

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

Tom Sloper said:

Not on-topic in the Game Design forum. Moving thread to a more appropriate forum.

I disagree. This is fundamentally a game design decision. You need to create the compromise between realism and playability that is right for your game.

It's easy to treat the recoil effect as a separate camera effect layer on top of the direction the player is facing. The direction the player is facing is represented by object A. Moving the mouse rotates object A. The actual camera is attached to object A, but camera effects like recoil can cause it to shake relative to A. The hit scan is performed relative to object A, and therefore unaffected by recoil.

Is this desirable? Well, it allows you to have a camera recoil effect while still aiming accurately, so if that's your goal, it might be. Personally, I'd rather go the other way around: no camera recoil effect, but aiming is affected by recoil. That's because camera recoil gives me motion sickness, and because I prefer to replicate the messiness of a real gun fight over the clean fantasy of perfect aim. But don't just blindly do what I do. Do what's right for your game.

Thaumaturge said:

As to the generation of weapon-spread, I think that I would likely just calculate spread-vectors on the fly; I'd only look to storing vectors beforehand if the former approach proved too slow.

That probably would make more sense. That way you could calculate a new random offset based on rate of fire and distance to object (within a spread limit) so every shot isn't exactly the same (but very close). I'll probably toy around with that route.

Thaumaturge said:

Regarding the raycasts, as an alternative to casting from the centre of the screen, I could see a system that instead casts from the muzzle of the gun. (Adjusted to line up with the closest point under the centre of the screen, as I think was done in the old Mechwarrior games.) This would result in recoil animations “naturally” affecting accuracy.

This sounds interesting. I might play around with this, as it seems like it may be entertaining to have to account for weapon sway (which one would have to do with this method, actually it may not have too much of an effect since it would only change the angle of the ray). My only concern would be aligning my weapon models to point exactly at center of screen without them looking “off” like they're too far rotated in one direction, but this might not even be an issue.

Thaumaturge said:

If bullets can take appreciable time to travel, then I might be inclined to simulate this: instead of a straightforward "infinite" hitscan, I might limit the maximum length of the hitscan segment (with that maximum being calculated based on the delta-time in the current frame). Then, should the segment not find a hit, I would move it forward so that its tail-position is at its previous head-position, and try again on the next frame.

I REALLY like this idea. When I was initially researching ways of incorporating projectiles I came across the ballistics method, or dynamic method, where you generate an actual physics object for each bullet that you apply various forces to and then raycast between each bullet object to detect hits (to account for bullets phasing through without registering hits), but ultimately decided on trying out the hitscan method first since that's what cs uses. What you describe above is similar in how you'd raycast between to points each tick. I like it.

a light breeze said:

It's easy to treat the recoil effect as a separate camera effect layer on top of the direction the player is facing. The direction the player is facing is represented by object A. Moving the mouse rotates object A. The actual camera is attached to object A, but camera effects like recoil can cause it to shake relative to A. The hit scan is performed relative to object A, and therefore unaffected by recoil.

This makes sense. At the moment I'm performing the hit scan relative to the camera, (converting center of screen to a vector in world space). However, if I were to cast the ray from the muzzle of the weapon (or any point not directly obtained from the camera transform) then…yeah jerking the camera around to emulate recoil would not affect accuracy would it. Thank you for pointing this out! ?

whitwhoa said:
… you could calculate a new random offset based on … distance to object

Hmm… Why would the distance to the object affect the degree of the spread? After all, the angle at which shot leaves a shotgun doesn't change as a result of what you point it at.

Unless you're using it to calculate the offset of the final position, in which case I might suggest using a bit of trigonometry instead, allowing you to essentially specify the angular offset from “straight ahead” and thus produce an offset vector.

whitwhoa said:
My only concern would be aligning my weapon models to point exactly at center of screen without them looking “off” like they're too far rotated in one direction, but this might not even be an issue.

Indeed, I think that you may find that it's more common than you think. As mentioned above, I recall the Mechwarrior games doing it, and I think that I've read of other, less-stompy games doing similarly.

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

Thaumaturge said:

whitwhoa said:
… you could calculate a new random offset based on … distance to object

Hmm… Why would the distance to the object affect the degree of the spread? After all, the angle at which shot leaves a shotgun doesn't change as a result of what you point it at.

Unless you're using it to calculate the offset of the final position, in which case I might suggest using a bit of trigonometry instead, allowing you to essentially specify the angular offset from “straight ahead” and thus produce an offset vector.

My current working example is pretty basic and I'm generating a far vector (from the camera far plane) and a near vector (camera near plane), and casting the ray from nearVec to farVec. Adjusting the offset of the farVec was to give the cast an angle that would be greater over greater distance. Will probably wind up changing this up as it was just to see the effect. Learning as I go on this one, and my higher level math skills are poor (but re-learning as I go).

So this warrants another question. Say I end up casting my hitscan ray from the muzzle of each weapon, which are pointed to the center of the screen (more or less). What would I then use as the end vector for the cast? Or would I just angle the weapons so that they point exactly at where I would have cast the end vector and simply cast the rays from the muzzle in the direction the muzzle is facing (possibly incorporating the length idea you mentioned above)?

whitwhoa said:
Or would I just angle the weapons so that they point exactly at where I would have cast the end vector and simply cast the rays from the muzzle in the direction the muzzle is facing (possibly incorporating the length idea you mentioned above)?

If I'm understanding you correctly, then this is exactly what I'd suggest.

In short, what I'd do is this:

  • Cast a ray through the centre of the screen, and find the location of the first hit
  • Point the weapon at said location
  • Use the weapon's “forward vector” as the basis for the bullet-vector, adjusted as appropriate for weapon-spread.

(That last point might want for some thought if integrating it with your current approach, however.)

whitwhoa said:
My current working example is pretty basic and I'm generating a far vector (from the camera far plane) and a near vector (camera near plane), and casting the ray from nearVec to farVec. Adjusting the offset of the farVec was to give the cast an angle that would be greater over greater distance. Will probably wind up changing this up as it was just to see the effect. Learning as I go on this one, and my higher level math skills are poor (but re-learning as I go).

Ah, I believe that I understand now. Fair enough, then!

And look, the fact that I would use trigonometry doesn't mean that it's the only, or even the best, approach. If your way works for you, and performance is fine, then I see no problem with it!

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

This topic is closed to new replies.

Advertisement