How to use constant_torque with move_and_collide on a RigidBody2D?

Godot Version

4.2.1

Question

I’m trying to learn game development moving from web development and I’m starting experimenting with a simple 2d physics based game. It is a spaceship navigating an asteroid field. This is my code for the ship rigid body:

const TORQUE = 4e6
const MAIN_DRIVE_FORCE = 1e6
const RCS_FORCE = 1e5


func _ready():
    mass = 10e3
    can_sleep = false
    gravity_scale = 0.0
    linear_damp = 0
    contact_monitor = true
    max_contacts_reported = 10
    

func _process(_delta):
    constant_torque = 0
    constant_force = Vector2.ZERO

    if Input.is_physical_key_pressed(KEY_Q):
        constant_torque = -TORQUE
    if Input.is_physical_key_pressed(KEY_E):
        constant_torque = TORQUE

    if Input.is_physical_key_pressed(KEY_W):
        add_constant_central_force(Vector2(RCS_FORCE * cos(rotation), RCS_FORCE * sin(rotation)))

    if Input.is_physical_key_pressed(KEY_S):
        add_constant_central_force(Vector2(RCS_FORCE * cos(rotation + PI), RCS_FORCE * sin(rotation + PI)))

    if Input.is_physical_key_pressed(KEY_D):
        add_constant_central_force(Vector2(RCS_FORCE * cos(rotation + PI / 2), RCS_FORCE * sin(rotation + PI / 2)))

    if Input.is_physical_key_pressed(KEY_A):
        add_constant_central_force(Vector2(RCS_FORCE * cos(rotation - PI / 2), RCS_FORCE * sin(rotation - PI / 2)))

    if Input.is_physical_key_pressed(KEY_SHIFT):
        add_constant_central_force(Vector2(MAIN_DRIVE_FORCE * cos(rotation), MAIN_DRIVE_FORCE * sin(rotation)))

    var acc := constant_force / mass
    var v := linear_velocity
    # var collision = move_and_collide(v + acc * _delta)

    # if collision:
    #     var collider := collision.get_collider()
    #     var col_position := collision.get_position()

    #     print("collided with ", collider, " at ", col_position)

    print("torque: ", constant_torque, "  ang_v: ", angular_velocity, "  force: ", constant_force, "  acc: ", acc, "  v: ", v)

If I keep it like that, it works perfectly.

The problem happens when I uncomment the last lines to detect collisions with the asteroids. If I do that, the ship rotation breaks completely. It doesn’t rotate for a while, then it jumps to a higher angle on one frame, then it does nothing for a few seconds more, then it jumps to an even higher angle, etc…

What is going wrong here? Is there a better way to get the KinematicCollision2D without using move_and_collide?

I think the problem is because you’re mixing the add_constant_central_force with the move_and_collide, the add/apply methods is to let the physics engine handle all the physics while the move_and_collide is for you handle the physics manually

Also there’s a better way for you get the collisions with your rigidbody, use the
body_entered signal

RigidBody2D — Godot Engine (stable) documentation in English

2 Likes

I kinda tried that.

func test(collider):
    print("Collided!",collider)

func _ready():
    ....    
    connect("body_entered", test)
    ....

The problem is I’m only getting the collider node there, I also want to get the collision position, because in some cases, it will collide with a tilemap, and I need to know exactly on which tile is it colliding to remove it.

That why I think I need the KinematicCollision2D and not only the node

In this case use body_shape_entered signal and Tilemap.get_coords_for_body_rid(), that will return the tilemap coordinate of the collision:

func _on_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
	if body is TileMap:
		var collision_tile_coord = body.get_coords_for_body_rid(body_rid)
1 Like