Creating timers in Unity

One of the most common things to do in game programming is to wait for a certain period of time before calling an event. In this article you will find several types of timers in Unity explained and when to use them.

Simple repeating timer in Update()

Let’s create the most basic timer that does something every x seconds:

  • waitTime means how long to wait in between action calls and can be overriden via the inspector.
  • timer is used to store the time that has passed.
  • Update() is called every frame, so we add our deltaTime to our timer in every Update() cycle. The property deltaTime returns how much time in seconds has passed since the last frame.
  • If our timer has risen above our waiting time, a method is called.
  • In place of the print() statement, you can call whatever action needs to repeat.
  • We restart the timer by resetting it to zero.

 

DeltaTime in Unity.
DeltaTime in Unity.

 

DeltaTime in Unity gives us the length of the previous frame, which if you’re running at 60 fps is 1/60 of a second, or about 0.016 seconds.

The basic timer shown above is easy and fast, but your code might end up being cluttered, because the timer is not sealed off in it’s own method.

Here’s another example, that can be turned on and off:

Toggle timer via Update()

 

First, OnTriggerEnter() is called, whenever our CannonBall enters the trigger area  of any GameObject tagged “Player”. This sets the boolean timerRunning true.

The Update() loop is checking every frame for timerRunning and when it becomes true, it calls the BombTimer method. Our timer waits for waitTime to pass and then does something.

Lastly, the timer resets itself until another Player trigger is entered.

Unity offers a few helper functions that can call methods after a period a time or repeat actions:

Destroy an object after x seconds

You can use the Destroy() method from MonoBehaviour and pass in a float parameter to delay it. Note, that you only want to call this method once, not in Update().

Invoking a method after x seconds or repeating it

The Invoke() method takes a method name as a string and the waitTime as a float parameter. This helper function is very convenient, because of it’s clean syntax, but be aware, that invoking methods via string is much slower than calling them directly. Only use this for testing or when performance isn’t an issue.

You can also use InvokeRepeating() to wait for a period of time and then repeat the method call every x seconds:

Again, the Invoke() methods are convenient but slow.

You can stop the Invoke() or InvokeRepeating() method by using CancelInvoke(“MethodName”).

Waiting timer in a Coroutine

Coroutines are incredibly cool and we can use them to create well-performing timers with clean syntax. A coroutine has the ability to pause and resume itself while running in your game.

Pay attention to the using statement that includes System.Collections; we need this to be able to use coroutines.

A coroutine returns a type of IEnumerator. It is not necessary to fully understand what this means, because we’re not making use of the return type with our timer.

Inside of a coroutine, you can pause it’s execution with the yield statement. The yield can return, for example, the WaitForSeconds() method, which waits for any number of seconds passed into it before continuing execution.

Be aware, that a coroutine must include at least one yield statement. If you do not want to wait for several seconds, you can yield return null to wait until the end of the frame like any standard method does. In this example, we could omit this last step, since we we’re already yielding earlier, but just for completeness, I included it.

To start a coroutine, use StartCoroutine() and be aware, that you should pass in a method call as a parameter, as it is much faster than using a string.

Repeating timer via recursive coroutine

This heading sounds complicated, but it actually isn’t. Just look at the code:

Only one line was added to make our coroutine repeat every three seconds. In line 17 HarmPlayer() calls itself, which is known as a recursive method call.

Many times, recursive methods can get very complicated and cause hard-to-understand problems, but in our case they work nice and easy: The method waits for a period of time, then performs the print() statement and finally calls itself again, therefore repeating the timer.

You can stop a coroutine with StopCoroutine(methodName ()) or cancel all running coroutines with StopAllCoroutines().

When to use coroutines over Update()

As you might be thinking, coroutines can replace your Update() loop. I suggest to use them whenever you need time-based functionality, but you want to keep your Update() clutter free.

Coroutines are ideal for timers, moving objects via script or lerping between values.

*lerping refers to Linear Interpolation. See the official Unity tutorial for more information.

 

Please leave me a comment, if you’d like to see more practical examples of timers or if you have any more questions.

 

Object linking – Photoshop linked files and Smart Objects

This is part 2 of the examples from Object linking and embedding – Smart workflows for game developers.

Here you can get an overview of different object linking tools in Photoshop and how to use them. Generally, this applies whenever you are working in a production pipeline, that needs auto-updating links and non-destructive processes with many iterations.

Linked Files

In Photoshop you can insert images in two ways:

Photoshop - Place embedded or linked.
Photoshop – Place embedded or linked.

 

Whenever you copy and paste or drag a compatible file into your current Photoshop composition, it creates an embedded copy. This means, there is no connection to the original file.

When you want to maintain a dynamic link to a source file, chose Place Linked… to insert an image.

Place Linked… creates a reference to the original file and therefore allows you to updated your placed file only by changing the source. No exporting and re-importing into Photoshop required. Here’s an example:

Marketing screenshots for a game.
Marketing screenshots for a game.

 

Most likely you are going to release screenshots of your game or similar marketing material for app stores etc. In the above image you can see a screenshot of a game that is framed and has marketing content around it. This is an ideal candidate to be linked dynamically. Using a static image would mean that you would have to reimport a new version whenever changes are made to the game. We want to avoid this to because it means a lot of manual work, that not only costs time, but can also lead to errors.

Instead, we create screenshots (or whatever content it may be) in a separate file, that is easy to manage and than place it as a linked file in our main composition document.

So this is my main composition document:

Main composition document.
Main composition document.

 

It features a framed content area and a few assets to create descriptions and decoration. The actual screenshots are going to be linked in this document.

photoshop_linkedFiles_2_images

In my case, I have a mockup-psd, but you can also link simple images, which you can edit or override from outside of Photoshop.

Click File > Place Linked… from within your main comp to link an external asset.

A linked file in Photoshop main comp.
A linked file in Photoshop main comp.

Note the chain symbol, which shows that this file is linked to a source.

Now you can manipulate the linked file as if it were a simple image by transforming it or adding layer effects to it.

photoshop_linkedFiles_editInMainComp

So far so good, but now comes the good part:

This was a one-time setup. From now on, you can update the separate mockup psd file or simple override screenshots in the file browser and your main comp will automatically update.

If you need to force an update, just right click the layer and hit Update All Modified Content:

Photoshop - Force update linked files.
Photoshop – Force update linked files.

 

Some more examples when to use linked files:

  • A logo that was designed in Illustrator or any other application can be linked in your marketing preview screens, your game design document, your website and of course in your game itself.
  • Mockups and iconic images like characters or important items can and should appear as a branding throughout your production pipeline.
  • Whenever you want to iterate over assets, place them as linked files in your workflow early on. This way, you can have everything in place and then make changes continuously.
  • If possible, avoid dummy graphics, that are not part of the pipeline. Don’t get me wrong, stand-in assets are very important to your workflow, but make those intermediate assets linked files, so that your production pipeline is set up from the beginning. Iterations come easy and show immediate results.

Use linked files in Photoshop whenever you split work among several files, you want to iterate over your assets without changing the production pipeline and when you want to make sure that a certain asset is always up-to-date at multiple locations.

Smart Objects

Smart Objects in Photoshop are, although they don’t always show it, linked files. Here’s a famous example from PixelResort’s App Icon Template (get it here or search for it online, if you want to follow along).

App Icon Template by PixelResort.
App Icon Template by PixelResort.

 

In this template file you can edit a single Smart Object to design an app icon. Once you are done with creating your icon, you save and Photoshop automatically creates different sizes for you to preview and even exports them via an action.

Let’s take this example and learn how Smart Objects work.

The Smart Object icon in Photoshop.
The Smart Object icon in Photoshop.

 

Double click the layer preview to open a Smart Object.

photoshop_smartObjects_objectOpenAsFile

You will notice that a new file opens (Icon.psb). You can see its content and edit it easily in a separate comp before saving it and seeing the main comp update (App Icon Template.psd).

So if this Smart Object links to another file, where is it? Try the Save As command (CMD/CTRL + Shift + S) and have a look at the inherited file location:

photoshop_smartObjects_fileLocation

As you can see, the Icon.psb Smart Object is a separate Photoshop file on your hard drive, but it’s hidden at a temporary location to avoid cluttering your working  folder. Let’s cancel saving and try something else.

Open the Properties window by selecting Window > Properties or clicking the sidebar icon:

Photoshop Smart Object properties.
Photoshop Smart Object properties.

 

From here you could open it again and edit it (just like when double clicking the layer preview) or you could convert it from a temporary file to a permanent, linked one. Don’t be fooled by the terminology: It is called an Embedded Smart Object because its source is hidden as if it weren’t a linked file, but in fact it is.

Use Convert to Linked… if you want to save out your temp file to use it with other applications. This does not change the functionality; as stated above, a linked file and a Smart Object only differ in the way their content is stored.

Note, that by convention Smart Objects create PSB (Large Document Format) files. In most situations there will be no difference in using the standard PSD format.

How to Create a Smart Object

To create a Smart Object from any layer, right click it and hit Convert to Smart Object.

Aside: Do you remember, that Photoshop let’s you resize Smart Objects non-destructively? Now you know how this works. If you have a simple layer and transform it, you must override it’s save state. If you have Smart Object, that is stored as a temp file, you always have the original source as backup and can go back and forth.

Let’s use Smart Objects to create assets for a card game:

photoshop_smartObjects_exampleCards_01

  • Create a new Photoshop document card.psd
  • Create a new layer, name it card_background or whatever suits the purpose
  • Convert the layer to a Smart Object
  • Copy the Smart Object for card variations

photoshop_smartObjects_exampleCards_02

The copied Smart Object now links to the same background files, meaning that you can open any one of them and edit its content, which will then be updated in all layer instances of your main comp. You can still perform transformations, layer styles and effects, all non-destructively in your main document.

Important: When creating a Smart Object from a layer, it will always inherit the layer name. This name cannot easily be changed, therefore, name your layer before converting it.

This way, you can build a very robust system for creating quick mockups or even your final assets. Here is how I used this technique:

  • I created a Smart Object for a generic background, that could be colored in the main comp.
  • Pictogramms and other graphic elements are all single Smart Objects, so that I can use them on different cards, but when I decide to change one element, they all update accordingly.
  • My main composition works as an overview for me to see all cards in context, compare color values and just make sure they look good together.
  • Individual cards are Smart Objects, that are also hooked up to the Image Asset Generator or a Photoshop action that exports them, if necessary (but as you can guess, I’d rather link my files to any other location, than export them)/

By making individual elements of a design Smart Objects, you can adjust them separately, while keeping up dynamic links to all instances of the elements use. Nesting Smart Objects makes this system very robust and still gives you the flexibility to iterate over your design.

Here are a few more ideas, I’ve used in my own projects:

  • When designing individual elements, always do so in context. Create dynamic links to backgrounds or other external elements so that you always have the most recent version, even if other artists are working on those files.
  • Create a central color scheme or art style document, where artists agree on a color palette and other significant elements. This could also be the main background or any design that dictates how child elements should look. Link to this file from your own images to always be up-to-date when the main design changes.
  • Especially when creating mockups, use the power of Smart Objects to easily test out ideas with complete flexibility. Here’s a quick tip:
Create a design element in an easy to handle Smart Object.
Create a design element in an easy to handle Smart Object.

 

Then, transform and recolor it in your main comp.
Then, transform and recolor it in your main comp.

 

Now just copy the Smart Object and use it in several places and with variations.

This should give you some inspiration to explore Smart Objects in Photoshop. Please let me know, if would like to see more examples in detail.

Object linking and embedding – Smart workflows for game developers

This article describes how to interlink source files, such as images or other assets, in multiple places of your project. Following this principle will make your workflow more streamlined and less prone to errors as it automates a big part of your production pipeline.

Examples given below:

Basic principle

During game development you will most likely create countless assets (images, sounds, etc.) that are going to be used in multiple places of your project. Such files are often exported in a format other than that of the source file and stored at different folders. These exported assets are also called generated files and they should be avoided.

Example: the game’s title logo. You will probably need to incorporate it at similar locations to the ones on this list:

  1. Game Concept
  2. Game Design Document.
  3. Pitching Document
  4. Technical Documentation
  5. Art Bible
  6. Game Engine
  7. Promotional (website, app store, news, etc.)

So what happens, if the logo was copied to all those different places and now the original designer wants to make a change?

  • If changes are made to the source file, the exported versions must be updated.
  • The version change must be made public by communicating that the file has changes.
  • All copies in the final documents and software must be manually updated.
  • Manual work and relying on clear communication is prone to errors.
  • It is difficult to track changes and see which files are up-to-date.
  • Outdated file may go unnoticed and linger around.

Avoid exporting generated assets to production folders.

One solution to the mentioned problems are linked files:

Linked files basics.
Linked files basics.

 

When you link to an asset’s source file from multiple locations in your project, you can modify it and all changes are automatically updates everywhere else.

Opt for dynamically linked assets between files and software.

Example: You’re the 2D artist. Instead of reexporting your images to some sort of folder for generated assets, let your source file (probably a PSD or AI file) be linked in all places, that need it. Now all files are auto-updated when you make a change to the source.

Object linking creates a reference to the source file, while embedded content creates a static copy.

Microsoft Word

Microsoft Word allows you to either paste objects as images (called embedding) or to insert an object with a link to the source file (object linking). Whenever possible, you will want to create a dynamic link instead of copy.

Read this tutorial for more information.

Adobe Photoshop

Photoshop offers several ways of working with object linking and embedding (OLE).

  • Place imported files as embedded or linked
  • Use Layer Compositions to arrange your content in multiple ways
  • Build a dynamic system of Smart Objects

See this tutorial for detailed instructions.

Unity

Unity’s asset import works entirely through object linking. This allows for many great features like auto-updating projects, but it also comes with a few thing to keep in mind.

Here is an overview of linked assets in Unity.

MonoDevelop’s Assembly Browser – Decompile managed plugins

MonoDevelop offers a great but often unnoticed feature for decompiling C# libraries: The Assembly Browser.

The Assembly Browser decompiles managed code and displays it in your MonoDevelop IDE.

Think of plugins from the Unity Asset Store or other third-party modules: Many tools come as a pre-compiled package, such as Dynamic Link Library (.DLL). While you can import and use these libraries easily in Unity, you can’t just open their files and look at the scripts underneath, or can you?

Let’s take a look under the hood of Unity and disassemble one of MonoBehaviour’s methods:

  1. Copy the code to a new C# script in Unity and open it in MonoDevelop.
  2. Place the text cursor within the method name Lerp and right-click Go to declaration or hit Cmd/Ctrl + Y.
Go to declaration of Mathf.Lerp().
Go to declaration of Mathf.Lerp().

When inspecting a MonoBehaviour method, this will take us to the Assembly Browser, since all Unity functions are part of our current Assembly.

Inspecting Mathf.Lerp with MonoDevelop's Assembly Browser.
Inspecting Mathf.Lerp with MonoDevelop’s Assembly Browser.

 

You’re not allowed to alter Unity methods directly, but via the Assembly Browser you can take a look at many implementations.

Inspecting the disassembled Mathf.Lerp(), you can see exactly how it works. This comes in handy when deciding on which implementation is the right for your project; sometimes the Unity MonoBehaviour methods might not be what you want.

Note, that the Assembly Browser only shows managed code.

In short: Managed code in Unity = C#

Managed code in Unity means C# and Java. These programming languages are easily decompiled by MonoDevelop, native code like C or C++, however, is not.

Since most of Unity’s inner workings are written in C++ or use other highly-optimized machine language libraries, there are many MonoBehaviour methods, which you can’t disassemble to their roots in MonoDevelop. Still, most of the time, the Assemble Browser will show you enough information to let you guess what is going on.

Here’s another example:

Vector3.Angle() in MonoDevelop's Assembly Browser.
Vector3.Angle() in MonoDevelop’s Assembly Browser.

Most functions from the Mathf or Vector3 class show us how they work in the Assembly Browser. I encourage you to occasionally look at the implementation of such methods when using them in your project. It can be incredibly helpful to understand the math behind these helpers, because one day you might want to use custom implementations that fit your needs exactly.

Disassembling third-party-plugins

Browsing through pre-compiled plugins from the Asset Store is just as simple as looking at MonoBehaviour methods:

  1. Open a Unity project and import a plugin.
  2. Open the project (Solution) in MonoDevelop by opening any script from the Unity editor or clicking Assets > Sync MonoDevelop Project.
  3. In MonoDevelop go to View > Solution to show the solution browser.
  4. A third-party plugin will show under References. Double click the file to open it in the Assembly Browser. Or just open View > Assembly Browser and find the plugin there.
  5. Make sure to set Visibility to All membersor else you will only see public variables.
  6. Methods and properties can usually be found in a main class with the same name as the plugin. (Look for the “C” on blue background icon to find classes.)

Use MonoDevelop’s Assembly Browser to decompile any managed library or plugin and learn from real-world examples!

Thank you for reading! I hope you found this quick tip inspiring.

Using Unity’s Debug Inspector

Unity’s debug option for the inspector is one of the small, but hugely important features. Here’s how to find it:

Normal Unity inspector.
Normal Unity inspector.

In the tab dropdown for the inspector chose the Debug option, or Normal to return to defaults.

Unity debug inspector.
Unity debug inspector.

Now the Inspector will show additional information, such as private variables from scripts like this:

Debug inspector showing private fields.
Debug Inspector showing private fields.

 

This is one of the easiest and most comfortable ways to inspect private fields from custom classes. Note, that inspector cannot show everything you might expect it to:

The Debug Inspector does not show properties or static variables.

Just to make sure: The Health field that is shown in the inspector is in fact our private variable health, not the property. Variable names are automatically capitalized and formatted in the inspector.

Quicktip: Use auto-implemented properties, if you don’t need additional code or special names for your backing fields. See this tutorial, if you need to freshen up on how properties work.

Here is the official C# documentation on auto-implemented properties.

Be aware that these “auto-props” will display with a particular name syntax in the debug inspector:

Auto-implemented property in the inspector.
Auto-implemented property in the inspector.

 

The Debug Inspector shows not only private fields on custom scripts, but detailed options for other components.

There are many ways to use the debug option to inspect hidden data or change advanced options on Unity components. Here are a few examples:

Inspector and project browser icons

The debug inspector also works when browsing assets in the project view. If you like, you can assign custom icons to your components. This can help your team to find certain important scripts more easily or if you’re developing your own custom component you might want to give it a branding.

Debug inspector icon field.
Debug inspector icon field.

 

Debug inspector fill in icon for script.
Debug inspector fill in icon for script.

 

Inspector with custom icon on script.
Inspector with custom icon on script.

Advanced animation options

There are several options hidden for animation clips, some of which can come in handy to change, such as the ability to switch to legacy animation, when not using Mecanim. You can also adjust options from this window, instead of switching to the Animation or Animator window (e.g. Sample Rate).

Advanced animation clip options.
Advanced animation clip options.

 

Compare objects by instance id

Sometimes you run into a problem, where an object’s instance ID can help you to debug your scene. (The instance ID is a unique identifier to any object in the scene.) Here is a simplified example to illustrate the use of instance IDs:

Often, you need scripts which persist between scenes, such as GameControllers or AudioManagers. If, for whatever reason, you want your manager class to be a MonoBehaviour that lives on a GameObject in the scene, you will have to make sure that there can only exist one instance of it during runtime (read up on the Singleton Pattern for more).

Usually there are ways to build objects in a way that they are true, problem-free singletons, but sometimes you’re stuck with a solution that is prone to errors:

Instance IDs in the debug inspector.
Instance IDs in the debug inspector.

 

Think of a case, when you have a GameController and due to human error there are multiple instances of it attached to GameObjects in the scene. Instance IDs can give you detailed information about which objects are involved when you run into problems:

Now, if you end up with multiple instances of the GameController, only the first one survives. Additionally, the instance IDs of both objects are printed out, to show you exactly which of the instances in the scene caused the problem.

As stated above, this example is purposely plain. Real-world scenarios, where instance IDs will save your life, are going to be complex and cumbersome to debug without the help of detailed object information.

These were only a few examples of how to make the most of the debug inspector in Unity. Keep your eyes open for hidden options and information that helps your work.

Event messaging in Unity – Creating a simple HUD

We can use delegates and events to create a messaging or broadcasting system that is much more robust and versatile than direct script communication via references.

Think of an event as a variable that is called like a static method. As soon as an event is raised from one script, we can listen to it from other scripts and perform corresponding actions. To do this, we want to subscribe another method to our event, which in turn is called. This functionality is given to us with delegates. A delegate holds a list of methods and when the delegate is called, all subscribing methods are called as well.

Best, we look at an example:

Creating a health display with events

This section will show you how to set up a HUD that displays the player’s health whenever it changes. Since there might be more objects that are interested in the player’s health, we will build an event system, that fires whenever the health changes and can be received by any number of other scripts easily.

  1. Create a Player C# script and attach it to a GameObject in the scene.
  2. Create a UI Text object on a Canvas in the scene. I’m using the Unity 4.6 upwards GUI system, but the old system or plain debug log messages will work fine for testing purposes.

Start with the player script:

Our player has a health variable that is going to be initialized in the Start() method. The UpdateHealth() method will be called to add or subtract from health and then call the appropriate event, which can be received by different listeners in the scene.

Next, add in a delegate and an event before line 7:

This is a typical delegate and event pair. Watch the official Unity tutorials on delegates and events for a detailed explanation.

In short: The event OnHealthUpdated is declared as static, so that we can call it from anywhere. It needs a type, which we declare with the delegate HealthUpdate. Note, that the type is HealthUpdate, but the actual delegate is a method, so it needs a return type of void and the parenthesis.

Let’s raise the OnHealthUpdated event in our player script:

If an event is raised without having subscribers, it will throw an error.

Before we call our event like a method we should include a null-check to avoid errors.

An event without subscribers returns null.

Be mindful of the parenthesis: the event itself is called OnHealthUpdated, but when we want to raise it, we use it like a method OnHealthUpdated().

Now that we have a player that raises an event as soon as its health is initialized, we can build the receiving end, the HUD script:

It is a good idea to subscribe to events only when an object is enabled, so we place our code in the OnEnable() method from MonoBehaviour. We can access our static event and assign a method from HUD to it with the += operator. This method can be any custom function that is already declared in your script, but it’s also very convenient to use auto completion and let MonoDevelop suggest an implementation (often called an EventHandler).

MonoDevelop auto implementation of event handlers.
MonoDevelop auto implementation of event handlers.

 

It’s time for our first test:

If you’ve done everything correctly (and both scripts are attached to GameObjects in the scene), the debug message will be printed to the console as soon as the player calls the HealthUpdated event.

Great, now there’s only one thing left to figure out: How to send parameters with events, so that our HUD knows what the player’s health is.

Change line 7 of the player script from:

to:

Now our delegate expects all subscribing methods to receive an integer parameter and we can send one from our event:

Adjust the HUD script to accept the incoming newHealth parameter:

One more important thing:

Whenever you subscribe a method to an event, be sure to unsubscribe it as well to prevent memory leaks and possibly errors.

That’s all there is to a basic messaging system! Events can be used for anything from updating stats over input to artificial intelligence. They can also include more interesting parameters like a reference to the event raising object, but that goes beyond this introduction.

Here are some more ideas how to continue:

Additional info: If you pay close attention to the console output from the last two scripts, you might notice, that the messages seem to come in the wrong order:

Debug messages are displayed in an incorrect order.
Debug messages are displayed in an incorrect order.

How can the event be received before it was fired? Of course, it can’t. Printing to the console is a very slow operation and due to many things going on at the same time, Debug.Log() might be too slow to accurately depict what is going on. Don’t worry, just be aware that it’s only the console messages that are slow, your event system is still working correctly.

Caching the ‘transform’ and ‘gameObject’ properties

The transform and gameObject properties of MonoBehaviour are often used to check property values against other values.

There are a few reasons to avoid using transform to move objects, but a position-check is a perfectly valid example. There is, however, a small problem with the above code: The transform property internally does a GetComponent() call. This means, that every frame a method call is needed to find the reference to the Transform component of our GameObject.

This code illustrates what is actually going on under the hood of Unity. At this point it is not necessary to fully understand how these internal calls work, just keep in mind that every method call and dot-operation costs performance and therefore we want to avoid them as much as possible.

The solution: Cache your variables and even Unity properties!

Instead of finding a reference to our Transform component in every frame, we do it only once and store it in a variable. You could call this variable myTransform or something, but I prefer to call it the same as the Unity transform property. This way, I don’t have to change any of my working code, when I want to optimize things at the end.

Pay attention to the new keyword, which we use to tell the compiler that we intend to override the inherited member transform from MonoBehaviour. This step is not entirely necessary, but sometimes Unity will throw a warning and remind you that there already exists a variable called transform.

Caching references in variables is a common way to optimize performance.

What we did with the transform property is just one example of caching a reference for later use. We do the same thing whenever we access another script or component, but in case of the built-in Unity properties, I think it is worth mentioning that we can override those with more performant ones.

Note, that this kind of optimization is only effective and noticeable when resources are limited or you are dealing with many script objects. Caching Unity properties for only your player will not speed up your game visibly!