C#坦克大战流程设计与源代码(1):基本对象类规划
小游戲坦克大戰,看似是一個很小的程序。
但實際使用做起來,發現需要用到多種功能:
多線程并發與同步,事件觸發,GDI繪圖。
可以采用事件訂閱 與事件觸發的觀察者模式。
從網絡上下載聲音文件 以及 各種坦克圖片等素材。
實體分類如下:
1.有靜止的地圖元素【MapElement】:如墻體、水域、草叢、鋼鐵墻、老鷹等,為了區分不同的元素,同時加入地圖元素類型枚舉【MapElementCategory】。
2.有坦克【Tank】,又細分為玩家坦克【PlayerTank】和敵方坦克【EnemyTank】兩種。玩家坦克可以升星,增加坦克等級枚舉【PlayerTankLevel】。敵方坦克也有不同的種類【EnemyTankCategory】。
3.坦克可以攻擊,產生子彈【Bullet】,子彈分玩家子彈和敵方子彈。這里用子彈類型枚舉【BulletCategory】表示。
4.玩家子彈擊中發光的敵方坦克【會掉落道具的】會產生道具【Prop】,每種道具都有不同的效果,因此增加道具枚舉【PropCategory】。
5.子彈和坦克的移動需要有方向,增加方向枚舉Direction.
6.以上的地圖元素、坦克、子彈、道具都可以認為是一個矩形,需要考慮兩個矩形的碰撞。因此建立抽象類矩形對象【RectangleObject】,所有對象都繼承該抽象類。
整體類的屬性源程序如下:
一、RectangleObject.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 【抽象類】矩形物體:所有的坦克,地圖元素【墻、鋼鐵、草叢】,子彈,道具都是由一個填充圖片的矩形構成
? ? /// 該類是所有地圖資源的基類,主要用于判斷兩個地圖資源是否碰撞(相交)
? ? /// </summary>
? ? public abstract class RectangleObject
? ? {
? ? ? ? public RectangleObject(Image image, int x, int y, int width, int height)
? ? ? ? {
? ? ? ? ? ? this.Image = image;
? ? ? ? ? ? this.X = x;
? ? ? ? ? ? this.Y = y;
? ? ? ? ? ? this.Width = width == 0 ? image.Width : width;
? ? ? ? ? ? this.Height = height == 0 ? image.Height : height;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 圖片資源,一般是位圖資源Bitmap
? ? ? ? /// </summary>
? ? ? ? public Image Image { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 起始X坐標
? ? ? ? /// </summary>
? ? ? ? public int X { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 起始Y坐標
? ? ? ? /// </summary>
? ? ? ? public int Y { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 寬度
? ? ? ? /// </summary>
? ? ? ? public int Width { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 高度
? ? ? ? /// </summary>
? ? ? ? public int Height { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 判斷兩個物體是否是相交的,
? ? ? ? /// 比如 子彈與敵方坦克是否碰撞,玩家坦克與道具是否碰撞,子彈與墻體進行碰撞等
? ? ? ? /// </summary>
? ? ? ? /// <param name="rectangleObject"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public virtual bool IsIntersected(RectangleObject rectangleObject)
? ? ? ? {
? ? ? ? ? ? Rectangle rect = new Rectangle(X, Y, Width, Height);
? ? ? ? ? ? return rect.IntersectsWith(new Rectangle(rectangleObject.X, rectangleObject.Y, rectangleObject.Width, rectangleObject.Height));
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 判斷當前物體與一個矩形區域是否相交
? ? ? ? /// </summary>
? ? ? ? /// <param name="rect"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public virtual bool IsIntersected(Rectangle rectangle)
? ? ? ? {
? ? ? ? ? ? Rectangle rect = new Rectangle(X, Y, Width, Height);
? ? ? ? ? ? return rect.IntersectsWith(rectangle);
? ? ? ? }
? ? }
}
?
二、MapElement.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 地圖元素
? ? /// </summary>
? ? public class MapElement : RectangleObject
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 實例化地圖元素
? ? ? ? /// </summary>
? ? ? ? /// <param name="image">位圖資源</param>
? ? ? ? /// <param name="x">起始X坐標</param>
? ? ? ? /// <param name="y">起始Y坐標</param>
? ? ? ? /// <param name="elementCategory">元素類型</param>
? ? ? ? public MapElement(Image image, int x, int y, MapElementCategory elementCategory, int width = 0, int height = 0)
? ? ? ? ? ? : base(image, x, y, width, height)
? ? ? ? {
? ? ? ? ? ? this.ElementCategory = elementCategory;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 地圖元素類型
? ? ? ? /// </summary>
? ? ? ? public MapElementCategory ElementCategory { get; set; }
? ? }
}
?
三、MapElementCategory.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 地圖元素類型【枚舉】
? ? /// 主要有:墻體、水域、草叢、鋼鐵墻等
? ? /// </summary>
? ? public enum MapElementCategory
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 墻體:無法移動通過。被子彈攻擊到將消失
? ? ? ? /// </summary>
? ? ? ? Wall = 0,
? ? ? ? /// <summary>
? ? ? ? /// 水域:無法移動通過,但子彈可以穿過去
? ? ? ? /// </summary>
? ? ? ? Water = 1,
? ? ? ? /// <summary>
? ? ? ? /// 草叢:可以移動通過,子彈可以穿過去
? ? ? ? /// </summary>
? ? ? ? Grass = 2,
? ? ? ? /// <summary>
? ? ? ? /// 鋼鐵墻:無法移動通過。可以抵擋所有敵方坦克的子彈。我方坦克達到3級【吃三個星星】后,擊中鋼鐵將消失,我方坦克低于三級將抵擋子彈
? ? ? ? /// </summary>
? ? ? ? Steel = 3,
? ? ? ? /// <summary>
? ? ? ? /// 象征,符號。鷹,Boss。玩家需要守護鷹不被擊中
? ? ? ? /// 子彈與鷹碰撞后,將游戲結束
? ? ? ? /// </summary>
? ? ? ? Symbol = 4
? ? }
}
?
四、Tank.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 分為玩家坦克 和 敵方坦克兩種
? ? /// 是玩家坦克、敵方坦克的基類
? ? /// </summary>
? ? public class Tank : RectangleObject
? ? {
? ? ? ? public Tank(Image image, int tankIndex, int x, int y, int width = 60, int height = 60, int health = 1, int speed = 15, Direction direction = Direction.Up)
? ? ? ? ? ? : base(image, x, y, width, height)
? ? ? ? {
? ? ? ? ? ? this.TankIndex = tankIndex;
? ? ? ? ? ? this.Health = health;
? ? ? ? ? ? this.Speed = speed;
? ? ? ? ? ? this.Direction = direction;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 坦克唯一編號:主要用于區分是否是當前坦克
? ? ? ? /// </summary>
? ? ? ? public int TankIndex { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 生命值
? ? ? ? /// </summary>
? ? ? ? public int Health { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 移動速度:速度越快,同一時間內 坦克移動的位置就越遠。也就是說:X坐標或者Y坐標偏移較大
? ? ? ? /// </summary>
? ? ? ? public int Speed { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 方向:上、下、左、右
? ? ? ? /// </summary>
? ? ? ? public Direction Direction { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 玩家坦克 和 敵方坦克 是否可以向前移動
? ? ? ? /// 玩家坦克 是手動控制,敵方坦克是自動
? ? ? ? /// </summary>
? ? ? ? /// <param name="MapWidth"></param>
? ? ? ? /// <param name="MapHeight"></param>
? ? ? ? /// <param name="mapElements"></param>
? ? ? ? /// <param name="tanks"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public bool IsAllowMove(int MapWidth, int MapHeight, List<MapElement> mapElements, List<Tank> tanks)
? ? ? ? {
? ? ? ? ? ? bool allowMove = true;
? ? ? ? ? ? Rectangle rect = new Rectangle(0, 0, 0, 0);
? ? ? ? ? ? switch (this.Direction)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //如果到達邊界,直接返回false
? ? ? ? ? ? ? ? case Direction.Up:
? ? ? ? ? ? ? ? ? ? if (this.Y - this.Speed < 0)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? rect = new Rectangle(this.X, this.Y - this.Speed, this.Width, this.Height);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case Direction.Down:
? ? ? ? ? ? ? ? ? ? if (this.Y + this.Speed > MapHeight - this.Height)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? rect = new Rectangle(this.X, this.Y + this.Speed, this.Width, this.Height);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case Direction.Left:
? ? ? ? ? ? ? ? ? ? if (this.X - this.Speed < 0)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? rect = new Rectangle(this.X - this.Speed, this.Y, this.Width, this.Height);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case Direction.Right:
? ? ? ? ? ? ? ? ? ? if (this.X + this.Speed > MapWidth - this.Width)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? rect = new Rectangle(this.X + this.Speed, this.Y, this.Width, this.Height);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? //如果與墻體、鋼鐵、老鷹、水域碰撞【可以穿過草叢】
? ? ? ? ? ? for (int i = 0; i < mapElements.Count; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Rectangle rectElement = new Rectangle(mapElements[i].X, mapElements[i].Y, mapElements[i].Width, mapElements[i].Height);
? ? ? ? ? ? ? ? if (mapElements[i].ElementCategory == MapElementCategory.Steel || mapElements[i].ElementCategory == MapElementCategory.Symbol
? ? ? ? ? ? ? ? ? ? || mapElements[i].ElementCategory == MapElementCategory.Wall || mapElements[i].ElementCategory == MapElementCategory.Water)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if (rect.IntersectsWith(rectElement))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //如果與坦克碰撞
? ? ? ? ? ? for (int i = 0; i < tanks.Count; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Rectangle rectElement = new Rectangle(tanks[i].X, tanks[i].Y, tanks[i].Width, tanks[i].Height);
? ? ? ? ? ? ? ? if (this != tanks[i] && rect.IntersectsWith(rectElement))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? return allowMove;
? ? ? ? }
? ? ? ? public override bool Equals(object obj)
? ? ? ? {
? ? ? ? ? ? if (!(obj is Tank))
? ? ? ? ? ? ? ? return false;
? ? ? ? ? ? return this.TankIndex == ((Tank)obj).TankIndex;
? ? ? ? }
? ? ? ? public override int GetHashCode()
? ? ? ? {
? ? ? ? ? ? return base.GetHashCode();
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 操作符重載,比較兩個坦克是否是同一個,即TankIndex相同
? ? ? ? /// </summary>
? ? ? ? /// <param name="tank1"></param>
? ? ? ? /// <param name="tank2"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public static bool operator ==(Tank tank1, Tank tank2)
? ? ? ? {
? ? ? ? ? ? if ((tank1 as object) == null)
? ? ? ? ? ? ? ? return (tank2 as object) == null;//引用基類object的比較操作符
? ? ? ? ? ? return tank1.TankIndex == tank2.TankIndex;
? ? ? ? ? ? //return tank1.Equals(tank2);
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 操作符重載,比較兩個坦克是否不是同一個,即TankIndex不同
? ? ? ? /// </summary>
? ? ? ? /// <param name="tank1"></param>
? ? ? ? /// <param name="tank2"></param>
? ? ? ? /// <returns></returns>
? ? ? ? public static bool operator !=(Tank tank1, Tank tank2)
? ? ? ? {
? ? ? ? ? ? return !(tank1 == tank2);
? ? ? ? }
? ? }
}
?
五、PlayerTank.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 玩家坦克
? ? /// </summary>
? ? public class PlayerTank : Tank
? ? {
? ? ? ? public PlayerTank(Image image, int tankIndex, int x, int y, int width = 60, int height = 60, int health = 1, int speed = 15, Direction direction = Direction.Up, PlayerTankLevel tankLevel = PlayerTankLevel.Initial)
? ? ? ? ? ? : base(image, tankIndex, x, y, width, height, health, speed, direction)
? ? ? ? {
? ? ? ? ? ? this.TankLevel = tankLevel;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 玩家坦克等級
? ? ? ? /// </summary>
? ? ? ? public PlayerTankLevel TankLevel { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 當前道具:玩家坦克 有定時道具 或者 無敵狀態 或者 為鷹增加鋼鐵墻道具等
? ? ? ? /// </summary>
? ? ? ? public Prop CurrentProp { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 玩家坦克移動
? ? ? ? /// </summary>
? ? ? ? public void Move(int MapWidth, int MapHeight, List<MapElement> mapElements, List<Tank> tanks, Prop prop = null)
? ? ? ? {
? ? ? ? ? ? //坦克是否可以向前移動,如果不能向前移動,嘗試轉換方向
? ? ? ? ? ? //我方坦克在移動中是否碰撞道具,如果碰撞道具,道具將消失,我方坦克增加相應持續狀態【生命值加強、火力加強、無敵等】
? ? ? ? ? ? if (IsAllowMove(MapWidth, MapHeight, mapElements, tanks))
? ? ? ? ? ? {
? ? ? ? ? ? ? ? switch (this.Direction)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? case Direction.Up:
? ? ? ? ? ? ? ? ? ? ? ? this.Y = this.Y - this.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Down:
? ? ? ? ? ? ? ? ? ? ? ? this.Y = this.Y + this.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Left:
? ? ? ? ? ? ? ? ? ? ? ? this.X = this.X - this.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Right:
? ? ? ? ? ? ? ? ? ? ? ? this.X = this.X + this.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (prop != null && this.IsIntersected(prop))
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? Prop propTemp = prop;
? ? ? ? ? ? ? ? ? ? System.Windows.Forms.MessageBox.Show($"玩家坦克與道具【{prop.PropCategory}】碰撞,將產生相應的事件");
? ? ? ? ? ? ? ? ? ? this.CurrentProp = propTemp;
? ? ? ? ? ? ? ? ? ? prop = null;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? System.Media.SystemSounds.Asterisk.Play();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ??
? ? ? ? /// <summary>
? ? ? ? /// 坦克攻擊:向玩家子彈列表增加數據
? ? ? ? /// </summary>
? ? ? ? public void Fire()
? ? ? ? {
? ? ? ? }
? ? }
}
?
六、EnemyTank.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 敵方坦克
? ? /// </summary>
? ? public class EnemyTank : Tank
? ? {
? ? ? ? public EnemyTank(Image image, int tankIndex, int x, int y, int width = 60, int height = 60, int health = 1, int speed = 15, Direction direction = Direction.Down, EnemyTankCategory tankCategory = EnemyTankCategory.Normal, bool isDropProps = false)
? ? ? ? ? ? : base(image, tankIndex, x, y, width, height, health, speed, direction)
? ? ? ? {
? ? ? ? ? ? this.TankCategory = tankCategory;
? ? ? ? ? ? this.IsDropProps = isDropProps;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 敵方坦克類型:快、慢、裝甲
? ? ? ? /// </summary>
? ? ? ? public EnemyTankCategory TankCategory { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 是否掉落物品:當為true時,敵方坦克被玩家坦克的子彈擊中,將隨機產生一個道具。然后將該屬性置為false
? ? ? ? /// </summary>
? ? ? ? public bool IsDropProps { get; set; }
? ? }
}
?
七、PlayerTankLevel.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 我方【玩家】坦克等級:攻擊速度和子彈個數
? ? /// </summary>
? ? public enum PlayerTankLevel
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 初始:攻擊速度1.5秒發射一發子彈
? ? ? ? /// </summary>
? ? ? ? Initial = 0,
? ? ? ? /// <summary>
? ? ? ? /// 一星:攻擊速度0.75秒發射一發子彈
? ? ? ? /// </summary>
? ? ? ? OneStar = 1,
? ? ? ? /// <summary>
? ? ? ? /// 二星:攻擊速度0.75秒發射兩發子彈
? ? ? ? /// </summary>
? ? ? ? TwoStar = 2,
? ? ? ? /// <summary>
? ? ? ? /// 三星:攻擊速度0.75秒發射兩發子彈,擊中鋼鐵墻,鋼鐵墻將消失
? ? ? ? /// </summary>
? ? ? ? ThreeStar = 3
? ? }
}
?
八、EnemyTankCategory.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 敵方坦克類型:普通、快速、裝甲
? ? /// </summary>
? ? public enum EnemyTankCategory
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 普通坦克
? ? ? ? /// </summary>
? ? ? ? Normal = 1,
? ? ? ? /// <summary>
? ? ? ? /// 快速坦克:移動速度較快
? ? ? ? /// </summary>
? ? ? ? Quick = 2,
? ? ? ? /// <summary>
? ? ? ? /// 裝甲坦克:生命值較多
? ? ? ? /// </summary>
? ? ? ? Armor = 3
? ? }
}
?
九、Direction.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 方向:坦克的移動方向 以及 子彈的前進方向
? ? /// </summary>
? ? public enum Direction
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 上
? ? ? ? /// </summary>
? ? ? ? Up,
? ? ? ? /// <summary>
? ? ? ? /// 下
? ? ? ? /// </summary>
? ? ? ? Down,
? ? ? ? /// <summary>
? ? ? ? /// 左
? ? ? ? /// </summary>
? ? ? ? Left,
? ? ? ? /// <summary>
? ? ? ? /// 右
? ? ? ? /// </summary>
? ? ? ? Right
? ? }
}
?
十、Bullet.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 子彈:有方向,分玩家子彈、敵方子彈
? ? /// 以及是否可以消除墻體
? ? /// </summary>
? ? public class Bullet : RectangleObject
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 初始化子彈
? ? ? ? /// </summary>
? ? ? ? /// <param name="image"></param>
? ? ? ? /// <param name="direction"></param>
? ? ? ? /// <param name="x"></param>
? ? ? ? /// <param name="y"></param>
? ? ? ? /// <param name="speed"></param>
? ? ? ? /// <param name="width"></param>
? ? ? ? /// <param name="height"></param>
? ? ? ? public Bullet(Image image, int bulletIndex, Direction direction, int x, int y, int speed, int width = 60, int height = 60, BulletCategory bulletCategory = BulletCategory.PlayerBullet, bool canEliminateSteel = false)
? ? ? ? ? ? : base(image, x, y, width, height)
? ? ? ? {
? ? ? ? ? ? this.BulletIndex = bulletIndex;
? ? ? ? ? ? this.Direction = direction;
? ? ? ? ? ? this.Speed = speed;
? ? ? ? ? ? this.BulletCategory = bulletCategory;
? ? ? ? ? ? this.CanEliminateSteel = canEliminateSteel;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 子彈的唯一索引
? ? ? ? /// </summary>
? ? ? ? public int BulletIndex { get; }
? ? ? ? /// <summary>
? ? ? ? /// 子彈的方向
? ? ? ? /// </summary>
? ? ? ? public Direction Direction { get; }
? ? ? ? /// <summary>
? ? ? ? /// 子彈的速度,可以認為是 坦克的攻擊速度。速度越快,同一時間內 子彈移動的位置就越遠。
? ? ? ? /// 子彈的移動速度邏輯:因速度越大,相同時間內移動的距離越遠。因此我們可以使用位移(距離、坐標)的大小來模擬表示
? ? ? ? /// 比如每隔50ms,坐標的變化來表示速度的快慢即可。
? ? ? ? /// </summary>
? ? ? ? public int Speed { get; set; } ? ? ? ?
? ? ? ? /// <summary>
? ? ? ? /// 子彈類型:玩家子彈還是敵方子彈
? ? ? ? /// </summary>
? ? ? ? public BulletCategory BulletCategory { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 子彈是否可以消除鋼鐵墻:玩家坦克等級3星時可以擊穿鋼鐵
? ? ? ? /// </summary>
? ? ? ? public bool CanEliminateSteel { get; set; }
? ? ? ? /// <summary>
? ? ? ? /// 所有子彈【玩家子彈 和敵方子彈的合集】與其他物體的碰撞
? ? ? ? /// 注意,子彈與子彈的碰撞要遞減處理
? ? ? ? /// </summary>
? ? ? ? /// <param name="mapElements"></param>
? ? ? ? /// <param name="bullets">玩家子彈 和 敵方子彈</param>
? ? ? ? /// <param name="enemyTanks"></param>
? ? ? ? public static void BulletHit(List<MapElement> mapElements, List<Bullet> bullets, List<EnemyTank> enemyTanks, int MapWidth, int MapHeight, Form form)
? ? ? ? {
? ? ? ? ? ? /*
? ? ? ? ? ? ?* 子彈在移動過程中一定會觸發碰撞事件。子彈在移動過程中沒有和其他物體碰撞,則最終會和地圖邊界碰撞
? ? ? ? ? ? ?* 玩家子彈碰撞事件:子彈與地圖元素【墻體、鋼鐵】的碰撞,子彈與敵方子彈的碰撞,子彈與敵方坦克碰撞
? ? ? ? ? ? ?* 玩家子彈與【掉落道具的敵方坦克 碰撞時,將隨機產生一個道具】
? ? ? ? ? ? ?*?
? ? ? ? ? ? ?* 敵方子彈碰撞事件:子彈與地圖元素【墻體、鋼鐵】的碰撞,子彈與玩家子彈的碰撞,子彈與玩家坦克碰撞
? ? ? ? ? ? */
? ? ? ? ? ? for (int bulletIndex = 0; bulletIndex < bullets.Count; bulletIndex++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Bullet bulletPlayer = bullets[bulletIndex];
? ? ? ? ? ? ? ? switch (bulletPlayer.Direction)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? case Direction.Up:
? ? ? ? ? ? ? ? ? ? ? ? bulletPlayer.Y = bulletPlayer.Y - bulletPlayer.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Down:
? ? ? ? ? ? ? ? ? ? ? ? bulletPlayer.Y = bulletPlayer.Y + bulletPlayer.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Left:
? ? ? ? ? ? ? ? ? ? ? ? bulletPlayer.X = bulletPlayer.X - bulletPlayer.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case Direction.Right:
? ? ? ? ? ? ? ? ? ? ? ? bulletPlayer.X = bulletPlayer.X + bulletPlayer.Speed;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (bulletPlayer.X <= 0 || bulletPlayer.X >= MapWidth || bulletPlayer.Y <= 0 || bulletPlayer.Y >= MapHeight)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //子彈到達邊界 或者 觸發碰撞事件,子彈從集合中清除。播放爆炸音效。顯示爆炸圖片");
? ? ? ? ? ? ? ? ? ? Blast(form, bulletPlayer);
? ? ? ? ? ? ? ? ? ? //賦值為null,用于清除集合中值為null的元素
? ? ? ? ? ? ? ? ? ? bulletIndex--;
? ? ? ? ? ? ? ? ? ? bullets.RemoveAt(bulletIndex);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? List<MapElement> listRemoves = new List<MapElement>();
? ? ? ? ? ? ? ? //子彈與墻體、鋼鐵碰撞
? ? ? ? ? ? ? ? for (int wallIndex = 0; wallIndex < mapElements.Count; wallIndex++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? MapElement mapElement = mapElements[wallIndex];
? ? ? ? ? ? ? ? ? ? if (mapElement.ElementCategory == MapElementCategory.Wall && bulletPlayer.IsIntersected(mapElement))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? //如果子彈與墻體的矩形 相交。則認為觸發 碰撞。子彈可以消失 多個窗體
? ? ? ? ? ? ? ? ? ? ? ? listRemoves.Add(mapElement);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else if (mapElement.ElementCategory == MapElementCategory.Steel && bulletPlayer.IsIntersected(mapElement))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? if (bulletPlayer.CanEliminateSteel)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //如果當前子彈可以 清除鋼鐵墻
? ? ? ? ? ? ? ? ? ? ? ? ? ? listRemoves.Add(mapElement);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? Blast(form, bulletPlayer);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else if (mapElement.ElementCategory == MapElementCategory.Symbol && bulletPlayer.IsIntersected(mapElement))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? //子彈與 老鷹碰撞,則游戲結束
? ? ? ? ? ? ? ? ? ? ? ? MessageBox.Show("游戲結束Game Over");
? ? ? ? ? ? ? ? ? ? ? ? Blast(form, bulletPlayer);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //清除相交的所有墻體
? ? ? ? ? ? ? ? for (int removeIndex = 0; removeIndex < listRemoves.Count; removeIndex++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? //如果子彈與墻體的矩形 相交。則認為觸發 碰撞。子彈可以消失 多個窗體
? ? ? ? ? ? ? ? ? ? mapElements.Remove(listRemoves[removeIndex]);
? ? ? ? ? ? ? ? ? ? if (removeIndex == 0)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? //只清除一個 子彈
? ? ? ? ? ? ? ? ? ? ? ? Blast(form, bulletPlayer);
? ? ? ? ? ? ? ? ? ? ? ? //bulletPlayer = null;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //移除臨時變量
? ? ? ? ? ? ? ? listRemoves.Clear();
? ? ? ? ? ? ? ? //子彈與敵方坦克的碰撞
? ? ? ? ? ? ? ? for (int tankIndex = 0; tankIndex < enemyTanks.Count; tankIndex++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if (bulletPlayer.IsIntersected(enemyTanks[tankIndex]))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? if (enemyTanks[tankIndex].IsDropProps)
? ? ? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //如果掉落物品
? ? ? ? ? ? ? ? ? ? ? ? ? ? Prop prop = new Prop(Properties.Resources.GEMSTAR, new Random().Next(0, MapWidth - 30), new Random().Next(0, MapHeight - 30), PropCategory.Star, 30, 30);
? ? ? ? ? ? ? ? ? ? ? ? ? ? MessageBox.Show($"隨機生成一個道具【{prop.PropCategory}】");
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? Blast(form, bulletPlayer);
? ? ? ? ? ? ? ? ? ? ? ? //敵方坦克和子彈都消失:這里應該考慮敵方坦克的生命值減少1.變成0時爆炸死亡
? ? ? ? ? ? ? ? ? ? ? ? //如果敵方坦克可以掉落道具
? ? ? ? ? ? ? ? ? ? ? ? enemyTanks.RemoveAt(tankIndex);
? ? ? ? ? ? ? ? ? ? ? ? //bulletPlayer = null;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? //子彈與敵方子彈的碰撞
? ? ? ? ? ? ? ? for (int i = bulletIndex + 1; i < bullets.Count; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? if (((bullets[i].BulletCategory == BulletCategory.EnemyBullet && bulletPlayer.BulletCategory == BulletCategory.PlayerBullet)
? ? ? ? ? ? ? ? ? ? ? ? || (bullets[i].BulletCategory == BulletCategory.PlayerBullet && bulletPlayer.BulletCategory == BulletCategory.EnemyBullet))
? ? ? ? ? ? ? ? ? ? ? ?&& bulletPlayer.IsIntersected(bullets[i]))
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? bullets.RemoveAt(i);
? ? ? ? ? ? ? ? ? ? ? ? bulletIndex--;
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? bullets.RemoveAt(bulletIndex);
? ? ? ? ? ? ? ? bulletIndex--;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? public static void EnemyBulletHit(Bullet bulletEnemy, List<MapElement> mapElements, List<Bullet> playerBullets, List<PlayerTank> playerTanks)
? ? ? ? {
? ? ? ? ? ? /*
? ? ? ? ? ? ?* 敵方子彈碰撞事件:子彈與地圖元素【墻體、鋼鐵】的碰撞,子彈與玩家子彈的碰撞,子彈與玩家坦克碰撞
? ? ? ? ? ? */
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 爆炸效果:子彈碰撞到坦克、墻體、鋼鐵墻、老鷹【子彈分我方子彈 和 敵方子彈】
? ? ? ? /// </summary>
? ? ? ? public static void Blast(Form form, Bullet bullet)
? ? ? ? {
? ? ? ? ? ? //爆炸音效
? ? ? ? ? ? System.Media.SoundPlayer sp = new System.Media.SoundPlayer(Properties.Resources.blast);
? ? ? ? ? ? sp.Play();
? ? ? ? ? ? //爆炸動畫
? ? ? ? ? ? Task taskBlast = Task.Run(() =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? for (int index = 0; index < 25; index++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? Image image = Properties.Resources.EXP1;
? ? ? ? ? ? ? ? ? ? if (index >= 5)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? image = Properties.Resources.EXP2;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else if (index >= 10)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? image = Properties.Resources.EXP3;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else if (index >= 15)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? image = Properties.Resources.EXP4;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? else if (index >= 20)
? ? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? image = Properties.Resources.EXP5;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? form.CreateGraphics().DrawImage(image, bullet.X, bullet.Y);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? Task.WaitAll(taskBlast);
? ? ? ? }
? ? }
}
?
十一、BulletCategory.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 子彈類型:我方【玩家】子彈、敵方子彈
? ? /// </summary>
? ? public enum BulletCategory
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 我方【玩家】子彈
? ? ? ? /// </summary>
? ? ? ? PlayerBullet,
? ? ? ? /// <summary>
? ? ? ? /// 敵方子彈
? ? ? ? /// </summary>
? ? ? ? EnemyBullet
? ? }
}
?
十二、Prop.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 道具:主要有 定時、炸彈、無敵、鋼鐵、升級星星等。
? ? /// 玩家子彈 擊中 可以掉落道具的敵方坦克,可以產生一個道具。
? ? /// 為了減少bug,同一時刻地圖上最多允許只有一個道具【上次的道具消失 或者 被新的道具覆蓋】。
? ? /// 我方坦克移動時,碰撞到道具時,道具消失,同時將觸發相應的事件
? ? /// </summary>
? ? public class Prop : RectangleObject
? ? {
? ? ? ? public Prop(Image image, int x, int y, PropCategory propCategory, int width = 0, int height = 0)
? ? ? ? ? ? : base(image, x, y, width, height)
? ? ? ? {
? ? ? ? ? ? this.PropCategory = propCategory;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 道具類別
? ? ? ? /// </summary>
? ? ? ? public PropCategory PropCategory { get; }
? ? }
}
?
十三、PropCategory.cs 源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuperTankDemo
{
? ? /// <summary>
? ? /// 道具類別,不同的道具將觸發不同的事件。主要有:星星,定時器,炸彈,箭頭等
? ? /// </summary>
? ? public enum PropCategory
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 升星:一級星增加攻擊速度【子彈的移動速度軌跡變快】 二級將攻擊兩次、三級可以擊穿鋼鐵墻
? ? ? ? /// </summary>
? ? ? ? Star = 1,
? ? ? ? /// <summary>
? ? ? ? /// 定時器。所有敵方坦克將靜止,無法移動和攻擊。持續15秒
? ? ? ? /// </summary>
? ? ? ? Timer = 2,
? ? ? ? /// <summary>
? ? ? ? /// 炸彈。當前所有敵方坦克 將爆炸消失
? ? ? ? /// </summary>
? ? ? ? Bomb = 3,
? ? ? ? /// <summary>
? ? ? ? /// 箭頭,我方坦克碰撞后,老鷹四方將產生鋼鐵墻,也就是說無敵狀態。持續15秒
? ? ? ? /// </summary>
? ? ? ? Arrow = 4,
? ? ? ? /// <summary>
? ? ? ? /// 帽子:我方坦克碰撞后 將無敵,持續15秒
? ? ? ? /// </summary>
? ? ? ? Hat = 5,
? ? ? ? /// <summary>
? ? ? ? /// 坦克禮物,復活次數加1
? ? ? ? /// </summary>
? ? ? ? TankGift = 6,
? ? ? ? /// <summary>
? ? ? ? /// 我方生命值增加1,可以抵擋一次攻擊傷害
? ? ? ? /// </summary>
? ? ? ? Apple = 7,
? ? ? ? /// <summary>
? ? ? ? /// 我方坦克直接到最高級3級,相當于3個星星【Super Weapon:超級武器】
? ? ? ? /// </summary>
? ? ? ? Blow = 8
? ? }
}
?
PS:目前只定義和相關的類與屬性,下一步將完善訂閱事件。比如子彈與窗體的碰撞,玩家子彈與敵方坦克的碰撞,玩家坦克與道具的碰撞事件等。
總結
以上是生活随笔為你收集整理的C#坦克大战流程设计与源代码(1):基本对象类规划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (JAVA)Integer类之基本数据类
- 下一篇: pta龟兔赛跑Java_PTA-龟兔赛跑