From 804c03b1d853c2a3f0f72aca47b12f2e4050ab5a Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Mon, 5 Jan 2026 09:16:58 -0500 Subject: [PATCH] Added new enemy ships. Cleaned up enemy code. --- AlientAttack.MonoGame/GameLoops/GameLoop.cs | 18 ++++ .../Things/Enemies/Enemy02Green.cs | 72 ++++++++++++++ .../Things/Enemies/Enemy02Red.cs | 72 ++++++++++++++ .../Things/Enemies/Enemy02Teal.cs | 72 ++++++++++++++ .../Things/Enemies/EnemyShip.cs | 63 +++++++++++- .../Things/Enemies/GreenEnemy.cs | 95 ++++--------------- .../Things/Enemies/RedEnemy.cs | 48 +--------- .../Things/Enemies/TealEnemy.cs | 57 ++--------- AlientAttack.MonoGame/Things/Items/Item.cs | 5 +- 9 files changed, 333 insertions(+), 169 deletions(-) create mode 100644 AlientAttack.MonoGame/Things/Enemies/Enemy02Green.cs create mode 100644 AlientAttack.MonoGame/Things/Enemies/Enemy02Red.cs create mode 100644 AlientAttack.MonoGame/Things/Enemies/Enemy02Teal.cs diff --git a/AlientAttack.MonoGame/GameLoops/GameLoop.cs b/AlientAttack.MonoGame/GameLoops/GameLoop.cs index 52cf1de..9d248b8 100644 --- a/AlientAttack.MonoGame/GameLoops/GameLoop.cs +++ b/AlientAttack.MonoGame/GameLoops/GameLoop.cs @@ -344,6 +344,24 @@ internal class GameLoop : GameLoopBase Sprites.Add(enemy); _spawnNewEnemyThreshold = 100 + _random.Next(0, 100); } + else if (randomNumber == 3) + { + Enemy02Green enemy = new(_random.Next(0, ViewTransform.ScreenWidth - 64), -64); + Sprites.Add(enemy); + _spawnNewEnemyThreshold = 100 + _random.Next(0, 100); + } + else if (randomNumber == 4) + { + Enemy02Red enemy = new(_random.Next(0, ViewTransform.ScreenWidth - 64), -64); + Sprites.Add(enemy); + _spawnNewEnemyThreshold = 100 + _random.Next(0, 100); + } + else if (randomNumber == 5) + { + Enemy02Teal enemy = new(_random.Next(0, ViewTransform.ScreenWidth - 64), -64); + Sprites.Add(enemy); + _spawnNewEnemyThreshold = 100 + _random.Next(0, 100); + } } } } diff --git a/AlientAttack.MonoGame/Things/Enemies/Enemy02Green.cs b/AlientAttack.MonoGame/Things/Enemies/Enemy02Green.cs new file mode 100644 index 0000000..55e9d01 --- /dev/null +++ b/AlientAttack.MonoGame/Things/Enemies/Enemy02Green.cs @@ -0,0 +1,72 @@ +using AlienAttack.MonoGame.Things.Bullets; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace AlienAttack.MonoGame.Things.Enemies; + +public class Enemy02Green : EnemyShip +{ + public const int Width = 64; + public const int Height = 64; + + protected int FireThreshold => 20; + protected int CurrentFireThreshold { get; set; } = 20; + protected override int Health { get; set; } = 5; + + public Enemy02Green(int x, int y) : base(x, y) + { + BoundBox = new(0, 0, Width, Height); + YVelocity = 2; + XVelocity = 0; + } + + public override void Draw(SpriteDrawArgs args) + { + int frame = XVelocity > 0 ? 2 : XVelocity < 0 ? 3 : 1; + SpriteEffects spriteEffects = XVelocity > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None; + Texture2D texture = args.Content.Load(@$"Sprites\Enemy02Green_Frame_{frame}_png_processed"); + //SpriteEffects spriteEffects = SpriteEffects.None; + + args.SpriteBatch.Draw(texture, Position, null, DrawColor, 0, new Vector2(0, 0), 1, spriteEffects, 1); + + base.Draw(args); + } + + protected override void TryMove(SpriteUpdateContext context) + { + if (XPosition + BoundBox.Width >= context.ViewTransform.ScreenWidth) + { + XPosition = context.ViewTransform.ScreenWidth - BoundBox.Width; + XVelocity *= -1; + } + else if (XPosition <= 0) + { + XPosition = 0; + XVelocity *= -1; + } + } + + protected override void TryFire(SpriteUpdateContext context) + { + if (CurrentFireThreshold > 0) + { + CurrentFireThreshold--; + } + + if (CurrentFireThreshold == 0 && context.Random.Next(0, 30) == 1) + { + float originX = XPosition + (BoundBox.Width / 2) - (7 / 2); + + //context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + //context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + + context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, -1, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 3, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 1, 2 + YVelocity, this)); + + CurrentFireThreshold = FireThreshold; + + context.AudioManager.PlayEnemyFire(); + } + } +} \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/Enemy02Red.cs b/AlientAttack.MonoGame/Things/Enemies/Enemy02Red.cs new file mode 100644 index 0000000..a5346d1 --- /dev/null +++ b/AlientAttack.MonoGame/Things/Enemies/Enemy02Red.cs @@ -0,0 +1,72 @@ +using AlienAttack.MonoGame.Things.Bullets; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace AlienAttack.MonoGame.Things.Enemies; + +public class Enemy02Red : EnemyShip +{ + public const int Width = 64; + public const int Height = 64; + + protected int FireThreshold => 20; + protected int CurrentFireThreshold { get; set; } = 20; + protected override int Health { get; set; } = 5; + + public Enemy02Red(int x, int y) : base(x, y) + { + BoundBox = new(0, 0, Width, Height); + YVelocity = 3; + XVelocity = 0; + } + + public override void Draw(SpriteDrawArgs args) + { + int frame = XVelocity > 0 ? 2 : XVelocity < 0 ? 3 : 1; + SpriteEffects spriteEffects = XVelocity > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None; + Texture2D texture = args.Content.Load(@$"Sprites\Enemy02Red_Frame_{frame}_png_processed"); + //SpriteEffects spriteEffects = SpriteEffects.None; + + args.SpriteBatch.Draw(texture, Position, null, DrawColor, 0, new Vector2(0, 0), 1, spriteEffects, 1); + + base.Draw(args); + } + + protected override void TryMove(SpriteUpdateContext context) + { + if (XPosition + BoundBox.Width >= context.ViewTransform.ScreenWidth) + { + XPosition = context.ViewTransform.ScreenWidth - BoundBox.Width; + XVelocity *= -1; + } + else if (XPosition <= 0) + { + XPosition = 0; + XVelocity *= -1; + } + } + + protected override void TryFire(SpriteUpdateContext context) + { + if (CurrentFireThreshold > 0) + { + CurrentFireThreshold--; + } + + if (CurrentFireThreshold == 0 && context.Random.Next(0, 30) == 1) + { + float originX = XPosition + (BoundBox.Width / 2) - (7 / 2); + + //context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + //context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + + context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, -1, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 3, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 1, 2 + YVelocity, this)); + + CurrentFireThreshold = FireThreshold; + + context.AudioManager.PlayEnemyFire(); + } + } +} \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/Enemy02Teal.cs b/AlientAttack.MonoGame/Things/Enemies/Enemy02Teal.cs new file mode 100644 index 0000000..590a859 --- /dev/null +++ b/AlientAttack.MonoGame/Things/Enemies/Enemy02Teal.cs @@ -0,0 +1,72 @@ +using AlienAttack.MonoGame.Things.Bullets; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace AlienAttack.MonoGame.Things.Enemies; + +public class Enemy02Teal : EnemyShip +{ + public const int Width = 64; + public const int Height = 64; + + protected int FireThreshold => 20; + protected int CurrentFireThreshold { get; set; } = 20; + protected override int Health { get; set; } = 5; + + public Enemy02Teal(int x, int y) : base(x, y) + { + BoundBox = new(0, 0, Width, Height); + YVelocity = 1; + XVelocity = 4; + } + + public override void Draw(SpriteDrawArgs args) + { + int frame = XVelocity > 0 ? 2 : XVelocity < 0 ? 3 : 1; + SpriteEffects spriteEffects = XVelocity > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None; + Texture2D texture = args.Content.Load(@$"Sprites\Enemy02_Teal_Frame_{frame}_png_processed"); + //SpriteEffects spriteEffects = SpriteEffects.None; + + args.SpriteBatch.Draw(texture, Position, null, DrawColor, 0, new Vector2(0, 0), 1, spriteEffects, 1); + + base.Draw(args); + } + + protected override void TryMove(SpriteUpdateContext context) + { + if (XPosition + BoundBox.Width >= context.ViewTransform.ScreenWidth) + { + XPosition = context.ViewTransform.ScreenWidth - BoundBox.Width; + XVelocity *= -1; + } + else if (XPosition <= 0) + { + XPosition = 0; + XVelocity *= -1; + } + } + + protected override void TryFire(SpriteUpdateContext context) + { + if (CurrentFireThreshold > 0) + { + CurrentFireThreshold--; + } + + if (CurrentFireThreshold == 0 && context.Random.Next(0, 30) == 1) + { + float originX = XPosition + (BoundBox.Width / 2) - (7 / 2); + + //context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + //context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + + context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, -1, 3 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 3, YPosition + BoundBox.Height - 12, 0, 3 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 1, 3 + YVelocity, this)); + + CurrentFireThreshold = FireThreshold; + + context.AudioManager.PlayEnemyFire(); + } + } +} \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/EnemyShip.cs b/AlientAttack.MonoGame/Things/Enemies/EnemyShip.cs index 3eee471..809fce2 100644 --- a/AlientAttack.MonoGame/Things/Enemies/EnemyShip.cs +++ b/AlientAttack.MonoGame/Things/Enemies/EnemyShip.cs @@ -1,6 +1,67 @@ -namespace AlienAttack.MonoGame.Things.Enemies; +using AlienAttack.MonoGame.Things.Bullets; + +namespace AlienAttack.MonoGame.Things.Enemies; public abstract class EnemyShip(int x, int y) : MoveableSprite(x, y) { + protected abstract int Health { get; set; } + public virtual int CrashDamage => 10; + + public override sealed void Update(SpriteUpdateContext context) + { + if (Health <= 0) + { + IsDead = true; + SpawnExplosion(context); + OnKilled(context); + return; + } + + base.Update(context); + + TryMove(context); + + if (YPosition > context.ViewTransform.ScreenHeight) + { + IsDead = true; + return; + } + + TryFire(context); + } + + protected virtual void TryMove(SpriteUpdateContext context) + { + + } + + protected virtual void TryFire(SpriteUpdateContext context) + { + + } + + public override void OnCollision(SpriteCollisionContext context) + { + if (context.Sprite is Bullet bullet && bullet.Owner is Player) + { + Health -= bullet.Damage; + } + + if (context.Sprite is Player) + { + Health = 0; + } + } + + private void SpawnExplosion(SpriteUpdateContext context) + { + context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity)); + context.AudioManager.PlayExplosion(); + } + + protected virtual void OnKilled(SpriteUpdateContext context) + { + + } } \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/GreenEnemy.cs b/AlientAttack.MonoGame/Things/Enemies/GreenEnemy.cs index 3dd21cb..264d47d 100644 --- a/AlientAttack.MonoGame/Things/Enemies/GreenEnemy.cs +++ b/AlientAttack.MonoGame/Things/Enemies/GreenEnemy.cs @@ -14,7 +14,7 @@ public class GreenEnemy : EnemyShip protected ICollection ActiveWeapons = []; protected int FireThreshold => 20; protected int CurrentFireThreshold { get; set; } = 20; - protected int Health { get; set; } = 5; + protected override int Health { get; set; } = 5; public GreenEnemy(int x, int y) : base(x, y) { @@ -34,43 +34,8 @@ public class GreenEnemy : EnemyShip base.Draw(args); } - public override void Update(SpriteUpdateContext context) + protected override void TryFire(SpriteUpdateContext context) { - //YPosition += 1; - - if (Health <= 0) - { - IsDead = true; - SpawnExplosion(context); - - switch (context.Random.Next(0, 5)) - { - case 0: - context.SpawnSprite(new Health((int)XPosition, (int)YPosition)); - break; - case 1: - context.SpawnSprite(new Shields((int)XPosition, (int)YPosition)); - break; - case 2: - context.SpawnSprite(new Ammo((int)XPosition, (int)YPosition)); - break; - case 3: - context.SpawnSprite(new Energy((int)XPosition, (int)YPosition)); - break; - case 4: - context.SpawnSprite(new Rockets((int)XPosition, (int)YPosition)); - break; - } - - return; - } - - if (YPosition > context.ViewTransform.ScreenHeight) - { - IsDead = true; - return; - } - if (CurrentFireThreshold > 0) { CurrentFireThreshold--; @@ -87,48 +52,30 @@ public class GreenEnemy : EnemyShip context.AudioManager.PlayEnemyFire(); } - - //CheckMove(context); - CheckFire(context); - - base.Update(context); } - private void SpawnExplosion(SpriteUpdateContext context) + protected override void OnKilled(SpriteUpdateContext context) { - context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity)); + int itemXPosition = (int)XPosition + 32 - Item.Width / 2; + int itemYPosition = (int)YPosition + 32 - Item.Height / 2; - //int number = context.Random.Next(1, 7); - - //SoundEffect soundEffect = context.Content.Load(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS"); - //soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0); - - context.AudioManager.PlayExplosion(); - } - - private void CheckFire(SpriteUpdateContext context) - { - //foreach (IWeapon weapon in ActiveWeapons) - //{ - // weapon.UpdateFireThreshold(); - //} - - //foreach (IWeapon weapon in ActiveWeapons) - //{ - // weapon.TryFire(this, context); - //} - } - - public override void OnCollision(SpriteCollisionContext context) - { - if (context.Sprite is Bullet bullet && bullet.Owner is Player) + switch (context.Random.Next(0, 5)) { - Health -= bullet.Damage; - } - - if (context.Sprite is Player) - { - Health = 0; + case 0: + context.SpawnSprite(new Health(itemXPosition, itemYPosition)); + break; + case 1: + context.SpawnSprite(new Shields(itemXPosition, itemYPosition)); + break; + case 2: + context.SpawnSprite(new Ammo(itemXPosition, itemYPosition)); + break; + case 3: + context.SpawnSprite(new Energy(itemXPosition, itemYPosition)); + break; + case 4: + context.SpawnSprite(new Rockets(itemXPosition, itemYPosition)); + break; } } } \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/RedEnemy.cs b/AlientAttack.MonoGame/Things/Enemies/RedEnemy.cs index 29b47b1..62c614d 100644 --- a/AlientAttack.MonoGame/Things/Enemies/RedEnemy.cs +++ b/AlientAttack.MonoGame/Things/Enemies/RedEnemy.cs @@ -8,7 +8,7 @@ public class RedEnemy : EnemyShip { protected int FireThreshold => 20; protected int CurrentFireThreshold { get; set; } = 20; - protected int Health { get; set; } = 5; + protected override int Health { get; set; } = 5; public RedEnemy(int x, int y) : base(x, y) { @@ -28,7 +28,7 @@ public class RedEnemy : EnemyShip base.Draw(args); } - public override void Update(SpriteUpdateContext context) + protected override void TryMove(SpriteUpdateContext context) { //YPosition += 2; //if (YPosition > context.ViewTransform.ScreenHeight / 5 - BoundBox.Y / 2) @@ -49,38 +49,9 @@ public class RedEnemy : EnemyShip // XVelocity = 0; // } //} - - if (Health <= 0) - { - IsDead = true; - SpawnExplosion(context); - return; - } - - if (YPosition > context.ViewTransform.ScreenHeight) - { - IsDead = true; - return; - } - - TryFire(context); - - base.Update(context); } - private void SpawnExplosion(SpriteUpdateContext context) - { - context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity)); - - //int number = context.Random.Next(1, 7); - - //SoundEffect soundEffect = context.Content.Load(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS"); - //soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0); - - context.AudioManager.PlayExplosion(); - } - - private void TryFire(SpriteUpdateContext context) + protected override void TryFire(SpriteUpdateContext context) { if (CurrentFireThreshold > 0) { @@ -100,17 +71,4 @@ public class RedEnemy : EnemyShip context.AudioManager.PlayEnemyFire(); } } - - public override void OnCollision(SpriteCollisionContext context) - { - if (context.Sprite is Bullet bullet && bullet.Owner is Player) - { - Health -= bullet.Damage; - } - - if (context.Sprite is Player) - { - Health = 0; - } - } } \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Enemies/TealEnemy.cs b/AlientAttack.MonoGame/Things/Enemies/TealEnemy.cs index 0fdb29f..b8bf8cc 100644 --- a/AlientAttack.MonoGame/Things/Enemies/TealEnemy.cs +++ b/AlientAttack.MonoGame/Things/Enemies/TealEnemy.cs @@ -8,7 +8,7 @@ public class TealEnemy : EnemyShip { protected int FireThreshold => 20; protected int CurrentFireThreshold { get; set; } = 20; - protected int Health { get; set; } = 5; + protected override int Health { get; set; } = 5; public TealEnemy(int x, int y) : base(x, y) { @@ -29,7 +29,7 @@ public class TealEnemy : EnemyShip base.Draw(args); } - public override void Update(SpriteUpdateContext context) + protected override void TryMove(SpriteUpdateContext context) { if (XPosition + BoundBox.Width >= context.ViewTransform.ScreenWidth) { @@ -41,39 +41,9 @@ public class TealEnemy : EnemyShip XPosition = 0; XVelocity *= -1; } - - if (Health <= 0) - { - IsDead = true; - SpawnExplosion(context); - return; - } - - if (YPosition > context.ViewTransform.ScreenHeight) - { - IsDead = true; - return; - } - - //CheckMove(context); - TryFire(context); - - base.Update(context); } - private void SpawnExplosion(SpriteUpdateContext context) - { - context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity)); - - //int number = context.Random.Next(1, 7); - - //SoundEffect soundEffect = context.Content.Load(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS"); - //soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0); - - context.AudioManager.PlayExplosion(); - } - - private void TryFire(SpriteUpdateContext context) + protected override void TryFire(SpriteUpdateContext context) { if (CurrentFireThreshold > 0) { @@ -84,25 +54,16 @@ public class TealEnemy : EnemyShip { float originX = XPosition + (BoundBox.Width / 2) - (7 / 2); - context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); - context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + //context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + //context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + + context.SpawnSprite(new MinigunBulletSmall(originX - 9, YPosition + BoundBox.Height - 12, -1, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 3, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this)); + context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 1, 2 + YVelocity, this)); CurrentFireThreshold = FireThreshold; context.AudioManager.PlayEnemyFire(); } } - - public override void OnCollision(SpriteCollisionContext context) - { - if (context.Sprite is Bullet bullet && bullet.Owner is Player) - { - Health -= bullet.Damage; - } - - if (context.Sprite is Player) - { - Health = 0; - } - } } \ No newline at end of file diff --git a/AlientAttack.MonoGame/Things/Items/Item.cs b/AlientAttack.MonoGame/Things/Items/Item.cs index aeeafa0..2f6d00b 100644 --- a/AlientAttack.MonoGame/Things/Items/Item.cs +++ b/AlientAttack.MonoGame/Things/Items/Item.cs @@ -14,12 +14,15 @@ public abstract class Item : MoveableSprite protected string TextureName; + public const int Width = 48; + public const int Height = 29; + protected abstract PickupKind Kind { get; } public Item(int x, int y) : base(x, y) { YVelocity = .5f; - BoundBox = new Rectangle(0, 0, 48, 29); + BoundBox = new Rectangle(0, 0, Width, Height); _anchor = new Vector2(x, y); }