- Home /
Re-target new Enemy
Hello! I have one Problem that my Object is attacking only one enemy and then the other one get not harmed. (because of my Awake Function) but I dont know how to fix this issue into the Update Function (The FindwithTag & Healththing(?))
Here is my code so far:
using UnityEngine;
using System.Collections;
public class SkeletonWarriorAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 13; // The amount of health taken away per attack.
GameObject playereast; // Reference to the player GameObject.
ElvenWarriorHealth eastHealth; // Reference to the player's health.
SkeletonWarriorHealth westHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
void Awake ()
{
// Setting up the references.
playereast = GameObject.FindGameObjectWithTag ("PlayerEast");
eastHealth = playereast.GetComponent <ElvenWarriorHealth> ();
westHealth = GetComponent<SkeletonWarriorHealth>();
}
void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == playereast)
{
// ... the player is in range.
playerInRange = true;
}
}
void OnTriggerExit (Collider other)
{
// If the exiting collider is the player...
if(other.gameObject == playereast)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if(timer >= timeBetweenAttacks && playerInRange && westHealth.currentHealth > 0)
{
Attack ();
}
}
void Attack ()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if(eastHealth.currentHealth > 0)
{
// ... damage the player.
eastHealth.TakeDamage (attackDamage);
}
}
}
Maybe it is possible to do it with something like:
GameObject[] targets = GameObject.FindGameObjectsWithTag ("PlayerEast"); foreach (GameObject target in targets)
{
//tell the update function that this target is now "Targeted" and is going to be attacked! (?)
}
but I don't know how to get any further with this issue...
Thanks for your time! Flowered
Question approved because it has commented code. You should write more detailed descriptions of your situations and issues, rather than leaving others to hunt for it to discover the meaning of nebulous statements. We want to understand your issue, then proofread your code, not the other way around. ;)
Answer by AlwaysSunny · May 12, 2015 at 11:59 PM
I now see you're creating a detection system. Entity discovery (one entity seeking another) is often best handled with triggers.
Do not rely on Finds for reference management. Ideally all entities should belong to some collection and get "found" by having access to that collection. (e.g. a GameManager singleton who keeps collections of like entities.)
Triggers (or Finds obviously) would work in this scenario too, but the manager singleton approach to reference management is a super great way to manage complex scenes. These are concepts that may be biting off a bit much right now, but I'd feel irresponsible if I didn't mention them.
You need some way for your seeker objects to find their sought objects. A Find() is fine for now. Whatever approach you choose to satisfy this requirement must support changing targets when the current target is no longer available. Whatever approach you choose will give you some collection of discovered sought objects. Your new current target becomes the next discovered sought object in that collection. You'll need to run the Find() again to re-discover the object(s) you're seeking, or at the very least, make provisions to deal with nullified elements.
I tried to make my object pick a target now, but it's picking all targets-alive the same time and not re-target any new ones when spawned-new
This is doing kinda fine but for my main issue I am still out of sight...
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SkeletonWarriorAttack : $$anonymous$$onoBehaviour
{
public int attackDamage = 13;
public float attackTimer;
public float coolDown;
public List<GameObject> targets;
GameObject playereast;
ElvenWarriorHealth eastHealth;
SkeletonWarriorHealth westHealth;
void Start ()
{
attackTimer = 0;
coolDown = 1.0f;
GameObject[] enemyTargets = GameObject.FindGameObjectsWithTag("PlayerEast");
if (enemyTargets != null)
{
foreach(GameObject go in enemyTargets)
{
targets.Add(go);
}
}
}
void Update ()
{
if(attackTimer > 0)
attackTimer -= Time.deltaTime;
if(attackTimer < 0)
attackTimer = 0;
if(attackTimer == 0)
{
Attack();
attackTimer = coolDown;
}
}
void Attack ()
{
if (targets == null) return;
foreach (GameObject target in targets)
{
if (target != null)
{
float distance = Vector3.Distance(target.transform.position, transform.position);
if (distance < 2.5f)
{
ElvenWarriorHealth currentHealth = (ElvenWarriorHealth)target.GetComponent("ElvenWarriorHealth");
if (currentHealth != null)
{
currentHealth.TakeDamage (attackDamage);
}
}
}
}
}
}
"...but it's...not re-target any new ones when spawned-new."
"You'll need to run the Find() again to re-discover the object(s) you're seeking..."
If you only discover objects once, you're always operating on that same set of objects. Because these can come and go, you'll need to re-discover your objects each time you want to change targets. This is one of many reasons a trigger & line-of-sight based detection system is superior. Finds are expensive, messy, and offer none of the flexibility of other detection systems.
"...but it's picking all targets-alive the same time"
This is because your logic states: for every discovered target, if non null and distance less than whatever and has a health script, take damage. Presumably you should sort these targets by distance, then attack only the closest. Something like that. For now, it would be sufficient to "break" after a successful attack.
currentHealth.TakeDamage();
break;
Also, there's nothing wrong with your ti$$anonymous$$g mechanism, but I suspect you would benefit from learning about couroutines ins$$anonymous$$d. Google Unity Coroutines.