1

I am adding a set of array values through inspector window. I am trying to achieve to trigger a function, when I change my array values. That is, my script should check if the new values are not equal to old values and then call this function. I do not want to use Update as it will take more memory and processing power, so what could be the alternative?


public class SetValues : MonoBehaviour {

    [Serializable]
    public struct SetValues
    {
        public float Position;
        public float Value;
    }
 
    public SetValues[] setValues;


    void Function_ValuesChanged()
    {
        Debug.Log("The Value is changed");
        //Do Something
    }

}
Techno
  • 67
  • 2
  • 9
  • here's a simple tutorial for Unity events if it helps: https://stackoverflow.com/a/36249404/294884 – Fattie Jan 20 '21 at 13:11
  • @Fattie Unity events and C# events are not the same. You can't use Unity Events for this case. Unity Events intended use area is UI Interaction. – SeLeCtRa Jan 20 '21 at 13:19
  • HI @SeLeCtRa - I have no idea what you're talking about, and it makes no sense. (Sorry!) To trigger something when a value is changed, you just use a Property (as explained in your answer). So that's the answer to the question. (As in your great answer!) Of course, it's very likely that after that, you will use an event - so I just put in the link to help the OP. – Fattie Jan 20 '21 at 13:22
  • I don't mean to offend you dude. We are just discussing, I know you wanted help but as far as I know Unity Event System is not the case for that.I just write comment because if someone saw it and try it, it will not work as intended because interaction between UI and interaction between scripts are different layers. Correct me if I am wrong. I am eager to learn that way too if possible. – SeLeCtRa Jan 20 '21 at 13:28
  • just BTW I'm confused about the discussion, but UnityEvents are not only for Unity.UI ? you can use them for anything in Unity in any monobehavior (I believe!) – Fattie Jan 20 '21 at 16:36

2 Answers2

3

Try MonoBehavior.OnValidate()

Example:

public class SetValues : MonoBehaviour {

[Serializable]
public struct SetValues
{
    public float Position;
    public float Value;
}

public SetValues[] setValues;


void OnValidate()
{
    Debug.Log("The Value is changed");
    //Do Something
}

}
  • 3
    This is the best answer if you only want this to happen in the inspector. Be careful with the OnValidate function as it is ONLY called on inspector change event. It will never be called in your built executable ... – avokado Jan 20 '21 at 13:11
  • What if the values are changed from the server? Since it is declared as public, it will still be called right? – Techno Jan 20 '21 at 13:22
  • 1
    @Techno , no, that's wrong. What avokado said is correct. What you need is simply a **Property** - as explained in the other answer – Fattie Jan 20 '21 at 13:23
  • 1
    @Techno , "OnValidate" is purely *a MonoBehavior function* - it is literally part of the Inspector: https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnValidate.html it is not a "general" function in C# or anything like that. – Fattie Jan 20 '21 at 13:27
2

If something happens in game and you want to notify other scripts use events. Events are lightweight and easy to implement.

In class that contain array, create property and change array value, only from property. Never directly interact with array field.

// Create Event Arguments
    public class OnArrayValueChangedEventArgs : EventArgs
    {
        public float Position;
        public float Value;
    }
    // Crate Event
    public event EventHandler<OnArrayValueChangedEventArgs> OnArrayValueChanged;
    
    Array[] myArray;
    // Change Array value only from this property, so when you change value, event will be called
    public Array[] MyArray
    {
        get { return myArray; }
        set { myArray = value; OnArrayValueChangedEvent(this, new OnArrayValueChangedEventArgs() { Position = myArray.Position, Value = myArray.Value };}
    }

From second class you should just subscribe to this event and do the thing. I will call this event from my GameManager Singleton class.

private void Awake()
{
    GameManager.Instance.OnArrayValueChanged += Instance_OnArrayValueChanged;
}

private void Instance_OnArrayValueChanged(object sender, GameManager.OnArrayValueChangedEventArgs e)
{
    // Do the thing
}
SeLeCtRa
  • 600
  • 1
  • 6
  • 14
  • FYI It's impossible to have a "singleton" in a game engine. – Fattie Jan 20 '21 at 13:11
  • @Fattie Could you elaborate please? The standard pattern, static variable to hold the one instance still works in Unity. Whether you should use singletons is another question . Personally I'd say there are a handful usecases. For example I use it for storing global user preferences\settings as well es rough states like "menu open" etc. – AlexGeorg Jan 20 '21 at 13:18
  • @Fattie Sorry dude but how come? Do you know what singleton is? Singleton is you can have only one class that script have. I have GameManager, ResourceManager, ProductionManager, etc maybe 20 or more singleton class. Singleton patern ensure you have only 1 instance and you can access variables easily. And no problem so far. BUT my use cases are a little bit special so in many type game singleton is less used but that doen't mean you can't use singleton. It is just programming pattern. – SeLeCtRa Jan 20 '21 at 13:21
  • You can't have a singleton component .. MonoBehavior in Unity .. in a game engine or any ECS system. It's totally meaningless. – Fattie Jan 20 '21 at 13:25
  • @Fattie Singleton is not type of component it is programming pattern. Here my Singleton class. using UnityEngine; public abstract class Singleton : MonoBehaviour where T : MonoBehaviour { private static T instance; public static T Instance { get { if (instance == null) { instance = FindObjectOfType(); } return instance; } } } It is just Monobehaviour with extra step. It ensure only 1 instance and easy access to variables. Nothing magical. – SeLeCtRa Jan 20 '21 at 13:33
  • Perfect thanks! I shall try both answers! – Techno Jan 20 '21 at 13:34
  • @Techno If it is only for editor OnValidate is far easier, but if it for game mechanic OnValidate will not work in runtime. You should use my answer(C# Event System) for it. Choose which applies to your case. – SeLeCtRa Jan 20 '21 at 13:36
  • @SeLeCtRa - heh - run your game. In inspector tap on the game object holding this component. Tap ctrl-D to duplicate it. – Fattie Jan 20 '21 at 13:38
  • @Fattie usually you additionally implement `private void Awake(){ if(instance && instance != this){ Destroy(gameObject); return; } instance = this; }` => fully working Singleton pattern .. if you duplicate it, it will immediately destroy itself => I see no reason why a Singleton would not make sense or not have no meaning in a game engine ... The final result is a built application as any other and using singletons is controversial .. but still a valid way to go ;) – derHugo Jan 20 '21 at 14:31
  • @derHugo ... purely regarding (unrelated to game engines) "are singletons good or bad?" Much as one might ask "Are globals bad?!" or "should variable names be long!" etc. I find, the idea that singletons are "bad" is incredibly confused. Note that if you develop for mobiles (iPhone, etc). Basically *everything* is a singleton. the compass, the screen, the app (!!!), the antenna, the gps, the speaker, the bluetooth, etc etc etc. do not even mention core data etc. iOS development from the first line to the last is singletons; this example really makes it incredibly whacky when ... – Fattie Jan 20 '21 at 14:36
  • .. folks say "singletons are bad!" furthermore, in game development specifically (unity, server side, realtime systems .. whatever) singletons are a completely natural, inevitable and necessary concept. For example "the AI system" "the scoring system", do not even mention "the networking" etc - all these things basically "have to be" singletons and it's totally whacky when folks assert they are "bad" (in the sense of "globals are bad!" etc). Back to the question at hand ... – Fattie Jan 20 '21 at 14:37
  • your `Destroy(gameObject);` is not usable in any real-world project, who knows what object in the scene you're destroying (so, we're working on the new Lara Croft game, and we destroy her, one of her avatars, animations, etc :) ) and who knows what components you're destroying that are also attached to the game object; and who knows what has already run (in Awake) in other components on this game object. Further, it's super-flakey to have to *rationalize* why one shouldn't randomly make/destroy game objects in a game engine scene. – Fattie Jan 20 '21 at 14:40
  • (there have been endless schemes in unity to "automatically create and destroy gamne objects, to result in a "singleton-like game object" ... none of them work of course, and they all have tremendous Code Smell anyway, so to speak) – Fattie Jan 20 '21 at 14:41
  • Setting that aside, I do find it incredible when otherwise HIGHLY intelligent engineers like YOU don't seethe very obvious, that a "singleton" is meaningless in a scene which is just a canvas with game objects on it. Components are just *things stuck on game objects*. Game engines ***are only about game objects, there's nothing in a game engine other than game objects***. game engines have absolutely no connection in any way, at all, to OO programming. indeed they have no connection to "programming" as one normally thinks of it! – Fattie Jan 20 '21 at 14:44
  • Say we were using photoshop and had a white canvas open, and we were making various marks on it (long, short, yellow, blue, etc). Say I said to you "oh, you see that red mark. I want it to be a singleton." **It doesn't even make any sense, it doesn't parse.** Let's further say that one could attach components to the marks on the white canvas. For example a "blink" component that makes it blink etc. Further, say programmers could *create* those components, using perhaps Pascal. Say the programming language Pascal features "singletons"........... – Fattie Jan 20 '21 at 14:46
  • .....if someone now started talking about the red, yellow marks and singletons that would ***just plain make no sense!!*** the red and yellow marks just have NO connection, in any way, conceptually, to "singletons". It would be like if I said "how do we determine the emotional state of the red mark" or "what is the golf handicap of the red mark" :) there's just literally NO connection, it's a *totally unrelated idea*. – Fattie Jan 20 '21 at 14:48
  • My "photoshop analogy" is the best I can do to try to explain to folks that "singleton" has no meaning in a game engine scene. I have not thought of a clearer way to think about it or explain it! That's the best I can do old mate! cheers @derHugo – Fattie Jan 20 '21 at 14:50
  • @Fattie I absolutely don't understand what red or yellow marks should be .. not even in a photoshop analogy ... But yes it does ^^ Singleton ad already said is a programming pattern .. you can use it .. well whatever you want to use it for. The "meaning" of a singleton is: "There exists only exactly one instance of this type" ... Nothing more nothing less .. basically everything that uses `FindObjectOfType` is basically assuming this singleton property and could as well be implemented via a static field .. except that the singleton additionally takes care that no other instanceay coexist – derHugo Jan 20 '21 at 15:01
  • @SeLeCtRa note that the way you did it you would get the event only if the entire array is reassigned with a new array reference .. not, if any of the contained elements is changed – derHugo Jan 20 '21 at 15:08
  • we are using photoshop, there is a white canvas, and we are drawing on it. we are using the "brush" tool. we draw some short lines on the white canvas, all over the place. the marks on the paper are identical to game objects in Unity. – Fattie Jan 20 '21 at 15:09
  • In programming most computer languages, a singleton is this, as you say: "There exists only exactly one Instantiation of this Class". Note that Unity game objects (A) have no connection at all to "Classes", (B) have no connection in any way to "programming languages", (C) have no connection to "software", (D) even in a kind of vague analogy, they have no connection to the notion that you can "only have one of them". Imagine we were using say **a spreadsheet** @derHugo , putting in numbers here and there, and you said "oh I want this '7' to be a 'singleton'" It doesn't even make any sense. – Fattie Jan 20 '21 at 15:12
  • Imagine we are playing checkers, there are the 20 or so black and white pieces on the board. You point at one and say "oh, I want this to be a singleton" What could it even mean? The answer would be "singletons relate to instantiating in memory classes in a computer program and there is not even an analogy here, there can be any number of any type of piece anywhere..." – Fattie Jan 20 '21 at 15:18
  • Note where you say "except that the singleton additionally takes care that no other instances coexist...." but there are no "instances" in a game engine, there's just game objects. – Fattie Jan 20 '21 at 15:19
  • @Fattie GameObjects are instances .. of the type `GameObject` which is a class so `A)` is wrong and `B)` as well: `GameObject` is a `c#` type and Unity's underlaying framework `c++` .. both are programming languages thereby also `C)` is wrong. ... Then it obviously makes little sense to say "I want that black field of my checkers board to be a singleton" .. that's true ... But the entire board could very well be one .. there exists exactly **one** board in a checkers game! So I really don't get what makes you think the pattern "Singleton" makes no sense/has no meaning in a Unity application ^^ – derHugo Jan 20 '21 at 15:27
  • U meant to type "black piece" – Fattie Jan 20 '21 at 15:28
  • they're ***not*** instances of the type gameobject. they're just a list of vectors and quaternions. {each one has a list of "components", and, generally "GameObject" is on all of them} – Fattie Jan 20 '21 at 15:30
  • Also! Consider what you're saying! The things you describe *are all the same Class* !!!!!! we're talking about a list of vectors, and (as you describe it) an associated instance of a certain class, ie all the same for the whole list. I don't even see how "singleton" could apply - metaphorically - to something in such a list. (perhaps, the position vectors could be exclusive, or something .. I don't even know) – Fattie Jan 20 '21 at 15:33
  • @Fattie I don't believe you understood my singleton use case. – SeLeCtRa Jan 20 '21 at 15:59
  • @derHugo OP completely change array everytime so I wrote the same in event system. If OP want to fire event for every changed event just can remove Array marks([]) and use for single object. – SeLeCtRa Jan 20 '21 at 16:01
  • @SeLeCtRa - I was talking to Der ! no need to stop. game objects can't be singletons since they are nothing more than a list of vectors – Fattie Jan 20 '21 at 16:32
  • @Fattie nobody said that a gameObject shall be a Singleton .. but the component that is attached to one can be a singleton ^^ .. a [`GameObject`](https://docs.unity3d.com/ScriptReference/GameObject.html) is **not** a collection of vectors .. it is a **class** implemented in the namespace UnityEngine .. and there are fields on a board .. so I ment black field ^^ but same applies to the pieces yes – derHugo Jan 20 '21 at 16:40
  • components cant be singletons, you have no control over what they are attached to. furthermore, it's "just silly" to think of a "part" as a singleton. a **person** could be a singleton (for example The Pope is (roughly speaking) "a singleton on Earth"). but it's just incoherent to talk about a **part** being a singleton. so, a stomach or a lung could not be "a singleton on Earth". – Fattie Jan 20 '21 at 16:45
  • @Fattie I can create a singleton `public class GameManager: MonoBehaviour { private static GameManager instance; public static GameManager Instance { get { if(instance) return instance; instance = FindObjectOfType(); if(instance) return instance; instance = new GameObject ("GameManager").Add.Component(); DontDestroyOnLoad (gameObject); return instance; } } void Awake(){ if(instance && instance != this) { Destroy(gameObject); } } }` now you have a component that is attached to a GameObject and is a singleton. And it makes absolutely sense to do so in a lot cases – derHugo Jan 20 '21 at 16:50