diff options
| -rw-r--r-- | Penguloon/Enemies/EnemyBase.cs | 88 | ||||
| -rw-r--r-- | Penguloon/Enemies/RedBalloon.cs | 15 | ||||
| -rw-r--r-- | Penguloon/Levels/IceLevel.cs | 7 | ||||
| -rw-r--r-- | Penguloon/Levels/LevelBase.cs | 4 | ||||
| -rw-r--r-- | Penguloon/Levels/Map.cs | 51 | ||||
| -rw-r--r-- | Penguloon/Levels/WaveManager.cs | 77 | ||||
| -rw-r--r-- | Penguloon/Penguloon.csproj | 3 | ||||
| -rw-r--r-- | Penguloon/Scenes/GameScene.cs | 36 | ||||
| -rw-r--r-- | Penguloon/StaticUIValues.cs | 4 |
9 files changed, 275 insertions, 10 deletions
diff --git a/Penguloon/Enemies/EnemyBase.cs b/Penguloon/Enemies/EnemyBase.cs new file mode 100644 index 0000000..2179e58 --- /dev/null +++ b/Penguloon/Enemies/EnemyBase.cs @@ -0,0 +1,88 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Penguloon.Levels; + +namespace Penguloon.Enemies +{ + public abstract class EnemyBase + { + public float Speed { get; set; } + + public int Health { get; set; } + + public Vector2 Position { get; set; } + public Vector2 TargetPosition { get; set; } + + public Texture2D Texture { get; set; } + + public Map Map { get; set; } + + public bool MovingTowardsFinish { get; set; } = false; + + public Type ChildObject { get; set; } + + public EnemyBase(Map map) + { + this.Map = map; + + this.Position = Map.SpawnPoint; + this.TargetPosition = Map.SpawnPointTargetPos; + } + + public void Update(float deltaTime) + { + int tileX = (int)(TargetPosition.X + 2) / Map.TileWidth; + int tileY = (int)(TargetPosition.Y + 2) / Map.TileHeight; + + if (Vector2.Distance(Position, TargetPosition) <= 3) + { + if(MovingTowardsFinish) + { + ReachEnd(); + return; + } + + Tile currentTile = Map.TileMap[tileY, tileX]; + + switch (currentTile.Direction) + { + case Direction.Up: TargetPosition = new Vector2(tileX * Map.TileWidth, (tileY - 1) * Map.TileHeight); break; + case Direction.Down: TargetPosition = new Vector2(tileX * Map.TileWidth, (tileY + 1) * Map.TileHeight); break; + case Direction.Left: TargetPosition = new Vector2((tileX - 1) * Map.TileWidth, tileY * Map.TileHeight); break; + case Direction.Right: TargetPosition = new Vector2((tileX + 1) * Map.TileWidth, tileY * Map.TileHeight); break; + case Direction.Finish: TargetPosition = Map.FinishPoint; MovingTowardsFinish = true; break; + } + } + + Vector2 movement = TargetPosition - Position; + movement.Normalize(); + + this.Position += (movement * Speed) * deltaTime; + } + + private void ReachEnd() + { + Map.Enemies.Remove(this); + } + + public void GetHit() + { + Health--; + + if (Health <= 0) + Map.Enemies.Remove(this); + + SpawnChild(); + + // play pop sound + } + + private void SpawnChild() + { + if (this.ChildObject == null) return; + + Map.SpawnEnemy(ChildObject, Position, TargetPosition); + } + } +}
\ No newline at end of file diff --git a/Penguloon/Enemies/RedBalloon.cs b/Penguloon/Enemies/RedBalloon.cs new file mode 100644 index 0000000..cfe9caf --- /dev/null +++ b/Penguloon/Enemies/RedBalloon.cs @@ -0,0 +1,15 @@ +using Penguloon.Levels; + +namespace Penguloon.Enemies +{ + class RedBalloon : EnemyBase + { + public RedBalloon(Map map) : base(map) + { + this.Texture = ContentManager.GetTexture("Enemies/red"); + this.Speed = 135f; + this.Health = 1; + this.ChildObject = null; + } + } +}
\ No newline at end of file diff --git a/Penguloon/Levels/IceLevel.cs b/Penguloon/Levels/IceLevel.cs index 5f8b4c7..47569a8 100644 --- a/Penguloon/Levels/IceLevel.cs +++ b/Penguloon/Levels/IceLevel.cs @@ -1,4 +1,6 @@ -using Microsoft.Xna.Framework.Input.Touch; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input.Touch; +using Penguloon.Enemies; using Penguloon.Scenes; namespace Penguloon.Levels @@ -23,6 +25,9 @@ namespace Penguloon.Levels public override void CreateMap() { Map = new Map(ParentScene); + Map.SpawnPoint = new Vector2(1 * Map.TileWidth, -1 * Map.TileHeight); + Map.SpawnPointTargetPos = new Vector2(1 * Map.TileWidth, 0 * Map.TileHeight); + Map.FinishPoint = new Vector2(18 * Map.TileWidth, 2 * Map.TileHeight); Tile OO = new Tile(0, Direction.None); diff --git a/Penguloon/Levels/LevelBase.cs b/Penguloon/Levels/LevelBase.cs index de17caf..7e88cb7 100644 --- a/Penguloon/Levels/LevelBase.cs +++ b/Penguloon/Levels/LevelBase.cs @@ -12,6 +12,10 @@ namespace Penguloon.Levels public Map Map { get; set; } + public int Health { get; set; } + + public int Money { get; set; } + public LevelBase() { diff --git a/Penguloon/Levels/Map.cs b/Penguloon/Levels/Map.cs index 699d9eb..19fd7c0 100644 --- a/Penguloon/Levels/Map.cs +++ b/Penguloon/Levels/Map.cs @@ -1,6 +1,9 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Penguloon.Enemies; using Penguloon.Scenes; +using System.Collections.Generic; +using System; namespace Penguloon.Levels { @@ -17,6 +20,14 @@ namespace Penguloon.Levels public SceneBase ParentScene { get; set; } + public List<EnemyBase> Enemies { get; set; } = new List<EnemyBase>(); + + public Vector2 SpawnPoint { get; set; } + public Vector2 SpawnPointTargetPos { get; set; } + public Vector2 FinishPoint { get; set; } + + public WaveManager WaveManager { get; set; } + public Map(SceneBase parentScene) { this.ParentScene = parentScene; @@ -28,6 +39,8 @@ namespace Penguloon.Levels TileHeight = MapHeight / 13; MapWidth = TileWidth * 18; + + WaveManager = new WaveManager(this); } public void Draw(float deltaTime) @@ -42,11 +55,49 @@ namespace Penguloon.Levels destinationRectangle: new Rectangle(x * TileWidth, y * TileHeight, TileWidth, TileHeight)); } } + + for (int i = 0; i < Enemies.Count; i++) + { + if (Enemies[i].Texture != null) + ParentScene.Main.SpriteBatch.Draw(Enemies[i].Texture, + destinationRectangle: new Rectangle((int)Enemies[i].Position.X, (int)Enemies[i].Position.Y, TileWidth, TileHeight)); + } } public void Update(float deltaTime) { + for (int i = 0; i < Enemies.Count; i++) + Enemies[i].Update(deltaTime); + + CheckIfRoundCompleted(); + } + private void CheckIfRoundCompleted() + { + if(Enemies.Count == 0 && WaveManager.DoneSpawning && WaveManager.RoundActive) + { + WaveManager.RoundActive = false; + } + } + + public void SpawnEnemy(Type childObject, Vector2 position, Vector2 targetPosition) + { + AddEnemyToList(position, targetPosition, childObject); + } + + public void SpawnEnemy(Type childObject) + { + AddEnemyToList(SpawnPoint, SpawnPointTargetPos, childObject); + } + + private void AddEnemyToList(Vector2 pos, Vector2 target, Type type) + { + if (type == typeof(RedBalloon)) + { + var b = new RedBalloon(this); + b.Position = pos; b.TargetPosition = target; + Enemies.Add(b); + } } } diff --git a/Penguloon/Levels/WaveManager.cs b/Penguloon/Levels/WaveManager.cs new file mode 100644 index 0000000..1a425a1 --- /dev/null +++ b/Penguloon/Levels/WaveManager.cs @@ -0,0 +1,77 @@ +using Penguloon.Enemies; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Penguloon.Levels +{ + public class WaveManager + { + public List<Wave> Waves { get; set; } = new List<Wave>(); + + public Map Map { get; set; } + + public int CurrentWave { get; set; } = 1; + + public bool RoundActive { get; set; } + + public bool DoneSpawning { get; set; } = false; + + public WaveManager(Map map) + { + this.Map = map; + + CreateWaves(); + } + + private void CreateWaves() + { + Waves.Add(new Wave(new List<Tuple<Type, int>>() { new Tuple<Type, int>(typeof(RedBalloon), 5) }, 500)); + } + + public void StartSpawningEnemies() + { + RoundActive = true; + DoneSpawning = false; + + new Thread(() => + { + Thread.CurrentThread.IsBackground = true; + + int waveToSpawn = CurrentWave - 1; + + if (waveToSpawn >= Waves.Count) + waveToSpawn = Waves.Count - 1; + + for (int i = 0; i < Waves[waveToSpawn].EnemiesToSpawn.Count; i++) + { + for(int x = 0; x < Waves[waveToSpawn].EnemiesToSpawn[i].Item2; x++) + { + Map.SpawnEnemy(Waves[waveToSpawn].EnemiesToSpawn[i].Item1); + Thread.Sleep(Waves[waveToSpawn].SpawnDelayMS); + } + } + + DoneSpawning = true; + + }).Start(); + } + + internal void FinishRound() + { + CurrentWave++; + } + } + + public class Wave + { + public int SpawnDelayMS { get; set; } + public List<Tuple<Type, int>> EnemiesToSpawn { get; set; } = new List<Tuple<Type, int>>(); + + public Wave(List<Tuple<Type, int>> EnemiesToSpawn, int SpawnDelayMS) + { + this.SpawnDelayMS = SpawnDelayMS; + this.EnemiesToSpawn = EnemiesToSpawn; + } + } +}
\ No newline at end of file diff --git a/Penguloon/Penguloon.csproj b/Penguloon/Penguloon.csproj index 86b2a65..c06358a 100644 --- a/Penguloon/Penguloon.csproj +++ b/Penguloon/Penguloon.csproj @@ -66,6 +66,9 @@ <Compile Include="ContentPathManager.cs" /> <Compile Include="Controls\Button.cs" /> <Compile Include="Controls\ControlBase.cs" /> + <Compile Include="Enemies\EnemyBase.cs" /> + <Compile Include="Enemies\RedBalloon.cs" /> + <Compile Include="Levels\WaveManager.cs" /> <Compile Include="Scenes\GameScene.cs" /> <Compile Include="Controls\LevelSelector.cs" /> <Compile Include="Enums.cs" /> diff --git a/Penguloon/Scenes/GameScene.cs b/Penguloon/Scenes/GameScene.cs index 406e784..14c2d96 100644 --- a/Penguloon/Scenes/GameScene.cs +++ b/Penguloon/Scenes/GameScene.cs @@ -10,25 +10,23 @@ namespace Penguloon.Scenes { public LevelBase Level { get; set; } - public bool RoundActive { get; set; } = false; + public Button StartRoundBtn { get; set; } public GameScene(Main main, LevelBase level) : base(main) { this.Level = level; this.Level.Initialize(this); - Button StartRoundBtn = new Button(this, - new Vector2(Level.Map.MapWidth + StaticUIValues.BorderWidth, StaticUIValues.ScreenViewport.Y - 120), - new Vector2(StaticUIValues.ScreenViewport.X - (Level.Map.MapWidth + StaticUIValues.BorderWidth), 120), "Start"); + StartRoundBtn = new Button(this, + new Vector2(Level.Map.MapWidth + StaticUIValues.BorderWidth, StaticUIValues.ScreenViewport.Y - 120), + new Vector2(StaticUIValues.ScreenViewport.X - (Level.Map.MapWidth + StaticUIValues.BorderWidth), 120), "Start"); StartRoundBtn.OnClick += StartRoundBtn_OnClick; - - Controls.Add(StartRoundBtn); } private void StartRoundBtn_OnClick(object sender, ClickArgs e) { - RoundActive = true; + Level.Map.WaveManager.StartSpawningEnemies(); Button btn = (Button)sender; btn.ControlState = ControlState.Disabled; } @@ -46,17 +44,37 @@ namespace Penguloon.Scenes base.Draw(deltaTime); + StartRoundBtn.Draw(deltaTime); + this.Level.Draw(deltaTime); + DrawUI(deltaTime); + } + + private void DrawUI(float deltaTime) + { Main.SpriteBatch.Draw(ContentManager.GetTexture("UI/border"), - destinationRectangle: new Rectangle(Level.Map.MapWidth, - 0, StaticUIValues.BorderWidth, (int)StaticUIValues.ScreenViewport.Y)); + destinationRectangle: new Rectangle(Level.Map.MapWidth, + 0, StaticUIValues.BorderWidth, (int)StaticUIValues.ScreenViewport.Y)); + + DrawText(ContentManager.GetFont(StaticUIValues.IngameFont), "Wave: " + Level.Map.WaveManager.CurrentWave.ToString(), + new Vector2(StaticUIValues.ScreenViewport.X - StaticUIValues.IngameUIWidth, 10), + new Vector2(StaticUIValues.IngameUIWidth, 200), + TextAllignment.CenterTop, Color.White, Color.Black, 2); } public override void Update(float deltaTime, TouchLocation[] touchLocations) { base.Update(deltaTime, touchLocations); + StartRoundBtn.Update(deltaTime, touchLocations); + + if (StartRoundBtn.ControlState == ControlState.Disabled && !Level.Map.WaveManager.RoundActive) + { + StartRoundBtn.ControlState = ControlState.Idle; + Level.Map.WaveManager.FinishRound(); + } + this.Level.Update(deltaTime, touchLocations); } } diff --git a/Penguloon/StaticUIValues.cs b/Penguloon/StaticUIValues.cs index 5407e6c..69a845e 100644 --- a/Penguloon/StaticUIValues.cs +++ b/Penguloon/StaticUIValues.cs @@ -19,6 +19,8 @@ namespace Penguloon public static string MenuFont { get; set; } + public static string IngameFont { get; set; } + public static int IngameUIWidth { get; set; } public static int BorderWidth { get; set; } = 20; @@ -56,6 +58,8 @@ namespace Penguloon MenuFont = "Fonts/GWENT/48"; } + IngameFont = "Fonts/GWENT/36"; + LoadingProgressbarPosition = new Vector2((ScreenViewport.X - LoadingProgressbarSize.X) / 2, ScreenViewport.Y - LoadingProgressbarSize.Y - 200); LoadingProgressbarValuePosition = new Vector2(LoadingProgressbarPosition.X + 5, LoadingProgressbarPosition.Y + 5); |
