- Home /
Storing Transforms On Awake, is this the best way?
Hello people, I have a question which can be related to script optimization. So, in the game, I have a one huge scene. Lets say that gameplay takes up to 30-45 mins. So I created a Level Manager by using Singleton Method, in order to use on the further scenes. The thing is, I have a lot of gameplay scripts, interactions, puzzles, animations, switches etc. I also have a lot of transform hierarchy on my player like camera animator, hand animator, the object that holds the camera script, the camera itself(object with the camera component and image effects) and a lot more like this. As I said, I have a lot of gameplay scripts that need to reach to these game objects on the player. For example, player is able to interact with a lever, when interacted, a script comes in, reaches the stored script called IS_CameraScript, disables it, reaches to the stored game object called "CameraScript" which holds the IS_CameraScript, and lerps the rotation of the object to a certain value, and then reaches to hand object which has Animator on it and plays the hand animations on the lever. So, I have lots of interactions like that. To achieve those, I scripted my storing like this :
IS_LevelManager code, has singleton method on it.
private Transform t_Player;
private Transform t_PlayerHolder;
private Transform t_PlayerCamera;
private Transform t_PlayerChildReference;
private Transform t_PlayerChildRefCrouch;
private Transform t_CameraHolder;
private Transform t_CameraScript;
private Transform t_CameraBaseParent;
private Transform t_CameraAnimator;
// Below these I have Property Methods, I didn't write all of them over here to prevent the code to be messy, but all of those private Transforms has public property methods like the one below.
public Transform T_Player
{
get { return t_Player; }
}
void Awake()
{
RegisterObjects();
}
public void RegisterObjects()
{
//Application.targetFrameRate = 60;
t_Player = GameObject.FindGameObjectWithTag("Player").transform;
t_PlayerHolder = GameObject.FindGameObjectWithTag("PlayerHolder").transform;
t_PlayerCamera = GameObject.FindGameObjectWithTag("PlayerCamera").transform;
t_PlayerChildReference = GameObject.FindGameObjectWithTag("PlayerChildRef").transform;
t_PlayerChildRefCrouch = GameObject.FindGameObjectWithTag("PlayerChildRefCrouch").transform;
t_CameraHolder = GameObject.FindGameObjectWithTag("CameraHolder").transform;
t_CameraScript = GameObject.FindGameObjectWithTag("CameraScript").transform;
t_CameraBaseParent = GameObject.FindGameObjectWithTag("CameraBaseParent").transform;
t_CameraAnimator = GameObject.FindGameObjectWithTag("CameraAnimator").transform;
t_Legs = GameObject.FindGameObjectWithTag("PlayerLegs").transform;
//t_Legs.gameObject.SetActive(false);
cc_Controller = t_Player.GetComponent<CharacterController>();
IS_PlayerController = t_Player.GetComponent<IS_PlayerController>();
IS_CameraController = t_CameraScript.GetComponent<IS_CameraController>();
IS_BobManager = t_CameraHolder.GetComponent<IS_BobManager>();
//IS_ObtainableItem = GameObject.FindGameObjectWithTag("ItemManager").GetComponent<IS_ObtainableItem>();
//IS_WheelInventoryNavigation = GameObject.FindGameObjectWithTag("InventoryCanvas").GetComponent<IS_WheelInventoryNavigation>();
v3_PlayerVelocity = cc_Controller.velocity;
cam_Player = t_PlayerCamera.GetComponent<Camera>();
}
So as you can see, I am storing the transforms like this. When I want to reach & use them, I do this:
One of the gameplay scripts:
private Transform t_Player;
void Start()
{
t_Player = IS_LevelManager.instance.T_Player;
}
void MovePlayer()
{
t_Player.position = ......
}
So what I am asking is, is this the right way to do what I need to do? Is there any better way, I believe like using GameObject.Find... is a very slow way, but since I am doing it on the Awake I wouldn't have much of a problem, but I am still not really sure. Thanks :)
GameObject.Find___
(or any other search function) will be slow in comparison to other functions. In particular, FindObjectsWithTag
needs to loop through all (or some, if using some fancy search) of the GameObjects that exist, and do a string comparison for each, which is why it's considered slow, especially when you have a lot of GameObjects.
If you call a search function every frame (e.g. in one of the update functions), your game might slow down a noticeable amount. However, using it once when an object is created for the first time won't be noticeable at all, unless you create a lot of objects at the same time.
As a personal preference, I would either make the fields public and drag the relevant GameObjects to where they need to be in the inspector, or I would just use the search functions in the Start
or Awake
functions in the scripts themselves ins$$anonymous$$d of using a manager script.
Also, in general, I prefer Transform.Find, since that saves me the trouble of making a lot of extra tags. (I would also guess that it's a bit faster than FindObjectsWithTag
, since it only needs to search through the children of a certain transform, rather than all of the GameObjects that exist... though this should be negligible if you're not doing it often.)
Finally, though unrelated, why do you have both private fields and properties that only access those fields? It seems a bit redundant to me since you could just have the properties like this
public Transform someTransform { get; private set; }
I'm not an expert on properties, so I'm actually curious.
You are right about properties actually, I never bothered to change it. I do not want to use drag & drop because that would take me a lot of time when designing the scenes, since most of my interactions are generated producerally. But Transform.Find, I never though of that, I don't have that much of objects, just like you see over the code, around 10-15, so I'll go with Transform.Find and Awake functions. Thanks!
Answer by Owen-Reynolds · Jul 08, 2015 at 08:02 PM
For many of these, you can probably use a much smaller search space. Isn't playerHolder just player.parent? Or a small loop up through parents? Is PlayerLegs just "player.Find("legs")", or a search through player children of some some?
But, yes, Inspector vars make this easier. No searching at all, and any NULL values stick right out (of course, you could have the code above print descriptive errors on NULL.)
And then, for things you rarely use, I find I get fewer errors not saving a link. Just do a quick search only when I need it. That way, everything is in one place.
Thanks for the reply! As a result, I'll go on using transform.Find function. I've been using Unity for a lot of years but just couldn't think about it, seems like the best way as you said.
Answer by Hellium · Jul 08, 2015 at 02:57 PM
Ouch .... As you said, the functions which find or get components are quite slow ...
Why don't you use public fields and drag & drop your elements inside the inspector ? If you don't want public fields, add a private set to your properties, and add the tag [SerializeField] above the property name to be able to see it in the inspector.
I have a lot of interactions and it would be really harsh to set them individually by dragging & dropping, and most of these interactions are created producerally, so I'd have a lot of problem if I just use public variables.