Extensible and maintainable architecture for Unity games

We invite future students of the "Unity Game Developer. Professional" course to attend an open webinar on the topic "Advanced Artificial Intelligence of Enemies in Shooters".

In the meantime, we suggest reading the translation of a useful article.


Introduction

Over the years working on many projects, I have developed a clear approach to structuring game projects in Unity, which has proven itself to be particularly extensible and maintainable.

For a long time, I wanted to write down my thoughts, converting them into a format suitable for the public.

This article is an updated version of my 2017 GDC talk (β€œData Binding Architectures for Rapid UI Creation in Unity”).

Disclaimer: you should understand that these are only practical recommendations that I have developed that reflect my experience and outlook on development, and not a universal solution to all problems and definitely not the only correct approach for every project or team.

: , , , , Kolibri Games :

:

, . , -, , . . , , , .

  1. (inversion of control)

  2. (MPI)

  3. / / (MVC)

  4. (Unit testing)

, :

ClassA ServiceA/ServiceB. ClassA .

(DI β€” Dependency Injection) β€” . :

(Builder) ClassA, . ClassA , , , , .

Zenject/Extenject. . (reflection-baking), .

--

β€” . -- (Model-View-Controller β€” MVC), Unity, :

Monobehaviour- Unity (View), , , Unity. . [SerializeField] drag’n’drop Unity. , .

- . , Unity. , .

, , - . β€” , .

, (Message Passing). .

, , - . : . .

(notification messages), / (events):

Zenject Signals.

:

struct MessageType {}

bus.Subscribe<MessageType>(()=>Debug.Log("Msg received"));

bus.Fire<MessageType>();

, (Signals) β€” MVC. β€” , .

, UniRx, , , , . , , , .

() .

Unity NUnit NSubstitute .

:

var level = Substitute.For<ILevel>();
var buildings = Substitute.For<IBuildings>();

// test subject: 
var build = new BuildController(null,buildings,level);

// smoke test
Assert.AreEqual(0, build.GetCurrentBuildCount());

// assert that `GetCurrent` was exactly called once
level.ReceivedWithAnyArgs(1).GetCurrent();

. , NSubstitute , .

- 0:

var level = Substitute.For<ILevel>();
var bus = _container.Resolve<SignalBus>();
var buildCommandSent = false;
bus.Subscribe<BuildingBuild>(() => buildCommandSent = true);

// test subject 
var build = new BuildController(bus,new BuildingsModel(),level);
// test call
build.Build(0);

Assert.AreEqual(1, build.GetCurrentBuildCount());

// assert signals was fired
Assert.IsTrue(buildCommandSent);

, GetCurrentBuildCount 0. , β€” , .

"-, , Zenject?" ( )

, , SignalBus , NSubstitute -β€” , .

, .

. :

, Unity -, Unity , Unity . , Unity ( playmode ).

, , , , , :

  • ,

  • SDK


- "Unity Game Developer. Professional" .

- " " .





All Articles