idanarye / bevy-tnua

A floating character controller for Bevy
https://crates.io/crates/bevy-tnua
Apache License 2.0
180 stars 12 forks source link

Feature request. Give us more control over the jump trajectory. #5

Closed kumorig closed 1 year ago

kumorig commented 1 year ago

Hey, I love the project and I'll definitely try to use it in the third bevy jam. I love how it's almost like dropping in a actor/controller in unreal engine and then things just works. It's almost too easy. and most things I check out in your code has a big nice explaining comment. So just know your efforts aren't going unnoticed, and thanks a bunch!

Anyway, to the issue I'm trying to work around. Modifying the jump trajectory. I'm using the 2d-features, and while I like how most things handle,

The part of the trajectory that is just before the peak of the jump feels very floaty and slow to me, like some Micheal Jordan air time... I recognize this might be the wanted trajectory for many, but I'm not making a basket ball game... 🏀 😭 I think it can be seen very easily in the 2d example demo by simply jumping and not releasing the jump button during the trajectory.

I've tried to poke around in the code and found the JumpState enum with SlowDownTooFastSlopeJump, MaintainingJump, and I figure one of those states are behind the jordan air logic https://github.com/idanarye/bevy-tnua/blob/0686bb36366bf5aca730cab5af797a55340d5ba2/src/platformer.rs#L302-L306

I've seen your comments about jump_shorten_extra_gravity, but it does not seem to do much - not in this context at least.

My next idea was to query on the TnuaPlatformerState and then replace the jumpState after some time in the jump, but since JumpState is private this isn't allowed. (maybe my dubious rust skills are at fault)

I hope this doesn't read too much like just a help request, but if you have some better idea of how I should approach this, then I'd love to hear it.


and if I might add another unrelated question (sorry!): https://github.com/idanarye/bevy-tnua/blob/0686bb36366bf5aca730cab5af797a55340d5ba2/src/platformer.rs#L180-L184 How do I lock the characters rotation? I figure it's a rapier thing?

idanarye commented 1 year ago

SlowDownTooFastSlopeJump is irrelevant here. This is something that happens at the start of the jump in order to solve an issue with jumping while running up a slope.

jump_shorten_extra_gravity is only applied when you leave the jump button before reaching the peak. When this happens, Tnua applies more gravity to make the jump shorter. Try it (in the demo or in your game) - do these shortened jumps fell like what you want a full jump to feel?

If so, I can try adding a feature where gravity increases before you reach the peak of the jump. This will make the calculation of the initial jump velocity more complex though, but it should be doable. It'll take some time before I'm available for it (I'm currently working on a huge refactor in one of my other plugins, which I want to finish before the jam), but if you want to try doing something yourself the relevant section of the code is:

https://github.com/idanarye/bevy-tnua/blob/0686bb36366bf5aca730cab5af797a55340d5ba2/src/platformer.rs#L635-L639

vertical_velocity is calculated from the speed of running up a slope, but basically if you add a small number to it then upward_velocity will get below vertical_velocity + your_new_number before reaching the peak, which should prevent the character from spending too much time with near-zero velocity on the Y axis.

How do I lock the characters rotation? I figure it's a rapier thing?

Yes: https://www.rapier.rs/docs/user_guides/bevy_plugin/rigid_bodies/#locking-translationsrotations

In your case (2D), this just means adding the LockedAxes::ROTATION_LOCKED component to the rigid body.

kumorig commented 1 year ago

Super helpful! I found the ROTATION_LOCKED in the example directly after posting - sorry for not doing my due diligence.

Next I'm looking to update sprites animation depending on where in the jump I am. I'm using velocity.linvel.y but I'd still want to know if I'm in a jump state or not. Thus, intuitively I'd like to check the jump state... maybe something like this:

fn update_sprite(
    query: Query<&TnuaPlatformerState>,
    ....
) {
    let platformer_state = query.single();
    if platformer_state.jump_state != JumpState::NoJump {
        sprite.index = .....;  
    }

This gives the error: "field 'jump_state' of struct 'TnuaPlatformerState' is private".

Sorry if this is irrelevant to the issue, but again I find myself wanting access to jump_state (and also for it to implement PartialEq).

Am I going about things the wrong way?

Please let me know if I should take those questions to discord instead =)

edit: Maybe just ignore my ramblings until I've looked into TnuaAnimatingState a bit more... =)

idanarye commented 1 year ago

TnuaAnimatingState is a helper utility, for operating whatever animation system you use. What you are actually looking for is TnuaPlatformerAnimatingOutput.