简介
通过核心部分的学习,我们已经可以做一些复杂的项目了。
我们这次会用我们学到的面向对象知识写一个飞机大战(性能可能不太好,因为毕竟是控制台项目)
如果你有所不懂,建议多查多思考多问。
因为这次的项目比较难,博主会稍微讲仔细一点。
基类设计:GameObject
抽象类
abstract class GameObject
{
protected int x; // 坐标X(列)
protected int y; // 坐标Y(行)
protected bool isAlive; // 存活状态
public GameObject(int x, int y)
{
this.x = x;
this.y = y;
this.isAlive = true; // 初始化时存活
}
// 只读属性:暴露坐标和存活状态(IsAlive可写)
public int X { get { return x; } }
public int Y { get { return y; } }
public bool IsAlive { get { return isAlive; } set { isAlive = value; } }
// 抽象方法:强制子类实现核心行为
public abstract void Move(); // 移动逻辑
public abstract void Draw(); // 绘制逻辑
public abstract void Attack(); // 攻击逻辑
}
- 核心作用:定义所有游戏对象(飞机、敌人、子弹、道具)的公共属性(坐标、存活状态)和必须实现的行为接口。
- 设计特点:
protected
修饰的字段允许子类直接访问,避免过度封装。- 抽象方法确保子类必须实现移动、绘制、攻击这三个核心功能,实现多态性(如飞机和敌人的移动方式不同)。
玩家飞机:Aircraft
类
class Aircraft : GameObject
{
public int health = 5; // 玩家生命值(初始5点)
public List<Bullet> bullets = new List<Bullet>(); // 玩家发射的子弹列表
public Aircraft(int x, int y) : base(x, y) { } // 调用基类构造函数初始化坐标
public override void Move()
{
while (Console.KeyAvailable) // 处理所有未读取的按键(避免漏键)
{
ConsoleKeyInfo key = Console.ReadKey(true); // 读取按键并隐藏输入字符
switch (key.Key)
{
case ConsoleKey.LeftArrow: if (x > 1) x--; break; // 左边界限制(x>1,避开左墙体)
case ConsoleKey.RightArrow: if (x < Console.WindowWidth - 2) x++; break; // 右边界限制
case ConsoleKey.UpArrow: if (y > 1) y--; break; // 上边界限制(避开顶部墙体)
case ConsoleKey.DownArrow: if (y < Console.WindowHeight - 3) y++; break; // 下边界限制(避开底部墙体和分数栏)
case ConsoleKey.Spacebar: Attack(); break; // 按下空格时调用攻击(发射子弹)
}
}
}
public override void Draw()
{
// 确保坐标在屏幕内,避免控制台异常
if (x >= 0 && x < Console.WindowWidth && y >= 0 && y < Console.WindowHeight)
{
Console.SetCursorPosition(x, y);
Console.Write("A"); // 用"A"字符表示玩家飞机
}
}
public override void Attack()
{
bullets.Add(new Bullet(x, y - 1)); // 在飞机当前位置上方一格生成子弹(玩家子弹向上移动)
}
}
关键逻辑:
- 移动控制:通过
Console.KeyAvailable
实时检测方向键,直接修改x/y
坐标,并通过边界判断(如x > 1
)确保飞机不会移出墙体范围。 - 子弹发射:按下空格时,调用
Attack()
方法,在飞机上方(y-1
)生成一颗非敌人子弹(isEnemyBullet=false
)。 - 绘制逻辑:使用
Console.SetCursorPosition
定位后输出字符 "A",直观显示玩家位置
敌人类型:NormalEnemy
和 RandomMovingEnemy类
普通敌人:垂直移动 + 概率射击(NormalEnemy
)
class NormalEnemy : GameObject
{
public List<Bullet> enemyBullets = new List<Bullet>(); // 敌人发射的子弹列表
public NormalEnemy(int x, int y) : base(x, y) { } // 初始化坐标
public override void Move()
{
// 50%概率向下移动(通过随机数控制速度,避免频繁移动)
if (new Random().Next(2) == 0)
{
y++; // 向下移动
if (y >= Console.WindowHeight - 2) // 触达底部墙体时死亡
isAlive = false;
}
}
public override void Draw()
{
if (isAlive && y < Console.WindowHeight - 2 && x >= 0 && x < Console.WindowWidth)
{
Console.SetCursorPosition(x, y);
Console.Write("E"); // 用"E"字符表示普通敌人
}
// 处理敌人子弹:移动、绘制、移除死亡子弹
for (int i = enemyBullets.Count - 1; i >= 0; i--)
{
Bullet bullet = enemyBullets[i];
bullet.Move(); // 子弹移动
bullet.Draw(); // 子弹绘制
if (!bullet.IsAlive) // 子弹超出屏幕则移除
enemyBullets.RemoveAt(i);
}
}
public override void Attack()
{
// 10%概率发射子弹(向下移动的敌人子弹)
if (new Random().Next(100) < 10)
enemyBullets.Add(new Bullet(x, y + 1, true)); // isEnemyBullet=true标识敌人子弹
}
}
随机移动敌人:四方向随机移动 + 概率射击(RandomMovingEnemy)
class RandomMovingEnemy : GameObject
{
public List<Bullet> enemyBullets = new List<Bullet>(); // 敌人子弹列表
private Random random = new Random(); // 随机数生成器(成员变量,避免重复创建)
public RandomMovingEnemy(int x, int y) : base(x, y) { }
public override void Move()
{
// 50%概率随机移动(上下左右四方向)
if (random.Next(2) == 0)
{
int direction = random.Next(4); // 0-3对应上下左右
switch (direction)
{
case 0: if (y > 1) y--; break; // 上移(避开顶部墙体)
case 1: if (y < Console.WindowHeight - 2) y++; break; // 下移(避开底部墙体)
case 2: if (x > 1) x--; break; // 左移(避开左墙体)
case 3: if (x < Console.WindowWidth - 2) x++; break; // 右移(避开右墙体)
}
}
}
public override void Draw()
{
// 逻辑与NormalEnemy类似,仅绘制字符为"R"
if (isAlive && y < Console.WindowHeight - 2 && x >= 0 && x < Console.WindowWidth)
{
Console.SetCursorPosition(x, y);
Console.Write("R"); // 用"R"字符表示随机移动敌人
}
// 子弹处理逻辑与NormalEnemy完全一致
for (int i = enemyBullets.Count - 1; i >= 0; i--)
{
Bullet bullet = enemyBullets[i];
bullet.Move();
bullet.Draw();
if (!bullet.IsAlive)
enemyBullets.RemoveAt(i);
}
}
public override void Attack()
{
// 与NormalEnemy相同:10%概率发射向下子弹
if (random.Next(100) < 10)
enemyBullets.Add(new Bullet(x, y + 1, true));
}
}
- 设计差异:
- 移动方式:普通敌人仅垂直向下移动,随机敌人通过
Random.Next(4)
实现四方向随机移动,增加游戏难度。 - 性能细节:
RandomMovingEnemy
中将Random
作为成员变量,避免每次调用Move()
时创建新实例
- 移动方式:普通敌人仅垂直向下移动,随机敌人通过
子弹与道具:Bullet
和 ClearScreenItem
类
子弹类:区分敌我子弹的移动方向(Bullet
)
class Bullet : GameObject
{
public bool isEnemyBullet; // 是否为敌人发射的子弹(决定移动方向)
public Bullet(int x, int y, bool isEnemyBullet = false) : base(x, y)
{
this.isEnemyBullet = isEnemyBullet; // 默认为玩家子弹(false)
}
public override void Move()
{
if (isEnemyBullet)