Adding a method to a game object

Good morning. I have a related question here GameObject properties collection can be added to? but this is an attempt to get help by making the problem more specific and less general.

I have a scene with hundreds of GameObjects, a few dozen of which have scripts attached with properties that affect its behavior in game.

At certain points of the game, I’d like to reset these few dozen objects to their original states. To make it more concrete let’s state that the few dozen objects each are either a Door, Window, Ball, or Chair, each of which have prefabs made with scripts attached to them holding these properties.

What I’d like is a variable array set up in the editor which the game’s designer can fill with objects that need this rest ability. Armed with this array of ResettableGameObjects in my GameManager, when the time comes to reset the GameObjects, I’d like to call a method of the GameObjects in a loop such as:

for (int i = 0; i <= ResettableGameObjects.Length - 1; i++)
{
ResettableGameObjects*.*Reset()
}

Unfortunately, you cannot extend the GameObject to add such a method.

I could add a Component script to each prefab that contains a Reset function, however as each type of game object(Door, Window, Ball, Chair) has different things that needs reset I cannot use a generic component script named “Reset.cs” unless I want to make the costly calls of finding out which type of object I am attached to. So, I cannot seem to make a generic loop as shown above. I’d need differently named component scripts for each type of object.

Is there a simply way to achieve the type of reset loop I am looking for above in which a “GameObject’s” reset function is called without needing to know exactly what type of GameObject we have?

Components can implement interfaces no problem.

interface IResetable { void OnReset(); }

public DoorReset : MonoBehaviour, IResetable
{
      // fill it in
}

public WindowReset : MonoBehaviour, IResetable
{
      // fill it in
}

Then you can use your loop with IResetable types and call OnReset() on them. Defining all of those reset scripts may be cumbersome depending on your setup, but you can always use inheritance to simplify things if there’s common elements among each resetable object.

Perhaps another cheeky way to do it would be to instantiate a clone of your objects on Start, and then on reset, destroy the original object and replace it with your cloned object and then re-clone them again for the next time you need to reset.

Interfaces are not something I am familiar with, could you help explain how that relates here?

edit: OK I did a quick read on interfaces and I’m not sure how this helps. Each GameObject would still have a differently named component script attached correct?

You can fetch interfaces through GetComponent.

IResetable resetable = gameObject.GetComponent<IResetable>();

Then it doesn’t matter what the “real” component is, just that it has an IResetable implementation. They’re very powerful.

So within any component script (named whatever they are named) attached to the various GameObject I can place an interface with the definition given above:

interface IResetable { void OnReset(); }

and then for the one attached to doors just have the public DoorReset function, the one attached to the chairs have the ChairReset function, etc?

Watching this:

Trying to learn. Will report back.

Well, this is not working so well yet.

I have created an IRESET interface:

public interface IReset
{
    void Reset();
}

Then in each object I need to reset, I implement a reset method on a component script attached to it, and add the IReset interface to the class.

An example for an object who has a reset behavior of simply changing position back to where it started…

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

public class PositionReset : MonoBehaviour, IReset
{
    private Vector3 ResetPosition;
    private Quaternion ResetRotation;
    private Vector3 ResetVelocity;
    private Vector3 ResetAngularVelocity;
    private Rigidbody rb;

    // Start is called before the first frame update
    void Start()
    {
        ResetPosition = gameObject.transform.position;
        ResetRotation = gameObject.transform.rotation;
        rb = gameObject.GetComponent<Rigidbody>();
        ResetVelocity = rb.velocity;
        ResetAngularVelocity = rb.angularVelocity;
    }

    public void Reset()
    {
        gameObject.transform.position = ResetPosition;
        gameObject.transform.rotation = ResetRotation;
        rb.velocity = ResetVelocity;
        rb.angularVelocity = ResetAngularVelocity;
    }
}

And finally, loop through all the Resetable Objects in my array of objects that need reset.

       for (int i = 0; i <= ResetableGameObjects.Length - 1; i++)
        {
            IReset resetee = ResetableGameObjects[i].GetComponent<IReset>();
            resetee.Reset();
        }

Unfortunately, I am getting null reference errors on resetee. (Second line of the script) Indicating none were found.

Any help?

Everything looks fine, so one (or more) of the objects you’ve added to your array lacks a component that implements the IReset interface. You can add a null check to figure out which one(s).

IReset resetee = ResetableGameObjects[i].GetComponent<IReset>();

if(resetee != null)
   resetee.Reset();
else
   Debug.Log(ResetableGameObjects[i].name + " lacks an IReset interface");

The issue…

Reset is a reserved keyword :frowning:

Changed Reset() to Resetable() and all OK. Thank you for your help GroZZler. Now I know a bit about Interfaces!

1 Like

Oh duh! Good catch. :slight_smile:

So, if more than one component contains a Resetable() script, could one use GetComponents()?

I honestly do not know, I’ve never tried. I’m sure you’ve tested it by this point… so does it work? :slight_smile:

Turns out SendMessage works even better. No more messy interfaces, and the GameObjects work more similar to normal objects.

According to the Unity 4.6 release notes a non-generic GetComponents was added that supports interfaces. I’m guessing it’s the following entry which is second from the bottom of the GetComponents reference page.

https://docs.unity3d.com/ScriptReference/GameObject.GetComponents.html

Here is the release notes entry and link.

https://unity3d.com/unity/whats-new/unity-4.6

Instead of all the kludgy GetComponents and Interface definitions, SendMessage seems to be doing fine.