Currently to find an object in my scene I am using FindObjectOfType. I don’t want to get use to this cause Unity says its slow. I was wondering if there are any other ways to find an object. Currently my game has an enemy, that is prefabbed, and my player which is an instance. I can’t connect prefab to instance so I had to use FindObjectsOfType. I was considering tags, but I kind of want to know if there are any other ways first.
when you instantiate your prefab, you can store it somewhere and access the variable.
You should look into a manager class that has a reference to your player. Than, when you spawn an enemy, it accesses your player gameobject through the manager script. As mentioned, you can also use this manager class to maintain a reference to enemies as they spawn or remove the reference as they die, but it handles things for you vs the individual enemies each having to create their own reference to the player when you instantiate them.
Here’s a whole list of methods. Different techniques are best for different situations, so having a list like this available will be handy.
For your purpose I just would add at the enemyController something like this:
public class Enemy : Monobehaviour
{
public static readonly List<Enemy> enemies = new List<Enemy>();
public void Awake() => enemies.Add(this);
public void OnDestroy() => enemies.Remove(this);
}
And just you call Enemy.enemies
in order to get all the current enemies.
I think some of you might have it backwards, or I do. He needs the enemies to know what gameobject is the player, not the player needing the enemies. Because the prefab can’t reference the player, when he instantiates an enemy, he’s using a FIndObjectWithTag call to have the enemy find the player.
Well, for the inverse purpose I may use a Singleton:
public class PlayerController : Monobehaviour
{
public static PlayerController Instance { get; private set; }
public void Awake()
{
if (!Instance) Instance = this;
}
}
And you call PlayerController.Instance
instead of FindObjectOfType<PlayerController>()
That might be some of the most useful comments here thanks so much
Sorry I am still too new for that
Exactly, I just realized I typed this question horribly. But you figured it out. I keep using FindObjectOfType and I hear that is bad for performance, so I would prefer not to get in the habit of using that. I know a couple of different ways, very simple ones, but I kind of want to learn more ways to do it.
a little to advance for me
I think I understand what your saying.
public class RubRub : MonoMonoMono
{
public GameObject gameObjectReference;
void Start()
{
gameObjectReference = this.gameObject;
}
}
So I make a new public GameObject, then when the enemy spawns just put it in GameObject? The problem is that there is only one instantiated, so like making a script for just this one is kind of useless.
Not exactly, it’s so important to have it static.
It’s a Singleton and I think I can explain you how it works.
The only you need is to understand what static
keyword means, i.e. what’s an instance variable and what’s a static variable.
We’re gonna create a really simple class called Dog:
public class Dog : Monobehaviour
{
public string name;
public int legs = 4;
public float weight = 20;
}
You also create 3 gameObjects at the inspector. You add them 3 Dog scripts and you modify the default values: These cells represent you pc memory:
You’ve 3 instances of Dog: Blue, Purple and Yellow; each one with its three instance values: name, legs and weight.
You’ve your Dog model with the data at Green.
Now from any script, you can take yellow, purple or blue dog name when you desire it:
public class Example1
{
private void Start()
{
Dog dog = GetComponent<Dog>();
//We can access the name of the Dog
Debug.Log(dog.name); //Dog 1st Lowcase, variable name
}
}
But you can’t take green dog’s name because it’s just a model and each dog has his own name:
public class Example2
private void Start()
{
//We can't call Dog.name.
Debug.Log(Dog.name); //Dog 1st Capital, class name.
}
}
But it could have sense to be able to call Dog.legs
because all the dogs has 4 legs. We don’t need to store the legs amount of each dog, so let’s make the legs
variable static.
public class Dog : Monobehaviour
{
public string name;
public static int legs = 4;
public float weight = 20;
}
Here it’s how you pc memory is stored now:
And we can’t call legs
for each instance of our three dogs, but we can call green value as this.
public class Example3
private void Start()
{
//Now we can acess Dog.legs
Debug.Log(Dog.name); //Works!
}
}
We don’t need to GetComponent()
anymore since we’re taking the static value of the green model: All the dogs share the same memory direction to know how much legs they have.
If we understand that, just remembering the code for what you was “still more new”
public class PlayerController : Monobehaviour
{
public static PlayerController Instance { get; private set; }
public void Awake()
{
if (!Instance) Instance = this;
}
}
Imagine public static PlayerController Instance { get; private set; }
as public static PlayerController instance;
. The get; set; keywords allows you to make it public to read and private to write, just ignore it because it works without perfectly.
Awake is something like Start, but Awake is called we the script is instantiated and Start just before first Update frame: When screen shows it by first time. It also works at Start… so lets rewrite the code
public class PlayerController : Monobehaviour
{
public static PlayerController instance;
public void Start()
{
if (instance == null)
{
instance = this;
}
}
}
So, when an instance of the script starts working, if the static PlayerController stored at the model has no value, just this script instance is that value. And now you can call the Model, your class directly, to get that value. So from another Script you can call PlayerController.instance
to access to the instance who registered itself when the value was null.
If you only has one PlayerController at all your Scene, you don’t need to make more
FindObjectOf Type<PlayerController>
because the only one will be accesible at the model. Now at your EnemyController you can do something like
public class Enemy : Monobehaviour
{
private void Update()
{
MoveTo(PlayerController.instance.transform);
}
private void OnTriggerEnter2D(Collider2D collider)
{
Destroy(PlayerController.instance.gameObject);
}
}
Thanks so much for the simple detailed explanation, first of all. It makes more sense why an plethora of people use static so much. Also is Static a datatype, or something else? Also is it possible to edit a static, I’ll try to show you what I am doing.
public class PlayerHealth : MonoBehaviour
{
//Our players health
public static int health = 10;
}
public class Enemy : MonoBehaviour
{
//if I hit a wall
//health--;
}
So in my case I have two different scripts, health script, and an enemy script. Problem is that these are two different scripts. I can’t simply just say health–; because its a reference and it doesn’t let me edit it. How would I exactly get a reference to the script and be able to edit it, without using FindGameObjectsOfType();
If enemy hits a wall, player health–?? So weird to lose player health when an enemy hits wall nut… If I understood what you wanna do, you can make it like:
public class Enemy : MonoBehaviour
{
//if I hit a wall
//health--;
private void OnTriggerEnter2D(Collider2D collider)
{
if(collider.transform.CompareTag("Wall"))
{
PlayerHealth.health--;
}
}
}
When OnTriggerEnter2D is called when a Collider trigger another one, and transform.ComparTag("Wall")
returns true if gameObject triggered tag is Wall
I don’t know why I said wall, I was trying to make some random example lmao. But the problem is that my OnTriggerEnter isn’t working, I tried multiple things and it doesn’t work. So that’s I am subtracting the player health from the enemy script, but I need make sure I can edit the player health, not just reference it.
If you use PlayerHealth.health--;
you substract the value.
I have done that before the problem is that the player is a instance, and the enemy is a prefab. You can’t connect a prefab and an instance directly, so I used FindGameObjectsOfType();
Oh wait never mind I was being an absolute idiot, I got it working, thanks so much.
Honestly, I caution the way you’re setting it up. Sure, this might work, but usually you don’t subtract playerHealth directly. Instead, you probably want to look into singletons for your player. Through the singleton, the player should have a method like “TakeDamage(int damage)” where you pass in a damage amount and then can do stuff like check if the player is dead, update visual gui, play damage effects, etc. You wouldn’t do all this from other scripts. The enemy script would only need to know how much damage it does.
But what if you have a spike or fire or other hazards? You’d be repeating a lot of code you don’t need to.