Improved Movement Using Coroutines

I created a version of the movement script in the lecture using coroutines. I also made it an option so that when you give a new move instruction, you can complete the previous one instantly or keep moving.

For the move issue. To not make any assumptions about if the speed will not overstep our target. I made it so that if the step we want to take is bigger than the actual distance, then we just traverse the distance. Else our movement speed applies.

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

public class Unit : MonoBehaviour
{
	#region Editor Variables

	[SerializeField]
	private float _speed = 4f;

	#endregion

	#region Variables

	private IEnumerator _moveRoutine = null;
	private Vector3 _targetPosition = default;

	#endregion

	#region Lifecycle

	protected void Update()
	{
		if(Input.GetKeyDown(KeyCode.T))
		{
			Move(new Vector3(4, 0, 4));
		}
	}

	#endregion

	#region Public Methods

	public void Move(Vector3 targetPosition, bool instantComplete = false)
	{
		StartMoveRoutine(targetPosition, instantComplete);
	}

	#endregion

	#region Private Methods

	private void StartMoveRoutine(Vector3 targetPosition, bool instantComplete)
	{
		EndMoveRoutine(instantComplete);
		_targetPosition = targetPosition;
		StartCoroutine(_moveRoutine = MoveRoutine());
	}

	private void EndMoveRoutine(bool complete)
	{
		if(_moveRoutine != null)
		{
			StopCoroutine(_moveRoutine);
			_moveRoutine = null;
			if(complete)
			{
				transform.position = _targetPosition;
			}
		}
	}

	private IEnumerator MoveRoutine()
	{
		bool isMoving = true;
		while(isMoving)
		{
			Vector3 totalStep = _targetPosition - transform.position;
			Vector3 step = totalStep.normalized * Time.deltaTime * _speed;

			if(totalStep.magnitude <= step.magnitude)
			{
				step = totalStep;
				isMoving = false;
			}

			transform.Translate(step);
			yield return null;
		}

		EndMoveRoutine(true);
	}

	#endregion
}

This is only ever false until you run the coroutine for the first time. After that, it’s always true. You have to explicitly set it to null.

This is an ‘interesting’ way of keeping track of the routine. The usual ways is to just get a reference to the coroutine

Coroutine _moveRoutine;
_moveRoutine = StartCoroutine(MoveRoutine());

Currently, the movement is started and it completes. We cannot start a new action until the current action completes, so there is no reason to account for completing the step when a new move instruction is given because it is already completed.


Edit I now see that you are still early in the course. Most of the movement will change, so don’t get too into your own thing too soon. I fully support experimentation, but suggest you complete the course first, and then experiment on the completed result.

Ow very sharp of you to notice me forgetting to set the _moveRoutine = null; within the EndMoveRoutine method. That is something I overlooked and should be part of the code. I edited it to reflect that.

Also, I have over 10 years of experience with programming in the game industry so I feel comfortable changing things up a bit and seeing the course more as a guideline. But thank you for the advice.

I wanted to experiment with how to follow courses with my level of experience.

Thank you for taking the time to look into the code. And yes, I look forward to the rest of the course. Really look up to coding monkey so I am happy to get the opportunity to follow a full course by him on this platform.

1 Like

Privacy & Terms