Improving Enemy Movement

Renato Figueiredo
3 min readDec 17, 2023

Objective: Learn how to improve our current enemy movement system, to include the enemy moving sideways.

So our visuals are looking good, we have a bunch of powerups and when our player is hit, we have a Camera Shake effect. How about we improve the difficulty of our enemies ?

Our enemies currently just go down their lane when spawned.

So in order to make our enemies more difficult, we are going to make them move sideways as well. This movement will last only for a couple of seconds, then our enemies continue down their lane as usual. With this, we can make more difficult to the player to predict where our enemies are going to move.

private int _direction = 1;
private bool isMovingSideways = false;

So we added two new variables. The direction is used to either move the player left or right, at random. And our bool is used to know if we should be moving sideways, or if we just move downwards.

private IEnumerator MoveSidewaysRoutine()
{
while (true)
{
isMovingSideways = true;
_direction = (Random.Range(0, 2) * 2) - 1;

yield return new WaitForSeconds(Random.Range(1f, 2f));

isMovingSideways = false;

yield return new WaitForSeconds(Random.Range(1f, 2f));
}
}

So how does our Coroutine works ? First, we are using a Coroutine to easily manipulate the time within the game, we can order our enemy to move sideways, and after the yield return, he will stop.

So first we assign true to our MovingSideways, and set a random direction between -1 and 1 (excluding zero). This allows our enemy to know that he should move sideways, and the direction will be random.

private float _maxXPosition = 9.2f;
private float _minXPosition = -9.2f;
private void CalculateMovement()
{
if (isMovingSideways)
transform.Translate(_enemySpeed / 2f * _direction * Time.deltaTime * Vector3.right);

if (transform.position.x >= _maxXPosition || transform.position.x <= _minXPosition)
_direction *= -1;

transform.Translate(_enemySpeed * Time.deltaTime * Vector3.down);
TeleportNewPosition();
}

So in our CalculateMovement method, if IsMovingSideways is true, we move at half of the enemy speed, at the direction we randomly generated.

Our second if, checks if we ran out of bounds, meaning that if we go outside of the limits of our enemy movement, we just change directions. This gives a ping-pong effect to our enemy.

And lastly, we continue our default moving downwards, and when the enemy is out of bounds in our Y axis, we just teleport him back up.

private void Start()
{
StartCoroutine(MoveSidewaysRoutine());
}

We now just have to make sure to start our Coroutine when our enemy is created. The Coroutine will last as long our enemy is alive, telling him to move for 1–2 seconds at random, them stop for 1–2 seconds at random, and repeat.

Our new enemy movement system at work.

And now, its harder for us to predict where our enemies are going to move. If you want, you can add a Yield Return in the middle of our Coroutine, to try and change directions, making it even harder. But this works wonders for me!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet