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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

what is best way of calling a function on another script for good mobile performance

Discussion in 'Scripting' started by ceteri, Mar 12, 2015.

  1. ceteri

    ceteri

    Joined:
    Mar 12, 2015
    Posts:
    11
    I am making a soccer game for iPhone, i have an game object called GameManager with a script attached that keeps track of things like the score score and time remaining. So my question is what is the best way to update this info from another script (e.g. on the soccer goals, with an OnTriggerEnter handler on it).

    the two solutions i can think of are to:
    create functions to update the score etc in GameManager and call collision.transform.sendMessage to call these functions.
    or
    create an instance of my game manager (GameObject.FindWithTag("GameManager");)
    then use GetComponent to access and change the variables from directly within my OnTriggerEnter function

    I'm quite new to unity and mobile development and am aware i should be careful not to use too many resources.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I'd do something like this.

    Code (csharp):
    1.  
    2. public class SoccerGoal : MonoBehaviour
    3. {
    4.     private static GameManager gameManager;
    5.  
    6.     void Start()
    7.     {
    8.         if (gameManager == null)
    9.         {
    10.             gameManager = FindObjectOfType<GameManager>();
    11.         }
    12.     }
    13. }
    14.  
     
  3. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    If you're doing this, might as well make it a singleton and avoid having each component using the manager do the check (and each component type having a static field pointing to a single instance ;).

    So, I would do that:
    Code (CSharp):
    1. public class GameManager: MonoBehaviour
    2. {
    3.    public static GameManager Instance { get; private set; }
    4.  
    5.    //If a script will be using the singleton in its awake method, make sure the manager is first to execute with the Script Execution Order project settings
    6.    void Awake()
    7.    {
    8.        if (Instance != null) //this depend how you want to handle multiple managers (like when switching/adding scenes) but this way should cover common use cases
    9.            Destroy(Instance);
    10.        Instance = this;
    11.    }
    12.  
    13.    void OnDestroy()
    14.    {
    15.        if (Instance == this)
    16.        {
    17.             Instance = null;
    18.        }
    19.    }
    20. }
    And every other script can use GameManager.Instance to reach it...
     
    Last edited: Mar 18, 2015
    Bunny83 and (deleted member) like this.
  4. Deleted User

    Deleted User

    Guest

    Look up Singletons. It would be more efficient than "GameObject.FindWithTag".
     
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Singleton is certainly another way of doing it. My way doesn't require you to expose GameManager to the world though. But - if that's what you need then that pattern will certainly do it.
     
  6. ceteri

    ceteri

    Joined:
    Mar 12, 2015
    Posts:
    11
    Thanks for your replies everyone, i'll have a read about singletons!
     
  7. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    The more you decouple your classes, best the code will be (readability, maintenance, easier tests).
    In other words, the soccer field class (or the thing that register goals) should never "knows" about a game manager.

    You should use the observer/dispatcher pattern: Register the game manager as a listener of the "goal" event at the global message handler, and then when time comes, the soccer field should dispatch a goal message. Even better you may realize that you don't need a game manager (for example, register as event listener of the "goal message" the score display object directly).

    http://en.wikipedia.org/wiki/Observer_pattern
     
  8. ceteri

    ceteri

    Joined:
    Mar 12, 2015
    Posts:
    11
    Thanks for the tip L-T i will definitely look into this it makes sense to do things this way. I didnt know how difficult it would be to dispatch and handle events between game objects. I'm currently using my game manager to handle events like: full time, half time, goal, reset ball to centre and pause. It seemed to make sense to put these in a common place but there is no real reason why i need to.
     
  9. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    I see problems with this Singleton pattern. The public instance is assignable, which shouldn't be the case. Any code can go GameManager.Instance = null.

    Also, the OnDestroy function is redundant. If the instance is assigned to GameManager Instance, it will be made null when destroyed, anyway.

    Here's the pattern I use:


    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public sealed class GameManager : MonoBehaviour {
    4.  
    5.     #region Singleton
    6.  
    7.     //Use a property so other code can't assign instance.
    8.     static GameManager _instance;
    9.     public static GameManager instance {
    10.         get {
    11.             if (!_instance)
    12.                 //Writing it this way names the new gameObject and adds the gameManager component to it, finally getting the added component and assigning it to
    13.                 //_instance.
    14.                 _instance = new GameObject("GameManager", typeof(GameManager)).GetComponent<GameManager>();
    15.        
    16.             return _instance;
    17.         }
    18.     }
    19.  
    20.     //This ensures that no other GameObjects have a GameManager either attached from the editor or instantiated by
    21.     //other code. Since it's always called on awake, no two GameManagers will ever be active at runtime.
    22.     void EnsureSingleton() {
    23.        //In case the instance was placed using the editor, rather than created by accessing the static member.
    24.         if (!_instance)
    25.             _instance = this;
    26.    
    27.         var gameManagerInstances = GameObject.FindObjectsOfType<GameManager>();
    28.    
    29.         if (gameManagerInstances.Length != 1) {
    30.             Debug.LogError ("Only one instance of the GameManager manager should ever exist. Removing extraneous.");
    31.        
    32.             foreach(var otherInstance in gameManagerInstances) {
    33.                 if (otherInstance != instance) {
    34.  
    35.                     //In case some moron added two GameManager instances to the same GameObject, somehow.
    36.                     if (otherInstance.gameObject == instance.gameObject)
    37.                         Destroy(otherInstance);
    38.                     else
    39.                         Destroy (otherInstance.gameObject);
    40.  
    41.                 }
    42.             }
    43.         }
    44.  
    45.     }
    46.  
    47.     #endregion
    48.  
    49.     void Awake() {
    50.    
    51.         EnsureSingleton();
    52.    
    53.     }
    54.  
    55. }
     
    Last edited: Mar 17, 2015
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I generally prefer to throw an exception instead of just silently destroying rogue instances. But that can boil down to preference.
     
    Bunny83 and BenZed like this.
  11. kdubnz

    kdubnz

    Joined:
    Apr 19, 2014
    Posts:
    177
    Excuse my ignorance on this.

    Can a distinction be made between coding efficiency on mobile compared to coding efficiency on PC. ??
     
  12. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    Not in terms of accessing members.
     
  13. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,739
    They major perforance differnces between mobile and PC is dealing with the GPU, also remeber dont pre-maturely optimize since its a waste of time, considering that you dont know yet what your bottle necks are.
     
  14. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    I'll also point out the other big hole in @_met44's implementation that @BenZed addressed was sealing the GameManager class.
     
  15. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    I replaced the field by a property with private set, sorry that i wrote a too simple version for the example.
     
  16. AzkaZia13

    AzkaZia13

    Joined:
    Sep 19, 2020
    Posts:
    1
    If you are using an instance of Game Manager you can do it like so:
    GameManger.instance.Reset();