Harder, Better, Faster, Stronger · Harder, Better, Faster, Stronger Code Style and Architecture in Unity3D Richard Fine Sunday, 29 April 12. Introduction What is this talk all about?

Post on 24-Apr-2020

11 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

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: rfine@tbrf.netSunday, 29 April 12

top related