Best way to reference a prefab game object?

Hey there,

Thanks in advance for reading/replying to this thread. Just as a disclaimer, I’m new to Unity and a novice when it comes to C# scripting. Right now, I am attempting to make floating damage numbers when an enemy gets hit and, of course, I am following a tutorial to do so. The video can be seen here:

The video is stating that I should create a new class called “Game Assets” to easily reference any game object that I need (in order to reference our damage popup prefab on cs10).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class DamagePopup : MonoBehaviour
{
    public static DamagePopup Create(Vector3 position, int damageAmount)
    {
        Transform damagePopupTransform = Instantiate(pfDamagePopup, position, Quaternion.identity);

        DamagePopup damagePopup = damagePopupTransform.GetComponent<DamagePopup>();
        damagePopup.Setup(300);

        return damagePopup;
    }

    private TextMeshPro textMesh;

    private void Awake()
    {
        textMesh = transform.GetComponent<TextMeshPro>();
    }

    public void Setup(int damageAmount)
    {
        textMesh.SetText(damageAmount.ToString());
    }
}

Do I need to go to all this trouble to reference a prefab? Is there a simple and easy way to do this? What are the best practices when it comes to referencing? Any insight would be appreciated.

Can you post the GameAsset class or provide a timestamp for the video where this is mentioned?

It’s kind of cumbersome to have a static method and a reference to a prefab, which is the syntax snafu you’re currently in.

I generally do not make a static “instantiate me” method; that’s the first method you list. It’s up to the caller to put their big boy pants on: they have a reference to the exact prefab that’s needed, and they can call the Instantiate method themselves because they probably need to customize it right away too.

A compromise would just be for the caller to pass a pfDamagePopup argument to your static “instantiate me” class method, and also any other setup information like the number you wanted to show.

Personally I like Resources.Load() but it gives some people here hives. Read up on the docs about it. The most common mistake is wrong file placement and wrong path specification. It matters, pay attention.

Attached is my simple Digits script, including a test scene and script, which does all the above.

It uses oldskool Text objects but it’s easy enough to refactor if you prefer some modern TMPro action.

9542701–1347769–Digits1.unitypackage (6.98 KB)

Serialization (setting data in the editor to save with your project, such as a reference to a prefab), static references, and how to connect all parts of your application is a more complex topic than you might hope.

Yes, see Kurt’s answer above. Any prefab in any folder named Resources can be loaded with Resources.Load() by providing the relative path to that asset.

If you were to ask any number of individual members of this forum, you would receive that many unique answers to this question. For various reasons, I hesitate to detail my opinion on the matter. However, I commend you for noticing something important and asking the right questions.

nah, the absolute easiest way is to just add

public GameObject DamageNumberPrefab;

to whatever component needs to instantiate the prefab. Then just drag the prefab in to the inspector.

There are two different things going on there. You’re correct that to get a prefab you can simply add public Transform damageFloaterPF; and create it with Instantiate.

But in this case you want to create it and go inside to set the textArea to the damage. That’s only a few lines, but it’s a pain to find and copy them onto everything that causes damage, and then to keep updated when you decide you need different colors as well. Basic computer programming says to put that into a function, like createDamagePopup(Vector3 worldPos, int damageAmt). Now everywhere that causes damage only has one thing to do, using obvious inputs and it has a nice obvious name.

If you just want to make a game, copy that stuff and use DamagePopup.create like it says. If you just want to write your own code for a game, forget that extra stuff and use Instantiate directly. But if you want to learn how programmers think with the excuse of making a game, then look at that until you can see “oh, since each damage pop-up already needs a script (to slowly move it, then fade out) we may as well add a ‘create one of me’ function to it to make them easier to use”.

Code Monkey’s tutorials are pretty quick and dirty. Not always the best practice, but in this instance he’s employing what is generally regarded as a “Factory Method”. Ergo, if you have something that’s used a lot in the same/similar configuration, then you may want a readily available way to generate it as needed from many different locations.

It may seem like an inordinate amount of work, but really it’s some upfront work that saves lots of time later down the line.

This is the video regarding the Game Assets class in question:

https://www.youtube.com/watch?v=7GcEW6uwO8E

Here is the code for Game Assets:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameAssets : MonoBehaviour
{
    private static GameAssets _i;

    public static GameAssets i
    {
        get
        {
            if (_i == null) _i = (Instantiate(Resources.Load("GameAssets")) as GameObject).GetComponent<GameAssets>();
            return _i;
        }
    }
}

Well that is certainly a very quick and very dirty way to do globally accessible assets.

I’ve usually gone the route of a scriptable object singleton implementation using Preloaded assets: Unity - Scripting API: PlayerSettings.GetPreloadedAssets

Thanks for the recommendation! I added a “public GameObject prefab” reference and tried to access the transform component of it with no avail. It still states that it needs a reference to the object.

I could have typed something incorrectly though.

Make sure to Instantiate(DamageNumberPrefab) to create a copy of the prefab asset in the active scene before attempting to access the transform.

Sounds like you missed the “drag it in” part!

The answer is always the same… ALWAYS!

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null ← any other action taken before this step is WASTED TIME
  • Identify why it is null
  • Fix that