harder, better, faster, stronger · harder, better, faster, stronger code style and architecture in...
TRANSCRIPT
Harder, Better, Faster, StrongerCode Style and Architecture in Unity3D
Richard Fine
Sunday, 29 April 12
Introduction
What is this talk all about?
1000 ways to SkinnedMeshRender a cat
It’s not what you do, it’s how you do it
(mostly)
Sunday, 29 April 12
Architectural Foundations
Sunday, 29 April 12
Pressing Concerns
Understandability
Flexibility
Extendability
Debuggability
Achievability
RunVeryFastability Performance
Sunday, 29 April 12
Understandability
The Zen of Ronseal
Comments not needed
Short names do not run faster
AutoComplete
Be concise, not compact
Be consistent, not chaotic
Sunday, 29 April 12
Flexibility and Extendability
You are frequently going to want to change your code a lot
Fearlessness through controlled coupling
Need To Know Basis
Think in sets
Be Liberal
Sunday, 29 April 12
Performance
First make it work. Then make it fast.
But plan ahead for that...
Bad performance comes from restrictive architectures
Sunday, 29 April 12
Technical Detailsthat I have known and loved
Sunday, 29 April 12
InitialisationAwake, OnEnable, Start...?
Dependencies
Inter-object
Intra-object
Configuration
Edit and Continue
Frametime spikes
Sunday, 29 April 12
InitialisationAwake
During scene load
During Instantiate()
Always after deserialization
No inter-object ordering with the same type
Not called on playmode recompileThus:
Good for self-init of public stateless things
Sunday, 29 April 12
InitialisationOnEnable
Called immediately after Awake(), if created enabled
Called whenever set enabled, if not
Called after playmode recompile
Can’t guarantee other objects are Awake() yetThus:
Good for self-init of private and stateful things
Sunday, 29 April 12
InitialisationStart
Before first Update
Not called if component is disabled
Not called on playmode recompile
Same frame as Instantiate(), but later on
Can be a coroutineThus:
Good for one-time-only public inter-object init
Sunday, 29 April 12
InitialisationLazy Init
Initialise on first use
Caching properties:private MyComponent _theComponent;public MyComponent TheComponent{get {if (!_theComponent) _theComponent = GetComponent<MyComponent>();return _theComponent;
}}
Con: Unpredictable frametime spikes
Pro: Easy to change later onSunday, 29 April 12
InitialisationCustom Events
Do your own damn initialisation!
Extend Unity’s message list
Allows for more modular initialisation
Required for object pooling/recycling
Sunday, 29 April 12
Messaging(Send|Broadcast)Message[Upwards]
Pros:Don’t need to know the receiver
Can be received by multiple components
Can start coroutines
Can be configured easily
ConsSlower than direct calls and delegates
Typo-prone
Sunday, 29 April 12
MessagingEvent Objects
Wrap event data in a class (e.g. Collision)
Lets you pack more than one parameter
It’s a regular class, though:
It can have methods
It can have mutable state
This makes for some very nice patterns...
Sunday, 29 April 12
MessagingExample: Bullet Damage System
RaycastAll and sort by distance
Pack shot information into a DamageEvent “evt”
SendMessage “TakeDamage” (evt) to each colliderSet evt.continue = false to stop the shot
Set evt.amount *= 0.5 to reduce damage
Set evt.type |= DamageTypes.Fire to ignite shot
Set evt.direction and re-raycast to ricochet
Sunday, 29 April 12
MessagingExample: Save/Load system
Create a new List<SaveData> ‘saveDatas’
BroadcastMessage “Save” (saveDatas)
Receivers add their save data to the listOpportunity to ensure receiver is in a consistent state
Include some way to tell who’s data is who’s
Store list in memory for quicksave, write to disk for full
BroadcastMessage “Load” (saveDatas) to load
Sunday, 29 April 12
ScriptableObjectNot just your regular Object
Custom asset types
Can’t be added to the scene
Don’t support components
No Start/Update, Coroutines, Invoke, messages, etc
Good for “data blobs,” tables, etc
Sunday, 29 April 12
ScriptableObjectExample: Speech Table
Store speech for an NPC
Multiple variants of lines, to avoid repetition
Subtitles
Easy playback
Different speech for different NPCs, but same tech requirements
Sunday, 29 April 12
ScriptableObjectExample: Speech Table
[Serializable] class SpeechTableEntry {
string Id;
AudioClip[] Clip;
string[] Subtitle;
}
class SpeechTable : ScriptableObject
{ SpeechTableEntry[] Entries; }
Sunday, 29 April 12
ScriptableObjectExample: Speech Table
Creating a new speech table:table = ScriptableObject.CreateInstance<SpeechTable>();
AssetDatabase.CreateAsset(table, “Speech.asset”);
Edit in the inspector like anything elseWrite a custom inspector for great justice
Sunday, 29 April 12
ScriptableObjectExample: Speech Table
Reference the table like any other object:SpeechTable MySpeechTable;
Use case: SpeechPlayer.PlayLine(“hurt”);
Find the entry with the given IDvar entry = MySpeechTable.Entries.First(e => e.Id == id);
Pick an AudioClip from the entry and play itAt random
Using an LRU
Sunday, 29 April 12
ScriptableObjectversus Prefabs
“Can’t you do all this with prefabs?”Mostly, yes:
Can use a component on a prefab as a ‘data dump’
Add components to provide extra data in a pluggable fashion
But not quite:
Prefabs don’t work so well in the Object Browser, and can be inconvenient to edit
Separate files for separate data is friendlier to teams
May not want to let it be added to the scene
Violates the Ronseal principle
Sunday, 29 April 12
I’ve probably run out of time by this point
So I’ll stop here.
Questions, Comments, Counterarguments?
Twitter: @Superpigemail: [email protected], 29 April 12