Assigning different behaviours to objects in a prefab based on their health value...

Hello,

I’m working my way through the platformer tutorial by GamesPlusJames, and reached the part with the flying enemy. I followed the tutorial without a hitch, and now have a script giving the flying enemy a perimeter around her, in which she follows the player whenever he’s inside the perimeter, and facing away from her (like the ghosts in Mario).

Unsatisfied with an idle enemy that you can just shoot while facing, I decided to add something into the code myself so that if the enemy has been damaged, she’ll follow the player regardless of his position, or where he’s facing.

I achieved this by accessing the separate script which manages the enemy’s health, and added the separate statement:

if(flyingHealth.enemyHealth < 3) { transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime); //Move the flying enemy towards the player return; //Prevents the rest of the effects below from occuring while the statement is running }

And it seemed to work. If I shot the enemy, she would follow me, no matter how far away I was, and regardless of whether I was facing her or not.

Then, naturally, I made the enemy a prefab, so I could create more of her in other parts of the game. And then the code I added no longer works. She’ll still follow the player if I enter her perimeter and face away, but if I shoot her, she’ll just stay idle.

I even tried creating an OnTrigger2D event for if the enemy’s collider comes into contact with the player’s projectile, but it didn’t change anything. I personally can’t understand why turning the enemy into a prefab like this has suddenly caused it to ignore this segment of its script, so I’ve decided to ask for help on the matter.

Here’s the script in full below:

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

public class FlyingEnemyAttack : MonoBehaviour
{
    private PlayerController thePlayer;     //Enables access to the Player Controller script

    public float moveSpeed;     //Flying enemy's movement speed

    public float playerRange;       //The distance from the flying enemy the player must enter before its pursuit

    public LayerMask playerLayer;       //Access the player's layer setting

    public bool playerInRange;      //Checks whether or not the player is within the flying enemy's pursuit perimeter
    public bool facingAway;     //Checks whether or not the player is facing away from the flying enemy

    public bool followOnLookAway;       //Makes the flying enemy pursue the player if he's not looking at her

    private EnemyHealthManager flyingHealth;        //Enables access to the Enemy Health Manager script

    // Start is called before the first frame update
    void Start()
    {
        thePlayer = FindObjectOfType<PlayerController>();       //Access the Player Controller script

        flyingHealth = FindObjectOfType<EnemyHealthManager>();      //Access the Enemy Health Manager script
    }

    // Update is called once per frame
    void Update()
    {
        playerInRange = Physics2D.OverlapCircle(transform.position, playerRange, playerLayer);      //Sets the flying enemy's pursuit perimeter

        if(flyingHealth.enemyHealth < 3)
        {
            transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime);     //Move the flying enemy towards the player
            return;     //Prevents the rest of the effects below from occuring while the statement is running
        }

        if (!followOnLookAway)      //If the player is facing the flying enemy
        {
            if (playerInRange)      //If the player enters the flying enemy's pursuit perimeter
            {
                transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime);     //Move the flying enemy towards the player
                return;     //Prevents the rest of the effects below from occuring while the statement is running
            }
        }

        if((thePlayer.transform.position.x < transform.position.x && thePlayer.transform.localScale.x < 0) ||       //If the player is facing left while the flying enemy is on the right
        (thePlayer.transform.position.x > transform.position.x && thePlayer.transform.localScale.x > 0))       //Or if the player is facing right while the flying enemy is on the left

            {
                facingAway = true;      //Recognises that the player is facing away
            }
        else          //If the player is facing towards the flying enemy
        {
            facingAway = false;     //Recognises that the player is facing her
        }

        if (thePlayer.transform.position.x > transform.position.x && thePlayer.transform.localScale.x > 0)       //If the player is facing right while the flying enemy is on the left
        {
            facingAway = true;      //Recognises that the player is facing away
        }

        if (playerInRange && facingAway)      //If the player enters the flying enemy's pursuit perimeter and facing away from her
        {
            transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime);     //Move the flying enemy towards the player
        }
    }

    /*void OnTriggerEnter2D (Collider2D other)
    {
        if(other.name == "PlayerProjectile")
        {
            transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime);     //Move the flying enemy towards the player
        }
    }*/

    void OnDrawGizmosSelected ()
    {
        Gizmos.DrawWireSphere(transform.position, playerRange);     //Draw a circle to see the flying enemy's pursuit perimeter during development
    }
}

Thanks in advance.

EDIT: I got the behaviour to finally work as I wanted to; the enemy is following the player now if I shoot them.

However, I now find that every flying enemy in the entire scene will follow the player like this if I reduce the health of just one. Is there a way I can separate their behaviour so that only the one I shoot will start following the player?

Hi @SilverFang180882, it’s hard to tell without seeing your set up and all the scripts involved, but it seems like you are referencing the same EnemyHealthManager class object for all of your enemies. So changing any value in that changes them for all.

If that is true, then want you really want is a unique EnemyHealthManager object for each enemy. It depends on what exactly is in the EnemyHealthManager class script, but I think one of the best ways to do this would be to make EnemyHealthManager a non-Monobehavor class, do not attached it to any object. Create a constructor for it, and the create an instance of by calling the constructor it at the top of each enemy class script - you only want to instance it once for each enemy, so if you have multiple scripts that define an enemy, you need to sort that out. The end result is you will reference that unique EnemyHealthManager object for each respective enemy.

I don’t know how you have arranged your scripts, but it looks like you need to do some refactoring if you don’t a have an OOP structure already set up for your enemies: create a base class called enemy that contains all of the variables and methods that are common for each type of enemy. It is here you should create an instance of the EnemyHealthManager. Then the class script for each different kind of enemy should inherit from that base class. That way, each individual enemy type can access its own unique EnemyHealthManager object, as well as all those other variables that they share in common but whose values are unique to each instance of your enemies.

I ended up creating a boolean called “isShot”, which controls the indefinite pursuit instead. I then set it to the player’s projectile so that isShot is set to true after it hits the enemy. Seeing as the projectile is the only way to damage these enemies without killing them, this got them to behave the way I wanted.

Thanks anyway!