How do I play the sound of a fall when a character has fallen?

Godot Version

Godot 4.2.1

Question

Please tell me, how do I play the sound of falling every time a character (CharacterBody2D) lands on the surface?
The AudioStreamPlayer node is already ready and all I have to do is add this sound.

Select the AudioStreamPlayer in your scene tree. You can add a sound file in the inspector. Then just call get_node("AudioStreamPlayer").play() once the player hits the ground. (Depending on where exactly your node is located, the node path might be different here, of course!)

If your question is actually about how to detect when the player lands on the ground, the easiest way would probably be to just poll is_on_floor() every frame – if it was false in the previous frame, but is true now, the character just landed!

1 Like

Thanks for the answer! The fact is that I just don’t understand how I can check is_on_ground_() every frame. Can you please give an example from the code or explain how to do it?

extends CharacterBody2D

const GRAVITY := 980 # pixels per second

var was_on_floor

func _physics_process(delta: float) -> void:
	velocity.y += GRAVITY * delta
	move_and_slide()

	if not was_on_floor and is_on_floor():
		print("Just landed!")

	was_on_floor = is_on_floor()

An even simpler version would be to just check if velocity.y == 0, although that assumes that you apply constant gravity each frame and there are no cases where gravity is canceled out.

this topic is tagged as c#…

Yes, I write in C#, but I also know GDScript a bit so that I can translate GDScript code into C#

1 Like

This code worked, but now, when I turn on the game, the sound of jumping turns on, although I did not jump…

was_on_floor
try start with true, your initial jump sound should be off. Is time to plan all interaction, you can try code state machine too

1 Like

:grimacing: For future readers, this would be the C# version:

public partial class CharacterBody2D : Godot.CharacterBody2D
{
	public const int GRAVITY = 980; // pixels per second
	public bool wasOnFloor = true;

	public override void _PhysicsProcess(double delta)
	{
		Vector2 velocity = Velocity;
		if (!IsOnFloor()) {
			velocity.Y += GRAVITY * (float)delta;
		}
		Velocity = velocity;
		MoveAndSlide();

		if (!wasOnFloor & IsOnFloor()) {
			GD.Print("Just landed");
		}

		wasOnFloor = IsOnFloor();
	}
}
1 Like

Let me just send the code, because the character still plays the sound of falling when spawning and I don’t understand what to do with it…

public partial class hero : CharacterBody2D
{
	public const float Speed = 300.0f;
	public const float JumpVelocity = -400.0f;
	[Export] Sprite2D imageHero;
 	[Export] AudioStreamPlayer walking_music;
	[Export] AudioStreamPlayer jumping_music;
	[Export] AudioStreamPlayer falling_music;
	bool isWalking = false;
	bool isJump = false;
	bool wasOnFloor = false;
	public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();

	public override void _Ready() 
	{
		spawn();
	}
	public override void _PhysicsProcess(double delta)
	{
		
		Vector2 velocity = Velocity;
		Vector2 screenSize = GetViewportRect().Size;

		if (!IsOnFloor()) {
			velocity.Y += gravity * (float)delta;
			isJump = true;
		}
		else {
			isJump = false;
		}
		
		
		if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) 
		{
			velocity.Y = JumpVelocity;
			jumping_music.Play();
		}
		
		if (!wasOnFloor && IsOnFloor())
		{
			falling_music.Play();
		}
		
		wasOnFloor = IsOnFloor();

		Vector2 direction = Input.GetVector("goLeft", "goRight", "goUp", "goDown");
		if (direction != Vector2.Zero)
		{
			if (!isWalking && !isJump) {
				walking_music.Play();
			}
			velocity.X = direction.X * Speed;
			isWalking = true;
		}
		else
		{
			isWalking = false;
			velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
		}
		
		if (velocity.X > 0) {
			imageHero.FlipH = false; 
		}
		else if (velocity.X < 0) {
			imageHero.FlipH = true; 
		}
		
		Velocity = velocity;
		MoveAndSlide();
		
		
		if (velocity.Y > screenSize.Y) {
			GetTree().ReloadCurrentScene();
		}
		if (!isWalking || isJump == true) {
			walking_music.Stop();
		}
		if (isWalking == true && isJump == true) {
			walking_music.Play();
		}
		if (IsOnFloor() == false) {
			walking_music.Stop();
		}
	}
	public void spawn() 
	{
		Position = Other.position;
	}
}

I think you should clean your code. Make basic state machine, with states like: Jump, Fall, Walk, Idle. can be enum for beginning( but if you can make basic state class and inherit all states from it. you can have better control). I don’t think you want any AudioStreamPlayer to .Play() every _PhysicsProcess. Use GD.Print() to check what going on in your code or debugger.
Your audio is in loop?
if you don’t plan play two audio at the same time you can use less AudioStreamPlayers. just change Stream with any AudioStream and play.

you create new methods and use in _PhysicsProcess like AudioUpdate and StateUpdate.
in your StateUpdate you do all state logic and check if is changed. And if is changed you AudioUpdate to play correct audio.

add something like

GD.Print($"Player fall at {Position}");

in

		if (!wasOnFloor && IsOnFloor())
		{
			falling_music.Play();
		}

and you will know how many times this code was triggered