MindVisceral / EZGame

1 stars 0 forks source link

Awful bullet_spread implementation for RayCast type weapons causes bugs #44

Closed MindVisceral closed 1 month ago

MindVisceral commented 1 month ago

Currently, the Bullets for the RayCast weapons are written like this: We get the Z Basis of the Node which the "Bullets" "come out of", multiply that by the weapon's max_distance and thus we get the final position (as in XYZ coordinates) of the RayCast "Bullet". Since this sytem relies on PhysicsDirectSpaceState3D, we cannot just pick a maximum distance for the RayCast and rotate it to face whichever direction the Player is looking at (this is the case for regular RayCast Nodes) - we must know the start and end positions before the Ray is cast.

Calculating the start and end positions seems to work fine, but the problem arrives when we want to add some random spread to the Bullets. In a better system, the RayCast can simply be rotated a bit on the X and Y axes. But in this sytem, we take the final position of the Ray and we add a random value to that. This is not the same as rotating a RayCast around its origin point.

This current implementation causes a few bugs; bullet_spread is dependant on max_distance - smaller distance, bigger spread bullet_spread works on 'global coordinates' - we add random spread to the Bullet's final destination on all axes. This is like taking the Bullet's end position and adding a ball of randomness inside of which the Bullet will land. Instead, there should be a kind of a flat plane perpendicular to Player vision.

MindVisceral commented 1 month ago

I found a forum post from someone with the same issue: https://godotforums.org/d/29104-shotgun-spread-raycast-from-center-of-screen

Basically, now we use the Player's Camera3D built-in functions to determine start and end positions for each RayCast Bullet. I'm not quite sure how this is better, but it works. I think this may have something to do with the fact that the Camera's view is a flat plane. Using that to cast the Rays just works out much better.

This even allows for only horizontal/vertical spread (or an uneven mix of the two), which is impossible with my flawed "ball of randomness" implementation.

The caveat is that this requires the bullet_start_pos_node (now renamed to player_camera) to be a Camera3D, always. With the way things are now, this could cause problems if I decide to add a 3rd person camera. Fortunately I have no plans for that - if having both First Person and Third Person views in the same game caused design problems for Bethesda in Skyrim, then I won't touch that issue with a 10-foot pole. Then again, maybe I have better chances of coming up with a solution, considering that Bethesda is utterly incompetent at everything they set out to do...

Oh, and this fixes that relation between max_distance and bullet_spread to boot, because it relies on the Camera. Great solution for my use case, really.

NOTE: The 'Bullet' RayCasts are, of course, cast from the Camera, but my Trails are created between the gun's muzzle and the end_pos. In result, when the Player stands close to a wall and shoots, the Bullet will still hit where they were looking, but the Trail created between the gun and the hit position will pass and clip through walls. This is especially jarring on the LMB-21 shotgun (though that might change once I give it a unique Trail).

This was a deliberate choice! I even commented so in the FirearmHitscan script:

NOTE: Since we use a Camera, the Player doesn't have to take the weapon's position into consideration for the weapons to not hit nearby obstacles. As a result, the Player must see their target to hit it.

Standing too close to a wall and missing all your bullets might be realistic, but it isn't fun. Leave that stuff for military shooters or R6S. If I'm forced to sacrifice realism for better gamefeel, that decision won't take me longer than a second. But I admit that this looks quite bad, especially on the shotgun. I better find a lore reason for this.