Skip to content
Sebastiano Mandalà edited this page Apr 1, 2019 · 2 revisions

The Composition Root and the EnginesRoot

The class Main is the Application Composition Root. A Composition Root is where dependencies are created and injected (I talk a lot about this in my articles). A composition root belongs to the context, but a context can have more than one composition root. For example a factory is a composition root. Furthermore an application can have more than one context but this is an advanced scenario and not part of this example.

Before to start digging in the code, let's introduce the first terms of the Svelto.ECS domain language. ECS is an acronym for Entity Component System. The ECS infrastructure has been analyzed abundantly with several articles written by many authors, but while the basic concepts are in common, the implementations differ a lot. Above all, there isn't a standard way to solve the few problems rising from using ECS oriented code. That's where I put most of my effort on, but this is something I will talk about later or in the next articles. At the heart of the theory there are the concepts of Entity, Components (of the entities) and Systems. While I understand why the word System has been used historically, I initially found it not intuitive for the purpose, so Engine is synonym of System and you may use it interchangeably according your preferences.

The EnginesRoot class is the core of Svelto.ECS. With it is possible to register the engines and build all the entities of the game. It doesn't make much sense to create engines dynamically, so all the engines should be added in the EnginesRoot instance from the same composition root where it has been created. For similar reasons, an EnginesRoot instance must never been injected and engines can't be removed once added.

We need at least one composition root to be able to create and inject dependencies wherever needed. Yes, it's possible to have even more than one EnginesRoot per application, but this is too not part of this article, which I will try to keep as simple as possible. This is how a composition root with engines creation and dependencies injection looks like:

            void SetupEnginesAndEntities()
            {
                _enginesRoot = new EnginesRoot(new UnitySumbmissionEntityViewScheduler());

                _entityFactory = _enginesRoot.GenerateEntityFactory();
                var entityFunctions = _enginesRoot.GenerateEntityFunctions();

                var playerHealthEngine = new HealthEngine(entityFunctions, playerDamageSequence);
                var playerShootingEngine = new PlayerGunShootingEngine(enemyKilledObservable, enemyDamageSequence, rayCaster, time);
                var playerMovementEngine = new PlayerMovementEngine(rayCaster, time);
                var playerAnimationEngine = new PlayerAnimationEngine();

                //Enemy related engines
                var enemyAnimationEngine = new EnemyAnimationEngine();
                var enemyHealthEngine = new HealthEngine(entityFunctions, enemyDamageSequence);
                var enemyAttackEngine = new EnemyAttackEngine(playerDamageSequence, time);
                var enemyMovementEngine = new EnemyMovementEngine();
                var enemySpawnerEngine = new EnemySpawnerEngine(factory, _entityFactory);

                //Player engines
                _enginesRoot.AddEngine(playerMovementEngine);
                _enginesRoot.AddEngine(playerAnimationEngine);
                _enginesRoot.AddEngine(playerShootingEngine);
                _enginesRoot.AddEngine(playerHealthEngine);
                _enginesRoot.AddEngine(new PlayerInputEngine());
                _enginesRoot.AddEngine(new PlayerGunShootingFXsEngine());
                //enemy engines
                _enginesRoot.AddEngine(enemySpawnerEngine);
                _enginesRoot.AddEngine(enemyAttackEngine);
                _enginesRoot.AddEngine(enemyMovementEngine);
                _enginesRoot.AddEngine(enemyAnimationEngine);
                _enginesRoot.AddEngine(enemyHealthEngine);
                //other engines
                _enginesRoot.AddEngine(new CameraFollowTargetEngine(time));
                _enginesRoot.AddEngine(damageSoundEngine);
                _enginesRoot.AddEngine(hudEngine);
                _enginesRoot.AddEngine(new ScoreEngine());
            }

This code is part of the survival example which is now well commented and follows almost all the good practice rules that I suggest to use, including keeping the engines logic platform independent and testable. The comments will help you to understand most of it, but a project of this size may be already too much to swallow if you are new to Svelto.