How do I make an object move by itself?

Viewed 495

I'm pretty new to unity3d and I'm teaching myself one small step after another. I've run into a hurdle though. I want to write a script for this sphere that I called "enemy" and I want it to move around in a pattern eg. forwards500 -sideways(left)500 -forwards(backward)500 sideways500 forwards500.

How do I do this so that each step is called on in order? Thanks

3 Answers

The (in my eyes) best way to control this is a Coroutine:

[Tooltip("Adjust how fast you want to move (units/second)")]
[SerilaizeField] private float moveSpeed;

[Tooltip("Fill this with your desired move steps")]
// via the INSPECTOR in Unity! (later changes here in code will have no effect!)
[SerializeField] private Vector3[] moveSteps = new []
{
    Vector3.forwards * 500,
    Vector3.left * 500,
    Vector3.backwards * 500,
    Vector3.right * 500
};

// Yes, this is possible!
// If start is an IEnumerator it is automatically started as Coroutine by Unity
private IEnumerator Start()
{
    // This looks creepy but is fine in an 
    // IEnumerator as long as you yield somewhere within!
    while(true)
    {
        // iterate through the array of movements
        foreach(var step in moveSteps)
        {
            var currentTargetPosition = transform.position + step;

            // This checks if the two positions match "exactly"
            // If it is enough that the positions match up to a precision of 0.00001 
            // it would be more efficient to simply compare 
            //while(transform.position != currentTargetPosition)
            while(!Mathf.Approximately(Vector3.Distance(transform.position, currentTargetPosition), 0f))
            {
                // move one step towards the current target position 
                // without overshooting
                transform.position = Vector3.MoveTowards(transform.position, currentTargetPosition, moveSpeed * Time.deltaTime);

                // Tells Unity to "pause" here, render this frame and 
                // continue from here in the next frame
                yield return null;
            }

            // to be sure to reach sharp positions set the target fix
            transform.position = currentTargetPosition;
        }
    }
}

This would move the object with a constant velocity of moveSpeed from one target position to the next using the configured moveStepsas pattern.


If you rather want to add some ease-in and -out towards the "edges" you could also do something like

private IEnumerator Start()
{
    while(true)
    {
        foreach(var step in moveSteps)
        {
            var currentPosition = transform.position;
            var currentTargetPosition = currentPosition + step;

            // Get the expected move duration according to the speed
            var duration = Vector3.Distance(transform.position, currentTargetPosition) / moveSpeed;

            var timePassed = 0f;
            while(timePassed < duration)
            {
                // Get a factor betwwen 0 and 1
                var factor = timePassed / duration;
                // add easing 
                factor = Mathf.SmoothStep(0, 1, factor);                    

                // Interpolate the position between the start and endpoint
                transform.position = Vector3.Lerp(currentPosition, currentTargetPosition, factor);

                // increase by the time passed since last frame
                timePassed += Time.deltaTime;
                yield return null;
            }

            // to be sure to reach sharp positions set the target fix
            transform.position = currentTargetPosition;
        }
    }
}

derHugo's answer is correct, but only if you must program the movement with a script.

The simpler and preferred way to do this is with an animation: just record the 4 points as keyframes and position them in the timeline as you wish to tell Unity how long you want between each keyframe — the time spent moving from point A to point B.

If you want to change the "curve", i.e. add some easeing or instead make it linear, go to the Curves menu in the Animation window. The default is ease-in.

You can learn more about animations in Unity's own tutorial. If you prefer videos, Jonas Tyroller has an excellent and in-depth tutorial on YouTube. (In fact, he shows exactly how to do what you're trying to.)

I would check out this documentation on the Translate function.

You would have to set up a Transform or GameObject variable to use it on:

public /*if you want to assign it in the editor*/ GameObject enemy;

Then, you'd need to create a new function called on startup (Start()). Then, inside it, move the enemy in your desired pattern:


void MoveEnemy() 
{

    //however you choose to move it

    enemy.Translate(Vector3.forward * 500);
    enemy.Translate(Vector3.right * 500);
    enemy.Translate(Vector3.back * 500);
    enemy.Translate(Vector3.left * 500);

    //Someone please correct me if this is an incorrect use of the Translate() function parameters
 
    //then once you've moved it, repeat it

    MoveEnemy();

}

void Start() 
{

    MoveEnemy();

}

As mentioned in the comments, a coroutine would be better for this process. A good way of doing this is in an answer above by derHugo.

I would also suggest checking out the Time.deltaTime documentation as it's useful for making a transition in position smooth.

There's also movement using RigidBody, but I'm not the best to explain it, so I'll just link some documentation: this.

Related