Quaternion.AngleAxis is a fuck.

so, i’m using hit.normal to make the player character’s ‘‘up’’ direction perpendicular to whichever surface they’re standing on, and if you jump, it retains the last ‘‘up’’ vector it measured, which is useful for me because the idea is to jump off any immediate surface

when i’m not using quaternion.angleaxis, jumping off of a wall works perfectly

when i am, as soon as the raycast is out of range it changes the transform.up to 0

why is this

why

is there any way i can fix this, make it so it doesn’t go to zero when using angleaxis or an alternative way of rotating the player with effectively the same results

i’m stumped

Post your code, otherwise its hard to help you

2 Likes

in the end, i fixed it in the most naïve and least sustainable way possible by just setting the rotation speed to 0
i’m happy with this, even if it’s suboptimal

however, if you have a better solution, please show me the way

{
    Rigidbody rb;
    bool airborne;
    bool jumping;
    float y_airspeed;
    public float rayDistance;
    public float spd;
    float stickmagnitude;
    float jump;
    sbyte jumping_drag;
    sbyte gravity;
    float angle;
    float ang = 40f;

    Quaternion targetrotation;
   


    // Use this for initialization

    void Start()

    {rb = GetComponent<Rigidbody>();}

    // Update is called once per frame
    void FixedUpdate()
    {  
        float hor = Input.GetAxisRaw("Horizontal");
        float ver = Input.GetAxisRaw("Vertical");
        stickmagnitude = Mathf.Clamp01(new Vector2(hor, ver).magnitude);
        if (hor != 0.0f || ver != 0.0f) { angle = Mathf.Atan2(hor, ver) * Mathf.Rad2Deg; }

        RaycastHit hit;
        var theRay = transform.TransformDirection(Vector3.down);

        if (Physics.Raycast(transform.position, theRay, out hit, rayDistance))
        {transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;}



        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.AngleAxis(angle, transform.up), Time.deltaTime * ang);
        transform.Translate(Vector3.forward * stickmagnitude * spd * Time.deltaTime, Space.Self);



        if (Input.GetButtonDown("Jump"))
        {
            jumping = true;
            jump = 48;
            airborne = true;
        }




        if (airborne == true)
        {
            gravity = 28;

            y_airspeed -= gravity * Time.deltaTime;

            if (jump <= 0) {jump = 0;}

            transform.Translate (Vector3.up * y_airspeed * Time.deltaTime, Space.World);
            transform.Translate(Vector3.up * jump * Time.deltaTime, Space.Self);

            if (jumping == true)

            {
                jumping_drag = 2;
                jump -= jumping_drag * Time.deltaTime;
            }
        }
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.collider)
        {
            airborne = false;
            jumping = false;
            gravity = 0;
            jumping_drag = 0;
            y_airspeed = -7;
            jump = 0;
            ang = 5;
        }
    }


    private void OnCollisionExit(Collision col)
    {
        if (col.collider)
        {   airborne = true;
            ang = 0;
        }
    }

}

Few tips:

  1. Do not use Input polling in the FixedUpdate, as that is unreliable somewhat. Use Update for that purpose;
  2. You’re not using Slerp correctly.
    https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/

Maybe you’d actually want Quaternion.RotateTowards instead.

  1. Double check if your math is correct.
    You can insert a few Debugs to check if the actual angle is not 0 (before changing transform’s rotation).

  2. For each quaternion approach, there a vector one (Which may be faster and easier to read / maintain).
    If you can illustrate what are you trying to achieve we’ll probably figure something out.

  3. var theRay = transform.TransformDirection(Vector3.down);

This one is probably can be transform.down.

  1. Reorder multiplication order:
Vector3.forward * stickmagnitude * spd * Time.deltaTime

To:

stickmagnitude * spd * Time.deltaTime * Vector3.forward

So instead of doing Vector3 (x, y, z) * float (3), Vector3 * float (), Vector3 * float, it will compile to float * float, float * float, float * Vector3, which will run faster.

  1. Time.deltaTime can be stored in a float variable inside method. Like float delta = Time.deltaTime.
    Each time you do Time.deltaTime that is an external c++ call. Its small, but in the end everything counts towards FPS count.

  2. Use Vector3.sqrMagnitude > 0 to check if the inputs are pressed instead of float comparison. Float comparison can be imprecise.
    Or, use stickMagnitude, because you’ve already got it.

void OnCollisionEnter(Collision col)
    {
        if (col.collider)
        {
            airborne = false;
            jumping = false;
            gravity = 0;
            jumping_drag = 0;
            y_airspeed = -7;
            jump = 0;
            ang = 5;
        }
    }

Collision.collider is always true in this case. Also, CollisionEnter could be called multiple times. Which will modify ang as well. Be aware of that.

1 Like

@VergilUa actually using getAxis and getKey is fine there, the problem is with the down/up variants that triggers with corelation to the Update loop.

thanks for replying, you really went above and beyond with giving me plenty of options and i’ve since had an opportunity to finally read through and put your suggestions into practice

i have some questions i’d like to ask and comments too and i’ll also supply my notes of what i’m planning to achieve

  1. quaternion.rotatetowards relies on a 2nd quaternion to rotate to from the first rotation, how do i go about modifying that 2nd quaternion to work like a quaternion.angleaxis? i.e: only rotate on a local pivot

  2. i know my code for moving the character is flaud, but i simply use it to move around so i can test how the player object handles slopes,

  3. the math is correct and the order of everything seems to be irrelevant; adding quaternion.angleaxis at any point in the code makes the transform.up revert back to 0 as soon as the raycast is out of range…i debugged this as you suggested, and when using angleaxis, the transform.up seems to always be set to 0, but the raycast normal negates that, until it becomes out of range

  4. while i heeded your advice about using vector3.sqrmagnitude and i’ll leave it that way, as it is still good practice, i noticed no difference in precision, granularity or stability when i switched over from float comparison

that’s all the questions and comments i’ve got for now, i’ve included a tagged-on png of my design notes, although i forgot to mention that you go very, very fast, too

4549570--422275--platformingphysics.jpg