Physics or collision problems

Godot Version

4.3

Question

Hello! Can someone explain this to me? When I move the box to the wall, it jumps above my character. Here are some scripts for the player and the box. The box is also very bouncy, no matter how much I change its mass or gravity.

player.gd
extends CharacterBody2D

const SPEED: float = 425.0
const JUMP_VELOCITY: float = -370.0

@onready var animated_sprite: AnimatedSprite2D = %AnimatedSprite2D

func _physics_process(delta: float) -> void:
  if not is_on_floor():  # Гравитация
    velocity.y += get_gravity().y * delta
  if Input.is_action_just_pressed("JUMP") and is_on_floor():  # Прыжок
    velocity.y = JUMP_VELOCITY

  var direction: float = Input.get_axis("MOVE_LEFT", "MOVE_RIGHT")  # Направление движения
  if direction > 0:
    animated_sprite.flip_h = false
  if direction < 0:
    animated_sprite.flip_h = true

  if is_on_floor(): 
    if direction == 0:
      animated_sprite.play("IDLE")
    else:
      animated_sprite.play("RUN")

  if direction != 0:
    velocity.x = direction * SPEED
  else:
    velocity.x = move_toward(velocity.x, 0, SPEED)

  move_and_slide()
  
  
  for index: int in range(get_slide_collision_count()):
    var collision := get_slide_collision(index)
    var collider := collision.get_collider()
    
    if collider is RigidBody2D:
      var box: RigidBody2D = collider
      var push_power := 2.0
      
      var box_collision := box.move_and_collide(Vector2(velocity.x * delta, 0))
      if box_collision:
        var box_collider := box_collision.get_collider()
        # Исправленная проверка группы с приведением типа
        if box_collider is Node:
          var node_collider := box_collider as Node
          if node_collider.is_in_group("wall"):
            continue
      
      var push_force := Vector2(
        clamp(velocity.x, -SPEED, SPEED) * delta * push_power as float,
        0
      )
      
      if abs(velocity.x) > 10:
        box.apply_central_force(push_force)
      
      box.linear_velocity.y = clamp(box.linear_velocity.y, -50 ,50)
Box.gd
extends RigidBody2D

# Called when the node enters the scene tree for the first time.
func _ready() -> void: 
  freeze_mode = RigidBody2D.FREEZE_MODE_KINEMATIC # Опционально


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
  pass

Looks like a classic rigid collision problem. The box gets slightly embedded in the wall, or slightly embedded in your character (or both) and the only way to unembed is to go up, so that’s what it does.

Can you explain how to fix it? Please?

I haven’t used godot’s physics so I’m not sure of the precise way to fix it, and I think the fix is also going to depend on what you ultimately want the game to do.

In principle (I think?) you could fix your current code by making it so that the player is much easier to push back; the problem looks to me like the box is getting squished between the player and the wall, and winds up unembedding upwards. If you can get the player to unembed first, away from the box, then the box will be able to unembed without going up, though it may take several resolution cycles to happen.

Where this becomes a problem, though, is if you want the player to be able to jump between the block and the wall to push the block away from the wall; if the block is too close, the player may launch instead. Or if you’re going to have multiple blocks and something other than the player can move them. Or, for that matter, if you have a row of two blocks and the player pushes them into a wall.

There are a lot of tradeoffs in game physics; you can do neat stuff, but there are cases like this where the simplified simulation causes undesirable effects. If all you want to be able to do is let the player push blocks horizontally and have them slide, stop at walls, and maybe fall down holes, you might be better off building that by hand rather than using a full physics system. You probably want to either build a system that simply doesn’t allow embedding (that is, check for possible collision before moving, only move if you won’t collide), or build a system where you can prioritize and hand-control embedding resolution.

1 Like

Maybe this would help:

https://kidscancode.org/godot_recipes/4.x/physics/character_vs_rigid/index.html

1 Like