Transform search function only sporadically works?!
Hello everybody,
so I am trying to implement a "Zelda"- or "Dark Souls"-like z-targeting system. You'll see in the code, that the function compiles a list of every enemy in the current scene. I'm still in the prototyping phase so the only credential for the targeting is the distance between enemy and player. The script is attached to my player and there are three enemies in the scene.
Now for the problem: The function is not reliable. Sometimes it updates the 'target', sometimes it doesn't. The debug.log fires as expected, only the most important thing appears to zoom in and out. This function is supposed to toggle the lockon as well, which doesn't reliably work either.
Tips on how to make the code lighter are appreciated as well!
void LockOnEnemy(){
bool check = false;
if (target == null) {
float enemyDistance = 100000000; //max lockon distance here
float enemyDelta = enemyDistance;
int enemyID = 0;
GameObject[] enemyList = GameObject.FindGameObjectsWithTag ("Enemy");
if (enemyList.Length > 0) {
for (int i = 0; i < enemyList.Length; i++) {
enemyDelta = (transform.position - enemyList [i].transform.position).magnitude;
if (enemyDelta < enemyDistance) {
enemyDistance = enemyDelta;
enemyID = i;
}
}
target = enemyList [enemyID].transform;
Debug.Log ("Found: Enemy( " + enemyID + ") at " + enemyDistance);
}
check = true;
}
if(check == false) {
this.target = null;
}
}
Answer by wibble82 · Dec 22, 2015 at 12:10 PM
Interesting!
Making your code a bit neater, the logic with the 'check' variable does seem a little odd:
void LockOnEnemy()
{
//we default to check == false
bool check = false;
//we will ONLY scan for new targets if current target is null
if (target == null)
{
GameObject[] enemyList = GameObject.FindGameObjectsWithTag("Enemy");
if (enemyList.Length > 0)
{
int enemyID = -1; //default this to 'invalid' value (just good practice!)
float closestEnemyDistanceSqr = float.MaxValue; //max lockon distance here (use float.MaxValue unless you have a good reason not to!)
//find closest enemy (only change is I'm looking at squared magnitudes, as they do the job and are more efficient)
for (int i = 0; i < enemyList.Length; i++)
{
float enemyDeltaSqr = (transform.position - enemyList[i].transform.position).sqrMagnitude;
if (enemyDeltaSqr < closestEnemyDistanceSqr)
{
closestEnemyDistanceSqr = enemyDeltaSqr;
enemyID = i;
}
}
//store the target. we can safely assume enemyID is no longer -1, as we know there is at least 1 enemy in enemyList
target = enemyList[enemyID].transform;
Debug.Log("Found: Enemy( " + enemyID + ") at " + Mathf.Sqrt(closestEnemyDistanceSqr));
}
//now we set check to true regardless of whether we found an enemy - is this what we want
check = true;
}
//if check is false (i.e. we didn't go through the above if statement), we clear 'target'.
if (check == false)
{
this.target = null;
}
}
That's mostly the same, aside from a little clean up (using squared distance as its faster, and putting variables inside the correct scope).
However it highlights that the behaviour will be:
If 'LockOnEnemy' is called when target != null, check will always be left false, so target will be instantly cleared
if 'LockOnEnemy' is called when target == null, check will always be set t true
So basically, assuming there are enemies in range, LockOnEnemy will flip between having a target and not having a target.
-Chris
Thanks for the cleanup. The tip with the default enemyID is really useful as well. I was searching for something like this but never considered putting in a negative value.
Sadly the problem is still present. Sometimes it works immediately, other times I have to press the button three+ times to lock on to an enemy. I just don't know what's causing this...