Lessons learnt from making a hit mobile game with Unity 3D

Post on 05-Jan-2016

55 views 10 download

description

Lessons learnt from making a hit mobile game with Unity 3D. David Jefferies, Technical Director PaperSeven Ltd. A Bit Of History. Used Unity to prototype Split/Second 2 The game + engine was large ~2mil lines code Turnaround times were slow - PowerPoint PPT Presentation

Transcript of Lessons learnt from making a hit mobile game with Unity 3D

Lessons learnt from making a hit mobile game with Unity 3D

David Jefferies, Technical DirectorPaperSeven Ltd

A Bit Of History• Used Unity to prototype Split/Second 2• The game + engine was large ~2mil lines code• Turnaround times were slow• Unity helped the developers test out

gameplay ideas quickly

A Bit Of History

A Bit Of History• At one point we even considered making S/S 2

with Unity• Unity renderer was about 80% at efficient

rendering models as S/S 2• Replace editor, asset pipeline and game

engine with Unity

2010 - 2011• Unity was widely seen as a capable

prototyping tool• Definitely not a commercial game engine

Unity• I think the reality is different

– Model Importer– Dependency Checker– Renderer– Extensible Editor– C# code

This is what I want. I don’t want to write these modules again.

Made In Chelsea Game• 9 months to develop• 4 coders, 4 artists plus contractors • Producer/GD• iOS and Facebook initially, Android update• Free with IAPs• #2 in the AppStore charts• 19k ratings at 4.5 stars• 10 hours in length if you rushed through• Won ‘Best Game’ in the Broadcast Digital Awards 2014

Made In Chelsea Game

Made In Chelsea Game

How We Made It• Exclusively C#• Used Prime31 plugins for most native code - IAPS, Twitter

and Facebook authentication etc • Coders used a mixture of MonoDevelop and .Net• MacMini server build machine that built iOS, Facebook

and eventually Android • Mainly developed on PC except for the iOS specific bits

which were kept to a minimum

Learnings• It’s easy to get something up and running• This is a great strength of Unity• However, not all features scale well from

prototype to full production• It’s this understanding which is vital

Memory• Rule [1]– Never write code that allocates while the game is

running– All allocations at load time– Same rules as C++ but it’s trickier with C#– Unity’s memory profiler is your friend

Memory• Know the difference between class and struct• We never use foreach loops• Use a heap safe Dictionary • Raycast was only exception• Use object pools. No runtime instantiation

Exceptions• Rule [2]– Always use Fast but no Exceptions in production

code– Speeds up managed to native calls by 3X– Managed code exceptions are still thrown– Write the exception to a log file and crash– Send the log file to your metrics server

Exceptionsvoid HandleLog(string logString, string stackTrace, LogType type) { string log = DateTime.UtcNow.ToString("HH:mm:ss") + " " + type.ToString() + " :\t" + logString; if (!string.IsNullOrEmpty(stackTrace)) { log = log + "\n\tstackTrace :\n" + stackTrace; } using (StreamWriter file = new StreamWriter(Application.persistentDataPath + "/logs" + "/LogFile_" + logSessionID + ".log", true)) { file.WriteLine(log); } if (type == LogType.Exception) { PlayerPrefs.SetInt(APP_CRASHED_KEY, 1); } }

Scenes & Prefabs• Prefabs are a great way of encapsulating code and data• When placed directly in a scene they make it un-

mergeable• If a prefab is edited in a scene and not applied it

becomes unique to that scene• References were forever being lost• Rule [4] No references between different prefabs

Scenes & Prefabs• Rule [5] Have a scene structure that

determines which prefabs to load & initialise– Load all the prefabs in the level folder– Custom intialisation steps to manage initialisation

dependencies– Inject dependencies into the components– Start game

Scenes & Prefabs

Custom Setup StepsAwake

Load AssetBundles

Load Prefabs

HandleInitFirstTime

SetupDependencies

HandleInit

Update

Code Structure• No Singletons• Loaded prefabs are available as a dictionary to

all classes• Dependency injectors push dependencies into

the components• Injectors are destroyed after being run

Code Structurepublic class GameTimeInjector : GameResourcesInjector<GameObject> {

[SerializeField] private string _pauseControllerObject = "PauseEventController";

public override void Inject (){

GameTime _gameTime = GetComponent<GameTime>();PauseEventController pauseController =

GameResources.GetLoadedObject(_pauseControllerObject).GetComponent<PauseEventController>();

pauseController.AddPauseableObjects(_gameTime);}

}

Code Structure• Common Library shared between all games• Lives in the Plugins Folder• Enforces the rule that game code cannot exist

in the library• We use a repository within a repository• Warnings as Errors using gmcs.rsp & smcs.rsp

Code Structure• Listener pattern• Reduces dependencies between modules• Uses the dictionary of objects to connect

listeners and distributors

Code Structurepublic class DriveAutoSaverInjector : GameResourcesInjector<GameObject> { [SerializeField] private string _saveStateDataObject = "StateManager"; [SerializeField] private string _gameStateObject = "Game";

public override void Inject() { AutoSaver autoSaver = gameObject.GetComponent<AutoSaver>(); GameState gamestate = GameResources.GetLoadedObject(_gameStateObject).GetComponent<GameState>(); gamestate.PostEndOfRaceListeners.Add (autoSaver); }}

Over Air Update• Rule [6] – All prefabs are built as asset bundles– This allows us to update all of the game data over the air– Versions.xml exists on Amazon AWS and serves new

prefabs to the game– Next time the game runs it loads the new downloaded

prefabs rather than the bundles prefabs– Use [SerializeField] attribute for private variables

Out Of Memory• Write guard file when app launches• Delete it when app enters the background• If you launch and the file is there then ran out of

memory• Tell user to reset their device• Log with metrics server• Use assembly stripping

Source Control• Internal Git repository hosted on our network• Everyone in the studio uses the Git client• Problems with empty directories / meta files

Auto Build• Hook into Unity’s build process• Have a config file that defines all the build settings• We use TeamCity• Building iOS more difficult than it should be• Upload to TestFlight / HockeyApp• Signed with Enterprise profile

Auto Build• We use Mind Candy’s Teamcity Unity3D runner• https://

github.com/mindcandy/Teamcity-unity3d-build-runner-plugin– iOS Build is fiddly– Write build number– Build Project– Build Xcode Archive– Build IPA– Upload to TestFlight– Lots of messing around with Provisioning Profiles

Performance• Scaled some features depending on device• Fast but no Exceptions• No memory allocations• Do all possible calculations at build time

That’s It• Any Questions

david@paperseven.com