Player stuck between other player and wall

In this situation, RED player can’t move and remains stuck between BLUE player and wall, no idea of how can i fix this.

Walls are tilemaps with collisions. Players are CharacterBody2D.

Here’s my code:

extends CharacterBody2D

var speed: float = 500.0
var moving: bool = false
var move_dir: Vector2 = Vector2.ZERO

func _ready() -> void:	
	$PlayerAnimation.play("Idle")

func _physics_process(delta):
	if not moving:
		read_input()
	else:
		var collision = move_and_collide(move_dir * speed * delta)
		if collision:
			var collider = collision.get_collider()
			stop_movement()
		else:
			play_walk_animation()
	
	
func read_input():
	if IsSelected == false:
		return
	var dir := Vector2.ZERO
	if Input.is_action_pressed("ui_right"):
		dir = Vector2.RIGHT
	elif Input.is_action_pressed("ui_left"):
		dir = Vector2.LEFT
	elif Input.is_action_pressed("ui_down"):
		dir = Vector2.DOWN
	elif Input.is_action_pressed("ui_up"):
		dir = Vector2.UP
		
	if dir != Vector2.ZERO:
		move_dir = dir
		moving = true

func play_walk_animation():
	match move_dir:
		Vector2.RIGHT:
			$PlayerAnimation.play("Walking_Right")
		Vector2.LEFT:
			$PlayerAnimation.play("Walking_Left")
		Vector2.DOWN:
			$PlayerAnimation.play("Walking_Down")
		Vector2.UP:
			$PlayerAnimation.play("Walking_Up")

func stop_movement():
	moving = false
	move_dir = Vector2.ZERO
	$PlayerAnimation.play("Idle")

Any help is appreciated!

Thank you!

It looks like that any collision will stop movement. Make your collision shapes smaller and see if the character can move then.

1 Like

Put all the players on a physics layer 2. Turn off physics layer 1 for them. Leave Physics Mask 1 on. Leave Physics mask 2 off. They will see walls and hit them, but will not run into each other.

1 Like

This way players will not collide, i need them to collide to block pathway

In which direction are you trying to move the player in the screenshot @Fpaez?

If it’s to the left, @dragonforge-dev ‘s answer should suffice, but if it’s down, I agree with @paintsimmon, it seems there’s something happening with your collision shapes preventing movement.

Are you using a grid, because the collision shapes seem not to be aligned on a grid specifically (At least not the same size as the tileset).

2 Likes

I’m trying to move the red player to the bottom down but it remains stuck, if i move the blue player to the left i can move the red player without problem.

Have you tried @paintsimmon’s suggestion? If you decrease the size of the collision, what happens?

1 Like

Yes, i’ve tryed to reduce the size of CollisionShape2D and use rounded shapes, same problem in both attempts.

I’m not so clued up on Godot since I’m a novice to it, but based on my own experiences with other engines I can think of a couple of ways that might work for you.

  1. Presuming that when two players meet they become locked in a constant collision check, on collision:
    Move one or both colliding players a pixel in the opposite direction in code to stop the collision (make them bounce off each other slightly).
    This method probably won’t work as it’s possible they’re colliding with both the wall and the player at the same time and that’s why movement is stuck.

  2. Raycast2D ( How to RayCast LineTrace in Godot - Blue Robot Guru ), modify your code so that if a collision occurs, do a short trace from the player origin to up, down, left and right and set movement direction booleans based on the collision.

Then, rather than stopping the player outright as you currently do, use a modified version of your movement code to then prohibit movement in that direction (so, do no movement, but play the idle animation).

However, if the key press is in a permitted direction, then apply the movement/walking animation and also set all the movement booleans to permit full movement again.

1 Like

Wow!, awesome, thank you!

Raycast seems a good way to fix this!

Finally i’ve discarded the use of raycast as i faced the same problem so i’ve used 1px knockback. Here’s the code:

func _physics_process(delta):
	if not PlayerIsMoving:
		read_input()
	else:
		var collision = move_and_collide(PlayerDirection * PlayerSpeed * delta)
		if collision: 
			var collider = collision.get_collider()
			if collider.name == "Scenario":
				stop_movement()
			else:
				KnockBack()
		else:
			play_walk_animation()
func KnockBack():
	global_position -= PlayerDirection 
	stop_movement()

Now all works ok and player can’t notice the 1px movement.
Thanks all or your help!! :slight_smile:

2 Likes