I know that it's better to cache a component if you use it often during runtime. How about if I cache a component as a static variable and access it during runtime? Let me give you an example:
public class AudioManager : MonoBehaviour
{
public static AudioManager audioManager;
void Awake()
{
audioManager = this;
}
}
Then if I access it from another class, should I use AudioManager.audioManager or cache it beforehand (speaking in the terms of performance)?
P.S. Let me know if something isn't clear.
Edit: I guess I don't know what the hell I'm doing regarding Singletons, but to make it clear, this is a newbie question regarding performance:
1) _audioManager = AudioManager.audioManager in Awake and then use _audioManager.someVariable in Update
VS
2) AudioManager.audioManager.someVariable in Update
You don't need to cache your own component for speed in any case. A component won't pay a performance penalty for accessing itself.
The use case you may be thinking of is caching access to other components or objects so that you don't have to do lookup with GetComponent or GetComponentWithChildren. That does save time, but it's not a complex pattern: just do the lookup the first time you encounter the other component or gameobject, store it in a field inside this component, and you're good:
class Example: MonoBehavior
{
public GameObject _TargetCharacter;
private Transform _cachedTransform;
private Animator _cachedAnimator;
void Awake()
{
if (_TargetCharacter != null)
{
_cachedTransform = _TargetCharacter.transform;
_cachedAnimator = _TargetCharacter.GetComponent<Animator>();
}
}
void Update()
{
DoSomething (_cachedTransform, _cachedAnimator);
}
}
GetComponent and GetComponentInChildren are comparatively expensive you do don't want to do them every frame. However direct access to something set as a field is not expensive there is no need to cache it.
And making it s Singleton: in this context, you would need to make a separate class which is NOT a Component and have that be the singleton - you can't prevent somebody from attaching lots of a given MonoBehavior to things in the Unity Editor so you don't want to assume there's only one of the component floating around. In the AudioManager example, you'd have to assume that many different components might all be looking at the same AudioManager.
Here a good example comparing shared behavior using Singletons vs shared behavior in a static class. Two means to the same end, with slightly different strengths and weaknesses.
Update In response to OP's comment below:
If the point of the original code is to gain speed using the common Unity caching trick, it's not needed. If the point is, as OP suggests in comment below, to make the manager into a 'service provider' that other classes can call there are two routes to go:
The standard unity trick would be to add the caching behavior to the other classes that need to get to the AudioManager. For example:
class SomeOtherComponent: MonoBehavior
{
AudioManager _manager;
void Awake()
{
AudioManager[] AllAudioManagers = GetComponents<AudioManager>();
if (AllAudioManagers.Count == 1)
{
_manager = AllAudioManagers[0];
}
else
{
throw new RuntimeError ("Expecting one (and only one) AudioManager in scene");
}
}
}
Switching to a proper Singleton implementation more or less amounts to just taking the boilerplate in the Awake method above and centralizing into the singleton class, allowing you to replace it.
For an extended discussion of the singleton pattern in unity try this book
I live by a simple rule, if I am going to be calling a component a lot of times, more than 5, then I cache it. The same rule I apply to Singletons. If it is only one call then I just use the Singleton.getInstance().
What you should be really caching
Unity Components such as Transform.
The logic behind caching things like Transform comes from looking at the documentation. Transform is not a variable but a property, which happens to contain getters and setters. These are hidden from you, but that's the way it is implemented. This property happens to be written in C or C++. Therefore this will cost you on performance.
Related
I have a source audio with this code:
public class Sound : MonoBehaviour {
Static Sound instance;
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
So when i change scenes the audio starts playing again. How do i limit it to having only 1?
Edit: How do i fix that? i get this error
1 - Unexpected symbol instance' in class, struct, or interface member declaration 2 - Unexpected symbol ;' in class, struct, or interface member declaration
Option 1:
The Singleton Pattern is likely to be your best choice when it comes to things like this. The intent of the Singleton Pattern is to restrict a class to only one Instance of itself. To read more about the pattern, see the Wiki on it.
It looks like you are already doing this (after your first edit) but the thing you're going to want to change is the capitalization of Static in your code. Static and static are two different things. For your sake, you are looking for static. This should fix your problem/error and allow you to use the Singleton Pattern correctly.
Option 2:
Also, another option if you want to avoid the typical Singleton Pattern would be to search through all GameObjects for any that have you Sound Class/Component on it. Then if there is already on in scene, have the GameObject that is trying to instantiate, destroy itself. You can do this with the following code:
public class Sound : MonoBehaviour
{
void Awake()
{
int numSoundInstances = FindObjectsOfType<Sound>().Length;
if (numSoundInstances > 1)
{
Destroy(this.gameObject);
}
else
{
DontDestroyOnLoad(this.gameObject);
}
}
}
In my opinion, this is way less efficient then using the Singleton Pattern. This is because using FindObjectsOfType forces the code to check every GameObject that is currently in the game. Depending on the amount of GameObjects in the game, this can be very taxing on the system.
Just as title say does GetComponent() does impact a lot on performance.
I am asking this because I do not like doing it like this:
public class Player : MonoBehaviour
{
PlayerStats playerStats = this.GetComponent<PlayerStats>();
void Update()
{
var something = playerStats.Asd;
}
}
Instead of that i like using it like this:
public class Player : MonoBehaviour
{
void Update()
{
var something = this.GetComponent<PlayerStats>().Asd;
}
}
Reason for that is because i like breaking code in lot of scripts (it is easier for me to later change something if needed and also use one script for multiple objects) and so if i have a lot of scripts i need to see if i have already defined PlayerStats playerStats.... but not only this one but about a lot of them.
So is using second approach going to slow down my game a lot?
It's worth noting that your first script is invalid and won't compile. The correct way to do that is to make it a global variable but cache or initialize the script in the Start or Awake function. These functions run once and are used for initialization.
Something like this:
PlayerStats playerStats;
void Start()
{
playerStats = this.GetComponent<PlayerStats>();
}
To answer your question, the GetComponent function impacting performance is greatly over exaggerated. You read this everywhere on the internet but it depends on how often it is used. If it is used once in a while or just in few scripts then it's totally fine.
If you have hundreds instances of scripts using GetComponent in the Update function then that's when you will start noticing a little bit of performance hit because GetComponent is making call to the native side. So, it depends on how often it is called and how many instances of scripts are making this call each frame.
The main appeal of using the first approach is that you can set those variables to be public, and in turn access them directly from the Unity Editor, allowing you to drag and drop components as you feel like it.
The second instance of your GetComponent function call means that you aren't caching your variables, slowing down your code with potentially unnecessary checks. So my advice would be to stick with the first instance in which your variable is defined in memory and then altered, rather than being allocated memory each time and then altered.
And a side note. You do not need to call this.GetComponent if the script is attached to an object since the script derives from a MonoBehaviour; you can just call GetComponent<type>() and go about your merry day. :)
I don't think it really matters. I just did a check and using for loop that looped 1,000,000 times and found the exact same 0.02 time delay between both frames.
That being said, it would make your code cleaner because Player.Stats.Asd is cleaner than Player.GetComponent<PlayerStats>().Asd. It makes it more obvious what the intent is. I'm sure it is still a micro optimization to store it as a variable with a public PlayerStats Stats { get; set; }, but that's really if you're using it all the time.
You shouldn't use a variable for every Component it has, because if you do that for every script, the memory being used will start to add up.
Also, note that I'm calling it Stats not PlayerStats because Player.PlayerStats is needlessly redundant. The actual type of it should be called PlayerStats yes, to not confuse it with, say, EnemyStats, but when you go to use both, having Player.Stats and Enemy.Stats is cleaner.
I have a persistent game object that I use to initialize basically everything. The script Persistence as I call it has some public references I just dragged on them via the inspector.
I'm trying to make it persistent like I found online:
public static Persistence instance;
void Awake()
{
if (instance != null)
{
DestroyImmediate(gameObject);
}
else
{
DontDestroyOnLoad(gameObject);
instance = this;
}
}
The thing is, when I load a level from main menu, it's fine. When I load back the main menu from that level, it says
MissingReferenceException: The object of type 'Persistence' has been destroyed but you are still trying to access it.
So I decided to let it create other instances when loading the main menu, but that messes up all the scripts on the game levels that rely on this data.
My question is, how to correctly implement this ~singleton persistent pattern in Unity, given I have inspector-added references?
NOTE that I initialize only from my Awake function in my persistent class and from nowhere else. Literally, my InitializeMe scripts are called from the Persistence class, one after the other.
What should I do differently to make this work? Initialize from a different, non-persistent gameobject? Forget dragging to the inspector? Any advice to make this work is appreciated.
I got it to work. So here's the thing one should know (I should have known) before messing around with persistence in Unity:
You don't drag references to a persistent GO via the inspector as they are gone the instant another scene is loaded except for additive loading. Also the persistent GO may hold data relevant to multiple scenes, hold functionality that is built for general purpose, as reusable as it goes, but it never initializes anything itself or interfere with non-persistent GOs other than being called - used as a tool - or providing the data.
This arcane wisdom is mine though, so anyone more skilled reading this, please do correct me if I'm wrong before others take this to heart.
So to be exact, I made a non-persistent master INITIALIZER that does the exact thing. I get all the scene GOs into a collection once and no GameObject.Find again. I used LINQ queries to conveniently filter my results from that collection. Another thing was my InitializeMe abstract class (or to be more precise, its descendants).
public abstract class InitializeMe : MonoBehaviour
{
public int orderNumber;
public abstract void INIT(INITIALIZER init);
}
here orderNumber is used to determine the order of the initializations, should one object depend on the other. It also worths mentioning that doing like so can result in a very predictable way to setting things up, as it is done one after the other. Note that this doesn't create a bottleneck, because Unity's scripting API only be executed in the main thread - dividing the code into multiple Awake or Start methods wouldn't perform better to my best knowledge as of 2017. It is used by a LINQ query in the INITIALIZER.
The good thing in INITIALIZER is that - again - it holds itself everything, including a reference to the persistent object and the save data as well, so via referencing itself to the InitializeMe methods they can do everything they need - as DataBank provides general purpose tools with persistent data, and INITIALIZER provides volatile (hope I use that right, I mean relevant to only main menu) data with some additional functionality that is used only for the main menu.
Now, persistence was ensured not by the persistent class itself, but by this INITIALIZER in Awake like so:
//find by tag or rename upon instantiation as by doing so will result in a "(Clone)" added to its name.
var d = GameObject.FindGameObjectWithTag("DataBank");
if (d == null)
{
//instantiating it
DATA = GameObject.Instantiate<DataBank>(DATA_blueprint);
//intializing the databank itself. The parameters are needed for me,
// but serve as a good example - all of those are dragged from the inspector to the _INITIALIZER_ but will remain in the whole game as long as databank exists.
DATA.LoadDataFromINIT(_baseColor, _baseColor2, _outlineColor,
new MMtoolBundle(DATA));
//to make it persistent.
DontDestroyOnLoad(DATA);
}else
{
//in this case the main menu is loaded from another scene.
//so we only find that loaded object and get its reference, no initialization as it was already setup.
this.DATA = d.GetComponent<DataBank>();
}
where DATA is my persistent DataBank. Note that by default I have NO DataBank object on the scene. DATA_blueprint is the prefab of DataBank dragged by the inspector (as INITIALIZER is not persistent). It could be loaded via AssetDatabase as well but this was a bit more convenient.
it worths mentioning that while DataBank is a MonoBehaviour itself so it can appear in Unity scenes, none of its members are MonoBehaviours so it is possible to harness the power of inheritance. Should one wish to start a coroutine in a non-mono toolkit, it would have to be started with a reference from DataBank itself.
An obvious drawback of this method is that the existence of my persistent GO depends on INITIALIZER, so that one has to be on the first scene. But again, as most games start with a main menu, this shouldn't pose a big issue (talking about single player games).
YET AGAIN I would recommend someone more skilled to correct me in case I lead others astray, but this solution worked for me - got the same and only persistent GO in all my scenes with no other ever created.
I have almost identical classes, PaddleLeft and PaddleRight. I am tired of calling both of those classes when I need something done, I rather them be done all at once. For example, here is what I have to do:
public void pause() {
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
}
And here is what I want to do:
public void pause() {
GameObject.Find("Paddle Objects/paddles").GetComponent<Paddle>().setIsPaused(true);
}
This seems unnecessary, however, in my game, there are times where the same line of code are copied and adjusted to up to ten similar objects.
Question Is there a way to make a super class like in Java for these objects. I have searched the internet and have found info, however I can't seem to understand how to make it work because I can't extend MonoBehavior and a superclass in Unity.
Thanks in advanced!
I have almost identical classes, PaddleLeft and PaddleRight
But your code is totally saying different stuff
GameObject.Find("Paddle Objects/paddleRight").GetComponent<Paddle>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<Paddle>().setIsPaused(true);
Maybe you want meant to write the code below?
GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>().setIsPaused(true);
GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>().setIsPaused(true);
I will assume the second code is what you meant to write.
When you have multiple GameObjects or Scripts with similar actions, you should create a central manager script that will make it easy to communicate with a those GameObjects or classes.
Since both your classes are called PaddleRight and PaddleLeft, You can simply call this class PaddleManager.
Don't forget that, of course, PaddleManager is just a script, it's not a "thing" in Unity. Naturally you will attach PaddleManager to some game object. You might ask "where should I attach it?" In a simple game, you might attach it to your camera, say. (Since you always have a camera, other developers working on your project always know to "look n the camera" for odds and ends like sound-effects, managers like this and so on.) Alternately, say that physically all your paddles are associated with (for example) an object that is the ping pong table. Then, a good place to attach PaddleManager.cs would be on the ping pong table. It doesn't matter where you attach it, so long as it is tidy. Some people like to make simply an empty object (you can refer to an empty object as a "marker"), just make an empty object named say "manager holder", put it at 0,0,0, and you can add scripts like PaddleManager.cs to that object.
Your PaddleManager.cs script:
public class PaddleManager : MonoBehaviour
{
private PaddleRight rightPaddle = null;
private PaddleLeft leftPaddle = null;
//Initialize variables
void Start()
{
//Get reference/Cache
rightPaddle = GameObject.Find("Paddle Objects/paddleRight").GetComponent<PaddleRight>();
//Get reference/Cache
leftPaddle = GameObject.Find("Paddle Objects/paddleLeft").GetComponent<PaddleLeft>();
}
//Call to pause and unpause
public void pause(bool pausePaddle)
{
rightPaddle.setIsPaused(pausePaddle);
leftPaddle.setIsPaused(pausePaddle);
}
}
Now, you can access both of your Paddles from one script, in another script.
public class YourOtherScript : MonoBehaviour{
PaddleManager paddleManager = null;
void Start()
{
//Get reference/Cache
paddleManager = GameObject.Find("GameObjectPaddleManaerIsAttchedTo") .GetComponent<PaddleManager>();
//To pause
paddleManager.pause(true);
//To un-pause
paddleManager.pause(false);
}
}
By doing this, you will avoid using static variable and also avoid using GameObject.FindGameObjectsWithTag("paddles")) in foreach loop like mentioned in the other answer. GameObject.Find... functions should NOT be used in the middle of the game because it will slow down your game. You need to use it once and cache the GameObject in the Start function, then you can re-use it without slowing down your game.
First of all paddle right and left are game-objects and not classes , the class name is paddle , and if the same script is on both the objects , the most simplest way would be to put it on another empty object and call it once and the code will work on all game-objects that the script is attached to . BUT! that is only regarding to what I cuold make out of your question , Here is what I really recommend , as you said "because I can't extend Mono-behavior and a super-class in Unity" . Ok so you have class A inheriting monobehavior , and you make class's B and C, then when you inherit them from A you will get all the abilities of a monobehaviour in class B and C and you can attach them to game objects , you can even make start and update functions as vrtual and override them in B and C and you can even call A's function use the keyword Base , So read on it , it will take time but in the long run makes you a better coder
Mm, wait. There is something wrong with your question:
YouPaddleLeft and PaddleRight are not classes. They are GameObjects existing in Unity scene. Class is Paddle to which you get reference by GetComponent<Paddle>() .
Now if you have a variable/function that affects all the instances of the class the same than you shell make them static. (Google static variables and functions if you don't know what they are).
So go to your Puddle class and change the declaration of setIsPaused(bool val) to this:
public static void setIsPaused(bool val) { /* implemenetation */ }
and then make a call to it via class token, not object:
Paddle.setIsPaused(true/false);
note that if the static function has references to class variables all those variables should be marked static as well. (e.g. if you have a bool isPaused than mark it static because it should be the same for all the objects all the time anyways)
I have my Pacman game working, and i'm trying to go back through it and "organize" my code better. Before, I had this "TopObject" which referenced the object in game1.cs which basically referenced every object in my game (pacman, ghosts, map, etc). I made it globally available from ANYWHERE so that I could access my Pacman object from my ghost objects, or my map/tile objects from my ghost objects, or even my ContentMananger from anywhere to load content.
I know this is bad practice, so i'm trying to eliminate it. For instance, I created LoadContent() methods on all my objects which take a "ContentManager" type, which eliminated the need for me to call ContentManager using my TopObject.
Proceeding further, i'm having a really hard time doing stuff without this global reference to all my objects. For instance:
- From within my Pacman Update()..
I need to know if i'm going to run into a wall. I need references to my map/tiles.
I need to know if i've collided with a ghost, so i need references to my ghost objects.
I need to know if I collided with some food and then update the scoreboard, so i need have reference to my scoreboard object.
So essentially, it feels like i'm going to be making a giant mess passing so many object references around to all my objects, that it feels like doing a "global" topobject is much cleaner.
Does anyone know how to organize this better, so that i'm doing it cleanly? Should I even be checking for collisions inside my Pacman Update(), or should I be creating seperate "PacmanObject.CheckCollisionWith()" and calling that from my Game1 Update()? Should collision logic also be seperated out into a new class?
Thanks!
Having a central point that contain reference toward your objects isn't a bad thing per se. However, a good design will put the actions that are best related to each object in the correct class. For example, your player doesn't need to have reference towards the tiles and walls. While doing an Move method, the player could call a static method in the Map class that return true/false if the next move is valid. This way, the player doesn't have any reference toward the map itself.
public class Player
{
public void Update()
{
//stuff to find nextTile position
//Call static function toward a class that contains the map data.
if (Map.TileIsWalkable(nextTile))
Move();
}
}
public class Map
{
public static Map loadedMap; // Handling it as singleton, normally you only load one map at a time.
public static bool TileIsWalkable(Vector2 position)
{
if (loadedMap == null) // Throw assert, shouldn't happen.
return //whatever test needed in loadedMap structure
}
}
You can also have a Ghost manager that keeps reference toward the ghost. The player would only need to call a method in that manager that would loop over all the ghost to see if he collides. Even better, that method could take a position and not a reference. That way, it can be reused to see if ghosts collide between each other. (random idea)
There's plenty of way to do something. The hardest in any code design is to put the stuff at the place that make the more sense and makes it the easiest to update and modify later.