Anda di halaman 1dari 31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

devmag.org.za
A game development magazine

50 Tips for Working with Unity (Best Practices)

About these tips


These tips are not all applicable to every project.
They are based on my experience with projects with small teams from 3 to 20 people.
Theres is a price for structure, re-usability, clarity, and so on team size and project size determine
whether that price should be paid.
Many tips are a matter of taste (there may be rivalling but equally good techniques for any tip
listed here).
Some tips may fly in the face of conventional Unity development. For instance, using prefabs for
specialisation instead of instances is very non-Unity-like, and the price is quite high (many times
more prefabs than without it). Yet I have seen these tips pay off, even if they seem crazy.

Process
1. Avoid branching assets. There should always only ever be one version of any asset. If you absolutely
have to branch a prefab, scene, or mesh, follow a process that makes it very clear which is the right
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

1/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

version. The wrong branch should have a funky name, for example, use a double underscore prefix:
__MainScene_Backup. Branching prefabs requires a specific process to make it safe (see under the section

Prefabs).
2. Each team member should have a second copy of the project checked out for testing if you are
using version control. After changes, this second copy, the clean copy, should be updated and tested. Noone should make any changes to their clean copies. This is especially useful to catch missing assets.
3. Consider using external level tools for level editing. Unity is not the perfect level editor. For
example, we have used TuDee to build levels for a 3D tile-based game, where we could benefit from the
tile-friendly tools (snapping to grid, and multiple-of-90-degrees rotation, 2D view, quick tile selection).
Instantiating prefabs from an XML file is straightforward. See Guerrilla Tool Development for more ideas.
4. Consider saving levels in XML instead of in scenes. This is a wonderful technique:
It makes it unnecessary to re-setup each scene.
It makes loading much faster (if most objects are shared between scenes).
It makes it easier to merge scenes (even with Unitys new text-based scenes there is so much data
in there that merging is often impractical in any case).
It makes it easier to keep track of data across levels.
You can still use Unity as a level editor (although you need not). You will need to write some code to
serialize and deserialize your data, and load a level both in the editor and at runtime, and save levels from
the editor. You may also need to mimic Unitys ID system for maintaining references between objects.
5. Consider writing generic custom inspector code. To write custom inspectors is fairly
straightforward, but Unitys system has many drawbacks:
It does not support taking advantage of inheritance.
It does not let you define inspector components on a field-type level, only a class-type level. For
instance, if every game object has a field of type SomeCoolType, which you want rendered
differently in the inspector, you have to write inspectors for all your classes.
You can address these issues by essentially re-implementing the inspector system. Using a few tricks of
reflection, this is not as hard as it seems, details are provided at the end of the article.

Scene Organisation
6. Use named empty game objects as scene folders. Carefully organise your scenes to make it easy to
find objects.
7. Put maintenance prefabs and folders (empty game objects) at 0 0 0. If a transform is not
specifically used to position an object, it should be at the origin. That way, there is less danger of running
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

2/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

into problems with local and world space, and code is generally simpler.
8. Minimise using offsets for GUI components. Offsets should always be used to layout components
in their parent component only; they should not rely on the positioning of their grandparents. Offsets
should not cancel each other out to display correctly. It is basically to prevent this kind of thing:
Parent container arbitrarily placed at (100, -50). Child, meant to be positioned at (10, 10), then placed at
(90, 60) [relative to parent].
This error is common when the container is invisible, or does not have a visual representation at all.
9. Put your world floor at y = 0. This makes it easier to put objects on the floor, and treat the world as a
2D space (when appropriate) for game logic, AI, and physics.
10. Make the game runnable from every scene. This drastically reduces testing time. To make all
scenes runnable you need to do two things:
First, provide a way to mock up any data that is required from previously loaded scenes if it is not
available.
Second, spawn objects that must persist between scene loads with the following idiom:
myObject = FindMyObjectInScene();
if (myObjet == null)
{
myObject = SpawnMyObject();
}

Art
11. Put character and standing object pivots at the base, not in the centre. This makes it easy to
put characters and objects on the floor precisely. It also makes it easier to work with 3D as if it is 2D for
game logic, AI, and even physics when appropriate.
12. Make all meshes face in the same direction (positive or negative z axis). This applies to meshes
such as characters and other objects that have a concept of facing direction. Many algorithms are
simplified if everything have the same facing direction.
13. Get the scale right from the beginning. Make art so that they can all be imported at a scale factor
of 1, and that their transforms can be scaled 1, 1, 1. Use a reference object (a Unity cube) to make scale
comparisons easy. Choose a world to Unity units ratio suitable for your game, and stick to it.
14. Make a two-poly plane to use for GUI components and manually created particles. Make the plane
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

3/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

face the positive z-axis for easy billboarding and easy GUI building.
15. Make and use test art
Squares labelled for skyboxes.
A grid.
Various flat colours for shader testing: white, black, 50% grey, red, green, blue, magenta, yellow,
cyan.
Gradients for shader testing: black to white, red to green, red to blue, green to blue.
Black and white checkerboard.
Smooth and rugged normal maps.
A lighting rig (as prefab) for quickly setting up test scenes.

Prefabs
16. Use prefabs for everything. The only game objects in your scene that should not be prefabs should
be folders. Even unique objects that are used only once should be prefabs. This makes it easier to make
changes that dont require the scene to change. (An additional benefit is that it makes building sprite
atlases reliable when using EZGUI).
17. Use separate prefabs for specialisation; do not specialise instances. If you have two enemy
types, and they only differ by their properties, make separate prefabs for the properties, and link them in.
This makes it possible to
make changes to each type in one place
make changes without having to change the scene.
If you have too many enemy types, specialisation should still not be made in instances in the editor. One
alternative is to do it procedurally, or using a central file / prefab for all enemies. A single drop down could
be used to differentiate enemies, or an algorithm based on enemy position or player progress.
18. Link prefabs to prefabs; do not link instances to instances. Links to prefabs are maintained
when dropping a prefab into a scene; links to instances are not. Linking to prefabs whenever possible
reduces scene setup, and reduce the need to change scenes.
19. As far as possible, establish links between instances automatically. If you need to link
instances, establish the links programmatically. For example, the player prefab can register itself with the
GameManagerwhen it starts, or the GameManagercan find the Playerprefab instance when it starts.

Dont put meshes at the roots of prefabs if you want to add other scripts. When you make the
prefab from a mesh, first parent the mesh to an empty game object, and make that the root. Put scripts
on the root, not on the mesh node. That way it is much easier to replace the mesh with another mesh
without loosing any values that you set up in the inspector.
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

4/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Use linked prefabs as an alternative to nested prefabs. Unity does not support nested prefabs, and
existing third-party solutions can be dangerous when working in a team because the relationship
between nested prefabs is not obvious.
20. Use safe processes to branch prefabs. The explanation use the Player prefab as an example.
Make a risky change to the Player prefab is as follows:
1. Duplicate the Playerprefab.
2. Rename the duplicate to __Player_Backup.
3. Make changes to the Playerprefab.
4. If everything works, delete __Player_Backup.
Do not name the duplicate Player_New, and make changes to it!
Some situations are more complicated. For example, a certain change may involve two people, and
following the above process may break the working scene for everyone until person two finished. If it is
quick enough, still follow the process above. For changes that take longer, the following process can be
followed:
1. Person 1:
1. Duplicate the Playerprefab.
2. Rename it to __Player_WithNewFeatureor __Player_ForPerson2.
3. Make changes on the duplicate, and commit / give to Person 2.
2. Person 2:
1. Make changes to new prefab.
2. Duplicate Playerprefab, and call it __Player_Backup.
3. Drag an instance of __Player_WithNewFeatureinto the scene.
4. Drag the instance onto the original Playerprefab.
5. If everything works, delete __Player_Backupand __Player_WithNewFeature.

Extensions and MonoBehaviourBase


21. Extend your own base mono behaviour, and derive all your components from it.
This allows you to implement some general functionality, such as type safe Invoke, and more
complicated Invokes (such as random, etc.).
22. Define safe methods for Invoke, StartCoroutine and Instantiate.
Define a delegate Task, and use it to define methods that dont rely on string names. For example:

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

5/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

public void Invoke(Task task, float time)


{
Invoke(task.Method.Name, time);
}

23. Use extensions to work with components that share an interface. It is sometimes convenient
to get components that implement a certain interface, or find objects with such components.
The implementations below uses typeofinstead of the generic versions of these functions. The generic
versions dont work with interfaces, but typeofdoes. The methods below wraps this neatly in generic
methods.
//Defined in the common base class for all mono behaviours
public I GetInterfaceComponent<I>() where I : class
{
return GetComponent(typeof(I)) as I;
}
public static List<I> FindObjectsOfInterface<I>() where I : class
{
MonoBehaviour[] monoBehaviours = FindObjectsOfType<MonoBehaviour>();
List<I> list = new List<I>();
foreach(MonoBehaviour behaviour in monoBehaviours)
{
I component = behaviour.GetComponent(typeof(I)) as I;
if(component != null)
{
list.Add(component);
}
}
return list;
}

24. Use extensions to make syntax more convenient. For example:


public static class CSTransform
{
public static void SetX(this Transform transform, float x)
{
Vector3 newPosition =
new Vector3(x, transform.position.y, transform.position.z);
transform.position = newPosition;
}
...
}

25. Use a defensive GetComponent alternative. Sometimes forcing component dependencies


(through RequiredComponent) can be a pain. For example, it makes it difficult to change components in
the inspector (even if they have the same base type). As an alternative, the following extension of
GameObjectcan be used when a component is required to print out an error message when it is not
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

6/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

found.
public static T GetSafeComponent<T>(this GameObject obj) where T : MonoBehaviour
{
T component = obj.GetComponent<T>();
if(component == null)
{
Debug.LogError("Expected to find component of type "
+ typeof(T) + " but found none", obj);
}
return component;
}

Idioms
26. Avoid using different idioms to do the same thing. In many cases there are more than one
idiomatic way to do things. In such cases, choose one to use throughout the project. Here is why:
Some idioms dont work well together. Using one idiom well forces design in one direction that is
not suitable for another idiom.
Using the same idiom throughout makes it easier for team members to understand what is going
on. It makes structure and code easier to understand. It makes mistakes harder to make.
Examples of idiom groups:
Coroutines vs. state machines.
Nested prefabs vs. linked prefabs vs. God prefabs.
Data separation strategies.
Ways of using sprites for states in 2D games.
Prefab structure.
Spawning strategies.
Ways to locate objects: by type vs. name vs. tag vs. layer vs. reference (links).
Ways to group objects: by type vs. name vs. tag vs. layer vs. arrays of references (links).
Finding groups of objects versus self registration.
Controlling execution order (Using Unitys execution order setup versus yield logic versus Awake /
Start and Update / Late Update reliance versus manual methods versus any-order architecture).
Selecting objects / positions / targets with the mouse in-game: selection manager versus local selfmanagement.
Keeping data between scene changes: through PlayerPrefs, or objects that are not Destroyed when
a new scene is loaded.
Ways of combining (blending, adding and layering) animation.

Time
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

7/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

27. Maintain your own time class to make pausing easier. Wrap Time.DeltaTimeand
Time.TimeSinceLevelLoadto account for pausing and time scale. It requires discipline to use it, but will

make things a lot easier, especially when running things of different clocks (such as interface animations
and game animations).

Spawning Objects
28. Dont let spawned objects clutter your hierarchy when the game runs. Set their parents to a
scene object to make it easier to find stuff when the game is running. You could use a empty game object,
or even a singleton with no behaviour to make it easier to access from code. Call this object
DynamicObjects.

Class Design
29. Use singletons for convenience. The following class will make any class that inherits from it a
singleton automatically:
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
protected static T instance;
/**
Returns the instance of this singleton.
*/
public static T Instance
{
get
{
if(instance == null)
{
instance = (T) FindObjectOfType(typeof(T));
if (instance == null)
{
Debug.LogError("An instance of " + typeof(T) +
" is needed in the scene, but there is none.");
}
}
return instance;
}
}
}

Singletons are useful for managers, such as ParticleManageror AudioManageror GUIManager.


Avoid using singletons for unique instances of prefabs that are not managers (such as the Player).
Not adhering to this principle complicates inheritance hierarchies, and makes certain types of
changes harder. Rather keep references to these in your GameManager(or other suitable God class
)
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

8/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Define static properties and methods for public variables and methods that are used often from
outside the class. This allows you to write GameManager.Playerinstead of
GameManager.Instance.player.

30. For components, never make variables public that should not be tweaked in the inspector.
Otherwise it will be tweaked by a designer, especially if it is not clear what it does. In some rare cases it is
unavoidable. In that case use a two or even four underscores to prefix the variable name to scare away
tweakers:
public float __aVariable;

31. Separate interface from game logic. This is essentially the MVC pattern.
Any input controller should only give commands to the appropriate components to let them know the
controller has been invoked. For example in controller logic, the controller could decide which commands
to give based on the player state. But this is bad (for example, it will lead to duplicate logic if more
controllers are added). Instead, the Player object should be notified of the intent of moving forward, and
then based on the current state (slowed or stunned, for example) set the speed and update the player
facing direction. Controllers should only do things that relate to their own state (the controller does not
change state if the player changes state; therefore, the controller should not know of the player state at
all). Another example is the changing of weapons. The right way to do it is with a method on Player
SwitchWeapon(Weapon newWeapon), which the GUI can call. The GUI should not manipulate transforms

and parents and all that stuff.


Any interface component should only maintain data and do processing related to its own state. For example,
do display a map, the GUI could compute what to display based on the players movements. However,
this is game state data, and does not belong in the GUI. The GUI should merely display game state data,
which should be maintained elsewhere. The map data should be maintained elsewhere (in the
GameManager, for example).

Gameplay objects should know virtually nothing of the GUI. The one exception is the pause behaviour,
which is may be controlled globally through Time.timeScale(which is not a good idea as well see ).
Gameplay objects should know if the game is paused. But that is all. Therefore, no links to GUI
components from gameplay objects.
In general, if you delete all the GUI classes, the game should still compile.
You should also be able to re-implement the GUI and input without needing to write any new game logic.
32. Separate state and bookkeeping. Bookkeeping variables are used for speed or convenience, and
can be recovered from the state. By separating these, you make it easier to
save the game state, and
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

9/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

debug the game state.


One way to do it is to define a SaveDataclass for each game logic class. The
[Serializable]
PlayerSaveData
{
public float health; //public for serialisation, not exposed in inspector
}
Player
{
//... bookkeeping variables
//Dont expose state in inspector. State is not tweakable.
private PlayerSaveData playerSaveData;
}

33. Separate specialisation configuration.


Consider two enemies with identical meshes, but different tweakables (for instance different strengths
and different speeds). There are different ways to separate data. The one here is what I prefer, especially
when objects are spawned, or the game is saved. (Tweakables are not state data, but configuration data,
so it need not be saved. When objects are loaded or spawned, the tweakables are automatically loaded in
separately)
Define a template class for each game logic class. For instance, for Enemy, we also define
EnemyTemplate. All the differentiating tweakables are stored in EnemyTemplate

In the game logic class, define a variable of the template type.


Make an Enemy prefab, and two template prefabs WeakEnemyTemplateand StrongEnemyTemplate.
When loading or spawning objects, set the template variable to the right template.
This method can become quite sophisticated (and sometimes, needlessly complicated, so beware!).
For example, to better make use of generic polymorphism, we may define our classes like this:
public class BaseTemplate
{
...
}
public class ActorTemplate : BaseTemplate
{
...
}
public class Entity<EntityTemplateType> where EntityTemplateType : BaseTemplate
{
EntityTemplateType template;
...
}
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

10/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

public class Actor : Entity <ActorTemplate>


{
...
}

34. Dont use strings for anything other than displayed text. In particular, do not use strings for
identifying objects or prefabs etc. One unfortunate exception is animations, which generally are accessed
with their string names.
35. Avoid using public index-coupled arrays. For instance, do not define an array of weapons, an array
of bullets, and an array of particles , so that your code looks like this:
public void SelectWeapon(int index)
{
currentWeaponIndex = index;
Player.SwitchWeapon(weapons[currentWeapon]);
}
public void Shoot()
{
Fire(bullets[currentWeapon]);
FireParticles(particles[currentWeapon]);
}

The problem for this is not so much in the code, but rather setting it up in the inspector without making
mistakes.
Rather, define a class that encapsulates the three variables, and make an array of that:
[Serializable]
public class Weapon
{
public GameObject prefab;
public ParticleSystem particles;
public Bullet bullet;
}

The code looks neater, but most importantly, it is harder to make mistakes in setting up the data in the
inspector.
36. Avoid using arrays for structure other than sequences. For example, a player may have three
types of attacks. Each uses the current weapon, but generates different bullets and different behaviour.
You may be tempted to dump the three bullets in an array, and then use this kind of logic:
public void FireAttack()
{
/// behaviour
Fire(bullets[0]);
}
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

11/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

public void IceAttack()


{
/// behaviour
Fire(bullets[1]);
}
public void WindAttack()
{
/// behaviour
Fire(bullets[2]);
}

Enums can make things look better in code


public void WindAttack()
{
/// behaviour
Fire(bullets[WeaponType.Wind]);
}

but not in the inspector.


Its better to use separate variables so that the names help show which content to put in. Use a class to
make it neat.
[Serializable]
public class Bullets
{
public Bullet FireBullet;
public Bullet IceBullet;
public Bullet WindBullet;
}

This assumes there is no other Fire, Ice and Wind data.


37. Group data in serializable classes to make things neater in the inspector. Some entities may
have dozens of tweakables. It can become a nightmare to find the right variable in the inspector. To make
things easier, follow these steps:
Define separate classes for groups of variables. Make them public and serializable.
In the primary class, define public variables of each type defined as above.
Do not initialize these variables in Awake or Start; since they are serializable, Unity will take care of
that.
You can specify defaults as before by assigning values in the definition;
This will group variables in collapsible units in the inspector, which is easier to manage.
[Serializable]
public class MovementProperties //Not a MonoBehaviour!
{
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

12/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

public float movementSpeed;


public float turnSpeed = 1; //default provided
}
public class HealthProperties //Not a MonoBehaviour!
{
public float maxHealth;
public float regenerationRate;
}
public class Player : MonoBehaviour
{
public MovementProperties movementProeprties;
public HealthPorperties healthProeprties;
}

Text
38. If you have a lot of story text, put it in a file. Dont put it in fields for editing in the inspector. Make
it easy to change without having to open the Unity editor, and especially without having to save the
scene.
39. If you plan to localise, separate all your strings to one location. There are many ways to do this.
One way is to define a Text class with a public string field for each string, with defaults set to English, for
example. Other languages subclass this and re-initialize the fields with the language equivalents.
More sophisticated techniques (appropriate when the body of text is large and / or the number of
languages is high) will read in a spread sheet and provide logic for selecting the right string based on the
chosen language.

Testing and Debugging


40. Implement a graphical logger to debug physics, animation, and AI. This can make debugging
considerably faster. See here.
41. Implement a HTML logger. In some cases, logging can still be useful. Having logs that are easier to
parse (are colour coded, has multiple views, records screenshots) can make log-debugging much more
pleasant. See here.
42. Implement your own FPS counter. Yup. No one knows what Unitys FPS counter really measures,
but it is not frame rate. Implement your own so that the number can correspond with intuition and
visual inspection.
43. Implement shortcuts for taking screen shots. Many bugs are visual, and are much easier to
report when you can take a picture. The ideal system should maintain a counter in PlayerPrefsso that
successive screenshots are not overwritten. The screenshots should be saved outside the project folder
to avoid people from accidentally committing them to the repository.
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

13/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

44. Implement shortcuts for printing the players world position. This makes it easy to report the
position of bugs that occur in specific places in the world, which in turns makes it easier to debug.
45. Implement debug options for making testing easier. Some examples:
Unlock all items.
Disable enemies.
Disable GUI.
Make player invincible.
Disable all gameplay.
46. For teams that are small enough, make a prefab for each team member with debug options.
Put a user identifier in a file that is not committed, and is read when the game is run. This why:
Team members do not commit their debug options by accident and affect everyone.
Changing debug options dont change the scene.
47. Maintain a scene with all gameplay elements. For instance, a scene with all enemies, all objects
you can interact with, etc. This makes it easy to test functionality without having to play too long.
48. Define constants for debug shortcut keys, and keep them in one place. Debug keys are not
normally (or conveniently) processed in a single location like the rest of the game input. To avoid shortcut
key collisions, define constants in a central place. An alternative is to process all keys in one place
regardless of whether it is a debug function or not. (The downside is that this class may need extra
references to objects just for this).

Documentation
49. Document your setup. Most documentation should be in the code, but certain things should be
documented outside code. Making designers sift through code for setup is time-wasting. Documented
setups improved efficiency (if the documents are current).
Document the following:
Layer uses (for collision, culling, and raycasting essentially, what should be in what layer).
Tag uses.
GUI depths for layers (what should display over what).
Scene setup.
Idiom preferences.
Prefab structure.
Animation layers.

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

14/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Naming Standard and Folder Structure


50. Follow a documented naming convention and folder structure. Consistent naming and folder
structure makes it easier to find things, and to figure out what things are.
You will most probably want to create your own naming convention and folder structure. Here is one as
an example.

Naming General Principles


1. Call a thing what it is. A bird should be called Bird.
2. Choose names that can be pronounced and remembered. If you make a Mayan game, do not
name your level QuetzalcoatisReturn.
3. Be consistent. When you choose a name, stick to it.
4. Use Pascal case, like this: ComplicatedVerySpecificObject. Do not use spaces, underscores, or
hyphens, with one exception (see Naming Different Aspects of the Same Thing).
5. Do not use version numbers, or words to indicate their progress (WIP, final).
6. Do not use abbreviations: DVamp@W should be DarkVampire@Walk.
7. Use the terminology in the design document: if the document calls the die animation Die, then use
DarkVampire@Die, not DarkVampire@Death.
8. Keep the most specific descriptor on the left: DarkVampire, not VampireDark; PauseButton, not
ButtonPaused. It is, for instance, easier to find the pause button in the inspector if not all buttons
start with the word Button. [Many people prefer it the other way around, because that makes
grouping more obvious visually. Names are not for grouping though, folders are. Names are to
distinguish objects of the same type so that they can be located reliably and fast.]
9. Some names form a sequence. Use numbers in these names, for example, PathNode0, PathNode1.
Always start with 0, not 1.
10. Do not use numbers for things that dont form a sequence. For example, Bird0, Bird1, Bird2 should
be Flamingo, Eagle, Swallow.
11. Prefix temporary objects with a double underscore __Player_Backup.

Naming Different Aspects of the Same Thing


Use underscores between the core name, and the thing that describes the aspect. For instance:
GUI buttons states EnterButton_Active, EnterButton_Inactive
Textures DarkVampire_Diffuse, DarkVampire_Normalmap
Skybox JungleSky_Top, JungleSky_North
LOD Groups DarkVampire_LOD0, DarkVampire_LOD1
Do not use this convention just to distinguish between different types of items, for instance Rock_Small,
Rock_Large should be SmallRock, LargeRock.
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

15/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Structure
The organisation of your scenes, project folder, and script folder should follow a similar pattern.

Folder Structure

Materials
GUI
Effects
Meshes
Actors
DarkVampire
LightVampire
...
Structures
Buildings
...
Props
Plants
...
...
Plugins
Prefabs
Actors
Items
...
Resources
Actors
Items
...
Scenes
GUI
Levels
TestScenes
Scripts
Textures
GUI
Effects
...

Scene Structure

Cameras
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

16/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Dynamic Objects
Gameplay
Actors
Items
...
GUI
HUD
PauseMenu
...
Management
Lights
World
Ground
Props
Structure
...

Scripts Folder Structure

ThirdParty
...
MyGenericScripts
Debug
Extensions
Framework
Graphics
IO
Math
...
MyGameScripts
Debug
Gameplay
Actors
Items
...
Framework
Graphics
GUI
...

How to Re-implement Inspector Drawing


1. Define a base class for all your editors
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

17/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

BaseEditor<T> : Editor
where T : MonoBehaviour
{
override public void OnInspectorGUI()
{
T data = (T) target;
GUIContent label = new GUIContent();
label.text = "Properties"; //
DrawDefaultInspectors(label, data);
if(GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
}

2. Use reflection and recursion to do draw components


public static void DrawDefaultInspectors<T>(GUIContent label, T target)
where T : new()
{
EditorGUILayout.Separator();
Type type = typeof(T);
FieldInfo[] fields = type.GetFields();
EditorGUI.indentLevel++;
foreach(FieldInfo field in fields)
{
if(field.IsPublic)
{
if(field.FieldType == typeof(int))
{
field.SetValue(target, EditorGUILayout.IntField(
MakeLabel(field), (int) field.GetValue(target)));
}
else if(field.FieldType == typeof(float))
{
field.SetValue(target, EditorGUILayout.FloatField(
MakeLabel(field), (float) field.GetValue(target)));
}
///etc. for other primitive types
else if(field.FieldType.IsClass)
{
Type[] parmTypes = new Type[]{ field.FieldType};
string methodName = "DrawDefaultInspectors";
MethodInfo drawMethod =
typeof(CSEditorGUILayout).GetMethod(methodName);
if(drawMethod == null)
{
Debug.LogError("No method found: " + methodName);
}
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

18/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

bool foldOut = true;


drawMethod.MakeGenericMethod(parmTypes).Invoke(null,
new object[]
{
MakeLabel(field),
field.GetValue(target)
});
}
else
{
Debug.LogError(
"DrawDefaultInspectors does not support fields of type " +
field.FieldType);
}
}
}
EditorGUI.indentLevel--;
}

The above method uses the following helper:


private static GUIContent MakeLabel(FieldInfo field)
{
GUIContent guiContent = new GUIContent();
guiContent.text = field.Name.SplitCamelCase();
object[] descriptions =
field.GetCustomAttributes(typeof(DescriptionAttribute), true);
if(descriptions.Length > 0)
{
//just use the first one.
guiContent.tooltip =
(descriptions[0] as DescriptionAttribute).Description;
}
return guiContent;
}

Note that it uses an annotation in your class code to generate a tooltip in the inspector.

3. Define new Custom Editors


Unfortunately, you will still need to define a class for each MonoBehaviour. Fortunately, these definitions
can be empty; all the actual work is done by the base class.
[CustomEditor(typeof(MyClass))]
public class MyClassEditor : BaseEditor<MyClass>
{}

In theory this step can be automated, but I have not tried it.

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

19/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Tw eet

Me gusta

343

537
130

No related posts.
This entry was posted in Development and tagged best practices, unity on 12 July 2012
[http://devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/] by Herman Tulleken.

About Herman Tulleken


Herman Tulleken is a freelance game developer and a toolmaker. He sees computers as a necesary evil to
make cool games, and likes to torture the bitbrains with cool tools. He really wants to run the world, but
for now, the only thing he runs is this site. [Articles]
View all posts by Herman Tulleken

76 comments

Leave a message...
Best

Share

Community
David Goemans

2 months ago

Great list!
Just a pointer for #30:
If you have public variables, but don't want them accessible in the inspector, you can
add [HideInInspector] ( C# ) or @HideInInspector (JS) before the declaration.
Conversely, if you want variables to be set in the inspector, but invisible in public scope,
you can add [SerializeField] (C#) or @SerializeField.
5

Tim

Reply

Share

a year ago

This is probably the best Unity "tips" article I've ever read. Very informative! I came up
with a few questions while I was reading and was wondering if Herman, or any one else
had any comments/answers to my questions.
#4 - Any example projects, code examples, or direction on how to acheive this?
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

20/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

#26 - "Coroutines vs. state machines." Are you saying use Coroutines or State
Machines, but not both? Or, Deciding if you are going to create state machines through
the use of coroutines or if you are going to create state machines by some other
method?
In addition to #26. I'm really struggling trying to decide how I want manage state. I've
seen several good FSMs and then there are some who say don't both, just use
coroutines. Then I've seen a hybrid of both. Any thoughts/tips on this, or examples of
how you manage state on an object?
#27 I understand what you are trying to achieve and why, but I don't understand how
you are explaining to do it. Could I get a short example of how you are wrapping
Time.DeltaTime and Time.SinceLevelLoad?
#34 says "Dont use strings for anything other than displayed text". Do you not use
Tags at all? Aren't strings the only way to reference tags/layers through code?
Any feedback is greatly appreciated, Thanks!
3

Reply

Share

Herman Tullek en

> Tim

a year ago

Thanks Tim!
About #4. It's quite a big chunk of code. I will see and post some if it at some
stage. The basic idea is to split off data that needs to be saved into Serializable
classes, implement a common interface for Savable classes (that includes presaving and post-loading logic, for example, to copy transforms), then implement
methods that serialize and deserialize lists of your Savable objects [and do the
stuff necessary to link this data up to the actual game objects] (including
instantiating assets from Resources), and a method to clear Savables from the
scene. The save and load needs to work both run time and edit time. It is easier
to start getting things work runtime, and then specialize behaviour for edit time
(so reducing the risk of stuffing up scenes).
All in all, not worth it if your levels are simple, and you only have a few. It also
requires very clear thinking, otherwise everything can become real messy.
#26. Yes, deciding to use co-routines for states, vs a nice wrapped solution. We
use light weight state machines that transition on command; each object
maintains it's own. The main reason not to mix these (or other idioms on the
1


Tim

see more

Reply

Share

> Herman Tulleken

a year ago

Thanks for all the great information! You said " We use light weight state
machines that transition on command" could you give a quick snippet of
how your state machines work? Since there are endless ways to do
state machines I would like to see one that someone has/is using within
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

21/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Unity. Thanks again for all the great information.


B arrie Treloar

Reply

Share

4 months ago

Can you elaborate on point "34. Dont use strings for anything other than displayed text."
What should use for identifying objects?
2

Reply

Share

> Barrie Treloar

weez z

2 months ago

.Net strings allocate memory each time you instance them or modify them

Reply

Iowas k a

> Barrie Treloar

Share

2 months ago

I like to use GUIDs


B runo

Reply

Share

3 months ago

Tip number 30:


[System.NonSerialized]
public float __aVariable;
this makes the variable not to appear on the editor even if it is public.
1

A mir A biri

Reply

Share

8 months ago

RE 46 - you can use PlayerPrefs with a custom inspector on a dummy


ScriptableObject. That way debug settings are stored in user data (registry / user home
dir) and there is no need to have multiple or user-named objects and mess around with
Subversion ignores for those objects.
1

Reply

Chris A my ot

Share

10 months ago

First of all - thank you for this GREAT article. I've been using the pattern you've
described in #'s 32 and 37, using serializable non-monobehavior classes to
encapsulate groups of variables. I'm relatively new to C#, so you kind of blew my mind
there.
While using this technique in Unity, I came to a stumbling block - copy/pasting the code
from either of those examples provided the error:
"Assets/Scripts/TestClass.cs(9,2): error CS0246: The type or namespace name
`Serializable' could not be found. Are you missing a using directive or an assembly
reference?"
The fix I found for this is to use [System.Serializable] instead of [Serializable] - not sure
if there's a better way of doing this..?
Also - it's worth noting that you must include the [System.Serializable] attribute above

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

22/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Also - it's worth noting that you must include the [System.Serializable] attribute above
any class declaration that you want to show up in your inspector.
Thanks again Herman - this is exactly the kind of resource I'd been looking for!
1

Reply

Share

Chris A my ot

> Chris Amyot

10 months ago

Actually - just realized that if I included "using System;" at the top of my CS file I
could use [Serializable] instead of [System.Serializable]. It seems to me (as a
newcomer to C#), that including the System namespace in your classes would
bring in a lot of unnecessary functionality.. Is this not the case? Is the compiler
smart enough to include only the required functionality from that namespace?
3

Reply

Share

A mir A biri

> Chris Amyot

8 months ago

There is absolutely no penalty for including a namespace, it's just not


how the C# language works. The using directive only helps the compiler
resolve type names that appear in the code file, nothing more. It's just a
way to narrow down the search and avoid ambiguity.
During compilation, these references to other types are resolved and
enter in their fully qualified form into the resulting bytecode. From there
on the using directive is meaningless. The only thing that matters is
which assemblies the compiled code needs to pull in or reference.
In that respect there is no difference between "using System" or
"System.Serializable", in both cases the code requires a reference to the
assembly that contains the System.Serializable class, irrespective of
what else the using directives may contain.


Farrell

Reply

Share

14 days ago

This is awesome. I'm a veteran game developer, but new to Unity. There were some
really nice tips.


am

Reply

Share

25 days ago

Could you provide an example for point 31? I think there is some tight coupling in Unity
that makes modifying state of an object update it on screen automatically. Especially
when using physics. In your example where you modify the player velocity, if you do that
on a rigidbody in unity you'll move the object. Or do you mean that you should have:
controller - code which calls something like Input.GetAxis and then calls a method on
the model/game logic. i.e. like Move(Vector3 inputDirection).
model/game logic - updates the player direction and velocity in the model class, but
doesn't touch the rigidBody or anything to actually move it. Then using some sort of
event manager possibly send out a notification message for this?
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

23/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

view/interface : Looks up the new velocity from the model code and just modifies the
physics velocity on the rigid body. Also may change the direction sprite or rotation of the
3d model?
Would you typically make this in one monobehavior script? Or multiple?
There is a logical order that things must happen.
Get the input - A MonoBehaviour class which gets the input
see more

Reply

elB logDeP ier

Share

a month ago

Write a book godammit! All Unity books are for beginners...

Reply

Share

S amuel A s her Rivello

2 months ago

FANTASTIC Overview. So when we open a new project and import any Unity
Technologies package and the only folder organization enforced is an 'Assets' folder
with a subfolder of 'Standard Assets'. What about our custom assets?
Here is the SOLUTION. What Unity Folder Structure Do you Use? - http://bit.ly/1b7cLyq
-Sam!


t hak k

Reply

Share

3 months ago

VampireDark is better than DarkVampire. I want all my VampireX mobs to appear


together, not spread all over the goddamn list.

Reply

Share

Mario A z evedo

> thakk

2 months ago

As he said, you should use a folder for that.

Reply

Share

Charles InCharge

> Mario Azevedo

2 months ago

It is more of a problem when debugging in the scene view. Lets say you
put all your spawns in a spawns folder so you don't clutter the hierarchy.
If you call them "DarkVampire" and "MrVampire", then your vampires are
going to be all over the list. You could add a logic code to your spawning
code though and have it create the empty game object folders at run
time. That way your scene view would have "Spawns\Vampires\
[Dark,Mr]". You could then put all that in an #if UNITY_EDITOR block so
your performance isn't even remotely hit.
1

Reply

devmag

Share

Mod

> CharlesInCharge

a month ago

I normally use empty game objects liberally to organise my


devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

24/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

I normally use empty game objects liberally to organise my


scene as well. I would typically root all my vampires to a game
object (named Vampires) if I find it's a problem. And of course
the search box is very handy for finding vampires (however they
are named). So yes, the rule works well in my workflow and
structure. If it does not for you, ditch it :)


A milia Jones

Reply

Share

3 months ago

This article is great, but the part I was most excited about is the part with which I'm
having the most difficulty. The code in "How to Re-implement Inspector Drawing" looks
great, but I'm not sure how to actually set this up in a cs file. I've tried, but I get many
errors no matter what I seem to do.


Flavio

Reply

Share

3 months ago

Very useful article! thanks for that!

Reply

Share

4 months ago

Bookmarked so hard. I am completely new to Unity but far from new in Game
development in general. This is just the type of guide I needed to get started. Thank you
so very much!
If I had a suggestion for an improvement I would recommend putting in a single
sentence for all the folders in the folder structure detailing what they contain. But I bet
it's obvious if you have been using Unity for any period of time.


c aue

Reply

Share

4 months ago

I'm not sure I follow what you mean on steps 1, 2 and 30.
1. By "branch" you mean just having an asset backup copy outside of the repository? If
so, I completely agree - this should never be done.
2. By second copy, you basically mean having the whole project with its compiled
library at hand? That makes a lot of sense, but then why not also enforcing the
repository usage on the rule? I don't see why that's not included.
30. Why not simply using [System.NonSerialized] to hide public parameters from the
inspector?
Additionally, I'd advice using POedit for dealing with text languages, on the tip #39:
http://wiki.unity3d.com/index....
Fucking awesome list, by the way. Kinda sad it's good being that big... Hope Unity can
"fix" most of it soon enough, though I couldn't bother taking note of how many here are
things Unity could "fix". :-)

Reply

Share

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

25/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Reply

Share

devmag

Mod

> caue

a month ago

1. By branch I mean making any duplicate that is not the *actual working* one
(not made through a formal version controlled branching process). This occurs
frequently when programmers or artists work on complicated prefabs or
gameObjects and are scared that they will break something. Although notbreaking-anything is a noble pursuit, the wrong version almost *always* come
and confuse the hell out of somebody, wasting many hours.
2. Yup, that is what I mean. On some projects version control is not used, in
which case the rule does not apply. (I don't recommend going without version
control of course).
30. Yes, the "on a rare occasion" part of that rule is really rare (I have not had
the need for it for over a year now). I like the extremely ugly name for something
that is also extremely ugly in itself. For me, a public variable _means_ it is a
tweakable. So if I am not in the class, I treat it as something that should not be
modified. The double underscore signifies something fishy is going on, and puts
the programmer on alert. Of course, if for you public means public in the
traditional sense, then simply using the annotation is perfectly fine. In either
event, it really should be very rare, and is in itself not so important compared to
the main part of the rule.
39. Thanks for the suggestion. I admit the solution I give is a bit poor-man-style.
Thanks for the feedback; it's very interesting to hear other's take on these
points.
1

Reply

c aue

Share

> devmag

a month ago

Thank you for the post! I'm trying to apply several of the rules here and
the prefabbing scene one helped a great deal already, for merging
scenes.
I just think you should enforce way more the "use version control" idea.
Even for 1 person minor projects free unity, just never go without a VCS.
I see both rules #1 and #2 exist because people aren't using it or are
using it poorly.

Reply
devmag

Share
Mod

> caue

a month ago

Yes I agree. Especially rule #1 is broken most often because of


lack in faith in the versioning system, or lack in faith in his/her
own capabilities to use it. Rule #2 is similarly to compensate for
poor commitment practices.


>

Reply

Mat t S c hoen
caue a month
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

Share
ago
26/31

19/08/13

Mat t S c hoen

50 Tips for Working with Unity (Best Practices) | devmag.org.za


a month ago

> caue

We've actually just created a tool for this purpose and released it on the Asset
Store. Check it out:
https://www.assetstore.unity3d...

Reply
c aue

Share

> Matt Schoen

a month ago

That sounds unreal! And seems like it even works with git!
I hate the Asset Server, and I advice no one to ever use it (in its current
form anyway). It's basically older than svn in terms of version control.
Just saying that because you do mention it twice on the documentation,
and seems like there is an issue with scene missing references and ID
mismatches in which you say AssetServer might be needed... No idea
what you meant there, but that might be because I haven't tried your tool.
The way I see it, a missing reference is missing. There's nothind to be
done there. Just report it's missing.


Rohit

Reply

Share

4 months ago

I found your tips very interesting. I have a problem. I made an object in Maya and
imported it into unity but the movement speed on device while testing is very slow. Can
you please tell me that whether is it fault with some maya fbx file or in Unity? I spent 2
days on this and reached nowhere. Please help. (Maya file is an office view)

Reply

Thomas

Share

5 months ago

Hey all,
I'm not able to recreate the steps from "How to Re-implement Inspector Drawing" into
final cs files. Could someone share that final or near work?
Thanks for this article !
Bye

Reply

Share

Mat t S c hoen

> Thomas

a month ago

This is a bit of a complicated answer (which I won't go into too deeply), but you
should look into SerializedProperty. Once you get a hang of the iterator pattern,
it makes re-creating the inspector a breeze!


W hit ebread

Reply

Share

5 months ago

I know this is a bit old at this point, but I had a question in regards to the MakeLabel
function. I am getting an error on field.Name.SplitCamelCase() saying that string does
not contain a definition for it. Is this defined somewhere else?
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

27/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

not contain a definition for it. Is this defined somewhere else?


Jac ob

Reply

Share

7 months ago

Just want to say thanks for this great article! so - thanks! :)

Reply

t hallippoli

Share

8 months ago

Thank you for this wonderful collection - it's a great reference!


About Item #29,
public class Singleton<t> : MonoBehaviour where T : MonoBehaviour
wouldn't this line work equally well as
public class Singleton< T > : MonoBehaviour where T : class
I'm trying to understand why you used "where T : MonoBehaviour"
because in my mind that looks redundant - as I understand, the expected usage would
be like this
public class World : Singleton< World >
Your code does work without any hitches though :)</t>

Reply

Share

devmag

Mod

> thallippoli

8 months ago

If you specify "where T : Monobehaviour", you can take advantage of


Monobehavior methods in your singleton class if you needed to add more
functionality.
If you use your specification, this for example, would be illegal:
if(instance == null)
{
instance = (T) FindObjectOfType(typeof(T));
instance.transform.position = Vector3.zeo; //would be illegal
if (instance == null)
{
Debug.LogError("An instance of " + typeof(T) +
" is needed in the scene, but there is none.");
}
}

Reply

t hallippoli

Share

> devmag

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

8 months ago
28/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Got it, thanks!


s hac har Oz

Reply

Share

9 months ago

excellent.
our team at Omek has learned not a few out of the 50 you wrote, so these tips are fully
supported by us too.

Reply

s hinriy o

Share

11 months ago

Hi. I have just a question.


How do you use Singleton class?
I think it can't attach to GameObject. it must be instance and assign some object to this
Instance property?
Singleton<monobehaviour> singleton = new Singleton<monobehaviour>();
singleton.Instance = hogeObject;</monobehaviour></monobehaviour>

Reply
c aue

Share

> shinriyo

2 months ago

As reference for one way this could be done, and while not sure if this would be
a best practice, I've changed the singleton implementation for myself so we
don't need to manually attach it to an object (same way as DebugConsole
works). Here's just the part changed:
if (_instance == null)
{
GameObject singleton = new GameObject();
singleton.AddComponent<t>();
singleton.name = "(singleton) "+ typeof(T).ToString();
DontDestroyOnLoad(singleton);
_instance = FindObjectOfType( typeof(T) ) as T;
Debug.Log("[Singleton] An instance of " + typeof(T) +
" is needed in the scene, so '" + singleton +
"' was created.");
}
</t>


s hinriy o

Reply

Share

> shinriyo

11 months ago

Ah..I see. If we attach Component to someobject. it automatically works, doesn't


it?

Reply

Share

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

29/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

s hinriy o

11 months ago

The source code of #23


I guess it can't be compiled. Because it return object type.
MonoBehaviour[] monoBehaviours = FindObjectsOfType<monobehaviour>();
I fixed below and it can be compiled.
MonoBehaviour[] monoBehaviours = FindObjectsOfType(typeof(MonoBehaviour)) as
MonoBehaviour[];
</monobehaviour>

Reply

Tim A idley

Share

11 months ago

Re #30, is there any reason why you wouldn't just use [HideInInspector] to prevent
someone playing with a public member variable?

Reply

Share

Jonat han Mac A lpine

11 months ago

I've been trying to sort out the rewriting-custom-inspector jazz, but I can't make heads
of tails of it. When I try to enter the code as-is, much of it won't compile (for example,
due to the SplitCamelCase method present). Do the three methods listed here belong
under one common class (BaseEditor)?
I'm fairly new to Unity and to C# in general, and I can't sort it out! :(

Reply

Share

Jonat han Mac A lpine

11 months ago

What are your thoughts on how Unity mingles assets and folders together in the Project
view? Do you think it's worthwhile to set up the folder hierarchy in such a way that there
are only ever folders *or* assets within a folder?

Reply

Share

Herman Tullek en

> Jonathan MacAlpine

11 months ago

Yes, it is annoying. I do think it is a good idea to set it up as you describe.


Looking at our projects, I see we have not done it religiously, but is almost a
natural consequence of just keeping things neat.


A dam Reed

Reply

Share

a year ago

Thanks for the tips especially the ones on the custom editor. I have one concern
though: I noticed that you did not use SerializedObject for your editor, is there a reason?
I have been planning on building a Editor base class that used reflection and the
SerializedPropertys to allow the flexibility I want and also the benefits from using
SerializedObject (prefab override, undo, multi editing etc) but I wonder if there is
somethingthat I am not aware of that made you decide not to in your example.
Thanks again for the wonderful tips.
devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

30/31

19/08/13

50 Tips for Working with Unity (Best Practices) | devmag.org.za

Thanks again for the wonderful tips.

Reply

Share

Herman Tullek en

> Adam Reed

a year ago

There is a reason, although not a very good one. I could not get it to work, or it
did not work as expected (or I wanted it to work). I started using it, but gave up at
some point. It would be nice if you can get it to work to post an example
somewhere.


Henning

Reply

Share

a year ago

Thank you SO much! As I'm new to Unity (12 days) and just putting the final tuchses on
my first Unity game. It's really nice to find some good solid guidelines/best practices.
Now I have a better grasp of what to do different for my next game, to make the
process a lot easier.
What is you input on GUI design.. After testing my game in different resolutions and
aspect ratios, I'm getting a serious urge to make all menus using Text Meshs instead of
using UnityGUI/Skin placement hell.
Thanks again.

Reply

Share

Herman Tullek en

> Henning

a year ago

A GUI is one of the few things that is almost in every game; I can't understand
why better systems has not been available for much longer. (At least the GUI
system in Unity 4 looks great).
We always use EZGUI, because Unity's build-in GUI framework is so slow (on
mobile it makes a huge difference). It has it's own sets of problems, but I think
overall it's a powerful system.

Reply

Share

Load more comments

C o m m e n t fe e d

Su b s cri b e vi a e m a i l

devmag.org.za/2012/07/12/50-tips-for-working-with-unity-best-practices/

31/31

Anda mungkin juga menyukai