Skip to content
This repository has been archived by the owner on Nov 29, 2022. It is now read-only.

Character controller #96

Open
yaymalaga opened this issue May 21, 2021 · 7 comments
Open

Character controller #96

yaymalaga opened this issue May 21, 2021 · 7 comments
Assignees
Labels
enhancement New feature or improvement

Comments

@yaymalaga
Copy link
Contributor

yaymalaga commented May 21, 2021

Right now, the only way to control kinematic bodies is by manually changing their transform. However, collisions are not taken into account by default, delegating that logic to the final user. This would be really useful to have even in basic games, such as platformers, where the player needs to collide with the floor.

For instance, Godot includes some high-level functions to handle this behavior, as explained in its documentation: Movement and collision and Detecting collisions.

This was discussed a while ago in the Bevy's discord physics channel, where Rapier's developer said:

Almost no physics engines compute contacts between two non-dynamic bodies (however kinematic bodies do affect dynamic bodies). So you are supposed to use shape-casting to detect collision with the static environment.
The godot "move_and_collide" and "move_and_slide" are just higher-level operations which are based on shape-casting.

@jcornaz
Copy link
Owner

jcornaz commented May 21, 2021

Yes, I aggree. But sadly that's rapier behavior.

And I'm not eager to solve this problem in heron. I'd rather see it solved in rapier first, and then add the API to use it in heron.

After all, even if move_and_slide is "higher-level", it is not especially related to bevy. Any user of rapier may want this feature, regardless of the game engine being used.

To be honest, I had the same feeling when I started to use rapier (as I'm coming from Godot). But I realized, that instead of using a kinematic body for a player character, I could use a dynamic body, and only make sure to redefine the body velocity before each physics step. Maybe it is just that a "kinematic body" is the best choice for a player character in godot (because of that higher level API), but with rapier it is "dynamic body" which is the best choice for a player character.

If you really want this feature, you can propose a PR. But, if that's the case, your efforts may be better spent on adding this feature to rapier directly.

Maybe later, after addressing more pressing issues (offset, multiple-shapes-per-body, ray-cast, layers, etc.), I may have a closer look at this. But when that day will come, I'll probably consider contribute the feature to rapier directly.

@jcornaz jcornaz added enhancement New feature or improvement up-for-grabs Good for newcomers labels May 21, 2021
@yaymalaga
Copy link
Contributor Author

yaymalaga commented May 21, 2021

Makes total sense, in fact I was checking Rapier's roadmap for this year just now and it says:

We also intend to implement some higher-level features like a character controller and a vehicle controller. Both should be available starting October. Most games will need controllers obeying their specific custom rules, so it is impossible to design a universal solution. Our goal is to provide something useful to start with, to serve as a basis to more specific character and vehicle controllers.

As you suggests, maybe it's better to just wait for that feature to land, and then rework it in Heron if necessary, or to contribute it directly to Rapier.

@jcornaz jcornaz added upstream Wait for changes in a dependency of heron (like Bevy or Rapier) and removed up-for-grabs Good for newcomers labels May 25, 2021
@zicklag
Copy link
Contributor

zicklag commented Jul 1, 2021

But I realized, that instead of using a kinematic body for a player character, I could use a dynamic body, and only make sure to redefine the body velocity before each physics step. Maybe it is just that a "kinematic body" is the best choice for a player character in godot (because of that higher level API), but with rapier it is "dynamic body" which is the best choice for a player character.

For what it's worth, this is the approach I've been taking and it is working well so far:

simplescreenrecorder-2021-06-22_09.43.50.mp4

I just set the velocity of the player every frame, and if I try to push him into a wall he just stops, as you would expect. In the video it only looks like he's moving jaggedly because I'm changing my direction diagonal as I push into the blue triangle.

Here's the code if anybody wants to check it out. ( keep in mind I have some of my own extension to the physics for generating sprite collision shapes in that example )

@edgarssilva
Copy link
Contributor

I think this should be fixed in Issue #140

@Whimfoome
Copy link

Whimfoome commented Feb 20, 2022

With RigidBody::KinematicVelocityBased, it detects collisions, but doesn't stop on them and falls right through them.

kinematicallysad.mp4
// Paltform
fn spawn_world(
    mut commands: Commands,
) {
    // The ground
    let size = Vec2::new(1000.0, 50.0);
    commands
        // Spawn a bundle that contains at least a `GlobalTransform`
        .spawn_bundle(SpriteBundle {
            sprite: Sprite {
                color: Color::WHITE,
                custom_size: Some(size),
                ..Default::default()
            },
            transform: Transform::from_translation(Vec3::new(0.0, -300.0, 0.0)),
            ..Default::default()
        })
        // Make it a rigid body
        .insert(RigidBody::Static)
        // Attach a collision shape
        .insert(CollisionShape::Cuboid {
            half_extends: size.extend(0.0) / 2.0,
            border_radius: None,
        });
}
// Player
#[derive(Default, Component)]
struct Movement {
    gravity: f32,
}

#[derive(Bundle)]
struct PhysicsBundle {
    movement: Movement,
    rigidbody: RigidBody,
    collision: CollisionShape,
    motion_velocity: Velocity,
}

pub fn setup(
    mut commands: Commands, 
) {
    // ....... some unrelated code

    .insert_bundle(PhysicsBundle {
        movement: Movement { 
            gravity: 37.5,
            ..Default::default()
        },
        rigidbody: RigidBody::KinematicVelocityBased,
        collision: CollisionShape::Cuboid {
            half_extends: Vec2::new(32.0 * 6.0, 32.0 * 6.0).extend(0.0) / 2.0,
            border_radius: None,
        },
        motion_velocity: Velocity::default(),
    });
}

fn movement_system(
    mut query: Query<(&mut Movement, &mut Velocity)>,
) {
    let (mut movement, mut motion_velocity) = query.single_mut();

    motion_velocity.linear.y -= movement.gravity;
}

Is there a similar function to Godot's move_and_slide to handle all that aabb + slopes + other things logic

Edit: Another question, how to get delta time as now it seems that the faster the computer a user has, the faster the physics are?

@jcornaz
Copy link
Owner

jcornaz commented Feb 20, 2022

With RigidBody::KinematicVelocityBased, it detects collisions, but doesn't stop on them and falls right through them.

That's expected behavior. If it is kinematic, it means you are controlling the movement, and the phyiscs engine will not alter that, not even to prevent inter-penetration.

Is there a similar function to Godot's move_and_slide to handle all that aabb + slopes + other things logic

No. Mostly because rapier doesn't have that functionallity. And I would prefer to see that solved in rapier first (see my first answer in this issue)

Edit: Another question, how to get delta time as now it seems that the faster the computer a user has, the faster the physics are?

If you use the default settings you may use the time resource normally. For more complex setups, you may retrieve the configured time from the PhysicsSteps resource.

@agg23
Copy link
Contributor

agg23 commented Apr 6, 2022

It's particularly unclear how to handle this in situations with gravity. Simply zeroing out velocity every tick isn't sufficient, as you lose gravity, and it's possible (though lower priority) that you do want some non-static bodies to impart forces on your character.

There's a recently opened issue on Rapier for this: dimforge/rapier#307

@jcornaz jcornaz removed enhancement New feature or improvement upstream Wait for changes in a dependency of heron (like Bevy or Rapier) labels May 16, 2022
@jcornaz jcornaz self-assigned this May 20, 2022
@jcornaz jcornaz added the enhancement New feature or improvement label Aug 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or improvement
Projects
None yet
Development

No branches or pull requests

6 participants