C#核心(25)练手小项目:飞机大战
简介
通过核心部分的学习,我们已经可以做一些复杂的项目了。
我们这次会用我们学到的面向对象知识写一个飞机大战(性能可能不太好,因为毕竟是控制台项目)
如果你有所不懂,建议多查多思考多问。
因为这次的项目比较难,博主会稍微讲仔细一点。
基类设计: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)相关文章:
C#核心(25)练手小项目:飞机大战
简介 通过核心部分的学习,我们已经可以做一些复杂的项目了。 我们这次会用我们学到的面向对象知识写一个飞机大战(性能可能不太好,因为毕竟是控制台项目) 如果你有所不懂,建议多查多思考多问。 因为这次的项目比较难,博主会稍微讲仔细一点。 基类设计:GameObject 抽…...
[经验总结]Linux双机双网卡Keepalived高可用配置及验证细节
1. 前言 这种配置需求比较少见,在网上也很少有相关文章,于是记录在此,供有需要的朋友参考。 本篇重点介绍配置的关键点,基础部分简单提及,不赘述。 2. 需求描述 如上图,即给两个主机配置两对高可用主从配…...
Go语言入门到入土——三、处理并返回异常
Go语言入门到入土——三、处理并返回异常 文章目录 Go语言入门到入土——三、处理并返回异常1. 在greetings.go中添加异常处理代码2. 在hello.go中添加日志记录代码3. 运行 1. 在greetings.go中添加异常处理代码 处理空输入的异常,代码如下: package g…...
2025.04.17【Dendrogram】生信数据可视化:Dendrogram图表详解
Dendrogram customization Go further with ggraph: edge style, general layout, node features, adding labels, and more. Customized circular dendrogram Learn how to build a circular dendrogram with proper labels. 文章目录 Dendrogram customizationCustomized c…...
Linux下的网络管理
一、ipv4原理 网络接口是指网络中的计算机或网络设备与其他设备实现通讯的进出口,一般是指计算机的网络接口即网卡设备 从RHEL7开始引入了一种新的“一致网络设备命名”的方式为网络接口命名,该方式可以根据固件、设备拓扑、设备类型和位置信息分配固…...
GPT-4o Image Generation Capabilities: An Empirical Study
GPT-4o 图像生成能力:一项实证研究 目录 介绍研究背景方法论文本到图像生成图像到图像转换图像到 3D 能力主要优势局限性与挑战对比性能影响与未来方向结论介绍 近年来,图像生成领域发生了巨大的变化,从生成对抗网络 (GAN) 发展到扩散模型,再到可以处理多种模态的统一生成架…...
Zookeeper介绍与安装配置
1.综述 1.1.Zookeeper介绍 Zookeeper 是一个分布式协调服务,由 Apache 开发,主要用于管理分布式应用中的配置信息、命名服务、分布式同步和组服务。它通过简单的接口提供高性能、高可用性和严格的顺序访问控制,广泛应用于分布式系统的协调与…...
提示词阶段总结
经过这些天的提示词学习,总结了一下提示词示例,可以直接拿来使用,规范大模型的输出。 CoT(适用于算术题) {问题},让我们一步一步思考。 Auto-CoT(自动思维链,适合回答多个问题一起…...
实验五 内存管理实验
实验五 内存管理实验 一、实验目的 1、了解操作系统动态分区存储管理过程和方法。 2、掌握动态分区存储管理的主要数据结构--空闲表区。 3、加深理解动态分区存储管理中内存的分配和回收。 4、掌握空闲区表中空闲区3种不同放置策略的基本思想和实现过程。 5、通过模拟程…...
用Webpack 基础配置快速搭建项目开发环境
Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具,但是Webpack有大量的配置项,对新手不太友好,但是我们可以根据webpack-cli的init命令根据项目需求快速生成webpack的配置文件,本文将手把手教你如何用 Webpack 和 npm 快…...
Axios 介绍及使用指南
本文将基于 Axios 原理,安装及封装方面展开描述,话不多说,现在发车! 一、原理 Axios 中文文档:起步 | Axios中文文档 | Axios中文网 赛前科普: 下文将涉及到三个关键词:Axios,Ajax…...
接口自动化测试(二)
一、接口测试流程:接口文档、用例编写 拿到接口文档——编写接口用例以及评审——进行接口测试——工具/自动化框架进行自动化用例覆盖(70%)——输出测试报告 自动化的目的一般是为了回归 第一件事情:理解需求,学会看接口文档 只需要找到我…...
Arduino+ESP826601s模块连接阿里云并实现温湿度数据上报
ArduinoESP826601s模块连接阿里云并实现温湿度数据上报 一、前言二、准备工作三、程序代码1. Arduino的程序2. ESP826601的程序3. 上面程序需要注意的地方 四、运行结果五、结束语 一、前言 看完我这三篇文章,相信各位朋友对于阿里云物联网平台的使用都有了一定的认…...
本地生活服务信息分类信息系统
最近在找分类信息系统,看了很多市面上常见的分类信息系统: 1,私集分类信息系统 2,火鸟分类信息系统 3,觅分类信息系统 4,框分类信息系统 5,蚂蚁分类信息系统 发现很多分类信息系统,…...
React Native 0.79 稳定版发布,更快的工具、更多改进
React Native 0.79 已发布。此版本在多个方面进行了性能改进,并修复了一些漏洞。首先,得益于延迟哈希技术,Metro 的启动速度变快了,并且对包导出提供了稳定支持。由于 JS 包压缩方式的改变等原因,Android 的启动时间也…...
【Dify应用】连接数据库生成Echarts图表
这里写自定义目录标题 需求文档内容测试环境实际效果工作流内容工具安装B工作流详解A工作流详解优化建议 需求 甲方要求。根据自然语言生成对应Echarts图表,并且数据来源于私有数据库。 文档内容 本文档内容主要展示使用Dify(本地源码)进行…...
无刷电机槽数相同、转子极数不同的核心区别
一、基础原理差异 无刷电机的核心参数: 槽数(定子槽数,记为 ( Z )):定子铁芯上的绕组槽数量,决定绕组布局。极数(转子磁极数,记为 ( 2p )):转子上的永磁体磁极对数(总极数为 ( 2p ),如 ( p=4 ) 表示 8 极)。核心关系:槽极配合(( Z/2p ))决定电机电磁结构,相同…...
RAG 实战|用 StarRocks + DeepSeek 构建智能问答与企业知识库
文章作者: 石强,镜舟科技解决方案架构师 赵恒,StarRocks TSC Member 👉 加入 StarRocks x AI 技术讨论社区 https://mp.weixin.qq.com/s/61WKxjHiB-pIwdItbRPnPA RAG 和向量索引简介 RAG(Retrieval-Augmented Gen…...
JavaScript 性能优化实战
一、代码执行效率优化 1. 减少全局变量的使用 全局变量在 JavaScript 中会挂载在全局对象(浏览器环境下是window,Node.js 环境下是global)上,频繁访问全局变量会增加作用域链的查找时间。 // 反例:使用全局变量 var globalVar = example; function someFunction() {con…...
ubuntu 22.04 使用ssh-keygen创建ssh互信账户
现有两台ubuntu 22.04服务器,ip分别为192.168.66.88和192.168.88.66。需要将两台服务器创建新用户并将新用户做互信。 创建账户 adduser user1 # 如果此用户不想使用密码,直接一直回车就行,创建的用户是没法使用用户密码进行登陆的 su - …...
【Linux网络】Socket 编程TCP
🌈个人主页:秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343 🔥 系列专栏:https://blog.csdn.net/qinjh_/category_12891150.html 目录 TCP socket API 详解 socket(): bind(): listen(): accept(): connect V0…...
C++指针与内存管理深度解析
前言: 在C开发的道路上,指针和内存管理就像是两个既强大又危险的朋友。掌握它们就如同学会驾驭一辆高性能跑车,稍有不慎可能导致灾难,但一旦熟练掌握,便能发挥出惊人的性能和灵活性。今天就让我们一起深入探讨C中的指…...
ESP32-idf学习(二)esp32C3作服务端与电脑蓝牙数据交互
一、当前需求 目前是想利用蓝牙来传输命令,或者一些数据,包括电脑、手机与板子的数据传输,板子与板子之间的数据传输。构思是一个板子是数据接收终端,在电脑或手机下发指令后,再给其他板子相应指令,也需要…...
NHANES指标推荐:CMI
文章题目:Association between cardiometabolic index and biological ageing among adults: a population-based study DOI:10.1186/s12889-025-22053-3 中文标题:成年人心脏代谢指数与生物衰老之间的关系:一项基于人群的研究 发…...
前端单元测试实战:如何开始?
实战:如何开始单元测试 1.安装依赖 npm install --save-dev jest2.简单的例子 首先,创建一个 sum.js 文件 ./sum.js function sum(a, b) {return a b; }module.exports sum;创建一个名为 sum.test.js 的文件,这个文件包含了实际测试内…...
react-native搭建开发环境过程记录
主要参考:官网的教程 https://reactnative.cn/docs/environment-setup 环境介绍:macos ios npm - 已装node18 - 已装,通过nvm进行版本控制Homebrew- 已装yarn - 已装ruby - macos系统自带的2.2版本。watchman - 正常安装Xcode - 正常安装和…...
【数据库系统概论】第3章 SQL(四)视图(超详细)
视图(View)是数据库中的虚拟表 通过执行查询定义并存储在数据库中,可以像普通表一样被查询和使用。 视图本身并不存储数据,而是基于一个或多个表的查询结果动态生成。 视图的概念 视图( View )是由其它表或视图上的查询所定义…...
观察者模式详解与C++实现
1. 模式定义 观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间的一对多依赖关系。当一个对象(被观察者/主题)状态改变时,所有依赖它的对象(观察者)都会自动收到通知…...
空调制冷量和功率有什么关系?
空调的制冷量和功率是衡量空调性能的两个核心参数,二者既有区别又紧密相关,以下是具体解析: 1. 基本定义 制冷量(Cooling Capacity)指空调在单位时间内从室内环境中移除的热量,单位为 瓦特(W) 或 千卡/小时(kcal/h)。它直接反映空调的制冷能力,数值越大,制冷效果越…...
【python报错解决训练】
在编程开发中,正确解读报错信息是解决问题的关键技能。以下是系统学习解读报错信息的方法指南: 一、理解报错信息的核心结构 典型的报错信息包含以下要素(以Python为例): Traceback (most recent call last):File &q…...
