Daniel Lip
Daniel Lip

Reputation: 11341

How can I calculate a moving object speed?

The goal is to show both transform and speed movement speed in text1 and text2.

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

public class Follow : MonoBehaviour
{
    public Transform targetToFollow;
    public Text text;
    public Text text1;
    public Text text2;
    public float lookAtRotationSpeed;
    public float moveSpeed;

    private float minMoveSpeed = 0f;
    private Vector3 originPos;

    // Start is called before the first frame update
    void Start()
    {
        originPos = targetToFollow.position;
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 lTargetDir = targetToFollow.position - transform.position;
        lTargetDir.y = 0.0f;
        transform.rotation = Quaternion.RotateTowards(transform.rotation,
            Quaternion.LookRotation(lTargetDir), Time.time * lookAtRotationSpeed);

        var distance = Vector3.Distance(transform.position, targetToFollow.position);

        text.text = "Transform Distance From Target " + distance.ToString();

        float ms = moveSpeed;

        if (distance > 5f)
        {
            ms = moveSpeed + 0.5f; //move faster
        }
        else if (distance < 1.5f)
        {
            ms = Mathf.Max(minMoveSpeed, ms - 0.3f); // move slower
        }
        else
        {
default value that equal moveSpeed here
                transform.position = Vector3.MoveTowards(transform.position, targetToFollow.position, Time.deltaTime * ms);
        }

        if(distance < 0.5f && originPos == targetToFollow.position)
        {
            ms = 0f;
        }

        transform.position = Vector3.MoveTowards(transform.position, targetToFollow.position, Time.deltaTime * ms);

        originPos = targetToFollow.position;
    }
}

Now I'm setting to text the transform distance from the target. But I want to add now to text1 and text2 the speed movement of the transform and the target. In the end there will be 3 texts ui's that will show the distance and movement speeds.

I tried like this for the target speed :

var speedPerSec = Vector3.Distance(originPos, targetToFollow.position) / Time.deltaTime;
text1.text = "Target Speed Per Second " + speedPerSec.ToString();

but when the target is moving the text of the speed the speedPerSec.toString() is blinking fast and not smooth like the distance in the first text.

maybe it's blinking because it's showing the speed a lot after the zero point like : 0.00656555 ?

Upvotes: 0

Views: 1629

Answers (2)

さんですVaya
さんですVaya

Reputation: 176

If you only want to know how much velocity of object in specific time you can do something like this.

public class VelocityDisplayer : MonoBehaviour
{

    public Transform Object; // your target gameobject
    public Text View; // your text object
    private Vector3 _position; // last position of target

    private void OnEnable() {
        _position = Object.transform.position;
    }

    private void Update() {
        var dt = Time.deltaTime;
        var current = Object.transform.position;
        var delta = Vector3.Distance(current, _position);
        var velocity = delta / dt;
        View.text = (velocity).ToString("#,##0.000");

        // replace current position
        _position = current;
    }

}

but this show actual speed which depend on game world/physics of object not your setup movement speed variable

PS1. I prefer to use update because is UI scope

PS2. I prefer to split new class to track object

Upvotes: 0

Thomas
Thomas

Reputation: 1265

Since you want to track the speed of multiple objects (your transform and the target) the easiest way is to introduce a separate object handling the tracking and use an array of these.

[Serializable]
private class SpeedTracking
{
    public Transform trackedObject;
    public Text uiOutput;
    private Vector3 _position;
    private float _speed;

    public void Update(float elapsedTime, float changeThreshold)
    {
        Vector3 newPos = trackedObject.position;
        float newSpeed = Vector3.Distance(newPos, _position) / elapsedTime;

        if ((newSpeed == 0 && _speed != 0) || Mathf.Abs(newSpeed - _speed) > changeThreshold)
        {
            _speed = newSpeed;
            uiOutput.text = $"speed: {newSpeed:F3}";
        }
        _position = newPos;
    }
}

private const float SPEED_CHANGE_THRESHOLD = 0.001F;
[SerializeField]
private SpeedTracking[] _trackings;

void OnEnable()
{
    if (_trackings.Any(t => t.trackedObject == null || t.uiOutput == null))
    {
        Debug.LogError("at least one invalid tracking found");
        enabled = false;
    }
}

void Update()
{
    //[...]
    UpdateTrackings();
}

void UpdateTrackings()
{
    foreach (SpeedTracking tracking in _trackings)
    {
        tracking.Update(Time.deltaTime, SPEED_CHANGE_THRESHOLD);
    }
}

I also added a format to your output string (F3) showing only 3 decimal digits. (This alone would solve the flickering, but why update the ui more often than necessary?)

Upvotes: 1

Related Questions