Jim
Jim

Reputation: 801

Finding the difference in rotation, as an average over time unity c#

I have a ships wheel the player is able to rotate. I currently record the angle change, which is added to a total angle. I can then work out how many times the ship wheel has been turned. This all works fine.

void Update()
        {
            //Record Amount of Wheel Turns
            currentAngle = wheelRectTransform.transform.rotation.eulerAngles.z;
            angleChange = Mathf.DeltaAngle(currentAngle, previousAngle);

            if ((Mathf.Abs(angle + angleChange) / 360) <=   wheelTurnsUntilRudderAtMaxAngle)
            {            
               angle += angleChange;               
            } 

            totalWheelTurns = angle / 360;
            shipStats.RudderAngle = totalWheelTurns / wheelTurnsUntilRudderAtMaxAngle;

            previousAngle = currentAngle;
        }

However, I'd also like to record the average angle change over time. Then I would be able to get an accurate idea as to wether the wheel is rotating left or right.

I have tried something simple like this

if (angleChange < 0)
{
     // Going Left
}
else if (angleChange > 0)
{
     // Going Right
} else
{
    // Not moving
}

In practice however, if the player is rotating the wheel very, very slowly the angle difference on the occasional frame is 0 and recorded as 'not moving'.

I believe the solution would be to find the average angle change over a short time so I tried to Lerp the angle to 0 over time.

newAngleDifference = Mathf.Lerp(angleChange, 0, Time.deltaTime * 0.2f);

This didn't work, it gives me the same feedback as I'm just using 'angleChange' which can be 0 anyway.

Thanks!

Jim

Upvotes: 2

Views: 906

Answers (2)

Jim
Jim

Reputation: 801

In the end I used a Lerp to get the average.

    public enum WheelDirection { Left, Right, Still }

    [Header("Average Wheel Direction")]
    public float lerpTime = 0.5f; // How many seconds average over
    private WheelDirection wheelDirection; 
    private float wheelDeltaX;
    private float wheelDirectionInterpolated;
    private float currentLerpTime;

 void Update()
    {
        // Get DeltaX of objects rotation 
        // I'm interested in the Z axis, but you could change this to x/y           
        float currentAngle = transform.rotation.eulerAngles.z;
        wheelDeltaX = (currentAngle - previousAngle);

        // Reduce the Lerp percentage
        currentLerpTime += Time.deltaTime;
        if (currentLerpTime > lerpTime)
        {
            currentLerpTime = lerpTime;
        }
        float perc = currentLerpTime / lerpTime;

        // Lerp!
        wheelDirectionInterpolated = (Mathf.Lerp(wheelDirectionInterpolated, wheelDeltaX, perc));

        // Wheel has finished rotating, so reset the Lerp
        if (wheelDirectionInterpolated == 0) currentLerpTime = 0;

        // Store Direction in an Enum
        if (wheelDirectionInterpolated > 0) wheelDirection = WheelDirection.Left;
        if (wheelDirectionInterpolated < 0) wheelDirection = WheelDirection.Right;
        if (wheelDirectionInterpolated == 0) wheelDirection = WheelDirection.Still;

        //This should always be at the end
        previousAngle = currentAngle;
    }

Upvotes: 1

Programmer
Programmer

Reputation: 125315

You don't need to average anything to detect the direction of the wheel. Simply use old and new variable to find which direction the wheel is going.

 void Start()
 {
        StartCoroutine(wheelDIRCalculator(_wheelTransform));
 }


bool continueWheelCalculation = false;

 IEnumerator wheelDIRCalculator(Transform wheelTransform)
 {
     yield return null;

     continueWheelCalculation = true;

     float oldZAngle = 0;
     float newZAngle = 0;
     bool isIdle = false;

     oldZAngle = Mathf.Abs(wheelTransform.rotation.eulerAngles.z);


     while (continueWheelCalculation)
     {

         //Get new rotation
         newZAngle = Mathf.Abs(wheelTransform.rotation.eulerAngles.z);

         if (oldZAngle < newZAngle)
         {
             isIdle = false;
             oldZAngle = newZAngle;
             Debug.Log("Left");

             //Do something 

         }
         else if (oldZAngle > newZAngle)
         {
             isIdle = false;
             oldZAngle = newZAngle;
             Debug.Log("Right");

             //Do something 

         }
         else if (!isIdle)
         {
             isIdle = true;
             oldZAngle = newZAngle;
             Debug.Log("Idle");

             //Do something 

         }


         yield return null;
     }
 }

 void stopWheelDIRCalculator()
 {
    continueWheelCalculation = false;
 }

Upvotes: 1

Related Questions