Our tips to improve Unity UI performance when making games for mobile devices

There is a Unity Unity talk named "Unite Europe 2017 - Squeezing Unity: Tips for raising performance" by Ian Dundore about things you can do in your game to improve Unity performance by explaining how Unity works behind the scenes.

Update: I just noted (when I was about to complete the post) there is another talk by Ian from Unite 2016 named "Unite 2016 - Let's Talk (Content) Optimization", which has other good tips as well.

There are two techniques to improve Unity UI performance we use at work they didn’t mention in the video and we want to share them in this blog post. One of them is using CanvasGroup component and the other one is using RectMask2D.

CanvasGroup

CanvasGroup component controls the alpha value of all the elements inside in its RectTransform hierarchy and whether that hierarchy handle input or not. The first one is mainly used for render purposes while the second one for user interaction.

What is awesome about CanvasGroup is, if you want to avoid rendering a hierarchy of elements, you can just put alpha in 0 and that will avoid sending it to render queue improving gpu usage, or at least that is what the FrameDebugger and our performance tests say. If you also want to avoid that hierarchy to consume events from the EventSystem, you can turn off the block raycast property and that will avoid all the raycast checks for its children, improving cpu usage. The combination of those two is important. It is also easier and more designer friendly than iterating over all the children with CanvasRender and disable them. Same thing to disable/enable all objects handling raycasts.

In our case, at work, we are using multiple Canvas objects and have all of them “disabled” (not being rendered nor handling input) using CanvasGroup alpha and block raycasts properties. That improves a lot the speed of activating and deactivating our metagame screens since it avoids regenerating the mesh and calculating layout again which GameObject SetActive() does.

RectMask2D

The idea when using masks it to hide part of the screen in some way, even using particular shapes. We use masks a lot at work in the metagame screens, mainly to show stuff in a ScrollRect in a nice way.

We started using just Mask component, with an Image without Sprite set, to crop what we wanted. Even though it worked ok, it wasn’t performing well on mobile devices. After investigating a bit with FrameDebugger we discovered we had tons of render calls of stuff that was outside the ScrollRect (and the mask).

Since we are just using rectangle containers for those ScrollRects, we changed to use RectMask2D instead. For ScrollRects with a lot of elements, that change improved enormously the performance since it was like the elements outside the mask weren’t there anymore in terms of render calls.

This was a great change but only works if you are using rectangle containers, doesn’t work with other shapes. Note that the Unity UI Mask tutorial only shows image masks and doesn't say anything about performance cost at all (it should).

Note: when working with masks there is a common technique of adding something over the mask to hide possible ugly mask borders, we normally do that on all our ScrollRect that doesn't cover all the screen.

Bonus track: The touch hack

There is another one, a hack, we call it the Touch Hack. It is a way to handle touch all over the screen without render penalty, not sure it is a great tip but it helped us.

The first thing we thought when handling touch all over the screen (to do popup logic and/or block all the other canvases) was to use an Image, without Sprite set, expanded to all the screen with raycast enabled. That worked ok but it was not only breaking the batch but also rendering a big empty transparent quad to all the screen which is really bad on mobile devices.

Our solution was to change to use a Text instead, also expanded to all the screen but without Font nor text set. It doesn’t consume render time (tested on mobile devices) and handles the raycasts as expected, I suppose it is because it doesn’t generate the mesh (since it doesn’t have text nor font set) and at the same time still has the bounding box for raycasts configured.

Conclusion

It is really important to have good tools to detect where the problems are and a way to know if you are improving or not. We use a lot the FrameDebugger (to see what was being drawn, how many render calls, etc), the overdraw Scene view and the Profiler (to see the Unity UI CPU cost).

Hope these tips could help when using Unity UI to improve even more the performance of your games.

More

Optimizing Unity UI - http://www.tantzygames.com/blog/optimizing-unity-ui/

A guide to optimizing Unity UI - https://unity3d.com/es/learn/tutorials/temas/best-practices/guide-optimizing-unity-ui

Implementing Multiple Canvas Groups In Unity 5 - http://www.israel-smith.com/thoughts/implementing-multiple-canvas-groups-in-unity-5/

 

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Pigs Mayhem in Space, our Ludum Dare Jam #38 entry

After some years of Ludum Dare (LD from now on) inactivity, we decided to participate in LD #38 Jam. And when I say we I mean Rubén and I! Of course, since we are great artists, we joined forces with Thony, a young artist who is really really good (just open the link and see it by yourself).

The theme of this LD was "A small world" and our game was Pigs Mayhem in Space:

After iterating over a thousand ideas (yeah, I like to exaggerate, they were only 999) the first day, we ended up with a 3d, turn by turn game where you have to use projectiles and physics to kill the other players (like Worms). This is one of the first concept:

And this is the how the game looked at the end:

Play the game!

Small post mortem

The bad

  • It took us a lot of time to define the game, and that means we did a lot of work on stuff we didn't use.
  • We didn't spend time polishing the controls and when we wanted it was already too late. That affected a lot the game experience.

The good

  • We were aligned with the game we wanted to do and with almost every decision.
  • The art style was quickly defined and without setbacks. It helped a lot to visualize the final game.
  • Working together was really smooth, the game was first and all decisions were to make the game better.

Conclusion

Even though Rubén and I work together at Ironhide, we are not in the same team and even though we share stuff between projects, I missed a lot working directly with him in the same project, since, you know, we fight discuss a lot but the results are always better 🙂

This was my first time working with Thony (Rubén and Thony work in the same team at Ironhide) and it was prety awesome. He has good control on 3d tools and Unity and does great 2d art (the game proves it!).

As always, it was a great experience, it helped on exercising the creative process of developing games and learning how different kind of games are made.

Links

The game at itchio

Thony's ArtStation page

Some visual references

 

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Playing with Starcraft 2 Editor to understand how a good RTS is made

When working on Iron Marines engine at work we did some research on other RTS games in order to have more knowledge on how they did some stuff and why. In this post, in particular, I want to share a bit of my research on the SC2 Editor which helped a lot when making our own editor.

The objective was to see what a Game Designer could do or not with the SC2 Editor in order to understand some decisions about the editor and the engine itself.

Obviously, by taking a look at the game mods/maps available it is clear that you could build entire games over the SC2 engine, but I wanted to see the basics, how to define and control the game logic.

As a side note, I love RTS games since I was a child, I played a lot of Dune 2 and Warcraft 1. I remember playing with the editors of Command & Conquer and Warcraft 2 also, it was really cool, so much power 😉 and fun. With one of my brothers, each one had to make a map and the other had to play and beat it (we did the same with Doom and Duke Nukem 3d editors).

SC2 Editor

SC2 maps are built with Triggers which are composed by Events, Conditions and Actions to define parts of the game logic. There are a lot of other elements as well that I will talk a bit after explaining the basics.

Here is an image of the SC2 Editor with an advanced map:

Trigger logic

The Triggers are where the general map logic is defined. They are triggered by Events and say which Actions should be performed if given Conditions are met. Even though behind the scenes the logic is C/C++ code and it is calling functions with similar names, the Editor shows it in a natural language like “Is Any Unit of Player1 Alive?” which helps for quick reading and understanding.

This is an example of a Trigger logic of a SC2 campaign map:

Events

Events are a way to Trigger the Trigger logic, in other words, when an event happens the logic is executed. Here is an example of an event triggered when the unit "SpecialMarine" enters the region "Region 001":

Conditions

Conditions are evaluated in order to execute the actions or not. Here is an example of a condition checking if unit "BadGuy" is alive or not:

Actions

Actions are executed when the event happened and the conditions are met. They could be anything supported by the editor, from ordering a structure to build a unit to showing a mission objective update on screen, among other things.

This example shows an action that enqueues to unit "BadGuy" an attack order with unit "SpecialMarine" as target, replacing existing enqueued orders in that unit. There is another action after that which turns off the Trigger in order to avoid processing its logic again.

The idea with this approach is to build the logic in a descriptive way, the Game Designer has tools to fulfill what he needs in terms of game experience. For example, he needs to make it hard to save a special unit when you reach its location, then he sends a wave of enemies to that point.

I said before that the editor generates C/C++ code behind the scenes, so, for my example:

The code generated behind the scenes is this one:

Here is a screenshot of the example I did, the red guy is the SpecialMarine (controlled by the player) and the blue one is the BadGuy (controlled by the map logic), if you move your unit inside the blue region, BadGuy comes in and attack SpecialMarine:

Even though it is really basic, download my example if you want to test it 😛 .

Parameters

In order to make the Triggers work, they need some values to check against, for example, Region1, is a region previously defined, or “Any Unit of Player1”. Most of the functions for Events, Conditions and Actions have parameters of a given Type, and the Editor allow the user to pick an object of that Type from different sources: a function, a preset, a variable, a value or even custom code:

It shows picking a Unit from units in the map (created instances).

It shows Unit picking from different functions that return a Unit.

This allows the Game Designer to adapt, in part, the logic to what is happening in the game while keeping the main structure of the logic. For example, I need to make the structures of Player2 explode when any Unit of Player1 is in Region1, I don’t care which unit I only care it is from Player1.

Game design helper elements

There are different elements that help the Game Designer when creating the map: Regions, Points, Paths and Unit Groups, among others. These elements are normally not visible by the Player but are really useful to the Game Designer to have more control over the logic.

As said before, the SC2 Editor is pretty complete, it allows you to do a lot of stuff, from creating custom cutscenes to override game data to create new units, abilities, and more but that's food for another post.

Our Editor v0.1

The first try of creating some kind of editor for our game wasn't so successful. Without the core of the game clearly defined we tried to create an editor with a lot of the SC2 Editor features. We spent some days defining a lot of stuff in abstract but in the end we aimed too far for a first iteration.

So, after that, we decided to start small. We starting by making a way to detect events over the "being defined core" at that point. An event could be for example: "when units enter an area" or "when a resource spot was captured by a player".

Here are some of the events of one of our maps:

Note: Even though they are Events we named them Triggers (dunno why), so AreaTrigger is an empty Trigger in terms of SC2 Editor with just an Event.

Events were the only thing in the editor, all the corresponding logic was done in code in one class, corresponding to that map, which captures all events and checks conditions for taking some actions, normally, sending enemies to attack some area.

Here is an example code for some of the previous defined events:

It wasn't a bad solution but had some problems:

  • The actions were separated from the level design which played against the iteration cycle (at some point our project needed between 10 and 15 seconds to compile in the Unity Editor).
  • Since it needs code to work, it requires programming knowledge and our team Game Designers aren't so good with code.

Our Editor v0.2

The second (and current) version is more Game Designer friendly, and tends to be more similar to SC2 Editor. Most of the logic is defined in the editor within multiple triggers. Each Trigger is defined as a hierarchy of GameObjects with specific components to define the Events, Conditions and Actions.

Here is an example of a map using the new system:

This declares for example a trigger logic that is activated by time, it has no conditions (so it executes always given the event) and it sends some enemies in sequence and deactivates itself at the end.

We also created a custom Editor window in order to help creating the trigger hierarchy and to simplify looking for the engine Events, Conditions and Actions. Here is part of the editor showing some of the elements we have:

All those buttons automatically create the corresponding GameObject hierarchy with the proper Components in order to make everything work according to plan. Since most of them need parameters, we are using the Unity built-in feature of linking elements given a type (a Component), so for example, for the action of forcing capture a Capturable element by team Soldiers, we have:

Unity allow us to pick a Capturable element (CapturableScript in this case) from the scene. This simplifies a lot the job of configuring the map logic.

Some common conditions could be to check if a resource spot is controlled by a given player or if a structure is alive. Common actions could be, send a wave of enemy units to a given area or deactivate a trigger.

The base code is pretty simple, it mainly defines the API while the real value of this solution is in the custom Events, Conditions and Actions.

Pros

  • Visual, and more Game Designer friendly (it is easier for Programmers too).
  • Faster iteration speed, now we can change things in Editor directly, even in runtime!
  • Easily extensible by adding more Events, Conditions and Actions, and transparent to the Game Designers since they are automatically shown in our Custom Editor.
  • Take advantage of Unity Editor for configuring stuff.
  • Easy to disable/enable some logic by turning on/off the corresponding GameObject, which is good for testing something or disable one logic for a while (for example, during ingame cinematics).
  • More control to the Game Designer, they can test and prototype stuff without asking programming team.
  • Simplified workflow for our ingame cinematics.
  • Compatible with our first version, both can run at the same time.

Cons

  • Merge the stage is harder now that it is serialized with the Unity scene, with code we didn’t have merge problems or at least it was easier to fix. One of the ideas to simplify this is to break the logic in parts and use prefabs for those parts, but it breaks when having links with scene instances (which is a common case).
  • A lot of programming responsibility is transferred to the scripting team which in this case is the Game Design team, that means possibly bad code (for example, duplicated logic), bugs (forget to turn off a trigger after processing the actions) and even performance.

Conclusion

When designing (and coding) a game, it is really important to have a good iteration cycle in each aspect of the game. Having switched to a more visual solution with all the elements at hand and avoiding code as much as we could, helped a lot with that goal.

Since what we end up doing looks similar to a scripting engine, why didn't we go with a solution like uScript or similar in the first place? the real answer is I didn't try in depth other Unity scripting solutions out there (not so happy with that), each time I tried them a bit they gave me the feeling it was too much for what we needed and I was unsure how they perform on mobile devices (never tested that). Also, I wasn't aware we would end up need a scripting layer, so I prefered to evolve over our needs, from small to big.

Taking some time to research other games and play with the SC2 Editor helped me a lot when defining how our engine should work and/or why we should go in some direction. There are more aspects of our game that were influenced in some way by how other RTS games do it, which I may share or not in the future, who knows.

I love RTS games, did I mention that before?

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Using Unity Text to show numbers without garbage generation

The idea of this post is to show different ideas and analysis on how to use Unity UI Text to show numbers without garbage generation. I need this for a framerate counter and other debug values.

Test case

Shows a fixed digit length number in screen, regenerated each frame with a new random value.

Shows how the test scene used for all test cases work.

Using Strings

Since strings are immutable in c#, common operations on strings generates new strings and hence allocates new heap memory. If you are using strings as temporary values like showing a changing number in a UI text then that memory becomes garbage. In PC that garbage could go unnoticed but not in mobile devices since that could derive in a hiccup when the garbage collector decides to collect it.

The idea with these tests is to try to use make the label work with strings without garbage generation. To detect generated garbage I am using the Unity profiler and avoiding ToString() of int, float, etc, to just calculate the cost of the string manipulation for now.

String concatenation

String concatenation generates 30 Bytes per frame since internally String.Concat() calls String.InternallyAllocateStr().

It is not as bad as expected, it is just creating a new string with the length of the first string plus the second and then it copies their values. Obviously it becomes worse when multiple concatenations are done in secuence.

Test code:

Text text;
 
static readonly string[] numbers = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
 
void Start () {
    text = GetComponent<Text> ();
}
 
void Update () {
     
    string a = numbers[UnityEngine.Random.Range(0, numbers.Length)];
    string b = numbers[UnityEngine.Random.Range(0, numbers.Length)];
 
    text.text = a + b;
}

String format

Using string.Format() generates 176 Bytes per frame, internally is using String.FormatHelper + StringBuilder.ToString().  The first one creates a new StringBuilder and the second is the transform from StringBuilder to string.

Test code:

 Text text;
 
 static readonly string[] numbers = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
 
 void Start () {
     text = GetComponent<Text> ();
 }
 
 void Update () {
     string a = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     string b = numbers[UnityEngine.Random.Range(0, numbers.Length)];
 
     text.text = string.Format ("{0}{1}", a, b);        
     
 }

String Builder Format

Using cached StringBuilder improves the previous one a bit, it generates 86 Bytes per frame, the AppendFormat is generating garbage and then the set_Length() (used to clear the StringBuilder).

Test code:

 Text text;
 StringBuilder stringBuilder = new StringBuilder(20, 20);
 
 static readonly string[] numbers = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
 
 void Start () {
     text = GetComponent<Text> ();
     stringBuilder.Length = 3;
 }
 -j
 void Update () {
     string a = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     string b = numbers[UnityEngine.Random.Range(0, numbers.Length)];
 
     stringBuilder.Length = 0;
     stringBuilder.AppendFormat ("{0}{1}", a, b);
 
     text.text = stringBuilder.ToString();
 }

Note: If I change the StringBuilder starting capacity and max capacity, the cost is the same but goes to ToString() method instead, but internally to the same method String.InternallyAllocateStr().

String Builder only Append

Instead of using StringBuilder.AppendFormat, change to use only String.Append. This reduces the cost to only 30 Bytes per frame (the same of the first one), the only cost here is the set_Length() which internally calls String.InternallyAllocateStr().

Test code:

 Text text;
 StringBuilder stringBuilder = new StringBuilder(20, 20);
 
 static readonly string[] numbers = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
 
 void Start () {
     text = GetComponent<Text> ();
     stringBuilder.Length = 3;
 }
 
 void Update () {
     string a = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     string b = numbers[UnityEngine.Random.Range(0, numbers.Length)];
 
     stringBuilder.Length = 0;
     stringBuilder.Append (a);
     stringBuilder.Append (b);
 
     text.text = stringBuilder.ToString();
 }

Note: Does the same behaviour if I change starting and max capacity, the cost is the same but is on ToString() instead of set_Length().

String Builder by replacing chars

If instead of Append I replace chars directly by using [] and avoid the set_Length(), the cost is the same, 30 Bytes per frame, since the String.InternallyAllocateStr() goes to set_Chars().

Test code:

 Text text;
 StringBuilder stringBuilder = new StringBuilder(20, 20);
 
 static readonly char[] numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
 
 void Start () {
     text = GetComponent<Text> ();
     stringBuilder.Length = 3;
 }

 void Update () {
     char a = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     char b = numbers[UnityEngine.Random.Range(0, numbers.Length)];
 
     stringBuilder [0] = a;
     stringBuilder [1] = b;
 
     text.text = stringBuilder.ToString();
 }

Note: Again, does the same behaviour if I change starting and max capacity, instead of set_Chars(), the cost is in ToString() method.

String Builder, access internal string by reflection

There is a suggestion at in this post to access by refleciton to _str field from StringBuilder class to avoid the cost of ToString() method.

Test code:

 Text text;
 StringBuilder stringBuilder = new StringBuilder(20, 20);

 static System.Reflection.FieldInfo _sb_str_info = 
        typeof(StringBuilder).GetField("_str", 
        System.Reflection.BindingFlags.NonPublic | 
        System.Reflection.BindingFlags.Instance);
 
 static readonly char[] numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
 
 void Start () {
     stringBuilder.Length = 3;
 
     text = GetComponent<Text> ();
 }
 
 void Update () {
     stringBuilder[0] = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     stringBuilder[1] = numbers[UnityEngine.Random.Range(0, numbers.Length)];
     stringBuilder[2] = (char) 0;
 
     var internalValue = _sb_str_info.GetValue (stringBuilder) as string;
     text.text = internalValue;
 }

In this case, there is no garbage at all. However, I see no change in the UI Text even though the editor shows the text field value is changing, like it is not being redrawn in screen. I suppose that could be because the string pointer is not changing and by taking a look at the Text code from the Unity UI it is comparing with != instead of Equals... not sure here.

 public virtual string text
 {
     get
     {
         return m_Text;
     }
     set
     {
         if (String.IsNullOrEmpty(value))
         {
             if (String.IsNullOrEmpty(m_Text))
                 return;
             m_Text = "";
             SetVerticesDirty();
         }
         else if (m_Text != value)
         {
             m_Text = value;
             SetVerticesDirty();
             SetLayoutDirty();
         }
     }
 }

I tried by forcing layout and vertices dirty after updating internal string, just in case, but had no luck (sad face).

Caching strings

Another option suggested in this blog post is to precache strings for different numbers but that is only reasonable for a small amount of digits. I like it because it is simple and could be generated at runtime, and works well for debug numbers like FPS where the number is normally between 0 and 60.

I tried it and it works really well and generates 0 Bytes per frame.

Test code:

 Text text;
 
 string[] generated;
 
 // Use this for initialization
 void Start () {
     text = GetComponent<Text> ();
 
     generated = new string[100];
 
     // should go from 0 to 99.
     for (int i = 0; i < 100; i++) {
         generated [i] = string.Format ("{0:00}", i);
     }
 }
 
 // Update is called once per frame
 void Update () {
     int random = UnityEngine.Random.Range (0, generated.Length);
     text.text = generated [random];
 }
 

Rendering numbers directly

One possible way to avoid all this garbage (I mean both the code and the unused memory) is to not use strings at all but to just render to the screen images for each number digit, where each digit is a different sprite.

When making TinyWarriors prototype I did a basic number rendering where I could specify the number of digits and it just created multiple Unity UI Images inside a horizontal layout.

Shows a test using images for each digit instead of a text.

Test code:

 public Image[] numbers;
 
 // in order, like 0, 1, 2, ..., 9
 public Sprite[] numberSprites;
 
 public bool fillZero = true;
 
 void Start()
 {
     SetNumber (0);
 }
 
 public void SetNumber(int number)
 {
     int tens = (number % 100) / 10;
     int ones = (number % 10);
 
     var tensActive = fillZero || tens != 0;
     var onesActive = fillZero || number > 0;
 
     numbers [0].gameObject.SetActive (tensActive);
     numbers [1].gameObject.SetActive (onesActive);
 
     if (tensActive)
         numbers [0].sprite = numberSprites [tens];
 
     if (onesActive)
         numbers [1].sprite = numberSprites [ones];
 }
 
 public void Update()
 {
     int random = UnityEngine.Random.Range (0, 100);
     SetNumber (random);
 }

The code could be adapted to support more digits. When profiling it in editor there is a lot of garbage generation, around 1KB per frame, in Canvas.SendWillRendereCanvases() because it is forcing a material rebuild each time a sprite is changed. However, I tested it on devices and it doesn’t so it must be something related with the Unity editor.

Other strategies

Other strategies include minimizing the garbage generation by reducing the text update frequency, for example, by avoiding updating the text if the number didn't change and/or updating the text from time to time and not every frame.

Conclusion

Since I just wanted a solution for a framerate counter (and other debug numbers) the last solutions are perfect and I believe those could even be extrapolated for other game needs, like showing the player points in an arcade game, with a bit of extra thinking.

References

Here is a list of some articles, forum and blog posts I took a look during the tests and the post writing.

Unity memory optimizations article - https://unity3d.com/es/learn/tutorials/temas/performance-optimization/optimizing-garbage-collection-unity-games

Memory management reference - http://www.memorymanagement.org/

FPS implementation caching strings - http://catlikecoding.com/unity/tutorials/frames-per-second/

Using reflection to set StringBuilder string to avoid garbage - http://www.defectivestudios.com/devblog/garbage-free-string-unity/

FPS Asset - http://blog.codestage.ru/unity-plugins/fps/

Another FPS Asset - https://www.assetstore.unity3d.com/en/#!/content/6513

StringBuilder API - https://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx

Performance tips for Unity for mobile - https://divillysausages.com/2016/01/21/performance-tips-for-unity-2d-mobile/

Unity UI Source code - https://bitbucket.org/Unity-Technologies/ui

Untiy Community Library - https://github.com/UnityCommunity/UnityLibrary

 Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

Guardar

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

A Simple Selection History Window For Unity

This is a small blog post about a Unity editor window we made at work to simplify our lives when using Unity.

In Unity, when you select a reference to an asset, it is focused in the Project window, losing the current selection and probably the folder you were working on. Since there is no navigation history, most of the time having to search the previous selection is a pain in the ass.

As we were doing some stuff today at work, we were inspired (after two million times we lost our selection) so I decided to do a simple Editor Window to store and show a history of selected objects. It took me like 30 minutes to make it (plus one more hour at home).

Here are the results:

In case you are interested in using and/or improving it, here is the github project:

https://github.com/acoppes/unity-history-window

As always, hope you like it.

Guardar

Guardar

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Understanding Unity Networking (Unet)

The objective of this blog post is to give you a first look at Unity Networking (Unet) based on my experience with it, and from my point of view.

Introduction

Unet is the Unity client/server architecture solution for networking, which provides the developer a wide range of options from high level logic like automatically synchronizing game objects state to low level like directly sending bytes through a network connection.

To have a quick understanding of how it normally works, here is a quick example. Imagine there are 3 machines connected, one server and two clients. Each machine is running the same game, that means the same code and the same Scene with same GameObjects. The code has a way to know if it is on a server or a client, and if has authority or not, and take action according to that. For example, for non player objects the server is the one with the authority and for player objects only one client has authority. Since it is a client/server architecture actions are processed on the server and then synchronized back to the clients.

note: I wrote normally because it is not always the case, you can have have objects created only on some clients, or on the server, etc.

Unet

The idea here is to give you a quick look of what I explored so far.

The NetworkManager is Unet point of entrance. It is the way to host or join a game. It is responsible for creating the player object for each client, etc. As a Unity behaviour, it allows configuring the player prefab, start positions, different scenes for being offline or online, or even advanced stuff like configuring connection timeouts, etc.

unity-networkmanager

All Unet network objects must have a NetworkIdentity behaviour, this is the way to identify an object is the same in different machines, used for synchronzation for example.

The NetworkBehaviour is the base class for behaviours that want to know about networking. Subclasses of this class can override easy methods to be aware of networking events, automatically synchronize fields, invoke methods on the server or on the clients, and to know current code has authority over the object or not (since normally all objects are created in each machine). Here is a code sample containing some of these concepts:

 public class NetworkExampleClass : NetworkBehaviour
 {
     [SyncVar]
     public int health;
 
     int maxHealth = 100;
 
     public Color myColor;
 
     public GameObject bombPrefab;
 
     public void Start()
     {
         if (isLocalPlayer) {
             myColor = Color.blue;
         } else {
             myColor = Color.red;
         }
     
         if (isServer) {
             Debug.Log ("Object started on server");
         }
     }
 
     // only want to process this Unity callback on clients (avoid server update)
     [ClientCallback]
     public void Update()
     {
         // don't want to process on the client that is not the object owner, this works only
         // for the player object I believe.
         if (!isLocalPlayer)
             return;
 
         if (Input.GetMouseButtonUp (0)) {
             CmdTakePotion(10);
         }
 
         if (Input.GetMouseButtonUp (1)) {
             CmdSpawnBomb(UnityEngine.Random.insideUnitCircle * 100);
         }
     }
 
     // send command to server to perform authoritative logic
     [Command]
     public void CmdTakePotion(int hitpoints)
     {
         health += hitpoints;
         if (health > maxHealth)
             health = maxHealth;
         RpcShowPotionFeedback (hitpoints);
     }
 
     // send command to clients to perform visual logic
     [ClientRpc]
     public void RpcShowPotionFeedback(int hitpoints)
     {
         CreatePotionFeedback ();
     }
 
     public void CreatePotionFeedback(int hitpoints)
     {
         // TODO: create visual feedback for taking a potion
     }
 
     [Command]
     public void CmdSpawnBomb(Vector2 position)
     {
         GameObject bombObject = GameObject.Instantiate (bombPrefab);
         bombObject.transform.position = position;
 
         // this spawns the object on all clients and syncrhonizes them with server object (identity, etc)
         NetworkServer.Spawn (bombObject);
     }
 
 }

(note: this code may not compile, it wasn't tested)

And here is a quick explanation of the example concepts:

  • isServer: this property lets you know if you are on the server or not.
  • hasAuthority: this property lets you know if you have authority over the game object or not.
  • isLocalPlayer: this property tells you if the gameobject represents the player on the local machine, to avoid for example moving another players gameobjects when processing the input.
  • [SyncVar]: this field annotation it is a way to specify you need a field to be synchronized over the same game object running in each machine (the object identified by the same network id). For example, the health was decreased from 10 to 5 in the server, then all clients must show the change in the health bar.
  • [Command]: this method annotation it is used on methods that want to be invoked from a client to run in the server, their names must start with Cmd prefix. For example, if you want to do damage over a unit you send that to the server since the server is the authority here.
  • [ClientRpc]: this method annotation it is used on methods that want to be invoked from a server to run in all clients, their names must start with Rpc prefix. For example, the server detected some unit died (after it received damage), then it invokes a RpcUnitDeath(), so each client show the unit death animation.
  • Other methods annotations like [ClientCallback] and [ServerCallback] are an easier way to not having to check isServer property in the code, it is used for Unity automatic gameobject callbacks like Update or Start methods.
  • NetworkServer.Spawn(): it is the way to synchronize server creation of objects on clients, that means creating a game object on each client with the same network id.

For automatically synchronizing state there are already some behaviours like the NetworkTransform. These behaviours not only provide an automatic way to synchronize a GameObject common state but, in some cases, also a way to configure interpolation strategies. Here is a picture showing the NetworkTransform configuration:

unity-networktransform

Note: in my tests I couldn’t find a way to make the transform interpolation to look smooth. Even looking at other developers examples, they normally create their own interpolation code to fix that.

Here is a video showing a quick example I did using Unet, there are two clients, the left one is also the server. Each player can control one hexagon by clicking where to move it, the movement logic is performed in each client machine and automatically synchronized using a NetworkTransform.

Conclusion

The Unet high level concepts are a way to get, as fast as possible, a multiplayer game working, and depending the kind of game you are making, it may fit perfectly your needs. The low level access may give you a real control of what is happening behind the scenes in case you need to optimize your game networking usage.

As a developer, being flexible to use from high to low level stuff is always an advantage, and that is a really good point of Unet. Also, even though it wasn’t so easy to understand for me in my first tests, I believe the HLAPI is not hard to use and gives a good start point, and, like other Unity stuff, it is really good for quick prototyping.

Another really good point is that it is open source which means I can take a look at implementation details if I want, or understand how something work behind the scenes, or even propose bug fixes.

The bad part is that the documentation is not good, but that happens for all the Unity stuff, when you need to understand something in detail the documentation says nothing or it is even wrong. Also, the first Unet tutorial results wasn’t what I expected, the movement was really choppy and it didn’t work so well (I believe they updated it, I tried the one for Unity 5.3.x), that was something that made me think about Unet not being the solution I wanted for my games, but in the end it was just a really bad example of Unet features.

Also, if you are making an action game, I don't know if Unet provides good support for client side prediction, server reconciliation or lag compensation but it shouldn't be a problem to implement what you need over Unet since it is very flexible.

Right now I am following another aproach of using low level send messages API since for my game I am trying to reduce the bandwidth cost by sending only player actioons and performing a synchornized simulation, something I will try to write about in a future blog post.

References

Some references in no specific order.

Tutorial videos for making a survival cooperative game

Unet overview

Unity forums - Multiplayer networking

Unity forums - Collection of multiplayer samples

Unity networking source code at Bitbucket

A simple implementation of authoritative movement on top of unet

VN:F [1.9.22_1171]
Rating: 5.0/5 (4 votes cast)