0

I'm trying to use the ang variable to check the degrees and make the name change. But it's never get to 180 degrees only close to it.

I want that while the transform is rotating using the StartCoroutine when the object rotated 180 degrees then make the name change.

Not when the transform is at 180 degrees but after the object rotated 180 degrees then change the name.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class OnMouseOverEvent : MonoBehaviour
{
    public float speed = 5f;
    public float distanceToMove = 1f;
    public bool goForward;
    public Vector3 startPos;
    public Vector3 endPos;

    private bool isRotating = false;
    private Vector3 lastFwd;
    private float curAngleX = 0;

    private void Start()
    {
        lastFwd = transform.forward;

        startPos = transform.position;
        endPos = transform.position - Vector3.forward * distanceToMove;
    }

    void Update()
    {
        if (goForward && isRotating == false)
        {
            transform.position = Vector3.MoveTowards(transform.position, endPos, speed * Time.deltaTime);
        }
        else if (isRotating == false)
        {
            transform.position = Vector3.MoveTowards(transform.position, startPos, speed * Time.deltaTime);
        }

        var curFwd = transform.forward;
        // measure the angle rotated since last frame:
        var ang = Vector3.Angle(curFwd, lastFwd);

        if (ang == 180f)
            transform.GetChild(0).GetComponent<TextMesh>().text = "Changed";
    }

    private void OnMouseOver()
    {
        goForward = true;
    }

    private void OnMouseExit()
    {
        goForward = false;
    }

    private void OnMouseDown()
    {
        if (isRotating == false && transform.name == "Options")
            StartCoroutine(Rotate(5));
    }

    IEnumerator Rotate(float duration)
    {
        Quaternion startRot = transform.rotation;
        float t = 0.0f;
        while (t < duration)
        {
            isRotating = true;
            t += Time.deltaTime;

            transform.rotation = startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up); //or transform.right if you want it to be locally based

            yield return null;
        }
        transform.rotation = startRot;

        isRotating = false;
    }
}

Update :

I'm not sure if it's the right solution but this is working :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class OnMouseOverEvent : MonoBehaviour
{
    public float speed = 5f;
    public float distanceToMove = 1f;
    public bool goForward;
    public Vector3 startPos;
    public Vector3 endPos;

    private bool isRotating = false;
    private Vector3 lastFwd;
    private float curAngleX = 0;

    private void Start()
    {
        lastFwd = transform.forward;

        startPos = transform.position;
        endPos = transform.position - Vector3.forward * distanceToMove;
    }

    void Update()
    {
        if (goForward && isRotating == false)
        {
            transform.position = Vector3.MoveTowards(transform.position, endPos, speed * Time.deltaTime);
        }
        else if (isRotating == false)
        {
            transform.position = Vector3.MoveTowards(transform.position, startPos, speed * Time.deltaTime);
        }

        var curFwd = transform.forward;
        // measure the angle rotated since last frame:
        var ang = Vector3.Angle(curFwd, lastFwd);

        if (myApproximation(ang, 110f, 10f) == true)
            transform.GetChild(0).GetComponent<TextMesh>().text = "Changed";
    }

    private bool myApproximation(float a, float b, float tolerance)
    {
        return (Mathf.Abs(a - b) < tolerance);
    }

    private void OnMouseOver()
    {
        goForward = true;
    }

    private void OnMouseExit()
    {
        goForward = false;
    }

    private void OnMouseDown()
    {
        if (isRotating == false && transform.name == "Options")
            StartCoroutine(Rotate(5));
    }

    IEnumerator Rotate(float duration)
    {
        Quaternion startRot = transform.rotation;
        float t = 0.0f;
        while (t < duration)
        {
            isRotating = true;
            t += Time.deltaTime;

            transform.rotation = startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up); //or transform.right if you want it to be locally based

            yield return null;
        }
        transform.rotation = startRot;

        isRotating = false;
    }
}

I'm using my own Approximation method (myApproximation) and I also changed back the lines :

lastFwd = transform.forward;

And

var curFwd = transform.forward;

To be forward it was up

Daniel Lip
  • 3,867
  • 7
  • 58
  • 120
  • 1
    Possible duplicate of [Compare floats in Unity](https://stackoverflow.com/questions/39898301/compare-floats-in-unity) – Ruzihm Aug 28 '19 at 05:04
  • Even if you use `Mathf.Approximately` it doesn't matter which of both `Vector3.SignedAngle` or `Vector3.Angle` you are using ... rotating with `startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up);` it is very unlikely that in one certain frame you'll have exactly or close to `180` degrees – derHugo Aug 28 '19 at 08:26
  • @derHugo I updated my question with a working solution. But I'm not sure if it's the right way to do it. And not sure how for example to make it with 180 degrees. I'm using float b and float tolerance as 110 and 10 – Daniel Lip Aug 28 '19 at 10:47
  • 1
    why `110` ? now with a range of `10` the angle can be `100 - 120` ... – derHugo Aug 28 '19 at 10:58
  • @derHugo Then 170, 20 and the range now is between 170 and 190 ? Seems to be working. Even if doing 179,1 – Daniel Lip Aug 28 '19 at 11:19

1 Answers1

0

I think the problem is that you never see 180 is because of comparing floats as someone mentioned in the comments or because you overshoot, and Vector.Angle(float a, float b); is never greater than 180 degrees so things you can try.

I would try this first:

if (Mathf.Approximately(ang, 180.0f))
        transform.GetChild(0).GetComponent<TextMesh>().text = "Changed";

If this not works then you should use

Vector3.SignedAngle(Vector3 from, Vector3 to, Vector3 axis);

DOC. So you will know when you overshoot cos your 181 degrees rotation would become -179. Note that the last solution assumes you rotate more then 180 degrees in one frame

Menyus
  • 6,633
  • 4
  • 16
  • 36
  • Even if you use `Mathf.Approximately` it doesn't matter which of both `Vector3.SignedAngle` or `Vector3.Angle` you are using ... rotating with `startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up);` it is very unlikely that in one certain frame you'll have exactly or close to `180` degrees – derHugo Aug 28 '19 at 08:25
  • I didn not said signed angle is for approx., it is for detecting overshooting – Menyus Aug 28 '19 at 08:38
  • And what I said is that it doesn't matter which of both you use ... the value might still never be exactly or close enough to `180` degrees in one certain frame during a movement – derHugo Aug 28 '19 at 08:41