Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Managing GameObject from non-MonoBehaviour script

Discussion in 'Scripting' started by unity_UUpHGU8iffWR7g, Jun 2, 2023.

  1. unity_UUpHGU8iffWR7g

    unity_UUpHGU8iffWR7g

    Joined:
    Dec 5, 2021
    Posts:
    17
    Hey all!
    I need a quick brainstorm...
    I have a some data that describes a game character and I want to show it on 2D UI map and 3D world terrain. This is not a minimap implementation.
    The UI is a different scene that reflects (and modifies) the position of the GameObject in 3D world and vice versa. The non-MonoBeahaviour script is keeping the world position and needs to apply it on both 2D and 3D GameObjects in the relevant scenes.

    My data class
    Code (CSharp):
    1.  
    2. public class SimulationEntity
    3. {
    4.     /// <summary>
    5.     /// Should the GameObject be displayed or not
    6.     /// </summary>
    7.     public bool IsActive { get; set; } = false;
    8.     /// <summary>
    9.     /// Should the GameObject be allowed to move
    10.     /// </summary>
    11.     public bool IsLocked { get; set; } = false;
    12.     /// <summary>
    13.     /// Current 3D world position (to be convered be 2D map helper)
    14.     /// </summary>
    15.     public Vector3 WorldPosition { get; set; } = Vector3.zero;
    16. }
    17.  
    I feel like I over complicated things here. what would be the best way to sync that data between objects?

    Thank you
     
  2. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    431
    Not easier will be to add a second camera that works in an orthographic mode (so the view will be flattened)?
     
  3. unity_UUpHGU8iffWR7g

    unity_UUpHGU8iffWR7g

    Joined:
    Dec 5, 2021
    Posts:
    17
    Different scenes. One shows the status on a UI image of the map. The other scene show the object in the actual scene
     
  4. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    431
    It sounds like you want to toggle between two scenes. I speak about the Unity logic scene that will destroy objects and load a new set, and again destroy all objects and load a new set. So you need an anchor to keep data between scenes?
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    You would still want a component that stores and updates this data for each specific game object you want to track. Then your other UI scene can read from all this game objects to display their position. Might some need some intermediary manager that all these component can register too, as well.
     
  6. unity_UUpHGU8iffWR7g

    unity_UUpHGU8iffWR7g

    Joined:
    Dec 5, 2021
    Posts:
    17
    I thought about using ScriptableObject to store List of these entities. Each scene will need a "spawer" for that type but I will need a way to track changes in the list between scenes and how to "assign" a simulation entity class to GameObject.
    That is where I got lost
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    I think you're over thinking this.

    A component on the UI can just read from each of these list entries in Update to read their current values. And a simple means to make them accessible would just be a static class that the marker game object components can register to.
     
  8. unity_UUpHGU8iffWR7g

    unity_UUpHGU8iffWR7g

    Joined:
    Dec 5, 2021
    Posts:
    17
    @AngryProgrammer just gave me an idea.
    How about I load additively a map scene and have a minimap camera of the terrain?
    I could replace the map image with a render texture and manage only the 3D prefabs that would have a simulation entity script as a monobehaviour.
    I really over complicated things
     
  9. AngryProgrammer

    AngryProgrammer

    Joined:
    Jun 4, 2019
    Posts:
    431
    With @spiney199 we are trying to decode your intentions to fit into some logic pattern. For now, everything sounds overcomplicated.

    Look for GameManager singleton pattern and check if this will be enough for what you need.
     
    Last edited: Jun 2, 2023
  10. unity_UUpHGU8iffWR7g

    unity_UUpHGU8iffWR7g

    Joined:
    Dec 5, 2021
    Posts:
    17
    Thanks for the advices, I now have a few things I could test.
    Much appreciated!
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    As Spiney and Angry have said, keep it simple. Loads of people sink their battleships trying to come up with clever new patterns to persist data between or across scenes. It is not hard, but they sure manage to tangle it up.

    Just... keep... it... simple.

    Here's my go-to list:

    ULTRA-simple static solution to a GameManager:

    https://forum.unity.com/threads/i-need-to-save-the-score-when-the-scene-resets.1168766/#post-7488068

    https://gist.github.com/kurtdekker/50faa0d78cd978375b2fe465d55b282b

    OR for a more-complex "lives as a MonoBehaviour or ScriptableObject" solution...

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance!

    The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

    OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

    If you really insist on a barebones C# singleton, here's a highlander (there can only be one):

    https://gist.github.com/kurtdekker/b860fe6734583f8dc70eec475b1e7163

    And finally there's always just a simple "static locator" pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

    WARNING: this does NOT control their uniqueness.

    WARNING: this does NOT control their lifecycle.

    Code (csharp):
    1. public static MyClass Instance { get; private set; }
    2.  
    3. void OnEnable()
    4. {
    5.   Instance = this;
    6. }
    7. void OnDisable()
    8. {
    9.   Instance = null;     // keep everybody honest when we're not around
    10. }
    Anyone can get at it via
    MyClass.Instance.
    , but only while it exists.