Enemy Pickup Behavior

Renato Figueiredo
3 min readDec 27, 2023

Objective: Learn how to implement a way for the enemy to shoot the player’s powerups and destroy them.

So our player has a bunch of powerups coming down the screen to help him save the day. But how about we make our enemies smarter, making sure to attack if a powerup appears in front of them ?

Lets start with the basics, lets make sure that our powerups are destroyed when hit by our enemies lasers.

private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Player player = other.GetComponent<Player>();
if (player != null)
{
ActivatePowerUp(player);
}
Destroy(gameObject);
}
else if (other.CompareTag("EnemyLaser"))
{
Destroy(gameObject);
}
}

This ensures that if the powerup is hit by an enemy, it will be destroyed. But the laser itself will continue to go downwards, piercing through our powerup.

Now onto our enemy. We want to make sure that if a powerups is shot, it doesn’t affect the ability to shoot at the player.

private float _canFireAtPowerup = -1f;
private void FireLaser(bool fireAtPlayer)
{
if(_type == EnemyType.Aggressive)
_fireRate = Random.Range(1.5f, 3f);
else
_fireRate = Random.Range(3f, 7f);

if(fireAtPlayer)
_canFire = Time.time + _fireRate;
else
_canFireAtPowerup = Time.time + _fireRate;
//rest of the method
}

So we added a parameter for our method. This will be passed when called, meaning that if we are firing at the player, we pass true, otherwise we pass false. How does this impact our game ?
Well, if our enemy fires at a powerup, it will use our new variable _canFireAtPowerup, which will handle the cooldown for shooting at powerups, instead of our normal _canFire.

private PowerUp[] _allPowerUps;
private void DetermineIfPowerupInfront()
{
_allPowerUps = SpawnManager.Instance.transform.GetChild(1).GetComponentsInChildren<PowerUp>();
for (int i = 0; i < _allPowerUps.Length; i++)
{
Vector2 toPowerup = _allPowerUps[i].transform.position - transform.position;
float angle = Vector2.SignedAngle(-transform.up, toPowerup.normalized);
float alignmentThreshold = 5f;
float verticalAlignment = Mathf.Abs(toPowerup.x) / Mathf.Abs(toPowerup.y);

if (Mathf.Abs(angle) < alignmentThreshold && verticalAlignment < 1f && _canFireAtPowerup <= Time.time)
{
FireLaser(false);
}
}
}

So to the moment we were waiting, how to check if the powerup is in front of our enemy ? Well, lets check our new method.

First we start with a new array of powerups, which will hold all powerups that are on the screen, although they shouldn’t be many.

Our Spawn Manager has two childs, one for each container.

So when we call GetChild(1), we are telling to return all from our powerup container. Now that we have all powerups in an array, lets run through our array and see if any powerup is in front of the enemy.

toPowerup: Calculates the vector from the enemy to the powerup.
angle: Calculates the signed angle between the enemy’s up direction and the normalized vector to the powerup. The negative transform.up is used to check in front (downwards) of the enemy.
verticalAlignment: Calculates the vertical alignment, representing how vertically aligned the powerup is relative to the enemy.
if statement: Checks conditions for firing at the powerup, considering angle alignment and vertical alignment. When the conditions are met, the enemy is aligned and we fire at it, passing false to ensure we don’t affect the enemy’s ability to shoot at our player.

In our testing, we can see as our enemy moves, when it has a powerup in front of him, it shoots it down.

Now we have our enemies being able to destroy our powerups. We better be careful!

--

--