Example #1
0
        IEnumerator IntervaledTick()
        {
            //this is of fundamental importance: Never create implementors as Monobehaviour just to hold
            //data (especially if read only data). Data should always been retrieved through a service layer
            //regardless the data source.
            //The benefits are numerous, including the fact that changing data source would require
            //only changing the service code. In this simple example I am not using a Service Layer
            //but you can see the point.
            //Also note that I am loading the data only once per application run, outside the
            //main loop. You can always exploit this pattern when you know that the data you need
            //to use will never change
            var enemiestoSpawny  = ReadEnemySpawningDataServiceRequest();
            var enemyAttackDatay = ReadEnemyAttackDataServiceRequest();

            yield return(enemiestoSpawny);

            yield return(enemyAttackDatay);

            var enemiestoSpawn  = enemiestoSpawny.Current;
            var enemyAttackData = enemyAttackDatay.Current;

            var spawningTimes = new float[enemiestoSpawn.Length];

            for (var i = enemiestoSpawn.Length - 1; i >= 0 && _numberOfEnemyToSpawn > 0; --i)
            {
                spawningTimes[i] = enemiestoSpawn[i].enemySpawnData.spawnTime;
            }

            _enemyFactory.Preallocate();

            while (true)
            {
                //Svelto.Tasks can yield Unity YieldInstructions but this comes with a performance hit
                //so the fastest solution is always to use custom enumerators. To be honest the hit is minimal
                //but it's better to not abuse it.
                yield return(_waitForSecondsEnumerator);

                //cycle around the enemies to spawn and check if it can be spawned
                for (var i = enemiestoSpawn.Length - 1; i >= 0 && _numberOfEnemyToSpawn > 0; --i)
                {
                    if (spawningTimes[i] <= 0.0f)
                    {
                        var spawnData = enemiestoSpawn[i];

                        //In this example every kind of enemy generates the same list of EntityViews
                        //therefore I always use the same EntityDescriptor. However if the
                        //different enemies had to create different EntityViews for different
                        //engines, this would have been a good example where EntityDescriptorHolder
                        //could have been used to exploit the the kind of polymorphism explained
                        //in my articles.
                        var enemyAttackStruct = new EnemyAttackStruct
                        {
                            attackDamage      = enemyAttackData[i].enemyAttackData.attackDamage,
                            timeBetweenAttack = enemyAttackData[i].enemyAttackData.timeBetweenAttacks
                        };

                        //has got a compatible entity previously disabled and can be reused?
                        //Note, pooling make sense only for Entities that use implementors.
                        //A pure struct based entity doesn't need pooling because it never allocates.
                        //to simplify the logic, we use a recycle group for each entity type
                        var fromGroupId = ECSGroups.EnemiesToRecycleGroups + (uint)spawnData.enemySpawnData.targetType;

                        if (entitiesDB.HasAny <EnemyEntityViewStruct>(fromGroupId))
                        {
                            ReuseEnemy(fromGroupId, spawnData);
                        }
                        else
                        {
                            yield return(_enemyFactory.Build(spawnData.enemySpawnData, enemyAttackStruct));
                        }

                        spawningTimes[i] = spawnData.enemySpawnData.spawnTime;
                        _numberOfEnemyToSpawn--;
                    }

                    spawningTimes[i] -= SECONDS_BETWEEN_SPAWNS;
                }
            }
        }