So I'm currently trying to implement a dash on my Player character(KinematicBody2D) that, when they collide with a wall or floor, they immediately bounce right off into the opposite direction. Think of it like how the dash works for Sparkster on the SNES. I manage to implement a dash well enough but I can't seem to make it ricochet at all; any wall halts all momentum entirely until the dash state finishes. Is there anything I'm doing wrong and is there a way to implement this? Here's the script for the dash:

func _ready():
	dash_timer.connect("timeout", self, "dash_timer_timeout")
	pass

func dash_timer_timeout():
	is_dashing = false

func get_direction_from_input():
	var move_dir = Vector2()
		move_dir.x = -Input.get_action_strength("ui_left") + Input.get_action_strength("ui_right")
		move_dir.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
		
	move_dir = move_dir.clamped(1)
	
	if (move_dir == Vector2(0,0)):
		if(ani.flip_h):
			move_dir.x = -1
		else:
			move_dir.x = 1
			
	return move_dir * dash_speed

func handle_dash(var delta):
	if(Input.is_action_just_pressed("dash") and can_dash):
		is_dashing = true
		can_dash = true
		dash_direction = get_direction_from_input()
		dash_timer.start(dash_length)
	
	if(is_dashing):

		if(is_on_floor()):
			is_dashing = true
		if(is_on_wall()):
			var collision = move_and_collide(motion * delta)
			if collision:
				motion = motion.bounce(collision.normal)
			is_dashing = true
		pass

Welcome to the forums @slamjam29!

Looking at the code, I think what is causing the issue is you do not have a condition that moves the KinematicBody2D unless it is colliding with a wall, at least not that I can see.

I think with a little restructuring, you can handle collisions and movement in the air while still detecting wall hits. Something like this I think might work:

if (is_dashing):
	var collision = move_and_collide(motion * delta)
	
	if (is_on_floor()):
		is_dashing = true
	if (is_on_wall()):
		if collision:
			motion = motion.bounce(collision.normal)
		is_dashing = true

With the code above, the KinematicBody2D should move in the air, on the floor, and against walls, which I think is what you are looking for. What I think may be causing the issue is the collision against the wall is leading the KinematicBody2D to be in the air, which was causing it not to move.

@TwistedTwigleg said: Welcome to the forums @slamjam29!

Looking at the code, I think what is causing the issue is you do not have a condition that moves the KinematicBody2D unless it is colliding with a wall, at least not that I can see.

I think with a little restructuring, you can handle collisions and movement in the air while still detecting wall hits. Something like this I think might work:

if (is_dashing):
	var collision = move_and_collide(motion * delta)
	
	if (is_on_floor()):
		is_dashing = true
	if (is_on_wall()):
		if collision:
			motion = motion.bounce(collision.normal)
		is_dashing = true

With the code above, the KinematicBody2D should move in the air, on the floor, and against walls, which I think is what you are looking for. What I think may be causing the issue is the collision against the wall is leading the KinematicBody2D to be in the air, which was causing it not to move.

The problem isn't the dash itself not working at all, it does detect the walls and floor. It's just the dash doesn't interact with the walls and floor beyond simply either stopping in place or sliding up and down them, when I'm trying to make the KinematicBody2D bounce around like a rubber ball. The suggestion doesn't really help much with that either. Should I post the func physics_process here as well to help with this?

@slamjam29 said:

@TwistedTwigleg said: Welcome to the forums @slamjam29!

Looking at the code, I think what is causing the issue is you do not have a condition that moves the KinematicBody2D unless it is colliding with a wall, at least not that I can see.

I think with a little restructuring, you can handle collisions and movement in the air while still detecting wall hits. Something like this I think might work:

if (is_dashing):
	var collision = move_and_collide(motion * delta)
	
	if (is_on_floor()):
		is_dashing = true
	if (is_on_wall()):
		if collision:
			motion = motion.bounce(collision.normal)
		is_dashing = true

With the code above, the KinematicBody2D should move in the air, on the floor, and against walls, which I think is what you are looking for. What I think may be causing the issue is the collision against the wall is leading the KinematicBody2D to be in the air, which was causing it not to move.

The problem isn't the dash itself not working at all, it does detect the walls and floor. It's just the dash doesn't interact with the walls and floor beyond simply either stopping in place or sliding up and down them, when I'm trying to make the KinematicBody2D bounce around like a rubber ball. The suggestion doesn't really help much with that either. Should I post the func physics_process here as well to help with this?

Oh okay! So its not movement but collision response then. It works fine up until hitting a wall or floor, correct?

Do you have scaled RigidBody2D or StaticBody2D nodes? If so, are they scaled uniformly? Godot in 3D gives skewed normal results if the physics node does not have a uniform scale. KidsCanCode has an old article that seems to show the same effect in 2D with skewed normals, so it may be that it is still present in 2D physics.

Looking at code online, it looks like the code you are using should work.

Oh okay! So its not movement but collision response then. It works fine up until hitting a wall or floor, correct?

Correct.

Do you have scaled RigidBody2D or StaticBody2D nodes? If so, are they scaled uniformly? Godot in 3D gives skewed normal results if the physics node does not have a uniform scale.

Nope, the whole thing is in 2D while the Player only has a KinematicBody2D, CollisionShape2D, and Position2D, while the walls/floor are also KinematicBody2D. Are you saying I should change the Player's type to a rigid/staticbody?

@slamjam29 said:

Oh okay! So its not movement but collision response then. It works fine up until hitting a wall or floor, correct?

Correct.

Okay, cool! :+1:

Do you have scaled RigidBody2D or StaticBody2D nodes? If so, are they scaled uniformly? Godot in 3D gives skewed normal results if the physics node does not have a uniform scale.

Nope, the whole thing is in 2D while the Player only has a KinematicBody2D, CollisionShape2D, and Position2D, while the walls/floor are also KinematicBody2D. Are you saying I should change the Player's type to a rigid/staticbody?

My bad! I should have explained what I meant better :sweat_smile: No, using KinematicBody2D nodes should be fine. What I was asking is whether the KinematicBody2D nodes have a scale applied to them that is non uniform (X != Y), as sometimes that can cause issues with the physics engine in 3D, so I have a hunch that 2D may also have issues with non-uniform scaled objects.

@TwistedTwigleg said: No, using KinematicBody2D nodes should be fine. What I was asking is whether the KinematicBody2D nodes have a scale applied to them that is non uniform (X != Y), as sometimes that can cause issues with the physics engine in 3D, so I have a hunch that 2D may also have issues with non-uniform scaled objects.

I'm sorry, I'm a bit new to all of this and now I'm a bit lost here. How exactly do you look for non-uniform scaled objects?

@slamjam29 said:

@TwistedTwigleg said: No, using KinematicBody2D nodes should be fine. What I was asking is whether the KinematicBody2D nodes have a scale applied to them that is non uniform (X != Y), as sometimes that can cause issues with the physics engine in 3D, so I have a hunch that 2D may also have issues with non-uniform scaled objects.

I'm sorry, I'm a bit new to all of this and now I'm a bit lost here. How exactly do you look for non-uniform scaled objects?

No worries! A non-uniform scaled object is an object whose scale on one axis is different than the other. Here's some example values:

vector2(1, 1) # uniform
vector2(0.5, 1) # non-uniform
vector2(4, 4) # scaled but uniform
vector2(3, 4) # scaled but non-uniform

You can check whether a node has a uniform scale or not by clicking the node in the Godot editor and checking the scale property. If the X and Y values are the same, then it has a uniform local scale. Generally, the local scale is all you need to check, but if the node's parent is scaled, then you will want to check it as well to see if the parent node's scale is uniform as it affects the global scale of the node.

@TwistedTwigleg said:

No worries! A non-uniform scaled object is an object whose scale on one axis is different than the other. Here's some example values:

vector2(1, 1) # uniform
vector2(0.5, 1) # non-uniform
vector2(4, 4) # scaled but uniform
vector2(3, 4) # scaled but non-uniform

You can check whether a node has a uniform scale or not by clicking the node in the Godot editor and checking the scale property. If the X and Y values are the same, then it has a uniform local scale. Generally, the local scale is all you need to check, but if the node's parent is scaled, then you will want to check it as well to see if the parent node's scale is uniform as it affects the global scale of the node.

So I'm assuming that's in the "transform" section, correct? I checked that and they're all (1, 1) so I don't think that's the issue.

@slamjam29 said:

@TwistedTwigleg said:

No worries! A non-uniform scaled object is an object whose scale on one axis is different than the other. Here's some example values:

vector2(1, 1) # uniform
vector2(0.5, 1) # non-uniform
vector2(4, 4) # scaled but uniform
vector2(3, 4) # scaled but non-uniform

You can check whether a node has a uniform scale or not by clicking the node in the Godot editor and checking the scale property. If the X and Y values are the same, then it has a uniform local scale. Generally, the local scale is all you need to check, but if the node's parent is scaled, then you will want to check it as well to see if the parent node's scale is uniform as it affects the global scale of the node.

So I'm assuming that's in the "transform" section, correct? I checked that and they're all (1, 1) so I don't think that's the issue.

Yup, its in the transform section. Okay, so if everything is (1, 1) then its something else.

The next thing I'd probably recommend trying is seeing if setting the motion is working by simply modifying it. That can help determine if the conditions are part of the issue or not. I'd probably try flipping motion on a wall hit:

	if (is_on_wall()):
		var collision = move_and_collide(motion * delta)
		if collision:
			#motion = motion.bounce(collision.normal)
			
			# For testing, just flip motion so it goes the other way.
			# If this works, then the line above may be the issue.
			motion = -motion
		
		is_dashing = true

@TwistedTwigleg said:

Yup, its in the transform section. Okay, so if everything is (1, 1) then its something else.

The next thing I'd probably recommend trying is seeing if setting the motion is working by simply modifying it. That can help determine if the conditions are part of the issue or not. I'd probably try flipping motion on a wall hit:

	if (is_on_wall()):
		var collision = move_and_collide(motion * delta)
		if collision:
			#motion = motion.bounce(collision.normal)
			
			# For testing, just flip motion so it goes the other way.
			# If this works, then the line above may be the issue.
			motion = -motion
		
		is_dashing = true

I tried it and the dash seems completely unaffected. So it seems like the problem is with the conditions itself, but the question is how do I fix this?

@slamjam29 said:

@TwistedTwigleg said:

Yup, its in the transform section. Okay, so if everything is (1, 1) then its something else.

The next thing I'd probably recommend trying is seeing if setting the motion is working by simply modifying it. That can help determine if the conditions are part of the issue or not. I'd probably try flipping motion on a wall hit:

	if (is_on_wall()):
		var collision = move_and_collide(motion * delta)
		if collision:
			#motion = motion.bounce(collision.normal)
			
			# For testing, just flip motion so it goes the other way.
			# If this works, then the line above may be the issue.
			motion = -motion
		
		is_dashing = true

I tried it and the dash seems completely unaffected. So it seems like the problem is with the conditions itself, but the question is how do I fix this?

What I would recommend in this case is to add print statements around key points in the code. The first I would add is one that prints is_on_wall to see if it ever becomes true. What I would do is add the statement after if (is_on_wall()): so the console isn't spammed with print statements. If is_on_wall is returning true, then I would delete that print statement and add one that prints collision to see what it returns.

Its slow and tedious, but I have found selectively printing the data you are working with can be a good way to narrow down exactly what part of the code is not working, especially with collisions.

@TwistedTwigleg said:

What I would recommend in this case is to add print statements around key points in the code. The first I would add is one that prints is_on_wall to see if it ever becomes true. What I would do is add the statement after if (is_on_wall()): so the console isn't spammed with print statements. If is_on_wall is returning true, then I would delete that print statement and add one that prints collision to see what it returns.

Its slow and tedious, but I have found selectively printing the data you are working with can be a good way to narrow down exactly what part of the code is not working, especially with collisions.

Alright, so I tried printing "is_on_wall" and it actually returns true whenever I hit a wall. However, when I print collisions, I'm getting rather inconsistent results depending how I collide into it. If I dash forward, it returns "[KinematicCollision2D:1361]" or "[KinematicCollision2D:1374]". However, if I dash at an angle, I simply get "[Object:null]". Are either of these normal or part of the problem?

8 days later

Well, after about a week of no response, I went ahead and figured it out on my own. For anyone curious, here's my completed dash that bounces off walls. If anyone has any suggestions to optimize it, I will gladly appreciate it:

	func handle_dash(var delta):
		if(Input.is_action_just_pressed("dash") and can_dash):
			is_dashing = true
			can_dash = true
			dash_direction = get_direction_from_input()
			dash_timer.start(dash_length)
		
		if(is_dashing):
			if (is_on_floor()):
				is_dashing = true
				if get_slide_count() > 0:
					var collision = get_slide_collision(0)
					if collision != null:
						dash_direction = dash_direction.bounce(collision.normal) 
			if (is_on_wall()):
				if get_slide_count() > 0:
					var collision = get_slide_collision(0)
					if collision != null:
						dash_direction = dash_direction.bounce(collision.normal) 
				is_dashing = true
	
			pass
2 years later