Key points from Ubisoft Blue Byte team talk at GDC about their way to overcome performance limitations on mobile devices.
Video 1. Assassin's Creed Identity: Creating a Benchmark Mobile Game. August 2015, GDC
- made with Unity
- 450k+ lines of code
- project build time ~30 minutes (iOS) (twice if profiler attached)
- one environment asset bundle takes up to 9 hours of build time
- self-imposed runtime memory budget: 40 Mb mesh and 60 Mb texture data on one level
- used Unity built-in features: static batching, LightMaps, LightProbes, NavMesh (OffMeshLinks for climbing).
Customized rendering pipeline for characters:
- glossy surfaces, AO and specular maps, LODed models
- crowd: low-poly characters are mixed from different parts (heads, body parts, accessories...) and colors to increase diversity, limited animations
- enemies: med-poly, only heads and some accessories randomized, animations based on enemy type
- main characters: high-poly, customizable color, outfit, weapons and faces; 800 animations, 2.4k animation transitions.
- environment art, character art and gamedesighn are separated and delivered to a client via asset bundles
- level art project is a separate project for artists and game designers
- game logic separated from Unity logic: ECS rebuild for game logic, implemented in separate .Net 3.5 compiled DLL
EntityManager holds a list of
TurnHandler keeps a distance buckets (entities based on player distance) and a visible bucket
TurnHandler distributes available turns within a frame to all components based on a bucket the entity is in: visible entities never skip updates, distant buckets may be updated once a second
- pros: full control over entities; custom game loop entry points; OOP approach and heavy usage of interfaces
- cons: code complexity; impossible to debug on device because of app size; il2cpp problems with generics and interfaces
- AI is driven by behavior trees
- all entities are prioritized based on gameplay relevance and only visible ones are processed in rendering
- there is a
HumanoidCache - collection of body parts baked in large meshes within
- logic pooling configured to max 10 visible gameplay-relevant entities + 5 cached
- switched to Protobuf serialization - better than Unity serialization both in terms of memory and speed
- 100+ gameplay-relevant entities in a mission (+crowd)
- 4 ms simulation per frame (on iPad 4) +8 ms for turn updates each 100 ms.
- custom node-based behavior tree editor with debug function (visualization during gameplay)
- mission editor; missions are set as a hierarchy of GameObjects with components describing objectives and its data
- mission graph flow and data visualization written to debug mission in runtime
- crowd editor: footsteps (probability of crowd walking here) map drawn with a brush, then it converted to node-like structure with weights like Voronoy diagram which is used by crowd agents; all editing is possible without game restart in the editor
- editor preview of possible humanoid parts combinations.
C# for Unity:
- Unity mono is not equals to Xamarin mono - features almost frozen at v2.6 (mid 2010)
- Unity mono source code available at github.com/Unity-T...
- everything that is not in Unity's micro corlib brings a lot of code to a project
- beware interfaces and generics with AOT on iOS/IL2CPP
- boxing overhead may be noticeable to performance
object parameters - in il2cpp builds every possible combination of types is generated in code, so try to restrict generic type parameters as much as possible
- allocation differs on device - use remote profiling
- avoid using reflection, but if you do - use link.xml to add linker exceptions to enforce the code to be compiled into player (when code stripping enabled)
- avoid value-type generics
- keep in mind any texture take twice memory while loading.