0

I'm making a skateboarding prototype in Unity, and like in skate 3, I'd like the player to sort of "align" gradually to their predicted landing slope. I've written the code that gets the predicted point at which the player will land, but actually rotating the player to it is proving difficult.

How can I make it so the player (by default) has their upward orientation gradually adjusted for a smooth landing, but still allow the player to spin in-air?

I've tried using LookRotation with the player's forward direction, and the predicted hit normal as the up, calculated when the player leaves the ground. This results in the player being unable to spin midair, and also tends to flip/spin out randomly.

Here's the code I'm using: (executed the frame they leave the ground)

predictedLandingRotation = Quaternion.FromToRotation(transform.up, predictedLandingInfo.normal);

In air, I do this every frame:

transform.rotation = predictedLandingRotation;

(I typed this on mobile so sorry if the formatting is a bit funky)

DMGregory
  • 134,153
  • 22
  • 242
  • 357
LeytonMate
  • 11
  • 5
  • Could you provide us with the code that you have been working on so far? that way you allow other members to know how to correctly approach your problem taking your implementation into account. – LifGwaethrakindo Apr 17 '23 at 18:25
  • What engine and language are you using? Unity? Please be sure to add the relevant tag(s). – Kevin Apr 17 '23 at 19:33
  • @Kevin Sorry! I didn't specify, I'm using unity. – LeytonMate Apr 17 '23 at 20:42

1 Answers1

0

You can use the formula I've given in quite a few past answers to update the up direction while respecting your current forward direction as well as possible:

Quaternion TurretLookRotation(Vector3 approximateForward, Vector3 exactUp) {
    Quaternion zToUp = Quaternion.LookRotation(exactUp, -approximateForward);
    Quaternion yToz = Quaternion.Euler(90, 0, 0);
    return zToUp * yToz;
}

(Fun fact: you can actually get the 90 degree rotation without a full quaternion multiplication if you want to get fancy)

So the orientation with up aligned to our landingNormal and forward as close as possible to our current facing direction is:

var targetRotation = TurretLookRotation(transform.forward, landingNormal);

Then we can gradually blend there, so we don't snap all at once. There are a lot of ways to do this, but here's one to start with:

// Keep a member variable to help maintain smooth continuity
// in the motion from frame to frame.
Vector3 _tiltCorrectionVelocity;

void AlignUpWith(Vector3 targetUp, float blendWindow) {

Vector3 smoothedUp = Vector3.SmoothDamp(
                        transform.up, // Start from current orientation
                        targetUp,     // Blend to target vertical
                        ref _tiltCorrectionVelocity, // Maintain continuity
                        blendWindow   // How many seconds should it take
                     );

transform.rotation = TurretLookRotation(transform.forward, smoothedUp);

}

This helps take the harshest snaps out of the rotation, by ensuring your up axis carries some momentum from frame to frame, and won't suddenly swing in a different direction. Though you will notice it change momentum when your targetUp changes - good to disguise this when you can with animations of your skater, so that it looks like the energy is coming from somewhere rather than just spooky magnetism.

There's a lot you can layer onto this basic idea to dial in the feel - see the section on world impact reactions around 20 minutes into this video for how we handled this on Starlink.

DMGregory
  • 134,153
  • 22
  • 242
  • 357
  • This looks like it could work! One thing though, the player also needs to be able to rotate inair, like being able to do 180s, 360s, you get it. Would this not prevent them from doing that? – LeytonMate Apr 18 '23 at 17:54
  • This would not prevent rotation around their up axis (local y rotations). If you want local x or z rotations, you should edit your question to clearly articulate what rotation actions need to be supported, and how they should combine with the landing alignment. (eg. if just before landing, a player tries to rotate so they land on their head, do you let them? What's the rule?) – DMGregory Apr 18 '23 at 18:23
  • Oh no, just local y is fine! Thank you for helping! – LeytonMate Apr 18 '23 at 19:31
  • Because we use our current transform.forward to calculate our new rotation, any other script that changes forward will see those changes carry through after this up vector adjustment (unless they're pitching up/down —the up vector blending will override that). Note that if you're using physics with this character, you should use MoveRotation or torques applied to the Rigidbody instead of manipulating the Transform directly. – DMGregory Apr 18 '23 at 21:53
  • Oh okay! thank you!

    One thing i wanted to ask, I'm currently calculating the time it'd take to get from the start to the end point of the trajectory, and then putting that into this. But for some reason, it doesn't always line up. would you have any idea what it could be?

    – LeytonMate Apr 22 '23 at 00:02
  • The smoothTime argument to SmoothDamp is approximate. Err toward less time than you have left to rotate more aggressively. – DMGregory Apr 22 '23 at 00:29
  • Woagh... Also, for some reason, the board will sometimes rotate upside down, usually when the board is horizontal and ollying onto the floor e.g off the side of a half pipe. Would you know anything about that? – LeytonMate Apr 25 '23 at 17:05
  • Sounds like something worth posting as a new question, with a diagram explaining the problem case(s). – DMGregory Apr 25 '23 at 20:48