- Home /
Find Target From List
Hi there Unity,
I'm having trouble consistently pulling my desired target from a list. Here's what I've set up. This is for a tower defense game, and the tower has two main settings. First and Last. As you can imagine, this sets the tower to either attack the first target in the list, or the last in the list. The targets are spawning and then running through a maze to the end zone.
Target spawns and gets added to list
If target dies, it gets subtracted from list.
The tower starts out (usually) attacking the first in the list, but once that target dies and gets subtracted, the tower moves to the last target. The tower's priority level is on First the entire time, but it acts as if it is on Last.
Here's my code!
Also, if you guys have any suggestions on how to efficiently check if the first in the list isn't necessarily the closest to the end zone, that would be a huge help.
void Update(){
UpdateTarget();
}
public void UpdateTarget()
{
//If I don't have a target...
if (myTarget != null) {
//Get the distance between me and the target.
if (Vector3.Distance (myTarget.gameObject.transform.position, this.transform.position) > maxAttackRange) {
//If the target is too far away, set target to null.
myTarget = null;
} else {
//Else, if my target is not in the target list...
if (!eList.targetList.Contains (myTarget)) {
//Set target to null
myTarget = null;
}
}
return;
} else {
//Else, if I DO have a target...
switch(selectPriorityLevel){
//If the priority level is set to first (Attack first enemy in the list...)
case priority.first:
//Iterate through the list and get the first available target in the list that is close enough to attack.
for (int i = 0; i < eList.targetList.Count; i++) {
//If the distance to the referenced target is within the maximum attack range..
if (Vector3.Distance (eList.targetList [i].transform.position, this.transform.position) < maxAttackRange) {
//Set said target to MY target.
myTarget = eList.targetList [i];
//Rotate tower to follow enemy.
FollowEnemy ();
//If this is an AoE tower, exit function. Else, attack.
if (launchStyle == projectileLaunchStyle.aoe)return;
StartCoroutine (AttackEnemy ());
}
}
break;
case priority.last:
//If priority level is set to last (Attack last enemy in list...)
for (int i = 0; i < eList.targetList.Count; i++) {
//Iterate through the list and get the last available target in the list that is close enough to attack.
if (Vector3.Distance (eList.targetList[eList.targetList.Count-1].transform.position, this.transform.position) < maxAttackRange) {
myTarget = eList.targetList [eList.targetList.Count-1];
//Rotate tower to follow enemy.
FollowEnemy ();
//If this is an AoE tower, exit function. Else, attack.
if (launchStyle == projectileLaunchStyle.aoe)return;
StartCoroutine (AttackEnemy ());
}
}
break;
}
}
}
Answer by NoseKills · Apr 12, 2015 at 09:09 AM
In case priority.first:
you don't break out of the search loop if you find a target, so you end up going through the whole list and the last thing you do will be attacking the last item on the list that is within range, not the first one you find.
In the second one you loop eList.targetList.Count
times but you compare distance to the last item on the list every time Vector3.Distance (eList.targetList [eList.targetList.Count - 1]...
.
Since you want to do the same thing in both cases, just in reverse order, you could do like this
public void UpdateTarget ()
{
if (myTarget != null)
{
if (Vector3.Distance (myTarget.gameObject.transform.position, this.transform.position) > maxAttackRange)
{
myTarget = null;
}
else
{
if (!eList.targetList.Contains (myTarget))
{
myTarget = null;
}
}
// no need to have a return; here because there's no code after the if.
// we entered the "if" so we won't enter the "else".
// return;
}
else
{
if (selectPriorityLevel == priority.first)
{
for (int i = 0; i < eList.targetList.Count; i++)
{
if (trySetAsTarget(eList.targetList[i]))
return;
}
}
else
{
for (int i = eList.targetList.Count-1; i >= 0; i--)
{
if (trySetAsTarget(eList.targetList[i]))
return; // if target was found, stop searching
}
}
}
}
// return whether a target was found or not
bool trySetAsTarget(MyTargetType target)
{
if (Vector3.Distance (target.transform.position, this.transform.position) < maxAttackRange)
{
//Set said target to MY target.
myTarget = target;
//Rotate tower to follow enemy.
FollowEnemy ();
//If this is an AoE tower, exit function. Else, attack.
if (launchStyle == projectileLaunchStyle.aoe)
return true;
StartCoroutine (AttackEnemy ());
return true; // target found and set
}
return false; // not close enough
}
This works beautifully. Thank you for taking the time to read/edit. This was one of the first times I've tried to use switch statements in place of if/else so I'm sure that's why I got confused. I assumed there was some benefit to them in this instance, but this way looks much more logical.
Thanks again!