cmd 控制台 RPG :追加无中生有的第一个敌人类,攻击类,敌群类,实现敌人死亡复活。

本文主要是介绍cmd 控制台 RPG :追加无中生有的第一个敌人类,攻击类,敌群类,实现敌人死亡复活。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 1.实现攻击类,玩家类,敌人类,敌群类,可进行更大规模的拓展,也可把图形学的画直线算法接入其中

2.攻击检测是通过地图网格数组记录攻击符号,敌人坐标在地图里检测攻击符号敌人就改变flag

3.实现了简单的消息提示

#include <iostream>
#include <string.h>
#include <windows.h>
#include <time.h>
#define KEY_DOWN(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1:0)							// 判断是否按下按键,按下之后,最高位变成 1,所以需要位运算去除其他位,只检测最高位
#define KEY_DOWN_FOREGROUND(hWnd, vk) (KEY_DOWN(vk) && GetForegroundWindow() == hWnd) 		// 前景窗口判断
#pragma warning(disable : 4996)																// 便于移植到非微软的编译器里 
using namespace std;// 加入的游戏背景数据,通常不修改,放到 Bkmap 进行修改
class Gamemap
{public:Gamemap(int height,int wide){this->wide=wide;this->height=height;this->gamemap=new int*[this->height];for(int i=0; i<height; i++){this->gamemap[i]=new int[this->wide];for(int j=0; j<this->wide; j++){this->gamemap[i][j]=0;}}}~Gamemap();public:int** gamemap;															// 游戏地图数组int wide;																// 游戏长宽int height;
};
// 游戏背景操作网格数组,可以通过坐标直接改
class Bkmap
{public:Bkmap(int height,int wide){this->wide=wide;this->height=height;this->bkmap=new char*[this->height];for(int i=0; i<height; i++){this->bkmap[i]=new char[this->wide];for(int j=0; j<wide; j++){this->bkmap[i][j]='\0';}}}public:char** bkmap;														// 游戏地图操作网格数组int wide;															// 操作网格长宽int height;public:// 测试用,程序闪退,检测当时哪里数组溢出,哪里数据缺失void adddata(){for(int i=0; i<this->height; i++)								// 地图数据写入{for(int j=0; j<this->wide-1; j++){this->bkmap[i][j]='*';}this->bkmap[i][this->wide-1]='\0';							// 截至符号,防止后续粘贴多粘贴其他奇奇怪怪的旧数据}}// 刷新缓冲区,清除之前的数据,防止混合新数据形成奇奇怪怪的bugvoid fresh(Gamemap* gamemap){for(int i=0; i<gamemap->height; i++)								// 地图复印到操作网格区{this->bkmap[i][0]='#';											// 最左侧是边界for(int j=1; j<gamemap->wide; j++){if(gamemap->gamemap[i][j]==0)this->bkmap[i][j]=' ';									// 这里决定地图打印在屏幕的样子}this->bkmap[i][gamemap->wide]='#';								// 设置截断点,防止残留数据this->bkmap[i][gamemap->wide+1]='\0';}for(int j=0; j<gamemap->wide; j++)this->bkmap[gamemap->height][j]='#';							// 底部也有边界线this->bkmap[gamemap->height][gamemap->wide+1]='\0';}};
// 字符串缓冲类
class Showmap
{public:Showmap(int height,int wide){this->showmap=new char[wide*height+1000];strcpy(showmap,"");
//			showmap={};												// 不能这样写,否则报错,指针重新变空}public:char* showmap;												// 显示区缓冲public:// 加入缓冲数据,用于一键打出,多个 cout printf 反而会打印慢,有一行行残影void adddata(Bkmap* bkmap){if(showmap==NULL){cout<<"NULL";cout<<"函数因空指针结束"<<endl;return;}strcpy(showmap,"");										// 清空旧数据 ,实际上是把标志位放到开头,保证从头粘贴数据for(int i=0; i<bkmap->height; i++)						// 选区加入到打印缓冲区{strcat(showmap,bkmap->bkmap[i]);strcat(this->showmap,"\n");}}// 一键显示到屏幕void show(){cout<<this->showmap;}
};// 玩家类,移动,攻击,地图修改
class Player
{public:Player(int x,int y,int limity,int limitx){this->playerx=x;this->playery=y;is_atk=0;is_buff=0;flag_x=0;flag_y=0;this->limitx=limitx;this->limity=limity;}~Player();public:char player='1';int playerx;int playery;int flag_x;int flag_y;int limitx;int limity;int is_atk;int is_buff;public://玩家移动检测void checkmove(HWND hwnd){flag_x=0;flag_y=0;if (KEY_DOWN_FOREGROUND(hwnd, 0x41))			// A{flag_x -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x57))			// W{flag_y -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x44))			// D{flag_x += 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x53))			// S{flag_y += 1;}}// 打包速度检测void checkspeed(){if (flag_x > 1)														// 速度限制flag_x = 1;else if (flag_x < -1)flag_x = -1;if (flag_y > 1)flag_y = 1;else if (flag_y < -1)flag_y = -1;}// 改变玩家位置void move(){if (flag_x)															// 位移改变playerx += flag_x;if (flag_y)playery += flag_y;}
//		边界检测void checkboundary(){if (playerx >= limitx)												// 角色位置限制playerx = limitx - 1;else if (playerx < 0)												// 左侧边界,可以修改成 1 这样就不会进入栅栏,和'#’重叠了playerx = 0;if (playery >= limity)playery = limity - 1;else if (playery < 0)playery = 0;}// 玩家通过操作网格可以通过坐标直接查找所在位置并写入地图中void putinmap(Bkmap* bkmap){bkmap->bkmap[playery][playerx]=player;}
//		检测攻击void checkatk(HWND hwnd){if (is_atk == 0 ){if( KEY_DOWN_FOREGROUND(hwnd, 0x4A))			// j 键攻击is_atk = 1;else if(KEY_DOWN_FOREGROUND(hwnd,0x31))			// 1 键攻击is_atk=2;}}
//		检测buffvoid checkbuff(HWND hwnd){if (is_buff == 0 && KEY_DOWN_FOREGROUND(hwnd, 0x4B))		// k 键增加范围 buff{is_buff = 1;}}// 绘制地图void drawmap(HWND hwnd,Gamemap* gamemap){if (KEY_DOWN_FOREGROUND(hwnd, 0x30))								// 0 键绘制地图gamemap->gamemap[playery][playerx] = 0;if (KEY_DOWN_FOREGROUND(hwnd, 0x36))								// 6 键绘制地图gamemap->gamemap[playery][playerx] = 6;if (KEY_DOWN_FOREGROUND(hwnd, 0x37))								// 7 键绘制地图gamemap->gamemap[playery][playerx] = 7;if (KEY_DOWN_FOREGROUND(hwnd, 0x38))								// 8 键绘制地图gamemap->gamemap[playery][playerx] = 8;if (KEY_DOWN_FOREGROUND(hwnd, 0x39))								// 9 键绘制地图gamemap->gamemap[playery][playerx] = 9;}
};
// 攻击类,这里直线攻击做测试
class Aking
{public:Aking(int height,int wide,int atk_time,int number){this->height=height;this->wide=wide;this->number=number;this->atk_time=atk_time;atk_count=0;}public:int height;																// 攻击范围长宽int wide;int number;																// 攻击序号,因为有多个攻击技能,所以编号,可以查找攻击int atk_time;															// 攻击时长int atk_count;															// 当前攻击持续时间public:// 攻击中void atking(Bkmap* bkmap,Player* player){if (atk_count != atk_time)										// 攻击{atk_count++;for(int j=0; j<10; j++){bkmap->bkmap[player->playery][player->playerx+1+j]='P';}}else{atk_count=0;player->is_atk=0; 												// 玩家状态复位}}
};
// 攻击类v2继承之前的攻击类,这里做范围攻击做测试
class Akingv2:public Aking
{public:Akingv2(int height,int wide,int atk_time,int number):Aking( height,wide,atk_time,number){this->height=height;this->wide=wide;this->number=number;this->atk_time=atk_time;atk_count=0;}public:void atkingv2(Bkmap* bkmap,Player* player){if (atk_count != atk_time)										// 攻击{atk_count++;for(int i=0; i<10; i++)for(int j=0; j<10; j++){bkmap->bkmap[player->playery-5+i][player->playerx+1+j]='P';}}else{atk_count=0;player->is_atk=0; 												// 玩家状态复位}}
};
// 敌人移动
class Enemy
{public:Enemy(char enemy,int number){x=rand()%50;													// 设置随机位置y=rand()%20;count=0;														// 参考攻击时长,记录时间,但是用于限速,延缓敌人行动sence=2;														// 每两次循环进行反应speed=1;this->enemy=enemy;this->number=number;											// 编号,同类敌人用于区分,在敌群时才有用this->islive=1;													// 默认刚创造出来的敌人是活的}public:char enemy; 														// 敌人样子int number;															// 敌人编号,因为敌群有好几个敌人int islive;															// 敌人死活,死敌人可以复活重复利用int x;																// 位置int y;int speed;															// 速度int count;															// 计时,用于选择某个时间移动int sence;															// 灵敏度,记录选择的时间public:// 移动,向玩家方向void move(Player* player){count++;if(count==sence)												// 到反应时间了才移动一次 这里设置的是每两次循环移动一次{if(x<player->playerx)x++;else if(x>player->playerx)x--;if(y<player->playery)y++;else if(y>player->playery)y--;count=0;}}// 死亡后不移动void movev2(Player* player){if(islive){count++;if(count==sence)												// 到反应时间了才移动一次 这里设置的是每两次循环移动一次{if(x<player->playerx)x++;else if(x>player->playerx)x--;if(y<player->playery)y++;else if(y>player->playery)y--;count=0;}}}// 撞击玩家void atk(Player* player){if(player->playerx==x&&player->playery==y)cout<<"被追击了"<<endl;else cout<<endl;						// 占位,因为之前测试有时敌群弹出就会导致最上面信息上下颠簸}// 写入地图// 敌人通过操作网格可以通过坐标直接查找所在位置并写入地图中void putinmap(Bkmap* bkmap){bkmap->bkmap[y][x]=enemy;}// 死亡就不写入地图void putinmapv2(Bkmap* bkmap){if(islive==1)bkmap->bkmap[y][x]=enemy;}// 敌人死亡,写敌群类时增加的void checkdead(Bkmap* bkmap){if(bkmap->bkmap[y][x]=='P')islive=0;}// 敌人复活 ,写敌群时增加的void relive(){if(islive==0){islive=1;x=rand()%50;y=rand()%20;}}
};
// 敌群
class Enemygroup
{public:Enemygroup(char enemy,int number,int limitnum)				// 设定敌人样子与敌人编号敌人个数{maxnum=30;enemys = new Enemy*[maxnum];for(int i=0; i<number; i++){enemys[i] = new Enemy(enemy,i);}this->limitnum=limitnum;									// 记录维持个数this->livenum=limitnum;}public:Enemy** enemys;int maxnum;										// 设定最大容量int limitnum;									// 设定敌群个数维持值,例如小于5个敌人就增加敌人int livenum;									// 当前存活敌人个数public:// 增加敌人void addenemy(){if(livenum<limitnum) 						// 当前存活敌人小于设定界限,开始补充敌人{for(int i=0; i<limitnum; i++){if(enemys[i]!=NULL){if(enemys[i]->islive==0){enemys[i]->relive();livenum++;}}if(livenum==limitnum)break;}}}// 敌人移动void move(Player* player){for(int i=0; i<limitnum; i++){if(enemys[i]!=NULL&&enemys[i]->islive==1){enemys[i]->move(player);}}cout<<"存活敌人数目:"<<livenum<<endl;}// 敌群死亡void dead(Bkmap* bkmap){livenum=0;															// 重新数有多少敌人for(int i=0; i<limitnum; i++){if(enemys[i]!=NULL){enemys[i]->checkdead(bkmap);if(enemys[i]->islive){livenum++;}}}}// 打印敌人void putinmap(Bkmap* bkmap){for(int i=0; i<limitnum; i++){if(enemys[i]!=NULL&&enemys[i]->islive){bkmap->bkmap[enemys[i]->y][enemys[i]->x]=enemys[i]->enemy;}}}
};
int main()
{Gamemap* gamemap = new Gamemap(20,50);									// 生成一个游戏地图Bkmap* bkmap=new Bkmap(20+3,50);										// 生成一个操作网格区Showmap* showmap= new Showmap(20,80);									// 生成一个显示区Aking* ak = new Aking(10,1,12,1);										// 直线攻击,长 10 宽 1 持续时间 12 次循环,序号是1Akingv2* akv2 = new Akingv2(10,1,12,2);									// 攻击方式v2Player* player = new Player(0,0,20,50);									// 生成一个玩家Enemy* mk = new Enemy('%',2);												// 生成一个敌人,敌人是 ”%"Enemy* mkv2= new Enemy('0',3);											// 生成另一个敌人,敌人是 “0”Enemygroup* mkvs = new Enemygroup('9',4,10);bkmap->fresh(gamemap);													// 清空旧数据
//	bkmap->adddata();														// 测试数据 改bug 测试用showmap->adddata(bkmap);
//	showmap->show();HWND hwnd = GetForegroundWindow();										// 获取前端窗口句柄,由于程序刚运行时是在前端,所以这就是本程序的窗口句柄//获取默认标准显示缓冲区句柄HANDLE hOutput;COORD coord= {0,0};hOutput=GetStdHandle(STD_OUTPUT_HANDLE);//创建新的缓冲区HANDLE hOutBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CONSOLE_TEXTMODE_BUFFER,NULL);//设置新的缓冲区为活动显示缓冲SetConsoleActiveScreenBuffer(hOutBuf);//隐藏两个缓冲区的光标CONSOLE_CURSOR_INFO cci;cci.bVisible=0;cci.dwSize=1;SetConsoleCursorInfo(hOutput, &cci);SetConsoleCursorInfo(hOutBuf, &cci);//双缓冲处理显示DWORD bytes=0;char data[4900];int cnt =0;srand(time(NULL));												// 设置随机数种子while(1){cout<<"2" ;															// 测试最顶端,顶端之上的是奇奇怪怪的数据cout<<endl;															// 把一些奇奇怪怪的数据顶上去,让地图下移两行显示cout<<endl;bkmap->fresh(gamemap);												// 清空操作网格区数据if (KEY_DOWN_FOREGROUND(hwnd, VK_ESCAPE)){printf("游戏退出\n");break;}player->checkmove(hwnd);											// 移动按键检测player->checkatk(hwnd);												// 攻击按键检测player->checkspeed();												// 速度检测player->move();														// 玩家移动player->checkboundary();											// 边界检测player->putinmap(bkmap);											// 玩家位置写入操作网格区switch (player->is_atk) 											// 攻击选择方式{case 1:ak->atking(bkmap,player);									// 攻击写入操作网格区break;case 2:akv2->atkingv2(bkmap,player);break;}// 一定要在攻击之后检测敌人死亡 ,地图在攻击之后才有标记mkv2->movev2(player);mkv2->atk(player);mkv2->checkdead(bkmap);												// 通过检测网格敌人坐标是否有攻击记号来确定是否被攻击mkv2->putinmapv2(bkmap);mkvs->move(player);mkvs->dead(bkmap);mkvs->putinmap(bkmap);// 不死的敌人要最后打印,因为之前先打印后,清除了攻击标记,敌群死亡个数少,表现为复活少了,但是总数还是正常的。mk->move(player);													// 敌人移动mk->atk(player);													// 敌人攻击mk->putinmap(bkmap);												// 敌人写入地图cnt++;if(cnt==16){if(mkv2->islive==0)mkv2->relive();}if(cnt==40){mkvs->addenemy();}if(cnt==60)cnt=0;cout<<"冲冲冲"<<endl;showmap->adddata(bkmap);											// 操作网格区写入显示缓冲区
//		system("cls");														// 双缓冲时,去除清屏命令cout<<"玩家位置:"<<player->playerx<<","<<player->playery<<endl;showmap->show();// 每增加一个cout输出,这里就注释掉一行cout<<endl;															// 用于顶到顶部,把一些奇奇怪怪的数据顶出屏幕cout<<endl;															// 这几条回车和最开头的回车可以调节地图在黑窗口的显示位置
//		cout<<endl;															// 这里被注释,地图就下移,上边被注释,地图就上移
//		cout<<endl;Sleep(50);ReadConsoleOutputCharacterA(hOutput, data, 4900, coord, &bytes);WriteConsoleOutputCharacterA(hOutBuf, data, 4900, coord, &bytes);
//		cout<<"测试数据位置。";}return 0;}

这篇关于cmd 控制台 RPG :追加无中生有的第一个敌人类,攻击类,敌群类,实现敌人死亡复活。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/881544

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

2024.6.24 IDEA中文乱码问题(服务器 控制台 TOMcat)实测已解决

1.问题产生原因: 1.文件编码不一致:如果文件的编码方式与IDEA设置的编码方式不一致,就会产生乱码。确保文件和IDEA使用相同的编码,通常是UTF-8。2.IDEA设置问题:检查IDEA的全局编码设置和项目编码设置是否正确。3.终端或控制台编码问题:如果你在终端或控制台看到乱码,可能是终端的编码设置问题。确保终端使用的是支持你的文件的编码方式。 2.解决方案: 1.File -> S

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页:

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

python实现最简单循环神经网络(RNNs)

Recurrent Neural Networks(RNNs) 的模型: 上图中红色部分是输入向量。文本、单词、数据都是输入,在网络里都以向量的形式进行表示。 绿色部分是隐藏向量。是加工处理过程。 蓝色部分是输出向量。 python代码表示如下: rnn = RNN()y = rnn.step(x) # x为输入向量,y为输出向量 RNNs神经网络由神经元组成, python

利用Frp实现内网穿透(docker实现)

文章目录 1、WSL子系统配置2、腾讯云服务器安装frps2.1、创建配置文件2.2 、创建frps容器 3、WSL2子系统Centos服务器安装frpc服务3.1、安装docker3.2、创建配置文件3.3 、创建frpc容器 4、WSL2子系统Centos服务器安装nginx服务 环境配置:一台公网服务器(腾讯云)、一台笔记本电脑、WSL子系统涉及知识:docker、Frp