using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Penguloon.Levels; using Penguloon.Projectiles; using System; using System.Collections.Generic; using System.Linq; namespace Penguloon.Objects { public abstract class ObjectBase { public int AttackSpeedMS { get; set; } public int AttackSpeedMSBase { get; set; } public DateTime LastAttack { get; set; } public float Range { get; set; } public float RangeBase { get; set; } public Texture2D Texture { get; set; } public Texture2D TextureBase { get; set; } public Texture2D RangeCircle { get; set; } public Texture2D InfoPanelTexture { get; set; } public Texture2D InfoPanelLineTexture { get; set; } public Vector2 InfoPanelPos { get; set; } public float InfoPanelRotation { get; set; } = -0f; public float Rotation { get; set; } = -0f; public Vector2 Position { get; set; } public Vector2 Center { get; set; } public int TileSpanX { get; set; } public int TileSpanY { get; set; } public string infoText { get; set; } public List Projectiles { get; set; } = new List(); public Map Map { get; set; } public Rectangle Box { get; set; } public bool ShouldRotate { get; set; } = true; public bool Selected { get; set; } = false; public List UpgradeList { get; set; } = new List(); public ObjectBase(Vector2 position, Map map) { this.Map = map; this.Position = position; this.AttackSpeedMSBase = AttackSpeedMS; this.RangeBase = Range; CreateUpgrades(); SetInfoPanel(); } private void SetInfoPanel() { InfoPanelTexture = ContentManager.GetTexture("UI/objectinfo"); InfoPanelLineTexture = ContentManager.GetTexture("UI/objectinfo-line"); InfoPanelPos = new Vector2(); // alight right if (Position.X < 450) { } // alight left else { } } public ObjectBase(Map map) { this.Map = map; } public virtual void CreateUpgrades() { } public bool RoundFinished { get; set; } = true; public void Update(float deltaTime) { // round has started if (Map.WaveManager.RoundActive && RoundFinished) RoundFinished = false; if (!Map.WaveManager.RoundActive && !RoundFinished) { RoundFinished = true; RoundIsFinished(); } this.Center = new Vector2(Position.X + ((TileSpanX * Map.TileWidth) / 2), Position.Y + ((TileSpanY * Map.TileHeight) / 2)); // loop from back of list to front so we always focus the balloons in front for (int i = Map.Enemies.Count - 1; i >= 0; i--) { if (Map.Enemies[i] != null && Contains(Map.Enemies[i].Box.Center.ToVector2())) { if(ShouldRotate) Rotation = (float)GetRotation(Map.Enemies[i].Box.Center.ToVector2()); if ((DateTime.Now - LastAttack).TotalMilliseconds > (AttackSpeedMS / (int)Map.Level.ParentScene.Speed)) { LastAttack = DateTime.Now; SpawnUnique(); } break; } } for (int i = 0; i < Projectiles.Count; i++) Projectiles[i].Update(deltaTime); UpdateUnique(deltaTime); RemoveUselessProjectiles(); } public virtual void RoundIsFinished() { } private void RemoveUselessProjectiles() { for (int i = 0; i < Projectiles.Count; i++) { if (i < Projectiles.Count) { if (Projectiles[i].Position.X < -50) { Projectiles.Remove(Projectiles[i]); return; } if (Projectiles[i].Position.X > StaticUIValues.ScreenViewport.X + 50) { Projectiles.Remove(Projectiles[i]); return; } if (Projectiles[i].Position.Y < -50) { Projectiles.Remove(Projectiles[i]); return; } if (Projectiles[i].Position.Y > StaticUIValues.ScreenViewport.Y + 50) { Projectiles.Remove(Projectiles[i]); return; } } } } public abstract void UpdateUnique(float deltaTime); public abstract void SpawnUnique(); public void Draw(float deltaTime) { if(RangeCircle == null) RangeCircle = CreateCircle((int)Range * 2); float rot = (float)Rotation + (float)MathHelper.PiOver2; if (!ShouldRotate) rot = 0f; Rectangle rec = new Rectangle( (int)Position.X + ((int)(Map.TileWidth * TileSpanX)) / 2, (int)Position.Y + ((int)(Map.TileHeight * TileSpanY)) / 2, Map.TileWidth * TileSpanX, Map.TileHeight * TileSpanY); // Draw object base if (TextureBase != null) Map.ParentScene.Main.SpriteBatch.Draw(TextureBase, destinationRectangle: rec, origin: new Vector2(Texture.Width / 2, Texture.Height / 2)); // Draw projectiles before drawing the object for (int i = 0; i < Projectiles.Count; i++) Projectiles[i].Draw(deltaTime); DrawUnique(deltaTime); // Draw object Map.ParentScene.Main.SpriteBatch.Draw(Texture, destinationRectangle: rec, rotation: (float)rot, origin: new Vector2(Texture.Width / 2, Texture.Height / 2)); if (Selected) { Rectangle rangeCircleRec = new Rectangle( (int)Position.X + ((TileSpanX * Map.TileWidth) / 2), (int)Position.Y + ((TileSpanY * Map.TileHeight) / 2), (int)(Range * 2), (int)(Range * 2)); if (RangeCircle != null) Map.ParentScene.Main.SpriteBatch.Draw(RangeCircle, destinationRectangle: rangeCircleRec, origin: new Vector2(RangeCircle.Width / 2, RangeCircle.Height / 2)); } } public abstract void DrawUnique(float deltaTime); public Texture2D CreateCircle(int radius) { Texture2D texture = new Texture2D(Map.ParentScene.Main.GraphicsDevice, radius, radius); Color[] colorData = new Color[radius * radius]; float diam = radius / 2f; float diamsq = diam * diam; for (int x = 0; x < radius; x++) { for (int y = 0; y < radius; y++) { int index = x * radius + y; Vector2 pos = new Vector2(x - diam, y - diam); if (pos.LengthSquared() <= diamsq) { colorData[index] = Color.FromNonPremultiplied(200, 0, 0, 50); } else { colorData[index] = Color.Transparent; } } } texture.SetData(colorData); return texture; } private double GetRotation(Vector2 enemyPos) { double radians = Math.Atan2(enemyPos.Y - Center.Y, enemyPos.X - Center.X); return (radians); } private bool Contains(Vector2 point) { return ((point - Center).Length() <= Range); } } }