I’m not using move_and_slide / collide, and I’ll post my code below. Let me explain what is happening first.
The player spawns in the air and falls to the ground with a “feet” area2d as its child that acts as the collision. The “feet” initially lands snugly inside the ground area, but if I jump and land again, the feet are a few pixels below the ground, and then the player falls straight through the floor on the second jump.
The structure of the player is:
Node2D (Parent Node) → Player script attached
Area2D “Feet” → Feet script attached, child of the Node2D
CollisionShape2D of the area above.
And now the code for the player and feet:
PLAYER
extends Node2D
static var gravity_resistance : float = 0.0
var player_gravity : float
var move = Enums.move_state
^ From an autoload that holds a bunch of enums I didn't include.
var min_jump_time : float = 0.1
var max_jump_time : float = 0.4
@onready var MOVE_STATE = move.fall
func _physics_process(delta):
apply_gravity(delta)
move_state()
func apply_gravity(delta) -> void:
player_gravity = (Room.room_gravity - gravity_resistance) * delta
#Room gravity is 600
position.y += player_gravity #This is a value of 10 while falling (with delta, 600 otherwise), -10 while jumping, and 0 when on the ground.
func move_state() -> void:
var pos = Vector2(position)
match MOVE_STATE:
move.fall:
search_transition("jump", pos)
move.jump:
jump()
func search_transition(parameter : String, pos) -> void:
var y_axis = Input.get_axis("down","up")
if parameter == "jump":
if Input.is_action_just_pressed("space") && y_axis != -1:
MOVE_STATE = move.jump
func jump() -> void:
gravity_resistance = Room.room_gravity * 2 #player_gravity becomes -600
await get_tree().create_timer(min_jump_time).timeout
if !Input.is_action_pressed("space"):
gravity_resistance = 0
MOVE_STATE = move.fall
else:
await get_tree().create_timer(max_jump_time).timeout
gravity_resistance = 0
MOVE_STATE = move.fall
Room_gravity is a constant 600. apply_gravity()'s in the player script player_gravity = (Room.room_gravity - gravity_resistance) * delta
is what I was referencing for #600 - 600, AKA 0, where room_gravity is the first 600 and the player’s said
resistance to gravity the latter, making the player’s change in y position when applied 0: position.y += player_gravity
I’m essentially trying to use gravity_resistance as the only variable that can change the player’s y position.
I’m not sure what signal callback would be, area_entered in the feet? Or when the static var gravity_resistance is changed? I’m not using actual signals so that’s confusing me. What would be my best alternative, to change gravity_resistance inside of physics_process after area_entered emits a signal?
It’s a classic example of “fast bullets, thin walls” gamedev problem, except it your case it’s a feet Area2D instead of a bullet.
Physics is games are simulated in a discrete way. That means that a movement of a physics body is not continuous like in real life, it is simulated only in discrete points of space, 60 times per second. The state between these points is not evaluated. Strictly speaking a body just teleports short distances 60 times per second creating an illusion of movement.
What happens with “too fast bullets, too thin walls” is that at a frame 1 the bullet is right in front of a wall, but doesn’t touch it so no collision is reported. On the next frame the bullet travels a great distance because of its great velocity, so on frame 2 the bullet is already behind the wall. No collision is reported, because there was no frame where the wall and the bullet clearly intersect.
It boils down to: if a collision body moves with a velocity which length is greater than a thickness of colliders, it may go through said colliders without ever reporting a collision.
TL;DR: your feet area is too small for the velocity the player is moving when falling. And your floor is too thin. In cases like these people use raycasts with length set to the length of the velocity vector, not areas. Raycasts can report a collision at any point along the line of the raycast, not only on the very tip.