- Home /
How can i reference the scripts of multiple Instantiated GameObjects?
Im kind of struggling calling a Function from my Enemy's Script when attacking. My current problem is not beeing able to reference the Script i need to call the Function on for the Enemy to get damaged. These Enemies are spawning over time while playing. How can this be achieved?
Well, there are several solutions to this. You could use tags and find those object via its tag through FindWithtag or if you dont want to use tags you could just use GameObject.Find("NameOfObject") and get the script you want a reference to via GetComponent().
Short example: YourScriptname temp = GameObject.Find("ObjectToFind").GetComponent(); temp.Some$$anonymous$$ethodYouWantToCall();
Another approach would be to let those instantiated objects register themselves into a central controller which holds a list of all current enemy objects. Its up to you which approach you want to use in considering how much control you really want to have. How dynamic your whole setup should be etc.
Wouldn't i need to call GameObject.Find every all the time ? Because its normally called in Start but when the Enemy just spawned at some other time it wont get found.
Another Problem is that i would have only 1 Script at a Time wont i ? But i want to attack all enemies and not only one. I dont know how Lists work, i only know they work like Arrays even though im never really using Arrays either..
From what I understand, GameObject.Find is really heavy and you shouldn't use it a lot because it will slow your game down. You should really look up how to use Lists as they are perfect for this sort of thing.
If you are using this for enemies you could pool the enemies in a List then just 'target' all the active enemies in the list. Seriously though, learn how to use Lists, they are awesome!
Answer by Desoxi · Nov 16, 2016 at 06:29 PM
Jep @Metorphium, you are right, GameObject.Find would work but in a scene with a lot of objects it could heavily affect your performance. Then i would recommend to use the generic Lists approach. And its the even better solution if you want to damage ALL enemies. The only thing you would have to do is to tell the enemy scripts to register themselves in some kind of EnemyManager script. And when you want to damage all of them just create a method inside your manager to do exactly that with iterating through the list of enemies and call a method like Damage(50.0f) or something. Ill try to write a really short example for it:
EnemyManager.cs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class EnemyManager : MonoBehaviour
{
public static EnemyManager instance = null;
List<Enemy> enemies;
void Awake()
{
if(instance == null)
{
instance = this;
}
else
{
Destroy(gameObject);
}
enemies = new List<Enemy>();
}
public void DamageAll(int damage)
{
foreach(Enemy e in enemies)
{
e.TakeDamage(damage);
}
}
public void RegisterEnemy(Enemy enemy)
{
enemies.Add(enemy);
}
}
Enemy.cs:
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour
{
int hp = 100;
void Start()
{
EnemyManager.instance.RegisterEnemy(this);
}
public void TakeDamage(int damage)
{
hp -= damage;
}
}
This is what I replied with, only written much better lol. This seems like it should be a pretty standard way to do what $$anonymous$$etorphium wants.
Thanks for the compliment, but from what i saw in your code it should work as well. I tried to write something more generic so it can be applied to any other manager as well :)
P.S.: I accidentally voted down your answer because i was reading stuff on my smartphone xD Its up again :)
Ofc you can write it with real generic types too.. :D
@$$anonymous$$etorphium If you want to hit ALL enemies one by one you can achieve that when you create a coroutine which would be called from DamageAll() which again would have a short breakt of, say 0.5f sec, each time it iterates through the for loop.
But if you just want to call a method on a object which you hit with a raycast i would recommend you to read the following docs: https://docs.unity3d.com/ScriptReference/Physics.Raycast.html and use the "out hit" param. To get the gameObject you just hit you then have to use hit.gameObject.GetComponent(). You dont need a list for this approach.
Answer by MaximumTre · Nov 16, 2016 at 07:42 PM
I'm not a pro at this, but here's an example for how to use a list:
// Forgot Preprocessor stuff >:(
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
List<GameObject> pooledEnemyList;
public int pooledAmount;
void Start()
{
pooledEnemyList= new List<GameObject>();
for (int x = 0; x < pooledAmount; ++x)
{
GameObject obj = (GameObject)Instantiate(pooledObject);
obj.SetActive(false);
pooledEnemyList.Add(obj);
}
void FindEnemies()
{
foreach(GameObject obj in pooledEnemyList)
{
// Do something here like...
if(obj.active)
{
obj.GetComponent<SomethingYouWant>().SomeFunction();
}
}
}
Sorry for crappy formatting.
Answer by Metorphium · Nov 17, 2016 at 04:32 PM
huh.... so i dont need a list afterall if i just normally want to damage 1 Enemy.... Well thats my bad, but Knowledge never is wrong. I may just keep the List for future capabilities.
I will read through that! Thank you!