Godot Version
4.5.1 Stable
Question
I am working on a Wall Cover mechanic, whereby if you are against the wall and push a button while moving, you will automatically take cover on the wall.
I use state machines for my player’s movement, I have the switch over to my “Wall” state in my “Running State” with the following code under my state machine level _input function;
if player.is_on_floor() and player.is_on_wall() and Input.is_action_just_pressed("testcrouchidle") and player.get_floor_angle() == 0.0:
lastwall = player.get_wall_normal()
state_machine.change_state("Wall")
This code works fine, posted just in case it’s relevant to troubleshooting.
Additional Context
player.get_floor_angle() == 0.0 is to check for standing on a slope/stairs to ensure that my player can only take cover on while standing on a flat surface
lastwall is a state machine level Vector3 variable that only gets updated here when switch from Running to Wall state specifically. I will explain the intentions behind lastwall later
Switching to Wall state now, it’s not complete at all, moving on the wall will be its own state that I have not created just yet, but all the dirty work I’m doing here should translate into that state (hopefully). The first thing I wanted to do was to stick the player to the wall, which was easy, using player.velocity.x = move_towards along with player.move_and_slide modifiers to keep player stopped on the wall. I found a circuitous method to flip my player model so that their back is against the wall on both x and z axes.
It “works” but I’m running into some issues. But for now I’ll post the code;
func Enter():
print("you are in wall cling")
var wallangle = player.get_wall_normal().normalized().x * (TAU / 2)
player.basis = player.basis.rotated(player.up_direction, wallangle)
var wallangle2 = player.get_wall_normal().normalized().z * (TAU / 2)
player.basis = player.basis.rotated(player.up_direction, wallangle2)
player.basis.orthonormalized()
func handle_input(_event: InputEvent):
if Input.is_action_just_pressed("testcrouchidle"):
state_machine.change_state("idle")
func Physics_Update(_delta: float):
var input_vector = Input.get_vector("testrunleft", "testrunright", "testrunforward", "testrundown")
var _direction := (player.transform.basis * Vector3(input_vector.x, 0, input_vector.y)).normalized()
print(player.get_wall_normal().normalized())
if player.get_wall_normal().normalized() == Vector3.ZERO:
player.position += lastwall * -Vector3.ONE
else:
player.velocity.x = move_toward(player.velocity.x, 0.0, SPEED)
player.velocity.z = move_toward(player.velocity.z, 0.0, SPEED)
player.move_and_slide()
func Exit():
var wallangle = player.get_wall_normal().normalized().x * (TAU / 2)
player.basis = player.basis.rotated(player.up_direction, wallangle)
var wallangle2 = player.get_wall_normal().normalized().z * (TAU / 2)
player.basis = player.basis.rotated(player.up_direction, wallangle2)
player.basis.orthonormalized()
Core Issue
When approaching a wall at certain angles, entering Wall state returns a get_wall_normal.normalized() value of Vector3(0.0, 0.0, 0.0), whereas I am looking for either the x value (vertical wall) or the z value (horizontal wall) to be -1.0/1.0. Exiting Wall state with my wall_normal returning Vector3.ZERO will either invert my controls or invert the rotation of my player character (this is a side effect of how my controls are set and the variance depends on whether or not my camera is in a certain position and rotation, a symptom, not the root problem).
I need a way to either avoid getting a Vector3.ZERO returned altogether or a contingency if statement that fixes the problem
Additional Context
So in this code are my attempts at mitigating my wall_normal value returning Vector3.ZERO, which includes my aforementioned lastwall variable, which copies the last wall_normal value of my Running state (and only updates in the transition between Running and Wall). wall_normal values are fine in Running state, always detects a wall (I used the same print command seen above in Running State).
In my state machine level _*physics process, I have attempted to force my player against the wall and see if it returns a valid wall_*normal value, I’ve tried using velocity, position and global_position, increased by the lastwall value, multiplied by negative Vector3.ONE to ensure opposite movement to the correct wall collision, this does not work. I can still get Vector3.ZERO values returned.
I call my rotations twice each upon entering and exiting the state, because I would get the same problem (inverted controls/rotation) even with valid wall_normal values if I only ran the rotation once. I would have to enter Wall state again to fix it. If the rotation script put in _physics_process, i get a funky jittery rotation because it may be interfering with my player _physics_process script which controls rotations based on velocity.
Could also use help with
idk if it’s related or not to the issue, but it’s something I’m going to have to deal with eventually, moving parallel to the wall while up against it returns a valid wall_normal value, which is fine, but the player model only rotates against the direction they are facing when entering Wall state, and of course, I’d like them to put their back to the wall regardless of which direction they are facing so as long as the wall_normal value is valid.
(Sometimes doing this also returns a Vector3.ZERO)
