有了弹幕,有了主角,敌人当然就该上场了。
其实敌人和主角类似,也是一架飞机,不同点在于敌人的飞机是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最好是用脚本来控制,但是为了简单,我们这里就这么做吧。
好了,游戏里有敌人了,而且分为不同的程度,有兴趣也可以自己添加新的,更聪明的敌机