🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Unity - Script worked fine, until I made the object a prefab...

Started by
5 comments, last by silverfang180882@yahoo.co.uk 4 years, 2 months ago

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
     }
 }

Really hoping to get a solution to this, because the plans I have for my later project will involve a lot of custom AI in enemy objects.

Thanks in advance.

Advertisement

A bit of an update on this. It seems the enemy behaviour I wanted is now working; if I shoot the enemy, it will follow the player indefinitely, as I wanted.

However, with multiple instances of the Prefab in the scene, I'm now finding that every flying enemy in the level will follow me if I shoot the first one.

Is there any way I can separate the behaviour of different objects in the same prefab, so that only the one that's been shot will follow the player?

Hi, without knowing the tutorial and code behind it, I would guess that the EnemyHealthManager (or at least health value) is shared between all (flying) enemies?

Maybe it is a Singleton or ScriptableObject?

The EnemyHealthManager script is attached to all enemy objects, yes (both the flying enemies and grounded ones, which have a different “patrol” script to the one above). Despite this, their health values decrease independently for each enemy object. If I shoot one flying enemy, that enemy's health reduces, but the others will stay on their starting value. Regardless, the other flying enemies will start to pursue the player as well.

silverfang180882@yahoo.co.uk said:
However, with multiple instances of the Prefab in the scene, I'm now finding that every flying enemy in the level will follow me if I shoot the first one.

Sorry for the late reply.

And only if you shoot the first one?
I see three conditions to move towards the player:

  1. flyingHealth.enemyHealth < 3
    • Not checking if player is in range or not
  2. !followOnLookAway && playerInRange
    • Is followOnLookAway something you set from the inspector?
  3. playerInRange && facingAway
    • Not checking if enemy was injured before

Please "Debug.Log()" which case is triggering on your enemies or even better, attach the debugger and set breakpoint on all three cases.

It was the first, as the others work fine without it.

I have now fixed it by using a different method however. I've removed the health < 3 condition, and instead created a boolean called “isShot”, which triggers the movement if set to true. I then added to the OnTriggerEnter part of the player's projectile script to set the isShot condition to true whenever the enemy is shot.

It works fine now; only an enemy that's been shot will begin pursuing the player.

Thanks anyway!

This topic is closed to new replies.

Advertisement