Each
Canvas
acts as a renderable collection of UI elements in a scene. You'll
likely benefit by using more than one in your scene as a single UI
change forces the entire Canvas
mesh to be regenerated.
Keep this in mind when designing your Canvas
layouts.
Canvas
>
Panel
>
UI Elements is a typical nested
structure for Unity UI. Examples of UI Elements include
Button
,
Text
,
Image
,
Slider
, etc. You can even nest a Panel
within a
Panel
, don't be scared.
There are three Render Mode settings for a
Canvas
. Screen Space – Overlay (2D perspectiveless HUD, rendered
above all scene objects), Screen Space – Camera (2D
perspective HUD, rendered with variable scene depth), and
World Space (3D perspective, with variable scene depth).
The
RectTransform
is the base component of all UI elements. You set its anchors to
control resizing based on its relationship to its parent. You set its
Pivot Point to control its 2D position (x, y), which also acts as the
position from which scaling and rotating occur.
All UI elements are comprised of
Text
and
Image
components in one form or another, that’s it. You can have an
Image
component be represented by a solid fill color as
opposed to an actual
Sprite
too, it’s no big deal.
All interactive UI elements extend the
Selectable
class. This class provides an interactable toggle, transition settings
(over, down, pressed, etc), and navigation settings (“tab order” for
PC keyboards, console controllers, etc).
Use a
CanvasGroup
component to fade out a collection of UI elements (panel and its
children) as one entity. This component also allows you to
enable/disable all interactive children at once. CanvasGroup is your
friend.
Unity renders UI elements in your Hierarchy view from top to bottom. This means the bottom most UI element in the Hierarchy view is rendered last, and thus above of all other UI elements on screen.
A
ToggleGroup
component is useful for mimicking “Radio Buttons”. It is best practice
to put the ToggleGroup component on the parent of the
Toggle
instances, though not required... why did I tell you that last part?
When importing PSD files, make sure to update its Texture Type setting to Sprite (2D & UI) if you intend to use the asset for 2D or UI. This is a gotcha that can be frustrating if not set properly.
For custom UI interaction events, have a custom component script
implement from UnityEngine.EventSystems.XXX where XXX is a Unity
built-in interface. Example interfaces include
IPointerEnterHandler
,
IDragHandler
,
ISelectHandler
, etc. and allow the execution of custom code within the interface’s
implemented method.
The
Navigation
setting on an interactive UI element is used to determine “tab order”
which changes the focus of UI elements in controller, keyboard, etc
based user interaction models. The Visualize button shows the
focus flow in the Scene view.
You can use the
EventTrigger
component on a
Selectable
UI element (Button
,
Slider
, etc) to expose additional event types in the Inspector. This is
useful if you want to make a UI or scene change dynamically based on
user input other than OnClick.
For masking, simply have a Panel (PanelA) nested inside another Panel
(PanelB) where PanelA is larger than PanelB. Then simply select PanelB
and add a
Mask
component. This enables PanelA’s content to show through. Remember,
the masked area is based on the Source Image property of
PanelB's
Image
component.
For a
Mask
, the mask area is based on the attached image component.
Transparency in the image cuts out the visible area of its children.
You can uncheck Show Mask Graphic to hide the graphic itself
but still provide the mask area, nice.
For masked scrolling, simply add a
ScrollRect
component to a parent Panel containing a
Mask
component. Then set the Content property of the ScrollRect to
the child panel whose bounds exceed those of the parent panel. Scrolly
time.
For Auto Layouts, simply add a
GridLayoutGroup
,
HorizontalLayoutGroup
, or
VerticalLayoutGroup
component to a Panel and then all children will automatically align.
You will likely want to edit this automatic alignment and you can do
so with the Start Corner, Start Axis, or
Child Alignment properties. The parent controls the “cell
size” of the children as well.
A
Button
can have a
GridLayoutGroup
,
HorizontalLayoutGroup
, or
VerticalLayoutGroup
component to automatically layout its children. This is useful if a
single button has numerous visual elements within it. In addition, the
children can have a
LayoutElement
component to set min, max, and preferred sizes that override or inform
the layout group to handle the child in a specific way. Go make cooler
buttons.
A
Button
with a
HorizontalLayoutGroup
component and padding can ensure the button resizes according to the
size of its children and no bigger. A
LayoutElement
component with no flexible width is necessary for this to work.
Set a UI element’s
LayoutElement
flexible width or flexible height properties to
decimal values to allow the parent layout group of each to organize
them by “weight” or “percent”. This percentage based layout works
until all children only have room to be their preferred width or
preferred height. This is super useful and similar to Android’s
layout_weight or the Web’s percentage based layouts.
You can use an empty
GameObject
with a
RectTransform
instead of a Panel to group UI elements. This is handy if you want a
“lighter Panel” that doesn’t require a visual representation itself.
Add a
CanvasScaler
component to a
Canvas
to better control resolution variations. It is a good idea, and most
common, to set the Screen Match Mode to
Width or Height with a value of .5. The
Expand and Shrink options are best for background
graphics that simply cover the entire screen area (smaller use case,
but depends on your game/app).
When dynamically adding UI elements to a scrollable content Panel, a
ContentSizeFitter
component is of great help. It will make the scrollable area size
“snap” to the combined area of the internal UI elements. For this to
work, 1) the children UI elements each need a
LayoutElement
with set preferred sizes (width, height, or both) and 2) the panel
with the ContentSizeFitter needs its layout group’s
Child Force Expand (width, height, or both) setting(s)
disabled.
For each texture, you can set platform overrides. This is useful for changing the graphic size and compression of image assets on a per-platform level.
Unity doesn’t have a built-in pixel-density solution, so sad face.
However, you can poll the device or machine using the
Screen
class to get the resolution,
pixel density (dpi), and more. An approach could be 1) get the Screen
info 2) calculate a “best fit” (similar to Android’s ldpi, mdpi, hdpi,
etc), and 3) ensure all graphic assets are utilized from the “best
fit”
Resources
folder.
To create your own preloader scene, just make the first scene
virtually empty (except for what you need to visually represent
preloading) and when this preloader scene is loaded, call
LoadLevelAsync()
or
LoadLevelAdditiveAsync()
and then query progress and draw the preloader visuals.
It is best practice to use generic lists as opposed to ArrayList. The Unify Wiki has a great breakdown of when to use one over the other, why, and alternatives.
Set up a looping coroutine in the Start() method of a
component instead of using the Update() method if updates for
a
Component
don’t need the game/app frame rate (.2f coroutine will run 5 times a
second vs 60fps)
If you have a scrollable view that holds a large amount of UI element instances (ex. list items), you’ll likely want to optimize. Conceptually, if you have a max of 10 instances out of 100 visible at any one time; creating all 100 is a waste. Instead, use the Object Pool pattern. This way you only instantiate 10 or so instances and based on scrolling position, you’ll recycle and update each view with the correct data. Android and iOS use this approach to optimize the performance of scrolling long lists.
A
Prefab
with an attached custom component (ideally by the same name) can hold
references to itself, and/or its children, and/or other connected
components. This allows a single
GetComponent<MyComponent>()
call to gain
reference to the Prefab instance's connected components or
GameObject
s whose properties change/update at runtime. This is a very useful
approach for succinctly "building" or "inflating" Prefab instances at
runtime based on dynamic data.
It is best practice to use a
Sprite Sheet (aka Atlas)
for your graphics assets in 2D (and 3D) games/apps as opposed to
having a one-to-one relationship between a texture and an image file.
The core advantage of this approach is performance related. Basically,
the device on which your game/app is running can minimize draw calls
by UV mapping part(s) of a texture (your Sprite Sheet)
multiple times to a geometry. The alternative is a draw call per
texture per geometry.
It is a common practice to use an empty
GameObject
as a “folder” within a scene. This helps you better organize and
structure your game in a visual way. A specific approach is to
position an empty GameObject at (0, 0, 0) which is then filled with
various manager classes, utility classes, and a top-level eventing
system. This is a useful approach, especially for persisting
components across scene loads.
When in the Scene view, have you ever wanted to make one
GameObject
point or “look at” another GameObject? To pull this off, simply hover
the GameObject in focus with your Rotate Tool selected and
then hold ctrl/cmd + shift
as you drag
the Rotate Gizmo. While dragging, the GameObject you’re
rotating will “look at” the GameObject you hover. Things are looking
up.
There are times when positioning a
GameObject
that you want its position to snap to the surface of another
GameObject. This is common when wanting to drag an object across a
floor for example. You can use Surface Snapping to achieve
this. Simply hold down
ctrl/cmd + shift
prior to selecting and
manipulating a GameObject’s position. As you drag, the target surface
to snap to updates as you hover different GameObjects.
If you need help aligning
GameObject
with vertex precision or to a grid, you need to use
Vertex Snapping. To pull this off, select the
Translate Tool, hold down the
v
key, hover the desired vertex of the
GameObject in focus, then click and drag. As you drag your GameObject,
its position snaps to the hovered vertex of another GameObject.
Snappy.
If you want to interpolate values over time in a succinct way, you can
use Unity’s built-in Lerp
(linear interpolation) methods.
Numerous classes have this method or a variation of it. Some common
examples are
Color.Lerp
,
Vector2.Lerp
,
Vector3.Lerp
,
Mathf.LerpAngle
, and
Vector3.Slerp
. Mmmm… Slerp.
If you repeatedly find yourself editing values only to realize you were in PlayMode when doing so (and thus losing all your edits), raise your hand… actually don’t raise it. Instead use Edit > Preferences > Colors > Playmode Tint to have Unity automatically color-tint the editor interface so you’re visually reminded that you’re in PlayMode. Damn handy.
To improve precision while moving a
GameObject
in a scene, you can hold down
ctrl/cmd
while dragging its
Translate Gizmo. This enables the position of the GameObject
you’re moving to snap in incremental units. Go to
Edit > Snap Settings to customize.
Slo-mo your thing? One approach to a slow motion effect is to leverage
Time.time
in conjunction with
Time.timeScale
. For instance, you could Lerp
or Tween
the
Time.timeScale
value over a period of time to transition
toward a “pause” or “freeze” state.
Having the pixelated-app-icon blues? Fix 'em in two easy steps. First, select all the icon images at once from within the Project. Second, select Editor GUI and Legacy GUI from the Texture Type drop down in the Inspector. Done. You can learn more detail about why this happens over on Unity Answers.
In cases where you are doing a lot of operations on a field or property, you can instead use a local variable cache to get a 3x performance improvement. Get the details in Jackson Dunstan's C# Performance: Properties vs. Fields vs. Locals article.
When using 3D physics with complex models it is often best to use
Compound Colliders instead of a Mesh Collider. A complex mesh collider will likely have many more vertices than a
combination of primitive colliders (BoxCollider
,
SphereCollider
, or
CapsuleCollider
). Fewer vertices = fewer calculations = better performance.
Shortcuts are your friend. Use
shift + spacebar
after focusing your
cursor in a specific window to toggle fullscreen. This is very useful
when focused on the Scene view and toggling PlayMode.
Having lights in your scene is computationally expensive. "But lighting looks so good," you say. Welcome to Lightmapping, the extremely efficient way to make scene objects look as if they are affected by lights without having lights in your scene.
Want to restrict a
GameObject
's position to a specific boundary, say the width and height of the
screen? Use
Mathf.Clamp
as the enforcer. Keep in mind he has many relatives such as
WrapMode.ClampForever
,
InputField.ClampPos
,
Vector3.ClampMagnitude
, and more.
Do you keep getting errors in the Console and not know what they mean? Welcome to the C# Error Messages list. There is a list for UnityScript too, but I'm not going to link to it. Seriously, bite the bullet and learn C# instead, you'll be glad you did.
So you like Lightmapping now (Tip #44) but you're not a fan of the "non-static objects" restriction right? You're S.O.L. Just kidding, check out your new best friend Light Probes.
Want to do simple and accurate collision detection in Unity? Want to see how to do it in 25 seconds? Then the Unity Collision Detection in 25 Seconds article is for you.
Having trouble expanding and collapsing large nested groups in the
hierarchy? Use alt + left-arrow
to
collapse and alt + right-arrow
to
expand.
Having unwanted hiccups in your game? Check out Wendelin Reich's C# Memory Management for Developers or Unity's Understanding Automatic Memory Management breakdown to learn how to manage memory and tame the Garbage Collector.
If you use the public
access modifier on
MonoBehaviour
fields just so you can edit them
through the editor... STOP. Look into adopting the
[SerializeField]
attribute instead.
If you use coroutines, then you should check @AngryAnt's short article Optimising coroutine yielding in C# to make sure you're not performing unneeded memory allocation. It's a simple fix if you're doing it wrong.
Do you ever wish it was easier to identify overlapping objects in the Scene view? Simply click an object, then click the Icon Dropdown just to the left of the name in the Inspector. You didn't know this was a button uh? From here you can label it with a color or texture for better identification and organization within the Scene view. This tip is brought to you by Iestyn Lloyd's Tweet.
When you cast objects, do you use prefix casting or as-casting? There are subtle benefits and potential performance gains depending on your choice. @jashan has the lowdown for you over at Unity Answers.
If you are like me and have been using Photoshop virtually everyday
for too many years to count, then you know how much of a habit the
spacebar
Hand Tool shortcut is. Unity
has this tool too, but you click the further away and pinky-awkward
Q
key. Make things right in the world
with Edit > Preferences > Keys > Tools/View.
If you ever make
Color
edits from within the Inspector, take note of the eye dropper to the
right of the color box. You can sample any on screen color with it,
not just colors within the Unity editor. Now you can sample the colors
from your Reddit EarthPorn with ease.
It may seem weird at first, but it is totally normal to have multiple Cameras in a scene. By leveraging a camera's Clear Flags and Culling Mask properties you can ensure certain cameras only render certain layers. A common example is to have one camera render only UI and another render only your game/app. You can get creative too, put your thinking cap on.
Ever heard of icon fonts? They are a super useful and popular approach to achieving scaleable and color independent icons in web development. Unity supports them too with some minor tweaking. Chris Sung has the lowdown in his Unity3D UI Typography: Font Awesome post. Please don't default to Font Awesome, buy or make your own.
As suggested by
@AngryAnt in a Tweet with @trinketben, you can use a [Comment]
attribute to provide visible
in-editor notes about an Inspector property. In fact there are a lot
of attributes that are useful.
@liortal53 has a
nice breakdown.
Ever had the need to capture a screenshot during gameplay or while
developing?
Application.CaptureScreenshot
is your friend.
If MonoDevelop is a pain in the ass, then try Visual Studio or Sublime Text 3. @wpg_denny has a great article titled Using Sublime with Unity to get you up and running on Windows or Mac.
Though it is often an ill-advised approach from a performance
perspective,
Reflection
can be a very useful tool. During authoring time for example,
Reflection can be used to log all the properties of a poorly
documented class instance to better understand its interface.
Brannon has a solid example of this on Stack Overflow, but don't forget to add your using System
and
using System.Reflection
statements when using the
snippet.
When working with physics in Unity, don't forget to leverage layers and the collision matrix for an easy optimization win. Ricardo Aguiar has more in his Physics Best Practices article.
Since iOS and Android can kill any app at will (to free up limited
resources), it is wise to use
OnApplicationPause
when your game/app loses focus. This enables you a chance to save data
that needs to persist between game/app sessions.
JavaScript for the web (not Unity Script) has a
console.log()
method that can handle a variable amount of
arguments. This is extremely handy as it replaces cumbersome typing
with a comma separated list of variable length to print to the
console. Lucky you, Teemu Ikonen has already created the
Console.Log() script
for C#.
If you create a lot of strings at runtime, you may be able to benefit by storing said strings in a fixed array as opposed to creating new ones all the time. Don’t risk tempting the ever hungry Garbage Collector to cause frame rate jitter. Check @catlikecoding Frames Per Second tutorial for an example.
If you do mobile Android dev and you need to store persistent data, then you need to check Supersegfault’s game dev blog. Specifically his Unity on Android Save Data Pitfall post so you're aware of the differences between internal and external storage.
Ever felt that Unity classes were missing obviously helpful methods? Do something about it using Extension Methods. Josh Sutphin (aka @invicticide) details the implementation in Adding to Unity's Built-in Classes Using Extension Methods.
When targeting iOS, is your framerate capped to 30fps? Use
Application.targetFrameRate
to get that 60fps. This can be used when targeting any platform btw.
Be aware that different platforms, in addition to your game/app, can
impact the target fps.
Do you want to implement a cross platform approach for storing persistent data? Look no further than the post How to Save and Load Your Players' Progress in Unity by @ericdaily. Take note of the iOS requirement regarding "MONO_REFLECTION_SERIALIZER" in the comments.
Do you ever wish PlayerPrefs.SetBool
and
PlayerPrefs.GetBool
methods existed? If so, then check
out
this Unity forum thread
to see how you can use PlayerPrefs.SetInt
and
PlayerPrefs.GetInt
in combination with the ternary
operator to create a succinct extension method that gets you what you
want.
When authoring for iOS and Android, do you wish
PlayerSettings.bundleVersion
was accessible at runtime?
Thankfully
@akaSurreal suggests a
nice approach to accomplish this (and more) using Unity's
BuildPipeline
class. Check it out in this
Unity forum thread.
Ever need to read from and/or write to a file during runtime in your game or app? Thankfully, there are a set of classes in .NET to help you out. Additionally, Jackson Dunstan has some performance tips in his File I/O Performance Tips article. Dunstan, you're the man!
Ever want to have finer control over a
GameObject
's
component order in the Unity Editor? Luckily
@kode80 has your back with
this tweet. Download the tools on
github.
C# has built-in events, but Unity created the
UnityEvent
class anyway. To be fair, I'm sure they had their reasons. At the very
least, they likely did so for cross-language compatibility and editor
integration. Regardless, you should be aware of the performance
implications. As always Jackson Dunstan has your back in
Event Performance: C# vs. UnityEvent.
When publishing to Android, do you wish you had finer control over
Android's Navigation and Status Bar display styles? Well you're in
luck because @zeh wrote
ApplicationChrome.cs
. Check out implementation details in
his
Unity tidbits
post.
Have you ever had the desire to visualize raycasts or helper lines
while authoring in Unity? If so, check out
Debug.DrawRay
and
Debug.DrawLine
.
Modeling by Numbers - An Introduction to Procedural Geometry
by @jayelinda does a great
job teaching how to create a
Mesh
at runtime. Procedural geometry opens up a lot of doors in terms of
flexibility and model variation at runtime. Check it out.
If you need or want the freedom to change the component order on your
GameObject
's
with greater ease, then I also suggest (Tip #74) looking into
XT Reorder
by @xeleh.
Are you creating an app with Unity that isn't supposed to be full screen? You can show the status bar easily on iOS, but Android's status and navigation bars are a different story. Thankfully, @yury_habets has the solution on GitHub with UnityShowAndroidStatusBar.
When your game/app starts up do you need to guarantee that some scripts load before others? If so, make sure to check out the Script Execution Order Settings via Edit > Project Settings > Script Execution Order. This is handy for example when you want to ensure a few manager classes load first.
Are you a big fan of animation? Same here. If you slave away editing keyframes though, you need to look into using a tweening engine. Not all animation styles will benefit, but you should know about them regardless. @Prime31's' ZestKit rocks!
Want 10 Steps to get 10x Performance when scripting in Unity? Checkout out @SorenTrautner's' bit in Tools, Tricks and Technologies for Reaching Stutter Free 60 FPS in INSIDE.
Making a 2D or 2.5D game? Want a badass camera system? Look no further than Pro Camera 2D by @lpfonseca.
If you are modifying one or more meshes at runtime, you're likely to get a performance increase by using double buffering. Check the Unity Mobile Optimizations page for a simple example.
Do you sometimes end up with too many fields in your MonoBehaviors? You may benefit from using a ScriptableObject as a reusable data table. @superpig has the lowdown in Overthrowing the MonoBehaviour Tyranny in a Glorious Scriptable Object Revolution.
It would be cool if there was a simple way to bookmark and reset the Scene View to a previous viewing angle right? Thought so too, checkout Scene Shot Bookmarks, an open source custom editor solution.
Do you ever have long running processing in your game/app that causes
GameObject
s or UI movement to be janky? You really need to check out
Thread Ninja - Multithread Coroutine
to keep motion smooth while doing heavy processing tasks.
Use Unity UI? Ever place your UI off-screen? Make sure you actually
disable your
Canvas
es as Unity doesn't automatically cull UIs that are off-screen as
you'd expect.
Do you use Animators on your UI? DON'T! Use a Tweening Engine instead. Check Ian Dundore of Unity's Squeezing Unity: Tips for raising performance talk for the low-down.
When troubleshooting an issue with a
GameObject
wouldn't it be cool if the Inspector revealed non-public
properties for all its script components? Unity already has you
covered. Simply click the Inspector's tab menu and toggle from
Normal to Debug mode. Piece of cake.
@rich_lloyd reminds us to check the Frame Debugger to help mitigate unwanted draw calls so you can increase your frame rate. Easy win.
Ever wish you could easily manipulate 3D models right in the Unity editor? @ProBuilder3D has you more than covered with ProBuilder Advanced. There's a free version too. Just buy it, it's more than worth it.
Want to improve your speed, precision, and quality during level construction? Of course. Get ProGrids 2 and take scene construction to a whole new level. See what I did there?
Ever have the desire to spawn many 3D models to form a larger 3D model shape? Think fireworks like dragons. In Brackeys How many Rigidbodies can Unity support? YouTube video they show you how. OK, I'll tell you, simply spawn a 3D model at each vertex of another 3D model. Cool.
If you want to have a shadow render on a surface without the surface material itself showing then @_kzr's ShadowDrawer shader is for you.
When working with 3D or 2D Physics in Unity, it's easy to forget that you can override the Default Physic Material. You can make the change via Edit > Project Settings > Physics (or Physics 2D) within the Physics Manager.
When rolling a circle (Circle Collider 2D) or sphere (Sphere Collider) on a slanted surface, does the physics simulation seem slow and
unrealistic? If so, you'll likely find a super simple fix by
increasing
RigidBody.maxAngularVelocity
on the
GameObject
in question. I love simple fixes.
You a fan of projectile motion? Same here. Check @Varaquilex's Projectile Motion Tutorial for Arrows and Missiles in Unity3D article to learn a bunch of great tips on how to pull off projectile motion yourself.
Do you like that isometric camera look? It's super easy to make
happen. First ensure your
Camera
's'
Transform
position, rotation, and scale are zero'd out. Then simply set the
Rotation X to 30
and Rotation Y to 45
.
Lastly change the camera Projection setting from Perspective to
Orthographic. Boom done.
@LiamSorta reinforces a
simple and impactful strategy for potentially massive performance
gains. You know you want perf wins, yes you do. Long story short, not
all your code needs to run at the FPS
Update()
interval. Check his
Tweet
for details.
Want a streamable world in one click? Of course you do. Check out this Generating 2D and 3D Streamable Worlds in Unity article to learn how a custom editor script + Sectr by @ProcWorlds work in harmony.
Ever create a new Script in the Editor via
Add Component > New Script only to delete Unity's default
Awake
and Start
definitions? You know you
can customize the
default Script
Unity creates for you right?