Reputation: 2689
I've written a homing missile script for my action platformer and I cant help but notice that this might not be the most efficient of weapons.
void Start()
{
target = GameObject.FindGameObjectWithTag("Enemy");
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
direction = (target.transform.position - transform.position).normalized;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
rotatetoTarget = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, rotatetoTarget, Time.deltaTime * rotationSpeed);
rb.velocity = new Vector2(direction.x * fowrardSpeed, direction.y * fowrardSpeed);
}
It works perfectly but there are a few issues with it. How do I ask it to randomly select a different enemy every time it is instantiated? Rather than all going for one enemy?
Also once that enemy has died, it should choose a new target, but wont performing GameObject.Find()
in Update()
be a bad thing? I understand that GameObject.Find()
is to be avoided as it goes over all of the gameObjects in the scene until it finds what it is looking for, and if need be should only be used in Start()
. Now I had to use GameObject.Find()
when the weapon instantiates as I could not find of any other way to locate the target for the weapon. So is there a better way to chose a new target once that target is destroyed? My game is a game where reaction time matters and I dont want to create any unnecessary lag due to this weapon
Thank you
Upvotes: 3
Views: 1344
Reputation: 4071
You could have an EnemyCache
and MissileSpawner
script.
Your EnemyCache
(most likely a singleton) would have a list of enemies in the world;
Enemies are added into that list when they are spawned, and removed from that list when they die.
Your MissileSpawner
(or something that spawns the projectiles) script would then need to assign the missiles a target each time it spawns a new missile.
It can fetch a target for the new missile via the EnemyCache
. (You can even filter the list to get the closest target too!)
Finally, your missile script can fetch a new target from the EnemyCache
if the old target died.
Overall, it should look similar to this:
public class YourMissile : MonoBehaviour {
// ...
GameObject target;
public void Update() {
// target is destroyed or gone
if (target == null) {
SetTargetFromEnemyCache();
}
}
private void SetTargetFromEnemyCache() {
if (EnemyCache.Instance.TryGetFirstEnemy(out Enemy newTarget)) {
target = newTarget.gameObject;
} else {
Debug.LogWarning("No enemy for missile to target!");
}
}
// ...
public void SetTarget(GameObject targetToSet) {
target = targetToSet;
}
// ...
}
public class EnemyCache : MonoBehaviour {
// Singleton
public static EnemyCache Instance { get; private set; }
private List<Enemy> cachedEnemies;
private void Awake() {
Instance = this;
cachedEnemies = new List<Enemy>();
// TODO: Subscribe to a delegate or event, that adds into the 'cachedEnemy' whenever an enemies spawned.
// Also, an event that removes from 'cachedEnemy' when an enemy dies too.
}
// ...
/// <summary>
/// Tries to fetch the first enemy in the cache.
/// </summary>
/// <param name="enemy">The fetched enemy; Null if there was nothing in cache</param>
/// <returns>True if there is an enemy fetched; False if none</returns>
public bool TryGetFirstEnemy(out Enemy enemy) {
if (cachedEnemies.Count > 0) {
enemy = cachedEnemies[0];
return true;
}
enemy = null;
return false;
}
}
public class YourMissileSpawner : MonoBehaviour {
[SerializeField]
private YourMissile missilePrefab;
// ...
public void SpawnProjectile() {
YourMissile newMissile = Instantiate(missilePrefab);
// Set position... etc...
// Try to get a target for the new missile
if (EnemyCache.Instance.TryGetFirstEnemy(out Enemy enemyToTarget)) {
newMissile.SetTarget(enemyToTarget.gameObject);
} else {
Debug.LogWarning("No enemy for newly spawned missile to target!");
}
// NOTE: The above is optional,
// since 'YourMissile' sets a new target from EnemyCache
// if the target is null; (checks per update)
// But I included it here in case you want it to filter
// what kind of enemy it needs to target on start :)
}
}
Upvotes: 2