I assume you’re using the GameObject
empty only as "activator" for animation of the enemy for performance reasons (that is, to avoid that it already comes animated since the instantiation of Prefab, even with the player’s avatar still far away from the enemy). This is a good thing to do, but still it would be interesting to put this control in the scope of the enemy himself.
IS more or less close to what preaches the agent orientation: Each "intelligent" entity in your game has its own goals, and so all the programming of these goals makes more sense in the agent’s scope. Think like this: your enemy starts or stops being excited because he aims to attack the player’s avatar. Then, in fantasy game, he is not moving or stopping for performance issues (although in the real world this is extremely useful!), but only because he is able to detect by itself the presence of the player.
So I’d do it this way:
I would not use an empty Gameobject as in your example to detect the player, but rather use a Trigger (the Colisor is more focused on physics) in the whole area of the Prefab (red). This Trigger capture the two input events (onTriggerEnter and onTriggerExit) to indicate to all existing enemies in Prefab that the player has entered and exited this threat area (Threat area).
The enemies' script/class would be inherited from a script/base class so that you could invoke an abstract method from the collision events of the Trigger. Thus, each enemy could implement his own behavior (i.e., each could do as he saw fit with the information that the enemy entered and/or left the threat area).
Sample Code
Basic class of the Enemy:
using UnityEngine;
using System.Collections;
public class EnemyBase : MonoBehaviour {
private bool playerNear;
public bool isPlayerNear {
get { return playerNear; }
protected set { playerNear = value; }
}
public void playerEnteredThreat ()
{
isPlayerNear = true;
}
public void playerExitedThreat ()
{
isPlayerNear = false;
}
}
Specific class of any enemy inherited from the basic class:
using UnityEngine;
using System.Collections;
public class EnemySpecific : EnemyBase {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (isPlayerNear) {
GameObject player = GameObject.FindGameObjectWithTag("Player");
Debug.Log ("Player esta proximo! Distancia: " + Vector3.Distance(transform.position, player.transform.position));
}
}
}
Example of use (detection of collisions and message passage to the abstract class of the enemy - this is the code that goes on Trigger; I only referenced an enemy in it, but it still gives in your case):
using UnityEngine;
using System.Collections;
public class Teste : MonoBehaviour {
public GameObject enemy;
void OnTriggerEnter(Collider oOther) {
if (oOther.tag == "Player")
enemy.GetComponent<EnemyBase> ().playerEnteredThreat ();
}
void OnTriggerExit(Collider oOther) {
if (oOther.tag == "Player")
enemy.GetComponent<EnemyBase> ().playerExitedThreat ();
}
}
Explanation of the Sample Code
The enemy class inherits from a base class, which contains all the code to receive input/output indications from the Competitor/Rigger (use whichever you prefer, but if you have no intention of physical results, Rigger is more suitable). These values are reused by the child class (via a property I created called isPlayerNear
, but you could overwrite the notification methods if it so wished.
The script that is in fact added to the object of the enemy is the EnemySpecific
, but note how in Trigger’s code he does the following:
enemy.GetComponent<EnemyBase> ().playerEnteredThreat ();
That is, it references whatever is in the enemy through the abstract class. How all enemies will inherit from this class (and consequently have in its interface the method playerEnteredThreat
, Whether it’s the original of the base class or a rewritten in the daughter class), it’s guaranteed to work. And allows Trigger to give generic warning, and every enemy implementation does with it what it wants.
Concluding
This approach has the advantage that it facilitates the creation of enemies with distinct behaviors, regardless of player movement detection. Today, for example, you can only detect the player’s approach. But imagine that the game is almost ready and then the game designer (the game designer) comes to you and asks for a "small change": he wants that if the player can get rid of the enemy and walk away, the enemy activates a single long-range shooter (I don’t know, spit out an explosive seed, for example). In that case, you’ll need also detect the player’s departure, and with the current architecture this will be much more difficult (maybe you will have to include a new GameObject
empty at the end, and more duplicated code to do the same as it already does).
Another advantage of knowing that the player’s avatar is in the threat area is that the enemy’s "intelligence" can change their attitude from the point of view of the observation. It is very easy for every enemy in the game to have a reference to the player’s object and calculate the Euclidean distance from themselves to it. The problem is that it has a very large computational cost. Imagine each enemy in a set of 100 doing these calculations (which involve square root, a very costly operation) to each frame. Using the indication of the presence or absence of the player in the threat area, this type of calculation can be performed with good performance only by enemies who are in the same threat area as the player. It may sound silly, but it facilitates the future implementation of more complex behaviors with better performance. For example, an enemy could intentionally expect the player to be too close (very short distance) to activate their surprise animation.
The goal of the blue object is just what you said, animate only when the enemy actually enters the scene and also to catch the player by surprise, for example, in the Prefab I showed above, the "flower" comes out from behind the barrel when the player hits the blue object, however there is a third that I did not mention (I forgot), which is to run the move only if the player goes through a specific area and so only have to reposition/resize the blue gameobject to where I want inside the Prefab.
– Filipe Moraes
Well, then the "blue object" is your Threat area. Still, it may be advantageous for you to capture both events (in and out), making it wider - just to facilitate possible future needs. Anyway, it makes a lot of sense for you to communicate these collision events from him directly to the enemy, and for him to turn around with what he has to do about it. As I said in your other question, using a generic class to center these behaviors will only make your life difficult.
– Luiz Vieira
Yes, I have come to understand that using a class for everything would not be a good solution... I will apply what was said here, including the 2 triggers mentioned! However how do I communicate to the enemy that the player has entered the Threat area? Also applying the solution that is in the Lollipop response?
– Filipe Moraes
About "how do I communicate to the enemy [...]", I edited the answer to add some examples. I hope it helps. Good luck. :)
– Luiz Vieira
Thank you very much for your help Luiz!
– Filipe Moraes