MindVisceral / EZGame

1 stars 0 forks source link

Basic Player-Wall movement (WallRunning, WallJumping, sliding down walls) #29

Open MindVisceral opened 7 months ago

MindVisceral commented 7 months ago

Wallrunning: When the Player gets close to a wall, isn't touching the ground, and moves horizontally along the wall, they will stick to it and will fall down much slower.

Sliding down a wall: When the Player gets close to the wall, isn't touching the ground, isn't wall-running (isn't moving horizontally), and is moving down vertically, they will slowly slide down the wall.

Walljumping: When the Player gets close to a wall, isn't touching the ground, and presses the "jump" button, they will be launched at the negative direction of the wall's normal (away from the wall perpendicularly).

MindVisceral commented 7 months ago

Implementation proposal:

Wall detection could be done either with many raycasts or a cylinder (a ShapeCast) surrounding the Player on all sides. I'm leaning more towards the cylinder; using raycasts seems to be less performant, and it makes it more annoying to deal with all the edge cases.

In case the Player is near many walls, we loop through them all and pick the one that is the closest to the Player's center; let the engine figure it out.

MindVisceral commented 7 months ago

Since Trenchbroom is used to make most walls, which are then turned into StaticBodies depending on a brush's group, most walls (that intersect) are part of the same StaticBody. So checking for the nearest wall is likely unnecessary, unless I'm missing something here.

Getting a wall's normal is more important for these Wall movement features.

MindVisceral commented 6 months ago

Walljumping works very well as of 2024.02.21

MindVisceral commented 6 months ago

Walljumping works very well as of 2024.02.21

No it fucking doesn't! It didn't work back then either! Because it never triggered for more than a frame! Look at https://github.com/MindVisceral/EZGame/issues/32#issuecomment-1965177199

MindVisceral commented 6 months ago

Wallrunning (and sliding down a wall) now works only if the Player is 'moving at a wall'.

To get if the Player is indeed smushed up against a wall, we make a Vector2 from X- and Z-axes of the Player's velocity, and we take the dot product between that Vector2, and the nearest wall's normal (we get this normal through find_closest_wall_normal(), which, I forgot to mention, was added as of https://github.com/MindVisceral/EZGame/issues/29#issuecomment-1957778387).

If this dot product is below a certain arbitrary value (0.11 for now; this is to be tested!), then the Player is not smushed up against a wall, so they aren't wallrunning. So they fall. The result of this is that the Player must be moving towards a wall at (at least) a small angle to run on a wall. This goes for sliding down a wall too.

NOTE: This ULTRAKILL-like implementation goes directly against the implementation that makes the Player stick to a wall until they stop sticking to a wall - that would be a SPRAWL-like implementation. That implementation would allow the Player to shoot while wallrunning, but I don't think I care for a mechanic like that. We'll see as we go on.

NOTE: This system is likely to also work with a controller, though the way input_dir is calculated right now prevents that. But that's a separate issue.

POSSIBLE PROBLEM: I'm not sure how this system interacts with slanted walls and ramps! The WallDetection ShapeCast should prevent the Player from wallrunning on low slopes, but slanted walls might still be an issue.

I'm quite proud of myself! This is some pretty good work.

MindVisceral commented 6 months ago

Found a bug: Since all TrenchBroom geometry and collisions are imported as polygons instead of simpler shapes, Godot's physics are a little more difficult to calculate.

This would be fine, but I use a CylinderShape3D for the WallDetectionCast, and those are currently very buggy, as they've been since Godot 3.4.2 at least. Fucking bastards, again. As a result, the WallDetectionCast just doesn't detect anything sometimes. It works fine for simpler Colliders, like a box, but it's fucked when it comes to Polygons.

I'm switching the WallDetectionCast's shape to a Capsule. Those suck due to their forced radius/height ratio, but this will have to do.

Two fucking years and such a basic issue persists! Allow us to use Jolt! I might just switch to it if it isn't much of a bother.

MindVisceral commented 6 months ago

Switched over to Godot Jolt. It seems to have caused its own issues (see #34), but the above bug is fixed. Cylinders are actually very buggy across all engines, or so I've heard. Still, it works well for now.

MindVisceral commented 6 months ago

Walljumping works very well as of 2024.02.21

Now, walljumping works well. Up until now it was affected by the previous state's vertical velocity, which often made the walljump weaker, because the Player was previously falling. It's also completely unlimited for now, i.e. you may walljump as many times as you want, but that will have to change once it's time for balancing.

MindVisceral commented 6 months ago

Turns out the Player couldn't walljump when in the stomp state and that the walljump state didn't check if the Player was is_moving_at_wall() before changing to wallrun_state, so I fixed that real quick.

While testing that, I realized that is_moving_at_wall() should work depending on Player Input, not actual Player velocity, because if velocity is used, then the wallrun_state is activated even if the Player isn't pressing any buttons.

MindVisceral commented 6 months ago

is_moving_at_wall() should work depending on Player Input, not actual Player velocity, because if velocity is used, then the wallrun_state is activated even if the Player isn't pressing any buttons.

but velocity must be used for the calculation itself, because move_and_slide() accounts for wall colliisions, which modifies velocity - and we use that to see if the Player is smushed up against a wall. But Player Input doesn't account for that, it's always flat!

I see a simple solution, though; We check if the Player is Inputting anything just to make sure they cannot stick to a wall if they aren't. This can go either into all the states which use is_moving_at_wall(), or into is_moving_at_wall() itself.

MindVisceral commented 6 months ago

I see a simple solution, though; We check if the Player is Inputting anything just to make sure they cannot stick to a wall if they aren't. This can go either into all the states which use is_moving_at_wall(), or into is_moving_at_wall() itself.

Done that.

MindVisceral commented 6 months ago

This whole system seems to work pretty well, but I think walljumping between two walls doesn't feel quite right. But it's hard to notice, so I will deal with that once I have a better testing level and the world's scale is properly set up. Everything looks so big right now. My own fault, obviously; the actual game levels likely won't be this big.