Unity Tips

Sunday, June 14, 2015

Here's a few generic programming things we use in Unity to make our lives easier. These might be useful to other people.

Singleton Component

GameManager, SteamClient, yadda yadda. You probably have a component somewhere where you only want one of them and you probably want to get access to it from everywhere for some reason. So we added SingletonComponent.
public class MainCamera : SingletonComponent { public void DoStuff() { } public static Vector3 position { get { return Instance.transform.position; } } }
Now you can access the component via MainCamera.Instance
MainCamera.Instance.DoStuff()
Source here.

List Component

You probably have a bunch of components that you want to keep a constantly updated list of too. Maybe all your enemies, or maybe all your bullets.
public class EnemyBullet : ListComponent { public void Explode() { } }
You can access the list via EnemyBullet.InstanceList (be aware of destroying while iterating etc)
foreach ( var bullet in EnemyBullet.InstanceList ) { bullet.Explode(); }
Source Here.

Interfaces

Components can implement interfaces and now Interfaces can be grabbed using the GetComponent methods. We use this in Rust to tag components with functionality and to mark them as cullable on the client/server (which means our build system will remove that component from all prefabs when targeting specific platforms).
public interface INeedsToStartDisabled { } public interface IEditorComponent { } public interface IServerComponent { } public interface IClientComponent { } public interface IServerComponentEx { void PreServerComponentCull( IPrefabProcessor p ); } public interface IClientComponentEx { void PreClientComponentCull( IPrefabProcessor p ); }
public class Decal : MonoBehaviour, IClientComponent {

Extensions

Not many people know that you can add extended class functionality in c#.
using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Linq; namespace UnityEngine { public static class TransformEx { public static string Log( this Transform transform, string strText ) { Debug.Log( transform.name + ": " + strText ); } } }
This lets you do
transform.Log( "Testing testing" );
More info.

Prefab Attribute

In Rust we have a problem with memory usage because of the pure number of GameObjects we have. We noticed early on that the more components the more memory. It's also pretty common that when you have a component it's usually identical and unchanged on every prefab, being used only to hold variables that go unchanged. So we added prefab attributes. These are like regular components except they get removed before the prefab is spawned. Our doorway prefab looks like this: But everything selected here is an attribute In this example, the sockets relate to the building system. They are snap points, they define where this building piece can attach to, and where other pieces can attach to it. Each socket has rules, more gameobjects, more components. All of which are static, they hold no variables specific to an in-game object. So we delete them all on the first spawn of the prefab but keep them all around. Even though they're deleted we can still access the functions and the variables. We store their local positions and rotations and can then transform them to the real in-game objects to be able to run tests etc based on their in-game locations. This all means that when 5,000 doorway entities are spawned on a server, we're spawning ~20,000 components instead of 300,000+
Turn your phone to view blog list