您的位置:首页 > 编程语言 > C#

基于C#弹幕类射击游戏的实现——(八)敌机

2013-12-17 20:06 507 查看
有了弹幕,有了主角,敌人当然就该上场了。

其实敌人和主角类似,也是一架飞机,不同点在于敌人的飞机是AI控制的,而玩家的飞机是自己控制而已~



public class GameEnemy : GameObject
	{
		protected int Life;
		public bool IsLive;
		protected int Type;
		protected Vector2 Speed;
		protected Vector2 Accel;
		
		/// <summary>
		/// 敌机的位图大小盒子
		/// </summary>
		public Box SourceBox
		{
			get
			{
				return new Box((int)Position.X, (int)Position.Y, EnemyWidth, EnemyHeight);
			}
		}
		
		/// <summary>
		/// 敌人发射子弹的类型
		/// </summary>
		public enum ShootType
		{
			None, // 不发射子弹
			Line, // 直线子弹
			Trace, // 追踪子弹
			Fan_3, // 成扇形发射3颗子弹
			Fan_5
		}
		
		protected ShootType mShootType;
		
		protected int EnemyWidth;
		protected int EnemyHeight;
		protected int HalfEnemyWidth;
		protected int HalfEnemyHeight;
		
		public GameEnemy(Vector2 position, int life, int type, ShootType shootType)
		{
			this.IsLive = true;
			
			base.Position = position;
			this.Speed = new Vector2(0, 0);
			this.Accel = new Vector2(0, 0);
			
			base.BoxCollider = new Box(0, 0, Data.EnemyBoxColliderRectangle[type].Width, Data.EnemyBoxColliderRectangle[type].Height);
			
			this.Life = life;
			this.Type = type;
			this.mShootType = shootType;
			
			this.EnemyWidth = Data.EnemySourceRectangle[type].Width;
			this.EnemyHeight = Data.EnemySourceRectangle[type].Height;
			this.HalfEnemyWidth = this.EnemyWidth / 2;
			this.HalfEnemyHeight = this.EnemyHeight / 2;
		}
		
		public void DecLife(int decLife)
		{
			Life -= decLife;
			
			if ( Life <= 0 )
			{
				IsLive = false;
				GameBombManager.AddBomb(Position, false, 0.5f);
			}
		}
		
		protected virtual void MoveLogic(float elapsedTime)
		{
			Speed += Accel * elapsedTime;
			Position += Speed * elapsedTime;
		}
		
		protected virtual void ShootLogic(float elapsedTime)
		{
			
		}
		
		public override void Update(float elapsedTime)
		{
			MoveLogic(elapsedTime);
			ShootLogic(elapsedTime);
			
			base.BoxCollider.X = (int)(Position.X + Data.EnemyBoxColliderRectangle[Type].X);
			base.BoxCollider.Y = (int)(Position.Y + Data.EnemyBoxColliderRectangle[Type].Y);
		}
		
		public override void Render(Graphics g)
		{
			g.DrawImage(Data.EnemySource,
			            new Rectangle((int)Position.X - HalfEnemyWidth, (int)Position.Y - HalfEnemyHeight, EnemyWidth, EnemyHeight),
			            Data.EnemySourceRectangle[Type],
			            GraphicsUnit.Pixel);
			
			if ( Config.IsDebug && Config.IsShowBox )
			{
				g.DrawRectangle(Pens.Green, BoxCollider.ToRectangle());
			}
		}
	}


可以看出,和GamePlayer很类似,因为基本上都是一个东西。

唯一需要注意的是MoveLogic和ShootLogic。就是这两个虚函数实现了敌人的AI

要创建不同类型的敌人(包括BOSS),就是集成GameEnemy,然后重写这两个函数就行了

public class GameEnemyManager
	{
		private List<GameEnemy> mEnemys;
		
		public GameEnemyManager()
		{
			this.mEnemys = new List<GameEnemy>();
		}
		
		public void AddEnemy(GameEnemy enemy)
		{
			mEnemys.Add(enemy);
		}
		
		public bool Collide(Box box, int decLife)
		{
			for ( int i = 0; i < mEnemys.Count; i++ )
			{
				if ( mEnemys[i].BoxCollider.Collide(box) == true )
				{
					mEnemys[i].DecLife(decLife);
					return true;
				}
			}
			
			return false;
		}
		
		public void Update(float elapsedTime)
		{
			for ( int i = 0; i < mEnemys.Count; i++ )
			{
				mEnemys[i].Update(elapsedTime);
				
				if ( mEnemys[i].IsLive == false )
				{
					mEnemys.RemoveAt(i);
					i--;
					continue;
				}
			}
		}
		
		public void Render(Graphics g)
		{
			foreach ( GameEnemy enemy in mEnemys )
			{
				enemy.Render(g);
			}
			
			if ( Config.IsDebug )
			{
				g.DrawString("Enemys:" + mEnemys.Count.ToString(), Data.NormalFont, Brushes.Red, 300, 15);
			}
		}
	}


管理类也很简单,重点都不是这里。接下来实现几种敌机



第一种,出现后直接就飞走的,企图用身体撞玩家的愚蠢飞机,因为它更本不追踪玩家,只是蒙头飞

// 直接飞走
	public class Enemy1 : GameEnemy
	{
		public Enemy1(Vector2 position)
			: base(position, 1, 0, ShootType.None)
		{
		}
		
		protected override void MoveLogic(float elapsedTime)
		{
			Position += new Vector2(0, 200 * elapsedTime);
			
			if ( GameScene.MainScene.InScreen(SourceBox) == false )
			{
				IsLive = false;
			}
		}
	}


这一个要聪明点,懂得追着玩家跑,而且会发射子弹了。

这里也可以看出如果重写MoveLogic和ShootLogic来实现简单的AI

// 追踪,单个子弹
	public class Enemy4 : GameEnemy
	{
		private Vector2 mDirection;
		private float ShootWaitTime;
		
		public Enemy4(Vector2 position)
			: base(position, 3, 3, ShootType.Trace)
		{
			this.Speed = new Vector2(225, 175);
			this.ShootWaitTime = 0.5f;
		}
		
		protected override void MoveLogic(float elapsedTime)
		{
			mDirection = GameScene.MainScene.Player1Position - Position;
			mDirection.Normalize();
			mDirection.Y = 1;
			
			Position = Position + (mDirection * Speed * elapsedTime);
			
			if ( GameScene.MainScene.InScreen(SourceBox) == false )
			{
				IsLive = false;
			}
		}
		
		protected override void ShootLogic(float elapsedTime)
		{
			if ( ShootWaitTime > 0 )
			{
				ShootWaitTime -= elapsedTime;
				return;
			}
			
			if ( Helper.GetRandomBool() )
			{
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(0, HalfEnemyHeight + 3), new Vector2(0, 200), Vector2.Zero, 0, 0, 0));
				ShootWaitTime = 2.0f;
			}
		}
	}


来个高端点的(AI其实很弱)

public class Enemy9 : GameEnemy
	{
		private float HorizonalMoveDistance; // 水平移动距离
		private bool MoveLeft; // 移动方向是否为左
		private float WaitTime;
		private float ShootWaitTime;
		
		public Enemy9(Vector2 position)
			: base(position, 20, 8, ShootType.Fan_5)
		{
			this.Speed = new Vector2(50, 150);
			
			this.HorizonalMoveDistance = 0;
			this.MoveLeft = true;
			this.WaitTime = 0;
			this.ShootWaitTime = 2.0f;
		}
		
		protected override void MoveLogic(float elapsedTime)
		{
			if ( Position.Y < 150 )
			{
				Position.Y += Speed.Y * elapsedTime;
				return;
			}
			
			if ( WaitTime > 0 )
			{
				WaitTime -= elapsedTime;
				return;
			}
			
			if ( HorizonalMoveDistance <= 0 )
			{
				WaitTime = 2.0f;
				
				MoveLeft = (Position.X - GameScene.MainScene.Player1Position.X) < 0 ? false : true;
				
				HorizonalMoveDistance = Helper.GetRandomFloat(30, 80);
				
				if ( MoveLeft && Position.X - HorizonalMoveDistance < HalfEnemyWidth )
				{
					MoveLeft = !MoveLeft;
				}
				if ( !MoveLeft && Position.X + HorizonalMoveDistance > Config.ScreenWidth - HalfEnemyWidth )
				{
					MoveLeft = !MoveLeft;
				}
			}
			else
			{
				if ( MoveLeft )
				{
					Position.X -= Speed.X * elapsedTime;
				}
				else
				{
					Position.X += Speed.X * elapsedTime;
				}
				
				HorizonalMoveDistance -= Speed.X * elapsedTime;
			}
		}
		
		protected override void ShootLogic(float elapsedTime)
		{
			if ( ShootWaitTime > 0 )
			{
				ShootWaitTime -= elapsedTime;
				return;
			}
			
			if ( Helper.GetRandomInt(0, 100) < 30 )
			{
				ShootWaitTime = 3.0f;
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(-5, HalfEnemyHeight + 3), new Vector2(-50, 200), Vector2.Zero, 0, 0, 0));
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(-2.5f, HalfEnemyHeight + 3), new Vector2(-25, 200), Vector2.Zero, 0, 0, 0));
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(0, HalfEnemyHeight + 3), new Vector2(0, 200), Vector2.Zero, 0, 0, 0));
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(2.5f, HalfEnemyHeight + 3), new Vector2(25, 200), Vector2.Zero, 0, 0, 0));
				GameScene.MainScene.AddBullet(new GameBullet(false, Position + new Vector2(5, HalfEnemyHeight + 3), new Vector2(50, 200), Vector2.Zero, 0, 0, 0));
			}
		}
	}


其实敌人的AI最好是用脚本来控制,但是为了简单,我们这里就这么做吧。



好了,游戏里有敌人了,而且分为不同的程度,有兴趣也可以自己添加新的,更聪明的敌机
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: