Browse Source

Fix star warrior (#26)

* Convert to an EntityUpdateSystem so we have access to Aspects to count the number of enemies

* Fix issue with rendering, where images flicker and randomly don't display

* Add way to distinguish owner of bullet.  Add simple collission detection.  Fix player bullets.  Fix enemy spawning.
Jeremy Swartwood 1 year ago
parent
commit
14fb3c59d6

+ 12 - 0
src/Games/StarWarrior/Components/OwnerComponent.cs

@@ -0,0 +1,12 @@
+// Copyright (c) Craftwork Games. All rights reserved.
+// Licensed under the MIT license.
+// See LICENSE file in the project root for full license information.
+
+
+namespace StarWarrior.Components
+{
+    public class OwnerComponent
+    {
+        public int OwnerID { get; set; }
+    }
+}

+ 2 - 1
src/Games/StarWarrior/EntityFactory.cs

@@ -14,13 +14,14 @@ namespace StarWarrior
         // TODO: Remove this property injection.
         public World World { get; set; }
 
-        public Entity CreateMissile()
+        public Entity CreateMissile(int ownerID)
         {
             var entity = World.CreateEntity();
             entity.Attach(new Transform2());
             entity.Attach(new SpatialFormComponent { SpatialFormFile = "Missile" });
             entity.Attach(new PhysicsComponent());
             entity.Attach(new ExpiresComponent { LifeTime = TimeSpan.FromMilliseconds(2000) });
+            entity.Attach(new OwnerComponent { OwnerID = ownerID });
             return entity;
         }
 

+ 95 - 31
src/Games/StarWarrior/Systems/CollisionSystem.cs

@@ -36,52 +36,116 @@
 
 using Microsoft.Xna.Framework;
 using MonoGame.Extended;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.ECS;
 using MonoGame.Extended.ECS.Systems;
+using StarWarrior.Components;
 
 namespace StarWarrior.Systems
 {
-    public class CollisionSystem : UpdateSystem
+    public class CollisionSystem : EntityUpdateSystem
     {
-        public override void Update(GameTime gameTime)
+        private ComponentMapper<Transform2> _transformMapper;
+        private ComponentMapper<EnemyComponent> _enemyMapper;
+        private ComponentMapper<OwnerComponent> _ownerComponent;
+        private ComponentMapper<PlayerComponent> _playerMapper;
+        private ComponentMapper<HealthComponent> _healthMapper;
+
+        private Bag<int> _enemies;
+        private Bag<int> _players;
+        private Bag<int> _bullets;
+
+        public CollisionSystem() : base(Aspect.One(typeof(HealthComponent), typeof(OwnerComponent)))
         {
-            //var bullets = EntityManager.GetEntitiesByGroup("BULLETS");
-            //var ships = EntityManager.GetEntitiesByGroup("SHIPS");
-            //if (bullets == null || ships == null)
-            //    return;
 
-            //// ReSharper disable once ForCanBeConvertedToForeach
-            //for (var shipIndex = 0; ships.Count > shipIndex; ++shipIndex)
-            //{
-            //    var ship = ships[shipIndex];
+        }
 
-            //    // ReSharper disable once ForCanBeConvertedToForeach
-            //    for (var bulletIndex = 0; bullets.Count > bulletIndex; ++bulletIndex)
-            //    {
-            //        var bullet = bullets[bulletIndex];
-            //        var bulletTransform = bullet.Get<Transform2>();
-            //        var shipTransform = ship.Get<Transform2>();
+        public override void Initialize(IComponentMapperService mapperService)
+        {
+            _transformMapper = mapperService.GetMapper<Transform2>();
+            _enemyMapper = mapperService.GetMapper<EnemyComponent>();
+            _ownerComponent = mapperService.GetMapper<OwnerComponent>();
+            _playerMapper = mapperService.GetMapper<PlayerComponent>();
+            _healthMapper = mapperService.GetMapper<HealthComponent>();
 
-            //        if (!CollisionExists(bulletTransform, shipTransform))
-            //            continue;
+            _enemies = new Bag<int>();
+            _players = new Bag<int>();
+            _bullets = new Bag<int>();
+        }
 
-            //        var bulletExplosion = EntityManager.CreateEntityFromTemplate(BulletExplosionTemplate.Name);
-            //        bulletExplosion.Get<Transform2>().Position = bulletTransform.Position;
-            //        bullet.Destroy();
+        protected override void OnEntityAdded(int entityId)
+        {
+            if (_enemyMapper.Get(entityId) != null)
+                _enemies.Add(entityId);
+            else if (_playerMapper.Get(entityId) != null)
+                _players.Add(entityId);
+            else if (_ownerComponent.Get(entityId) != null)
+                _bullets.Add(entityId);
+        }
+        protected override void OnEntityRemoved(int entityId)
+        {
+            if (_enemyMapper.Get(entityId) != null)
+                _enemies.Remove(entityId);
+            else if (_playerMapper.Get(entityId) != null)
+                _players.Remove(entityId);
+            else if (_ownerComponent.Get(entityId) != null)
+                _bullets.Remove(entityId);
+        }
+
+        public override void Update(GameTime gameTime) 
+        {
+            if (_bullets.Count == 0 || _enemies.Count == 0)
+                return;
 
-            //        var healthComponent = ship.Get<HealthComponent>();
-            //        healthComponent.AddDamage(4);
+            // Check bullets against enemy ships
+            foreach (int bulletId in _bullets)
+            {
+                Transform2 bulletTransform = _transformMapper.Get(bulletId);
+                OwnerComponent bulletOwner = _ownerComponent.Get(bulletId);
 
-            //        if (healthComponent.IsAlive)
-            //            continue;
+                PlayerComponent playerComponent = null;
+                if (bulletOwner != null)
+                {
+                    playerComponent = _playerMapper.Get(bulletOwner.OwnerID);
+                }
 
-            //        var shipExplosion = EntityManager.CreateEntityFromTemplate(ShipExplosionTemplate.Name);
-            //        shipExplosion.Get<Transform2>().Position = shipTransform.Position;
-            //        ship.Destroy();
-            //        break;
-            //    }
-            //}
+                // Player bullet, check against all enemies
+                if (playerComponent != null)
+                {
+                    foreach (int enemyId in _enemies)
+                    {
+                        Transform2 enemyTransform = _transformMapper.Get(enemyId);
+                        HealthComponent enemyHealth = _healthMapper.Get(enemyId);
+                        if (CollisionExists(bulletTransform,enemyTransform))
+                        {
+                            DestroyEntity(bulletId);
 
+                            // apply health reduction
+                            enemyHealth.AddDamage(1);
+                            if (!enemyHealth.IsAlive)
+                                DestroyEntity(enemyId);
+                        }
+                    }
+                }
+                // Enemy bullet, check against players
+                else
+                {
+                    foreach (int playerId in _players)
+                    {
+                        Transform2 playerTransform = _transformMapper.Get(playerId);
+                        HealthComponent playerHealth = _healthMapper.Get(playerId);
+                        if (CollisionExists(bulletTransform, playerTransform))
+                        {
+                            DestroyEntity(bulletId);
 
+                            // apply health reduction
+                            playerHealth.AddDamage(1);
+                            if (!playerHealth.IsAlive)
+                                DestroyEntity(playerId);
+                        }
+                    }
+                }
+            }
         }
 
         // ReSharper disable once SuggestBaseTypeForParameter

+ 1 - 1
src/Games/StarWarrior/Systems/EnemyShooterSystem.cs

@@ -68,7 +68,7 @@ namespace StarWarrior.Systems
                 return;
             weapon.ShootTimerDelay -= weapon.ShootDelay;
 
-            var missile = _entityFactory.CreateMissile();
+            var missile = _entityFactory.CreateMissile(entityId);
             var missileTransform = missile.Get<Transform2>();
 
             var worldPosition = transform.WorldPosition;

+ 29 - 2
src/Games/StarWarrior/Systems/EnemySpawnSystem.cs

@@ -38,25 +38,52 @@ using System;
 using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
 using MonoGame.Extended;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.ECS;
 using MonoGame.Extended.ECS.Systems;
 using StarWarrior.Components;
 
 namespace StarWarrior.Systems
 {
-    public class EnemySpawnSystem : UpdateSystem
+    public class EnemySpawnSystem : EntityUpdateSystem
     {
         private readonly GraphicsDevice _graphicsDevice;
         private readonly EntityFactory _entityFactory;
         private readonly Random _random = new Random();
+        private ComponentMapper<EnemyComponent> _enemyComponentMapper;
 
-        public EnemySpawnSystem(GraphicsDevice graphicsDevice, EntityFactory entityFactory)
+        private Bag<int> _enemies;
+
+        public EnemySpawnSystem(GraphicsDevice graphicsDevice, EntityFactory entityFactory) : base(Aspect.One(typeof(EnemyComponent)))
         {
             _graphicsDevice = graphicsDevice;
             _entityFactory = entityFactory;
         }
 
+        public override void Initialize(IComponentMapperService mapperService)
+        {
+            _enemyComponentMapper = mapperService.GetMapper<EnemyComponent>();
+            _enemies = new Bag<int>();
+        }
+
+        // Keep track of how many enemies there are
+        protected override void OnEntityAdded(int entityId)
+        {
+            if (_enemyComponentMapper.Get(entityId) != null)
+                _enemies.Add(entityId);
+        }
+        protected override void OnEntityRemoved(int entityId)
+        {
+            if (_enemyComponentMapper.Get(entityId) != null)
+                _enemies.Remove(entityId);
+        }
+
         public override void Update(GameTime gameTime)
         {
+            // Only allow 10 enemies
+            if (_enemies.Count > 10)
+                return;
+
             var viewport = _graphicsDevice.Viewport;
             var entity = _entityFactory.CreateEnemyShip();
             var transform = entity.Get<Transform2>();

+ 6 - 11
src/Games/StarWarrior/Systems/PlayerShipControlSystem.cs

@@ -59,9 +59,9 @@ namespace StarWarrior.Systems
             _missileLaunchTimer = TimeSpan.Zero;
         }
 
-        private void AddMissile(Transform2 parentTransform, float angle = 90.0f, float offsetX = 0.0f)
+        private void AddMissile(int ownerId, Transform2 parentTransform, float angle = 90.0f, float offsetX = 0.0f)
         {
-            var missile = _entityFactory.CreateMissile();
+            var missile = _entityFactory.CreateMissile(ownerId);
 
             var missileTransform = missile.Get<Transform2>();
             missileTransform.Position = parentTransform.WorldPosition + new Vector2(1 + offsetX, -20);
@@ -95,11 +95,6 @@ namespace StarWarrior.Systems
             if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right))
                 direction += Vector2.UnitX;
 
-            //if (keyboard.IsKeyDown(Keys.K) && !_lastState.IsKeyDown(Keys.K))
-            //{
-            //    BitmapFont.UseKernings = !BitmapFont.UseKernings;
-            //}
-
             var isMoving = direction != Vector2.Zero;
             if (isMoving)
             {
@@ -112,13 +107,13 @@ namespace StarWarrior.Systems
             if (keyboard.IsKeyDown(Keys.Space) || keyboard.IsKeyDown(Keys.Enter))
             {
                 _missileLaunchTimer += gameTime.ElapsedGameTime;
-                if (_missileLaunchTimer <= _missileLaunchDelay)
+                if (_missileLaunchTimer >= _missileLaunchDelay)
                 {
                     _missileLaunchTimer -= _missileLaunchDelay;
 
-                    AddMissile(transform);
-                    AddMissile(transform, 89, -9);
-                    AddMissile(transform, 91, +9);
+                    AddMissile(entityId, transform);
+                    AddMissile(entityId, transform, 89, -9);
+                    AddMissile(entityId, transform, 91, +9);
                 }
             }
 

+ 2 - 1
src/Games/StarWarrior/Systems/RenderSystem.cs

@@ -35,6 +35,7 @@
 // --------------------------------------------------------------------------------------------------------------------
 
 using System;
+using System.Diagnostics;
 using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Content;
 using Microsoft.Xna.Framework.Graphics;
@@ -76,7 +77,7 @@ namespace StarWarrior.Systems
                 if (!(worldPosition.X >= 0) || !(worldPosition.Y >= 0) ||
                     !(worldPosition.X < _spriteBatch.GraphicsDevice.Viewport.Width) ||
                     !(worldPosition.Y < _spriteBatch.GraphicsDevice.Viewport.Height))
-                    return;
+                    continue;
 
                 // very naive render ...
                 if (string.Compare("PlayerShip", spatialName, StringComparison.InvariantCultureIgnoreCase) == 0)