C#核心(25)练手小项目:飞机大战

发布于:2025-04-20 ⋅ 阅读:(73) ⋅ 点赞:(0)

简介

通过核心部分的学习,我们已经可以做一些复杂的项目了。

我们这次会用我们学到的面向对象知识写一个飞机大战(性能可能不太好,因为毕竟是控制台项目)

如果你有所不懂,建议多查多思考多问。

因为这次的项目比较难,博主会稍微讲仔细一点。

基类设计: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)
     

网站公告

今日签到

点亮在社区的每一天
去签到