Alpha Accesswebsite_badges_steamwishlistwebsite_badges_steamwishlist

Archive

Trello: simple task management for a tiny team


I just wanted to write a quick post about a very useful, indispensable, task management tool – especially for small teams: Trello. On the surface, it appears to be a simple todo list, but it’s very open-ended and fun to use, and has terrific mobile apps to boot!

Some of the completed todos on Hawken during crunch

Some of the completed todos on Hawken during crunch

When I worked on Hawken at Adhesive Games, we used some more robust and deeper tools out of necessity. The team grew quite large over time, which required our task management system (Atlassian JIRA) to be tightly integrated with our source control system (Perforce). However there were many periods of intense crunch, and for some of the strictly bug-squashing weeks we needed to be more agile and moved to a quick system of using post-it notes on a big wall. There is a real visceral sense of accomplishment when you grab a note and move it to the “done” stack, and it’s easier to see the massive progress from the team as a whole – a great morale booster. Trello mirrors this approach, and that’s why it’s so satisfying. As a fun fact: the Hawken team started out using Trello when we were only about 9 people or so.

As Sombr is an extremely small (as small as it gets) studio, I like to organize my Trello boards as such:

Trello Boards

  • Company Tasks (business items, marketing, legal, registrations, etc)
  • Game Dev (engineering tasks and bugs for the project)
  • Game Ideas (any feature ideas still in consideration before going to implementation)
  • Game Assets (todos for asset production such as audio and graphics)
  • Game Tools (todos for in-house tool development and tool bugs)

Check it out for your own project. It’s free to use, with paid plans for larger needs, so there’s no risk in seeing if it accommodates your team’s workflow.

Object pooling for performance in Unity


objectPoolExample64

Object pooling is a technique that you’re bound to need at some point in your game dev career. In fact, you may even be using some form of it (or your game engine might) without realizing it. In a nutshell, it is equivalent to caching. Rather than instantiating objects at runtime as you need them, you should instantiate everything you will need (or estimate you will need) beforehand, and pull from this “pool” when you need them. Instead of destroying objects when they are “dead,” you simply disable them and put them back into the pool.

The classic example in games are bullets: rather than instantiating a new bullet every time characters fire their weapons, and then destroying them when off screen or hitting another character, you simply disable them and move them off screen, then enable and move them back on screen as needed. Obviously, it doesn’t just apply to bullets, so keep an eye out for anything in your game that is instantiated frequently. The most common cases are projectiles and effects, such as explosions, dust, debris, etc, however you could even go as far as using it for common shared UI components for the ultimate in snappy performance.

The benefits to object pooling are: fewer game hiccups and lag due to expensive instantiation and destruction, and better estimation of memory needs up front since pooled objects are always loaded. If you have a lot of objects, you will definitely notice and feel these improvements right away. The only downside is from the developer’s perspective: it requires more attention to initialization of variables in objects as they are enabled and disabled, rather than created and destroyed. In Unity, this means you should handle this logic in OnEnable() and OnDisable() in game objects. Similarly, rather than creating and destroying, you are enabling and disabling the pooled objects.

There are many object pooling scripts in the Asset Store, but it’s easy enough to create your own if you understand the concept. As with all in-house solutions, you can tailor it slightly to better fit your exact needs when crafting your own. I’m including the full script here in case you’d like to use it in your own projects (or improve upon it). Some notes about my implementation:

  • The ObjectPool.cs script is attached to an empty game object in the scene.
  • It’s developed as a singleton, so it has a static reference: ObjectPool.shared
  • It’s designed to store any number of pooled object types, with each containing a game object, the amount to start in the pool, and whether or not the amount can dynamically grow or not. You set these up simply on the game object (see the screenshot example below).
  • To facilitate storing anything, the main data structure is a Dictionary full of Lists, with the keys of the dictionary being the names of the prefabs / game objects to be stored.
  • GetPooledObject() returns a regular instantiated prefab if there is no associated pool, so it’s safe to call from scripts that don’t know if there’s a pool or not.

objectPool

Note: This hasn’t really been stress tested too much, but so far it seems to be working great. I’m not sure if making it too flexible (a Dictionary of Lists) is actually more expensive than instantiating and destroying, thus defeating the purpose, but I imagine it isn’t and I’ll run some tests later.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class PooledObject
{
	public Object objectToPool;
	public int pooledAmount = 20;
	public bool canGrow = true;
}

public class ObjectPool : MonoBehaviour
{
	public static ObjectPool shared;
	public PooledObject[] pooledObjectTypes;

	private Dictionary<string, List<GameObject>> pool;

	void Awake()
	{
		// set up singleton reference
		if (shared == null)
		{
			shared = this;
		}
	}

	void Start()
	{
		// set up the pool and instantiate all initial objects
		pool = new Dictionary<string, List<GameObject>>();
		for (int i = 0; i < pooledObjectTypes.Length; i++)
		{
			PooledObject pooledObjectType = pooledObjectTypes[i];
			pool.Add(pooledObjectType.objectToPool.name, new List<GameObject>());
			for (int i2 = 0; i2 < pooledObjectType.pooledAmount; i2++)
			{
				AddPooledObject(pooledObjectType.objectToPool);
			}
		}
	}

	GameObject AddPooledObject(Object newObject)
	{
		GameObject pooledObject = Instantiate(newObject) as GameObject;
		if (shared.gameObject.transform != null)
		{
			pooledObject.transform.parent = shared.gameObject.transform;
		}
		pooledObject.SetActive(false);
		pool[newObject.name].Add(pooledObject);
		return pooledObject;
	}

	public void DisableAllPooledObjects()
	{
		foreach(string key in pool.Keys)
		{
		    foreach(GameObject pooledObject in pool[key])
		    {
		    	pooledObject.SetActive(false);
		    }
		}
	}

	public List<GameObject> GetPooledObjects(Object gameObject)
	{
		if (!pool.ContainsKey(gameObject.name))
		{
			return null;
		}
		return pool[gameObject.name];
	}

	public GameObject GetPooledObject(Object gameObject)
	{
		// return a regular non-pooled version if there is no pool for this type
		List<GameObject> pooledObjects = GetPooledObjects(gameObject);
		if (pooledObjects == null)
		{
			Debug.Log("Returning non-pooled instance of: " + gameObject.name);
			return (Instantiate(gameObject) as GameObject);
		}

		// return first available inactive pooled object
		for (int i = 0; i < pooledObjects.Count; i++)
		{
			if (!pooledObjects[i].activeInHierarchy)
			{
				return pooledObjects[i];
			}
		}

		// grow the pool if needed and return the new object
		for (int i = 0; i < pooledObjectTypes.Length; i++)
		{
			if (pooledObjectTypes[i].objectToPool.name == gameObject.name)
			{
				if (pooledObjectTypes[i].canGrow)
				{
					return AddPooledObject(gameObject);
				}
				else
				{
					return pooledObjects[0];
				}
			}
		}
		
		// return null if none was created
		// this should be handled by the caller script
		return null;
	}
}

Multiple character sprites using one animation controller


Update 2015.02.26
So, this post is actually a terrible way to go about this. When I was going down this path, I wasn’t aware of the built-in ways to handle something like this. Namely, you just need to create a single character’s animator controller and animation clips to feed it. Then you can create an “Animator Override Controller” that derives from that base animator for each additional character, and simply replace all the clips with unique ones. Part of this blog is to document the journey through my first Unity project, and, well, this is one of those learning experiences.

If you have several characters that your players can choose from, but all share a similar tree of Mecanim states and animations, you can use a single animation controller for all of them. Note that part of the process requires creating layers to “sync” to the master layer, and this is a Unity Pro-only feature. Here’s a quick example of some common player states, and how the process works:

animationStatesWith your animation states set up, make sure that you have created animation clips for each character for each of the states. For example, for the “player_fire” state, you would have animation clips such as “character1_fire”, “character2_fire”, “character3_fire”, etc. Have your first animation clip assigned to the state above.

With the first character all set up, simply add more layers in the animation controller for each character that you have. In the other layers, make sure you have “Sync” enabled (Pro-only feature). This syncs all the states with the top master layer, so all layers share the same states. Then you can simply click a layer to edit, and for each of the states, assign a different animation clip. In this example, I’ve added 4 other characters:

animationLayers

The last step is in your code. You can loop through all the layers in your animator, and set all their layer weights to 0 except for the chosen character, which should be 1. Here’s an example function that does this:

void SetCharacterLayer(int characterLayer)
{
	Animator animator = GetComponent();
	for (int i = 0; i < animator.layerCount; i++)
	{
		float layerWeight = (characterLayer == i) ? 1f : 0f;
		animator.SetLayerWeight(characterLayer, layerWeight);
	}
}

Custom Build Tools


While it’s easy enough to use Unity’s built-in build tools, you can make more customized build commands that are specifically tailored towards your game. This allows you to perform some tasks prior to exporting the final build, such as dynamically generating data files, or dynamically building a list of scenes to include.

buildTools

I have a custom class extending EditorWindow, and on that window I have some simple buttons that perform build-related tasks for me. Here are some simple examples, and I’m sure you can think of more that apply to your own game to save you some time:

Generate a dynamic, custom data file used by the game:
In my example, I will have many “maps” which are Unity scenes loaded into a main scene by LoadLevelAdditive(). I have a build tool that opens every single map, gets information about it, and saves all this data (width, height, supported game modes, etc) to a master maps.json file. That way, my game menus and logic can pull this info from the file at runtime.

Define build scenes in a Constants file, and add them to the build when generating:
This is useful if you have tons of scenes that will be loaded additively (such as my maps from above), and you don’t want to add them all to the build settings dialog manually. If you have a lot of churn during development, with maps being deleted and created continuously, this is a big time saver. I have my main build scenes defined in a Constants.cs file, and I combine this list with all my maps not in the list at build time. Here’s a quick example that doesn’t work on its own as a lot of surrounding code is missing, but gives the general idea:

//---[ Constants.cs ]--------------------------------------

// scenes to include in build (in Constants.cs)
#if UNITY_EDITOR
public static string[] BuildScenes = {
	"Assets/Scenes/TitleScene.unity",
	"Assets/Scenes/OptionsScene.unity",
	"Assets/Scenes/PlayerSetupScene.unity",
	"Assets/Scenes/BattleScene.unity"
};
#endif

//---[ build tools ]---------------------------------------

// combine all the scenes to include:
List allBuildScenes = new List();
allBuildScenes.AddRange(Constants.BuildScenes);
allBuildScenes.AddRange(otherScenesToInclude);

// finally, generate the build:
BuildPipeline.BuildPlayer(
    allBuildScenes.ToArray(),
    buildExportPath,
    buildPlatformTarget,
    BuildOptions.None
);

Pull in information and data from external sources:
I have a data file hosted on a web server that makes it easy for myself and others to continuously contribute to it whenever we have ideas. I can pull down this file in my build process and sync it with the game’s version. That way, we can contribute to it at any time, and it will be included in the next build:

// import external data file
WWW dataFileWWW = new WWW(dataURL);
while (!dataFileWWW.isDone)
{
    EditorUtility.DisplayProgressBar("Importing data...", dataURL, dataFileWWW.progress);
}
File.WriteAllText(Application.dataPath + "/Resources/data.txt", dataFileWWW.text);
AssetDatabase.Refresh();
EditorUtility.ClearProgressBar();
©2017 Sombr Studio LLC