Detect collision between StaticBody2D and CharacterBody2D

Godot Version

v4.2.2.stable.official [15073afe3]

Question

For some context, this is the first ever thing I’m making in Godot (and the first ever game I’m making)

I’ve got a CharacterBody2D (Player) with a CollisionShape2D, and a StaticBody2D (Level) with several CollisionShape2Ds. I want to detect the moment when the Player collides with any of the individual CollisionShape2Ds in the Level, and have it trigger something.

I’m using move_and_slide(), because I want the player to be able to slide along a surface, but I want them to do this only after having landed and stopped.

I got this working by storing the is_on_wall() values for the previous frame and the current frame, when the previous is False and the current is True, it stops the player, otherwise it lets the player slides. (Motion Mode is set to floating, so “floors” and “ceilings” also return true for is_on_wall())

But this feels like a hacky workaround, and doesn’t work for detecting a new collision while sliding. And, is_on_wall() is kind of inconsistent, sometimes it goes false for a frame after starting the slide.

I imagine I could do something with area2D nodes, since they can detect when something enters them, but it feels unnecessarily inconvenient to need an area2D for every CollisionShape2D in the Level. And they wouldn’t be very accurate, since they’d have to stick out from the CollisionShape2D to detect the Player entering.

I’m pretty sure there’s something I’m doing fundamentally wrong here, considering my inexperience and how complicated this simple of a problem has been to solve. If that’s the case, please let me know.

Edit to describe the desired behavior:

  • The player should be launched in a straight line towards the mouse when pressing a “launch” button. This should only happen if the player is on a surface, not in the air.
  • The player should stop upon impacting any surface in the level.
  • If the launch key is pressed again after landing, the player should be launched again in whatever direction the mouse is
  • If the mouse is “behind” the surface is landed on when the “launch” key is pressed, the player should slide across the surface.
  • While sliding, the player should not be able to launch itself.
  • The player should stop sliding upon encountering any new surface, allowing the player to launch again

This issue may be caused by the order in which you handle the simulation. Here is another post I wrote:

I noticed this issue while working on physics simulations with the state machine, where a slight change in the order impacted the simulation quality.

I figured out what was causing the inconsistency with is_on_wall(). I had another piece of code setting X and Y velocities to 0 if they were too low, that apparently messes with is_on_wall().

I did this because of another problem. The Player is supposed to only be able to move when they are standing still (can’t move in air, or while sliding), but when hitting a corner while sliding, the velocity is maintained, even though the Player doesn’t move.

I tried using get_real_velocity(), but it seems whenever the velocity is moving the player into a platform, the “real velocity” is not set to 0. Instead it alternates between a few different values that add up to 0 over a few frames. This means that while the character’s movement is practically perfect, neither velocity nor get_real_velocity() can be checked against 0 to see if the character is still.

I can check of both of the “Real velocities” are under a certain value (they don’t seem to go above 6 or 7 while “moving” into a wall) to see if the character is in a corner. But that won’t work for when the player encounters an angled surface during a slide. Instead, it’ll just continue sliding.

All that to say I still need a built-in way to detect collisions between a CollisionShape2Ds in a CharacterBody2D and a StaticBody2D :sweat_smile:

Or to know if I should be using different nodes lol