Best Methods & Practices: Calling Variables from Other Instances? (REF - Unity Tut: Space Shooter)

It seems like there’s more than one way of getting variables of objects and they seem very circumstantial. I’d like to know if I’m doing things correctly and if there are better methods in some of these cases.

Single Global Game Object: Player

public class ScriptName : MonoBehavior {
    private PlayerController player;
}

private void Start()
{
    player = FindObjectOfType<PlayerController>();
}

private void OnTriggerEnter(Collider other) {
    if (player != null)
        {
            playerBoltDamage = player.shotDamage * powerUp.shot.damage; //would powerUp possibly be defined as a single, global GameObject?
        }
}

Is there a better way to go about this? Is this recommended with other objects that are guaranteed to have one instance of? Is there a way I could globally declare somewhere what PlayerController player is so I can simply use player.variable anywhere in any script instead declaring it per script?

Instantiated Object

Should other.CompareTag(“Tag Name”) be used to find a specific object? How do I handle a case where I need to declare more than one kind of tag? In the Space Shooter tutorial, there’s the “Enemy” tag, and two enemy types: the ship and asteroids. I’m uncertain how to call an instance in such a scenario to change a variable.

When a variable of an object is being changed, should the script on that object change the variable, or should an external object’s script change it?

Example:

Collision detected between playerBolt and asteroid
–Should playerBolt’s script tell the asteroid to do something?
or
–Should asteroid’s script do something when it collides with playerBolt?

Or am I confusing myself by going beyond the scope of this tutorial and need to go forward with other tutorials? :stuck_out_tongue:

–addon–

Or could I perhaps make a blanket script that works depending on a variable selected?

Single Global Game Object: Player

Globals are often considered bad design, but can be useful for certain things.

Often I create a ‘Game’ class that is a global store of some general purpose things I might need on demand a lot (a reference to my InputManager, the Score, pause/resume, that sort of thing). I usually implement it as a Singleton:
http://wiki.unity3d.com/index.php/Singleton

I usually make it exist for the life of the game (do not destroy the gameobject between scene loads, see:Object.DontDestroyOnLoad.

Instantiated Object

well, other.CompareTag(“…”) doesn’t find objects… if you want to determine if an object that you have a reference to is tagged something, than use CompareTag.

Usually I have a ‘Entity’ script on the GameObject for my things like enemies and the sort. And those Entities might have a ‘type’ property of type enum that allows me to determine general information. Beyond that scripts usually don’t care what type of enemy something is beyond “it’s an enemy”. And instead search for “Health” scripts or the sort on the enemy to apply damage. Allowing those scripts to care about the specifics about the enemy.

That’s personal taste.

PERSONALLY I go with a design of ‘actor acts, passive receives’.

Basically, since the playerBolt is acting upon the asteroid, it would be the one to do something. Such as inflict damage on the asteroid. Here’s a simple method I’d go about doing it:

public class BoltWeapon : MonoBehaviour
{
   
    public float Damage = 1f;
   
    //an event that fires to signal that the bolt hit something
    //you can connect this to another script to play an animation, or a sound effect, or whatever
    //you can then have different bolts that sound/look different
    public UnityEvent OnStrike;
   
    void OnTriggerEnter(Collider other)
    {
        var health = other.GetComponent<HealthMeter>();
        if(health == null) return;
       
        health.Strike(this.Damage);
        this.OnStrike.Invoke();
    }
   
}

–addon–

Not sure to what you mean…

If you mean a generalized script that doesn’t care about specifics of who or what it’s attached to. Yeah, my previous example is just that.

1 Like

This makes much more sense! The stretch goals video even admitted that the current implementation wasn’t the best way to go about it, so now I understand more why I’m having difficulty with this.

Another question, if I may. I’ve not come across the following yet, and the API reference material isn’t very helpful on this one:

this.OnStrike.Invoke();

I’m not sure how Invoke is working.

It’s what invokes the UnityEvent.

Getting this from another thread:

So basically the ability to call a method with the option to control execution timing?

Otherwise could you use this.OnStrike();?

Which ‘Invoke’ is that referring to?

I sourced you the documentation for the specific ‘Invoke’ I was using, it’s the one on the UnityEvent class, UnityEvent.Invoke:

On the UnityEvent class:

Other classes can have other methods named ‘Invoke’.

To me it sounds like you’re referring to the method ‘MonoBehaviour.Invoke’:

Please refer to documentation for the specific class/method that you’re concerned about, rather than a random thread on a forum. This is why I include links to documentation.

Also, note, I merely added the UnityEvent ‘OnStrike’ as a added flourish. It is not necessary to get your code working. I was demonstrating a design that allows for easy expansion later on. Like for example adding in fx, animations, etc.

The documentation for invoke doesn’t have an example and gives one line of explanation.

I roughly understand callbacks but I’m still learning how to program. It’s been an on-and-off thing over the years with different languages and applications. :stuck_out_tongue:

The documentation for the class includes the example, which is why I included it in my most recent post.

Or, while at the UnityEvent.Invoke documentation, clicking the bolded text for ‘UnityEvent’ would bring you there.