diff --git a/shmupgame2022.sln b/shmupgame2022.sln
new file mode 100644
index 0000000000000000000000000000000000000000..e234d143a7adb6b3b78da9cc940cf85d797d1bf0
--- /dev/null
+++ b/shmupgame2022.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32228.343
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "shmupgame2022", "shmupgame2022\shmupgame2022.csproj", "{AC9D58F9-A2DB-45EA-9B91-517E5B09857C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "shmupgame2022Tests", "shmupgame2022Tests\shmupgame2022Tests.csproj", "{749E8F48-CD46-4A07-AB23-B230B7AE27D5}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AC9D58F9-A2DB-45EA-9B91-517E5B09857C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AC9D58F9-A2DB-45EA-9B91-517E5B09857C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AC9D58F9-A2DB-45EA-9B91-517E5B09857C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AC9D58F9-A2DB-45EA-9B91-517E5B09857C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{749E8F48-CD46-4A07-AB23-B230B7AE27D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{749E8F48-CD46-4A07-AB23-B230B7AE27D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{749E8F48-CD46-4A07-AB23-B230B7AE27D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{749E8F48-CD46-4A07-AB23-B230B7AE27D5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {168A0637-FC67-40DF-9729-0B8DA918FF7F}
+	EndGlobalSection
+EndGlobal
diff --git a/shmupgame2022/Content/Content.mgcb b/shmupgame2022/Content/Content.mgcb
new file mode 100644
index 0000000000000000000000000000000000000000..7e825c5d28d1d32333390eeb6a922cc0d560347c
--- /dev/null
+++ b/shmupgame2022/Content/Content.mgcb
@@ -0,0 +1,81 @@
+
+#----------------------------- Global Properties ----------------------------#
+
+/outputDir:bin/$(Platform)
+/intermediateDir:obj/$(Platform)
+/platform:DesktopGL
+/config:
+/profile:Reach
+/compress:False
+
+#-------------------------------- References --------------------------------#
+
+
+#---------------------------------- Content ---------------------------------#
+
+#begin Explosion.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/processorParam:Quality=Best
+/build:Explosion.wav
+
+#begin gameover.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyColor=255,0,255,255
+/processorParam:ColorKeyEnabled=True
+/processorParam:GenerateMipmaps=False
+/processorParam:PremultiplyAlpha=True
+/processorParam:ResizeToPowerOfTwo=False
+/processorParam:MakeSquare=False
+/processorParam:TextureFormat=Color
+/build:gameover.png
+
+#begin laser_shoot_enemy.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/processorParam:Quality=Best
+/build:laser_shoot_enemy.wav
+
+#begin Laser_Shoot_player.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/processorParam:Quality=Best
+/build:Laser_Shoot_player.wav
+
+#begin sovproj2022_bullet_ph_sprite.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyColor=255,0,255,255
+/processorParam:ColorKeyEnabled=True
+/processorParam:GenerateMipmaps=False
+/processorParam:PremultiplyAlpha=True
+/processorParam:ResizeToPowerOfTwo=False
+/processorParam:MakeSquare=False
+/processorParam:TextureFormat=Color
+/build:sovproj2022_bullet_ph_sprite.png
+
+#begin sovproj2022_enemy1_ph_sprite.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyColor=255,0,255,255
+/processorParam:ColorKeyEnabled=True
+/processorParam:GenerateMipmaps=False
+/processorParam:PremultiplyAlpha=True
+/processorParam:ResizeToPowerOfTwo=False
+/processorParam:MakeSquare=False
+/processorParam:TextureFormat=Color
+/build:sovproj2022_enemy1_ph_sprite.png
+
+#begin sovproj2022_player_ph_sprite.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyColor=255,0,255,255
+/processorParam:ColorKeyEnabled=True
+/processorParam:GenerateMipmaps=False
+/processorParam:PremultiplyAlpha=True
+/processorParam:ResizeToPowerOfTwo=False
+/processorParam:MakeSquare=False
+/processorParam:TextureFormat=Color
+/build:sovproj2022_player_ph_sprite.png
+
diff --git a/shmupgame2022/Content/Explosion.wav b/shmupgame2022/Content/Explosion.wav
new file mode 100644
index 0000000000000000000000000000000000000000..f99f61f1f4202024ad7c6085630c1e278fdbade4
Binary files /dev/null and b/shmupgame2022/Content/Explosion.wav differ
diff --git a/shmupgame2022/Content/Laser_Shoot_player.wav b/shmupgame2022/Content/Laser_Shoot_player.wav
new file mode 100644
index 0000000000000000000000000000000000000000..978a14905c22f123653756299f499ea368f91489
Binary files /dev/null and b/shmupgame2022/Content/Laser_Shoot_player.wav differ
diff --git a/shmupgame2022/Content/gameover.png b/shmupgame2022/Content/gameover.png
new file mode 100644
index 0000000000000000000000000000000000000000..16f4a4e79947c3a2d03d657fcb80b7d867f5da3b
Binary files /dev/null and b/shmupgame2022/Content/gameover.png differ
diff --git a/shmupgame2022/Content/laser_shoot_enemy.wav b/shmupgame2022/Content/laser_shoot_enemy.wav
new file mode 100644
index 0000000000000000000000000000000000000000..ecb4b743ac8c1f3d9d83269d42d278c5b8b7d486
Binary files /dev/null and b/shmupgame2022/Content/laser_shoot_enemy.wav differ
diff --git a/shmupgame2022/Content/sovproj2022_bullet_ph_sprite.png b/shmupgame2022/Content/sovproj2022_bullet_ph_sprite.png
new file mode 100644
index 0000000000000000000000000000000000000000..aa387eca45dd4ee806f063c5c6c69588add9659f
Binary files /dev/null and b/shmupgame2022/Content/sovproj2022_bullet_ph_sprite.png differ
diff --git a/shmupgame2022/Content/sovproj2022_enemy1_ph_sprite.png b/shmupgame2022/Content/sovproj2022_enemy1_ph_sprite.png
new file mode 100644
index 0000000000000000000000000000000000000000..c175c5b63afe95a8397fc37b1229e9d2037fe4be
Binary files /dev/null and b/shmupgame2022/Content/sovproj2022_enemy1_ph_sprite.png differ
diff --git a/shmupgame2022/Content/sovproj2022_player_ph_sprite.png b/shmupgame2022/Content/sovproj2022_player_ph_sprite.png
new file mode 100644
index 0000000000000000000000000000000000000000..d88319fd60b5aa083b2e7775452a08b8b06867ba
Binary files /dev/null and b/shmupgame2022/Content/sovproj2022_player_ph_sprite.png differ
diff --git a/shmupgame2022/EnemyBullet.cs b/shmupgame2022/EnemyBullet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e7e25f425ef1a3bf45a992c93f3ca05a1bbe13a
--- /dev/null
+++ b/shmupgame2022/EnemyBullet.cs
@@ -0,0 +1,52 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    class EnemyBullet : IGameEntity
+    {
+        public const float DEFAULT_SPEED = 2f;
+        public const float PLAYER_BULLET_SIZE = 4f;
+
+        private TextureManager _textureAssetManager;
+
+        public Vector2 Position { get; set; }
+        public Vector2 Speed { get; set; }
+        public int DrawOrder { get; set; } = 9;
+        public EntityType entityType { get; set; } = EntityType.ENEMY;
+        public bool IsDead { get; set; } = false;
+        public float Size { get; set; } = PLAYER_BULLET_SIZE;
+
+        public void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
+        {
+            SpriteBatch.Draw(_textureAssetManager.PlayerBulletTexture, this.Position, Color.Red);
+        }
+
+        public void Update(GameTime GameTime, PlayerShip player)
+        {
+            this.Position = this.Position + this.Speed;
+        }
+
+        public bool Collide(IGameEntity other)
+        {
+            if (other.entityType == EntityType.PLAYER)
+            {
+                this.IsDead = true;
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public EnemyBullet(Vector2 spawnLocation, Vector2 initialSpeed, TextureManager textureManager)
+        {
+            this.Position = spawnLocation;
+            this.Speed = initialSpeed * DEFAULT_SPEED;
+            this._textureAssetManager = textureManager;
+            this._textureAssetManager.ShootSoundEnemy.Play();
+        }
+    }
+}
diff --git a/shmupgame2022/EnemyShip.cs b/shmupgame2022/EnemyShip.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98f99f918f7ee36c68023c1b91b83547891a618c
--- /dev/null
+++ b/shmupgame2022/EnemyShip.cs
@@ -0,0 +1,56 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    public class EnemyShip : IGameEntity
+    {
+        private TextureManager _textureAssetManager;
+
+        public const float DEFAULT_SPEED = 0.3f;
+        public const float DEFAULT_RANDOMNESS = 0.4f;
+
+        public int DrawOrder { get; set; } = 8;
+        public Vector2 Speed { get; set; } = new Vector2(0, DEFAULT_SPEED);
+        public Vector2 Position { get; set; }
+        public EntityType entityType { get; set; } = EntityType.ENEMY;
+        public bool IsDead { get; set; } = false;
+        public float Size { get; set; } = 10f;
+        public float ShootingCooldown { get; set; } = 2f;
+        private Random RandomGenerator { get; set; }
+
+        public void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
+        {
+            SpriteBatch.Draw(this._textureAssetManager.EnemyShipTexture, this.Position - new Vector2(10,10), Color.White);
+        }
+
+        public void Update(GameTime GameTime, PlayerShip player)
+        {
+            this.Position = this.Position + this.Speed;
+            this.ShootingCooldown = this.ShootingCooldown - (float)GameTime.ElapsedGameTime.TotalSeconds;
+        }
+
+        public bool Collide(IGameEntity other)
+        {
+            if(other.entityType == EntityType.PLAYER)
+            {
+                this.IsDead = true;
+                return true;
+            }
+            return false;
+        }
+
+
+        public EnemyShip(TextureManager textureManager, Vector2 spawnPosition)
+        {
+            this.RandomGenerator = new Random();
+            this.Speed = this.Speed + new Vector2(0, DEFAULT_RANDOMNESS * ((float)this.RandomGenerator.NextDouble()));
+            this.ShootingCooldown = this.ShootingCooldown + (float)this.RandomGenerator.NextDouble();
+            this._textureAssetManager = textureManager;
+            this.Position = spawnPosition;
+        }
+    }
+}
diff --git a/shmupgame2022/EnemyWave.cs b/shmupgame2022/EnemyWave.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b341608ebe0b09f3b24983a59ea6b5ff49b42f43
--- /dev/null
+++ b/shmupgame2022/EnemyWave.cs
@@ -0,0 +1,14 @@
+namespace shmupgame2022
+{
+    internal class EnemyWave
+    {
+        public int EnemyNumber { get; set; }
+        public float SecondsToEncounter { get; set; }
+
+        public EnemyWave(int n, float seconds)
+        {
+            this.EnemyNumber = n;
+            this.SecondsToEncounter = seconds;
+        }
+    }
+}
\ No newline at end of file
diff --git a/shmupgame2022/EnemyWaveManager.cs b/shmupgame2022/EnemyWaveManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a1512b475350864d8ee0a869e583f4a10c3abfde
--- /dev/null
+++ b/shmupgame2022/EnemyWaveManager.cs
@@ -0,0 +1,63 @@
+using Microsoft.Xna.Framework;
+using System.Collections.Generic;
+
+namespace shmupgame2022
+{
+    internal class EnemyWaveManager
+    {
+        public const float ENEMY_WAVE_INTERVAL = 10f;
+        public const int ENEMY_WAVE_COUNT = 1;
+        public const int ENEMY_PER_WAVE = 4;
+
+        public List<EnemyWave> WaveQueue { get; set; }
+
+        public void addWave (EnemyWave wave)
+        {
+            this.WaveQueue.Add(wave);
+        }
+
+        public EnemyWave PopFirstWave()
+        {
+            if (this.WaveQueue.Count > 0)
+            {
+                EnemyWave wave = this.WaveQueue[0];
+                this.WaveQueue.RemoveAt(0);
+                return wave;
+            }
+            else
+                return null;
+        }
+
+        public bool TimeToSpawnNextWave()
+        {
+            if (this.WaveQueue.Count > 0 && this.WaveQueue[0].SecondsToEncounter <= 0)
+            {
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public void Update(GameTime gameTime)
+        {
+            if(this.WaveQueue.Count > 0)
+            {
+                this.WaveQueue[0].SecondsToEncounter = this.WaveQueue[0].SecondsToEncounter - (float)gameTime.ElapsedGameTime.TotalSeconds; 
+            }
+            else
+            {
+
+                this.addWave(new EnemyWave(ENEMY_PER_WAVE, ENEMY_WAVE_INTERVAL));
+            }
+        }
+
+        public EnemyWaveManager()
+        {
+            this.WaveQueue = new List<EnemyWave>();
+            for (int i = ENEMY_WAVE_COUNT; i > 0; i--)
+            {
+                this.addWave(new EnemyWave(ENEMY_PER_WAVE, ENEMY_WAVE_INTERVAL));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/shmupgame2022/EntityManager.cs b/shmupgame2022/EntityManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..50ebac98af91f7933a296baa04ae6ab31dac3ea2
--- /dev/null
+++ b/shmupgame2022/EntityManager.cs
@@ -0,0 +1,159 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    class EntityManager
+    {
+        List<IGameEntity> _gameEntities;
+        List<IGameEntity> _playerEntities;
+        List<IGameEntity> _enemyEntities;
+        InputController _inputController;
+        TextureManager _textureAssetManager;
+        PlayerShip _playerShip;
+        private Random _random;
+        private EnemyWaveManager _enemyWaveManager;
+
+        public const float STATIC_ENEMY_SHOOTING_INTERVAL = 4f;
+
+        public void AddEntity(IGameEntity Entity)
+        {
+            _gameEntities.Add(Entity);
+            if (Entity.entityType == EntityType.PLAYER)
+                _playerEntities.Add(Entity);
+            if (Entity.entityType == EntityType.ENEMY)
+                _enemyEntities.Add(Entity);
+        }
+
+        public void RemoveEntity(IGameEntity Entity)
+        {
+            _gameEntities.Remove(Entity);
+            if (Entity.entityType == EntityType.PLAYER)
+                _playerEntities.Remove(Entity);
+            if (Entity.entityType == EntityType.ENEMY)
+                _enemyEntities.Remove(Entity);
+        }
+
+        public void UpdateEntities(GameTime gameTime)
+        {
+            _inputController.PollControls();
+
+            foreach (IGameEntity e in _gameEntities)
+            {
+                e.Update(gameTime, _playerShip);
+            }
+            foreach (IGameEntity e in _playerEntities)
+            {
+                if(e.entityType == EntityType.PLAYER)
+                {
+                    foreach (IGameEntity entity in _enemyEntities)
+                    {
+                        if(CollisionDetected(e, entity))
+                        {
+                            e.Collide(entity);
+                            entity.Collide(e);
+                        }
+                    }
+                }
+            }
+            List<IGameEntity> shoot_list = new List<IGameEntity>();
+            foreach (IGameEntity e in _enemyEntities)
+            {
+                if (e is EnemyShip)
+                {
+                    EnemyShip eship = (EnemyShip)e;
+                    if (eship.ShootingCooldown <= 0)
+                    {
+                        Vector2 initialspeed = (_playerShip.Position - eship.Position);
+                        initialspeed.Normalize();
+                        shoot_list.Add(new EnemyBullet(eship.Position, initialspeed, _textureAssetManager));
+                        eship.ShootingCooldown = eship.ShootingCooldown + (float)_random.NextDouble() * 3f + STATIC_ENEMY_SHOOTING_INTERVAL;
+                    }
+                }
+            }
+            foreach (IGameEntity e in shoot_list)
+            {
+                this.AddEntity(e);
+            }
+            
+            List<IGameEntity> kill_list = new List<IGameEntity>();
+            foreach (IGameEntity e in _gameEntities)
+            {
+                if (e.IsDead || e.Position.Y > 650)
+                {
+                    kill_list.Add(e);
+                }
+            }
+            if(kill_list.Count > 0)
+            {
+                _textureAssetManager.ExplosionSound.Play();
+            }
+            foreach (IGameEntity e in kill_list)
+            {
+                this.RemoveEntity(e);
+                if (e is PlayerShip)
+                {
+                    this.AddEntity(new GameOverUI(_textureAssetManager));
+                }
+            }
+
+            _enemyWaveManager.Update(gameTime);
+
+            if(_enemyWaveManager.TimeToSpawnNextWave())
+            {
+                this.SpawnEnemyWave(_enemyWaveManager.PopFirstWave().EnemyNumber);
+            }
+        }
+
+        public void DrawEntities(SpriteBatch spriteBatch, GameTime gameTime)
+        {
+            if(spriteBatch != null)
+            {
+                foreach (IGameEntity e in _gameEntities)
+                {
+                    e.Draw(gameTime, spriteBatch);
+                }
+            }
+        }
+
+        public void SpawnPlayer()
+        {
+            PlayerShip ship = new PlayerShip(_textureAssetManager);
+            _inputController.playerShip = ship;
+            _playerShip = ship;
+            this.AddEntity(ship);
+        }
+
+        public void SpawnEnemyWave(int number)
+        {
+            for (int i = number; i > 0; i--)
+            {
+                this.AddEntity(new EnemyShip(_textureAssetManager, new Vector2((float)_random.NextDouble()*300, -10)));
+            }
+        }
+
+        public bool CollisionDetected(IGameEntity a, IGameEntity b)
+        {
+            if (Vector2.Distance(a.Position, b.Position) < (a.Size+b.Size))
+            {
+                return true;
+            }
+            return false;
+        }
+
+        public EntityManager(TextureManager textureManager)
+        {
+            _random = new Random();
+            _enemyWaveManager = new EnemyWaveManager();
+            _gameEntities = new List<IGameEntity>();
+            _playerEntities = new List<IGameEntity>();
+            _enemyEntities = new List<IGameEntity>();
+            _textureAssetManager = textureManager;
+            _inputController = new InputController(this, _textureAssetManager);
+
+        }
+    }
+}
diff --git a/shmupgame2022/GameOverUI.cs b/shmupgame2022/GameOverUI.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ade1c891e1eba48b11a01c6fa7574f4b3b7908a5
--- /dev/null
+++ b/shmupgame2022/GameOverUI.cs
@@ -0,0 +1,41 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    class GameOverUI : IGameEntity
+    {
+        public int DrawOrder { get; set; } = 12;
+        public EntityType entityType { get; set; } = EntityType.NONE;
+        public bool IsDead { get; set; } = false;
+        public Vector2 Position { get; set; }
+        public float Size { get; set; }
+
+        private TextureManager _textureAssetManager;
+
+        public bool Collide(IGameEntity other)
+        {
+            // doesn't collide in any way
+            return false;
+        }
+
+        public void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
+        {
+            SpriteBatch.Draw(_textureAssetManager.GameOverUITexture, this.Position, Color.White);
+        }
+
+        public void Update(GameTime GameTime, PlayerShip player)
+        {
+           // doesn't update in any way
+        }
+
+        public GameOverUI(TextureManager textureManager)
+        {
+            this._textureAssetManager = textureManager;
+            this.Position = new Vector2(75, 300);
+        }
+    }
+}
diff --git a/shmupgame2022/IGameEntity.cs b/shmupgame2022/IGameEntity.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ec24c37aa48767d8dba62fc56c59e9a8aae9193
--- /dev/null
+++ b/shmupgame2022/IGameEntity.cs
@@ -0,0 +1,22 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    public enum EntityType { NONE, PLAYER, ENEMY}
+
+    public interface IGameEntity
+    {
+        void Update(GameTime GameTime, PlayerShip player);
+        void Draw(GameTime GameTime, SpriteBatch SpriteBatch);
+        int DrawOrder { get; set; }
+        bool Collide(IGameEntity other);
+        EntityType entityType { get; set; }
+        bool IsDead { get; set; }
+        public Vector2 Position { get; set; }
+        public float Size { get; set; }
+    }
+}
diff --git a/shmupgame2022/Icon.bmp b/shmupgame2022/Icon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2b481653e241818d2894e4ef33234eaff9aad701
Binary files /dev/null and b/shmupgame2022/Icon.bmp differ
diff --git a/shmupgame2022/Icon.ico b/shmupgame2022/Icon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..7d9dec18704053ee43cd7c956022ddbdb34d8de1
Binary files /dev/null and b/shmupgame2022/Icon.ico differ
diff --git a/shmupgame2022/InputController.cs b/shmupgame2022/InputController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..861271dd319731fc77c5bc8d49e9bfa52451c678
--- /dev/null
+++ b/shmupgame2022/InputController.cs
@@ -0,0 +1,75 @@
+using Microsoft.Xna.Framework.Input;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    class InputController
+    {
+        private EntityManager _entityManager;
+        private TextureManager _textureAssetManager;
+
+        // this can be null, watch out!
+        public PlayerShip playerShip { get; set; }
+        
+        public InputController(EntityManager entityManager, TextureManager textureManager)
+        {
+            this._entityManager = entityManager;
+            this._textureAssetManager = textureManager;
+            
+        }
+
+        internal void PollControls()
+        {
+            if (playerShip != null)
+            {
+                if (Keyboard.GetState().IsKeyDown(Keys.Up))
+                {
+                    playerShip.IsMovingUp = true;
+                }
+                else
+                {
+                    playerShip.IsMovingUp = false;
+                }
+
+                if (Keyboard.GetState().IsKeyDown(Keys.Down))
+                {
+                    playerShip.IsMovingDown = true;
+                }
+                else
+                {
+                    playerShip.IsMovingDown = false;
+                }
+
+                if (Keyboard.GetState().IsKeyDown(Keys.Left))
+                {
+                    playerShip.IsMovingLeft = true;
+                }
+                else
+                {
+                    playerShip.IsMovingLeft = false;
+                }
+
+                if (Keyboard.GetState().IsKeyDown(Keys.Right))
+                {
+                    playerShip.IsMovingRight = true;
+                }
+                else
+                {
+                    playerShip.IsMovingRight = false;
+                }
+
+                if (Keyboard.GetState().IsKeyDown(Keys.Space))
+                {
+                    if(playerShip.ShootingCooldown <= 0)
+                    {
+                        playerShip.ShootingCooldown = 0.2f;
+                        _entityManager.AddEntity(new PlayerBullet(playerShip.Position, _textureAssetManager));
+                    }
+                }
+
+            }
+        }
+    }
+}
diff --git a/shmupgame2022/PlayerBullet.cs b/shmupgame2022/PlayerBullet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f10fe89937f485dcc99c6778d92c9e3858d5260d
--- /dev/null
+++ b/shmupgame2022/PlayerBullet.cs
@@ -0,0 +1,51 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    class PlayerBullet : IGameEntity
+    {
+        public const float DEFAULT_SPEED = 10f;
+        public const float PLAYER_BULLET_SIZE = 4f;
+
+        private TextureManager _textureAssetManager;
+
+        public Vector2 Position { get; set; }
+        public Vector2 Speed { get; set; } = new Vector2(0, -DEFAULT_SPEED);
+        public int DrawOrder { get; set; } = 9;
+        public EntityType entityType { get; set; } = EntityType.PLAYER;
+        public bool IsDead { get; set; } = false;
+        public float Size { get; set; } = PLAYER_BULLET_SIZE;
+
+        public void Draw(GameTime GameTime, SpriteBatch SpriteBatch)
+        {
+            SpriteBatch.Draw(_textureAssetManager.PlayerBulletTexture, this.Position, Color.White);
+        }
+
+        public void Update(GameTime GameTime, PlayerShip player)
+        {
+            this.Position = this.Position + this.Speed;
+        }
+
+        public bool Collide(IGameEntity other)
+        {
+            if (other.entityType == EntityType.ENEMY)
+            {
+                this.IsDead = true;
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public PlayerBullet(Vector2 spawnLocation, TextureManager textureManager)
+        {
+            this.Position = spawnLocation;
+            this._textureAssetManager = textureManager;
+            this._textureAssetManager.ShootSoundPlayer.Play();
+        }
+    }
+}
diff --git a/shmupgame2022/PlayerShip.cs b/shmupgame2022/PlayerShip.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8f9733579ab44afe63153629a3a567a74a6b9581
--- /dev/null
+++ b/shmupgame2022/PlayerShip.cs
@@ -0,0 +1,89 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    public class PlayerShip : IGameEntity
+    {
+        public const int SHIP_HEIGHT = 20;
+        public const int SHIP_WIDTH = 20;
+        public const float SHIP_SPEED = 100f;
+
+        public const int DEFAULT_X = 150;
+        public const int DEFAULT_Y = 400;
+
+        public const int SHIP_DRAW_ORDER = 10;
+
+        private TextureManager _textureAssetsManager;
+        public int DrawOrder { get; set; } = SHIP_DRAW_ORDER;
+
+        // Note: you can add vectors together
+        public Vector2 Position { get; set; } = new Vector2(DEFAULT_X, DEFAULT_Y);
+        
+        // Note: This method needs more advanced setters (never set to below zero), define later
+        public float ShootingCooldown { get; set; }
+
+        public Vector2 Speed { get; set; }
+
+        public bool IsMovingDown { get; set; } = false;
+        public bool IsMovingUp { get; set; } = false;
+        public bool IsMovingLeft { get; set; } = false;
+        public bool IsMovingRight { get; set; } = false;
+        public EntityType entityType { get; set; } = EntityType.PLAYER;
+        public bool IsDead { get; set; } = false;
+        public float Size { get; set; } = 10f;
+
+        public bool Die()
+        {
+            this.IsDead = true;
+            return true;
+        }
+
+        public void Update(GameTime gameTime, PlayerShip player)
+        {
+            this.Speed = Vector2.Zero;
+
+            if (this.IsMovingUp)
+                this.Speed = this.Speed + new Vector2(0, -SHIP_SPEED);
+            if (this.IsMovingDown)
+                this.Speed = this.Speed + new Vector2(0, SHIP_SPEED);
+            if (this.IsMovingLeft)
+                this.Speed = this.Speed + new Vector2(-SHIP_SPEED, 0);
+            if (this.IsMovingRight)
+                this.Speed = this.Speed + new Vector2(SHIP_SPEED, 0);
+
+            this.Position = this.Position + new Vector2(this.Speed.X, this.Speed.Y) * (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+            this.ShootingCooldown = this.ShootingCooldown - (float)gameTime.ElapsedGameTime.TotalSeconds;
+        }
+
+        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+        {
+            if (spriteBatch != null)
+            {
+                spriteBatch.Draw(this._textureAssetsManager.PlayerShipTexture, this.Position - new Vector2(13,13), Color.White);
+            }
+                
+        }
+
+        public bool Collide(IGameEntity other)
+        {
+            if(other.entityType == EntityType.ENEMY)
+            {
+                this.Die();
+                return true;
+            }
+            return false;
+        }
+
+        public PlayerShip(TextureManager textureManager)
+        {
+            this.Position = new Vector2(DEFAULT_X, DEFAULT_Y);
+            this._textureAssetsManager = textureManager;
+        }
+
+    }
+}
diff --git a/shmupgame2022/Program.cs b/shmupgame2022/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad2e956fb2c7fbec80b706d4bbd48ad9b04f8997
--- /dev/null
+++ b/shmupgame2022/Program.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace shmupgame2022
+{
+    public static class Program
+    {
+        [STAThread]
+        static void Main()
+        {
+            using (var game = new SHMUPgame())
+                game.Run();
+        }
+    }
+}
diff --git a/shmupgame2022/SHMUPgame.cs b/shmupgame2022/SHMUPgame.cs
new file mode 100644
index 0000000000000000000000000000000000000000..de062f059583ed022ca4cc85e73d9895e2494375
--- /dev/null
+++ b/shmupgame2022/SHMUPgame.cs
@@ -0,0 +1,101 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+
+namespace shmupgame2022
+{
+    public class SHMUPgame : Game
+    {
+        EntityManager _entityManager;
+
+        private const string ASSET_NAME_BULLET_SPRITE = "sovproj2022_bullet_ph_sprite";
+        private const string ASSET_NAME_ENEMY1_SPRITE = "sovproj2022_enemy1_ph_sprite";
+        private const string ASSET_NAME_PLAYER_SPRITE = "sovproj2022_player_ph_sprite";
+        private const string ASSET_NAME_GAME_OVER_SPRITE = "gameover";
+
+        private const string ASSET_NAME_EXPLOSION_SOUND = "Explosion";
+        private const string ASSET_NAME_PLAYER_SHOOT_SOUND = "Laser_Shoot_player";
+        private const string ASSET_NAME_ENEMY_SHOOT_SOUND = "laser_shoot_enemy";
+
+        private GraphicsDeviceManager _graphics;
+        private SpriteBatch _spriteBatch;
+
+        //this is how to use sound effects in monogame
+        //private SoundEffect _sfx_shoot;
+
+        private TextureManager _textureManager;
+
+
+        public SHMUPgame()
+        {
+            _graphics = new GraphicsDeviceManager(this);
+            _textureManager = new TextureManager();
+            Content.RootDirectory = "Content";
+            IsMouseVisible = true;
+        }
+
+        protected override void Initialize()
+        {
+            _graphics.PreferredBackBufferWidth = 300;  // set this value to the desired width of your window
+            _graphics.PreferredBackBufferHeight = 600;   // set this value to the desired height of your window
+            _graphics.ApplyChanges();
+            // TODO: Add your initialization logic here
+            _entityManager = new EntityManager(_textureManager);
+
+            base.Initialize();
+        }
+
+        protected override void LoadContent()
+        {
+            _spriteBatch = new SpriteBatch(GraphicsDevice);
+
+            // TODO: use this.Content to load your game content here
+
+            _textureManager.PlayerBulletTexture = Content.Load<Texture2D>(ASSET_NAME_BULLET_SPRITE);
+            _textureManager.EnemyShipTexture = Content.Load<Texture2D>(ASSET_NAME_ENEMY1_SPRITE);
+            _textureManager.PlayerShipTexture = Content.Load<Texture2D>(ASSET_NAME_PLAYER_SPRITE);
+            _textureManager.GameOverUITexture = Content.Load<Texture2D>(ASSET_NAME_GAME_OVER_SPRITE);
+
+            _textureManager.ShootSoundPlayer = Content.Load<SoundEffect>(ASSET_NAME_PLAYER_SHOOT_SOUND);
+            _textureManager.ShootSoundEnemy = Content.Load<SoundEffect>(ASSET_NAME_ENEMY_SHOOT_SOUND);
+            _textureManager.ExplosionSound = Content.Load<SoundEffect>(ASSET_NAME_EXPLOSION_SOUND);
+
+            // It's very awkward to tell the EntityManager to spawn the player entity here, but it's the only way to do it after assets are loaded
+            // This is probably due to threading
+            _entityManager.SpawnPlayer();
+            _entityManager.SpawnEnemyWave(7);
+
+        }
+
+        protected override void Update(GameTime gameTime)
+        {
+            // we leave this here for now
+            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
+                Exit();
+
+            // TODO: Add your update logic here
+            _entityManager.UpdateEntities(gameTime);
+            base.Update(gameTime);
+        }
+
+        protected override void Draw(GameTime gameTime)
+        {
+            GraphicsDevice.Clear(Color.Black);
+
+            _spriteBatch.Begin();
+            // TODO: Add your drawing code here
+
+            // just for testing purposes, let's render the 3 loaded sprites on the screen
+            //_spriteBatch.Draw(_bulletSprite, new Vector2(20, 20), Color.White);
+            //_spriteBatch.Draw(_enemy1Sprite, new Vector2(40, 20), Color.White);
+            //_spriteBatch.Draw(_playerSprite, new Vector2(60, 20), Color.White);
+
+            _entityManager.DrawEntities(_spriteBatch, gameTime);
+
+            _spriteBatch.End();
+
+            base.Draw(gameTime);
+        }
+    }
+}
diff --git a/shmupgame2022/Sovproj 2022.ncp b/shmupgame2022/Sovproj 2022.ncp
new file mode 100644
index 0000000000000000000000000000000000000000..3f8ae0f2176a4d4ffb7f80200926979ff02d417f
--- /dev/null
+++ b/shmupgame2022/Sovproj 2022.ncp	
@@ -0,0 +1,229 @@
+<Project>
+  <Name>Sovproj 2022</Name>
+  <ProjectItem type="NClass.DiagramEditor.ClassDiagram.Diagram" assembly="NClass.DiagramEditor, Version=2.4.1823.0, Culture=neutral, PublicKeyToken=null">
+    <Name>SHMUP game</Name>
+    <Language>CSharp</Language>
+    <Entities>
+      <Entity type="Class">
+        <Name>SHMUPgame</Name>
+        <Access>Public</Access>
+        <Location left="36" top="177" />
+        <Size width="326" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Field">EntityManager _entityManager</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>PlayerShip</Name>
+        <Access>Public</Access>
+        <Location left="438" top="769" />
+        <Size width="221" height="399" />
+        <Collapsed>False</Collapsed>
+        <Member type="Field">private const int SHIP_HEIGHT = 20</Member>
+        <Member type="Field">private float SHIP_SPEED = 5f</Member>
+        <Member type="Field">private int SHIP_WIDTH = 20</Member>
+        <Member type="Property">public bool IsAlive { get; set; }</Member>
+        <Member type="Property">public Vector2 Position { get; set; }</Member>
+        <Member type="Property">public float ShootingCooldown { get; set; }</Member>
+        <Member type="Property">public Vector2 Speed { get; set; }</Member>
+        <Member type="Method">public bool IsMovingDown()</Member>
+        <Member type="Method">public bool IsMovingLeft()</Member>
+        <Member type="Method">public bool IsMovingRight()</Member>
+        <Member type="Method">public bool IsMovingUp()</Member>
+        <Member type="Method">public bool Die()</Member>
+        <Member type="Method">public void Draw(gameTime GameTime, spriteBatch SpriteBatch)</Member>
+        <Member type="Method">public bool Shoot()</Member>
+        <Member type="Method">public void Update(gameTime GameTime)</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>EnemyShip</Name>
+        <Access>Public</Access>
+        <Location left="693" top="788" />
+        <Size width="162" height="216" />
+        <Collapsed>False</Collapsed>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>Bullet</Name>
+        <Access>Public</Access>
+        <Location left="895" top="88" />
+        <Size width="162" height="216" />
+        <Collapsed>False</Collapsed>
+        <Modifier>Abstract</Modifier>
+      </Entity>
+      <Entity type="Interface">
+        <Name>IGameEntity</Name>
+        <Access>Public</Access>
+        <Location left="438" top="290" />
+        <Size width="372" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Method">void Update(GameTime gameTime)</Member>
+        <Member type="Method">void Draw(gameTime GameTime, SpriteBatch spriteBatch)</Member>
+        <Member type="Property">int DrawOrder { get; }</Member>
+      </Entity>
+      <Entity type="Class">
+        <Name>Boss</Name>
+        <Access>Public</Access>
+        <Location left="980" top="769" />
+        <Size width="162" height="216" />
+        <Collapsed>False</Collapsed>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>BossSegment</Name>
+        <Access>Public</Access>
+        <Location left="1181" top="769" />
+        <Size width="162" height="216" />
+        <Collapsed>False</Collapsed>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>Game</Name>
+        <Access>Public</Access>
+        <Location left="36" top="29" />
+        <Size width="162" height="216" />
+        <Collapsed>True</Collapsed>
+        <Modifier>Abstract</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>BossBar</Name>
+        <Access>Public</Access>
+        <Location left="895" top="340" />
+        <Size width="269" height="216" />
+        <Collapsed>False</Collapsed>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>InputController</Name>
+        <Access>Public</Access>
+        <Location left="783" top="1030" />
+        <Size width="298" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Field">private PlayerShip _playerShip</Member>
+        <Member type="Method">public void ProcessControls(gameTime GameTime)</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>EntityManager</Name>
+        <Access>Public</Access>
+        <Location left="36" top="488" />
+        <Size width="365" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Field">private List&lt;IGameEntity&gt; _gameEntities</Member>
+        <Member type="Method">public void AddEntity(IGameEntity entity)</Member>
+        <Member type="Method">public void RemoveEntity(IGameEntity entity)</Member>
+        <Member type="Method">public void UpdateEntities(GameTime gameTime)</Member>
+        <Member type="Method">public void DrawEntities(SpriteBatch spriteBatch, GameTime gameTime)</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>EnemyWaveManager</Name>
+        <Access>Public</Access>
+        <Location left="47" top="788" />
+        <Size width="235" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Method">public bool NextWave(GameTime gameTime)</Member>
+        <Member type="Property">public List&lt;EnemyWave&gt; WaveQueue { get; set; }</Member>
+        <Member type="Method">public void AddWave(EnemyWave enemyWave)</Member>
+        <Member type="Method">public EnemyWave RemoveWave()</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+      <Entity type="Class">
+        <Name>EnemyWave</Name>
+        <Access>Public</Access>
+        <Location left="47" top="1073" />
+        <Size width="162" height="216" />
+        <Collapsed>False</Collapsed>
+        <Member type="Property">public int EnemyNumber { get; set; }</Member>
+        <Member type="Property">public float SecondsToWave { get; set; }</Member>
+        <Modifier>None</Modifier>
+      </Entity>
+    </Entities>
+    <Relationships>
+      <Relationship type="Realization" first="1" second="4">
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <BendPoint relativeToStartShape="False">
+          <X>478</X>
+          <Y>531</Y>
+        </BendPoint>
+      </Relationship>
+      <Relationship type="Realization" first="2" second="4">
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <BendPoint relativeToStartShape="False">
+          <X>551</X>
+          <Y>535</Y>
+        </BendPoint>
+      </Relationship>
+      <Relationship type="Realization" first="3" second="4">
+        <StartOrientation>Horizontal</StartOrientation>
+        <EndOrientation>Horizontal</EndOrientation>
+        <BendPoint relativeToStartShape="False">
+          <X>835</X>
+          <Y>317</Y>
+        </BendPoint>
+      </Relationship>
+      <Relationship type="Generalization" first="0" second="7">
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <BendPoint relativeToStartShape="False">
+          <X>139</X>
+          <Y>116</Y>
+        </BendPoint>
+      </Relationship>
+      <Relationship type="Realization" first="8" second="4">
+        <StartOrientation>Horizontal</StartOrientation>
+        <EndOrientation>Horizontal</EndOrientation>
+      </Relationship>
+      <Relationship type="Association" first="9" second="1">
+        <Label>controls</Label>
+        <StartOrientation>Horizontal</StartOrientation>
+        <EndOrientation>Horizontal</EndOrientation>
+        <Direction>Unidirectional</Direction>
+        <AssociationType>Aggregation</AssociationType>
+      </Relationship>
+      <Relationship type="Association" first="10" second="4">
+        <Label>
+        </Label>
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Horizontal</EndOrientation>
+        <BendPoint relativeToStartShape="True">
+          <X>235</X>
+          <Y>433</Y>
+        </BendPoint>
+        <Direction>Unidirectional</Direction>
+        <AssociationType>Aggregation</AssociationType>
+      </Relationship>
+      <Relationship type="Association" first="0" second="10">
+        <Label>
+        </Label>
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <BendPoint relativeToStartShape="True">
+          <X>88</X>
+          <Y>418</Y>
+        </BendPoint>
+        <Direction>Unidirectional</Direction>
+        <AssociationType>Composition</AssociationType>
+      </Relationship>
+      <Relationship type="Association" first="11" second="12">
+        <Label>
+        </Label>
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <Direction>Unidirectional</Direction>
+        <AssociationType>Composition</AssociationType>
+      </Relationship>
+      <Relationship type="Association" first="10" second="11">
+        <Label>
+        </Label>
+        <StartOrientation>Vertical</StartOrientation>
+        <EndOrientation>Vertical</EndOrientation>
+        <Direction>Unidirectional</Direction>
+        <AssociationType>Composition</AssociationType>
+      </Relationship>
+    </Relationships>
+  </ProjectItem>
+</Project>
\ No newline at end of file
diff --git a/shmupgame2022/TextureManager.cs b/shmupgame2022/TextureManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..446e633c3b23a94bcbde2752dc9123c7c82eabd9
--- /dev/null
+++ b/shmupgame2022/TextureManager.cs
@@ -0,0 +1,27 @@
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022
+{
+    public class TextureManager
+    {
+        public Texture2D PlayerShipTexture { get; set; }
+        public Texture2D PlayerBulletTexture { get; set; }
+        public Texture2D EnemyShipTexture { get; set; }
+        public Texture2D GameOverUITexture { get; set; }
+
+        public SoundEffect ExplosionSound { get; set; }
+        public SoundEffect ShootSoundPlayer { get; set; }
+        public SoundEffect ShootSoundEnemy { get; set; }
+
+
+        public TextureManager()
+        {
+
+        }
+
+    }
+}
diff --git a/shmupgame2022/app.manifest b/shmupgame2022/app.manifest
new file mode 100644
index 0000000000000000000000000000000000000000..657d45597984a8b64ab0f21aa0bf852cbe40f2b1
--- /dev/null
+++ b/shmupgame2022/app.manifest
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <assemblyIdentity version="1.0.0.0" name="shmupgame2022"/>
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- A list of the Windows versions that this application has been tested on and is
+           is designed to work with. Uncomment the appropriate elements and Windows will 
+           automatically selected the most compatible environment. -->
+
+      <!-- Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
+
+      <!-- Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
+
+      <!-- Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
+
+      <!-- Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
+
+      <!-- Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
+
+    </application>
+  </compatibility>
+
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
+      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2,permonitor</dpiAwareness>
+    </windowsSettings>
+  </application>
+
+</assembly>
diff --git a/shmupgame2022/shmupgame2022.csproj b/shmupgame2022/shmupgame2022.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..db416ef1c41cdf5a885978285eee24aa6a25f999
--- /dev/null
+++ b/shmupgame2022/shmupgame2022.csproj
@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>WinExe</OutputType>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <PublishReadyToRun>false</PublishReadyToRun>
+    <TieredCompilation>false</TieredCompilation>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+    <ApplicationIcon>Icon.ico</ApplicationIcon>
+  </PropertyGroup>
+  <ItemGroup>
+    <None Remove="Icon.ico" />
+    <None Remove="Icon.bmp" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Icon.ico" />
+    <EmbeddedResource Include="Icon.bmp" />
+  </ItemGroup>
+  <ItemGroup>
+    <MonoGameContentReference Include="Content\Content.mgcb" />
+  </ItemGroup>
+  <ItemGroup>
+    <TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.0.1641" />
+    <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.0.1641" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/shmupgame2022Test/UnitTest1.cs b/shmupgame2022Test/UnitTest1.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f69d6c6e5ce7edf5ee3a01d7e459c5f47a965b0c
--- /dev/null
+++ b/shmupgame2022Test/UnitTest1.cs
@@ -0,0 +1,13 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace shmupgame2022Test
+{
+    [TestClass]
+    public class UnitTest1
+    {
+        [TestMethod]
+        public void TestMethod1()
+        {
+        }
+    }
+}
diff --git a/shmupgame2022Test/shmupgame2022Test.csproj b/shmupgame2022Test/shmupgame2022Test.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..1c3ed2603a549acac16c848f99ac39a04de8c773
--- /dev/null
+++ b/shmupgame2022Test/shmupgame2022Test.csproj
@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
+    <PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
+    <PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
+    <PackageReference Include="coverlet.collector" Version="3.0.2" />
+  </ItemGroup>
+
+</Project>
diff --git a/shmupgame2022Tests/PlayerShipTests.cs b/shmupgame2022Tests/PlayerShipTests.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5aaba2e52a8eebc911a452b1a6d1e4a698a83dd2
--- /dev/null
+++ b/shmupgame2022Tests/PlayerShipTests.cs
@@ -0,0 +1,50 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Microsoft.Xna.Framework;
+using shmupgame2022;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace shmupgame2022.Tests
+{
+    [TestClass()]
+    public class PlayerShipTests
+    {
+        [TestMethod()]
+        public void DieTest()
+        {
+            PlayerShip testShip = new PlayerShip(new TextureManager());
+            testShip.Die();
+            Assert.IsTrue(testShip.IsDead);
+        }
+
+        [TestMethod()]
+        public void UpdateTest()
+        {
+            PlayerShip testShip = new PlayerShip(new TextureManager());
+            Vector2 initpos = testShip.Position;
+            testShip.Update(new GameTime(new TimeSpan(0, 1, 0), new TimeSpan(0, 0, 2), false), testShip);
+            if (initpos + testShip.Speed*2 != testShip.Position)
+            {
+                Assert.Fail();
+            }
+        }
+
+        [TestMethod()]
+        public void DrawTest()
+        {
+            PlayerShip testShip = new PlayerShip(new TextureManager());
+            Assert.IsTrue(true);
+            // we don't unit test graphical methods, not sure how that'd be even possible
+        }
+
+        [TestMethod()]
+        public void CollideTest()
+        {
+            PlayerShip testShip = new PlayerShip(new TextureManager());
+            EnemyShip testEnemyShip = new EnemyShip(new TextureManager(), new Microsoft.Xna.Framework.Vector2(0,0));
+            testShip.Collide(testEnemyShip);
+            Assert.IsTrue(testShip.IsDead);
+        }
+    }
+}
\ No newline at end of file
diff --git a/shmupgame2022Tests/shmupgame2022Tests.csproj b/shmupgame2022Tests/shmupgame2022Tests.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..e6e6829cc1956f992cb5582419fc365c3278929a
--- /dev/null
+++ b/shmupgame2022Tests/shmupgame2022Tests.csproj
@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>.NETCoreApp,Version=v3.1</TargetFramework>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
+    <PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
+    <PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
+    <PackageReference Include="coverlet.collector" Version="3.0.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\shmupgame2022\shmupgame2022.csproj" />
+  </ItemGroup>
+
+</Project>