4.打怪兽拯救公主游戏控制台实践
4.1 知识点
需求分析
开始界面
大字显示游戏名。菜单有开始游戏和退出游戏两个选项。用颜色标明当前正在选的选项,可以输入ws上下切换选项。回车确认进入对应选项,跳出开始界面,进入游戏界面或退出游戏。
游戏界面
整个场景分成战斗区域和信息区域。可以输入wasd上下左右在战斗区域移动玩家。游戏开始前随机出玩家和敌人的攻击力和血量。四周有红墙限制玩家位置不会超出战斗区域。战斗区域中间有一个绿色敌人。玩家移动时不可以覆盖敌人。贴住敌人时可以按j键进行回合制战斗。每次按下j键进行一回合的战斗,下放信息区输出战斗信息。战斗时玩家禁止移动。直到敌人是我或玩家死亡时战斗结束,跳出游戏界面,进入结束界面。
结束界面
大字显示游戏结束。菜单有回到开始界面和退出游戏两个选项。用颜色标明当前正在选的选项,可以输入ws上下切换选项。回车确认进入对应选项,跳出结束界面,回到开始界面或退出游戏。
界面间的切换
开始界面-> 游戏界面 退出游戏
游戏界面-> 结束界面
结束界面-> 开始界面 退出游戏
导入库
#include <iostream>
#include "CustomConsole.h"
#include <conio.h>
using namespace std;
int main()
{
}
控制台基础设置
隐藏光标:
setCursorVisibility(false);
设置控制台大小:
int w = 50;
int h = 30;
setConsoleSize(w, h);
场景切换
当前场景 ID:
int nowSceneID = 1;
传递数据变量,例如游戏失败,游戏通关等文字需要显示:
string gameOverInfo = "";
游戏死循环逻辑:
//游戏的本质就是死循环
while (true)
{
switch (nowSceneID)
{
//开始场景处理的对应的逻辑
case 1:
{
break;
}
//游戏场景处理的对应逻辑
case 2:
{
break;
}
//结束场景处理的对应逻辑
case 3:
{
break;
}
}
}
开始场景逻辑实现
清空场景:
system("cls");
显示标题:
setCursorPosition(w / 2 - 7, 8);
cout << "韬老狮营救公主";
场景选择逻辑:
//当前选择选项的编号
int nowSelIndex = 0;
//是否退出标识
bool isQuitScene = false;
//我们可以在内部再使用死循环来处理开始界面相关的逻辑
while (true)
{
if (isQuitScene)
break;
//如果要退出当前场景 就直接退出这个输入break
if (isQuitScene)
break;
//不停的要根据输入 来决定选中谁 来更新他们的颜色信息
setCursorPosition(w / 2 - 4, 13);
//根据当前选中的标签号 来决定 自己是什么颜色
setTextColor(nowSelIndex == 0 ? 4 : 4 | 2 | 1);
cout << "开始游戏";
setTextColor(nowSelIndex == 1 ? 4 : 4 | 2 | 1);
setCursorPosition(w / 2 - 4, 15);
cout << "结束游戏";
int input = _getch();
switch (input)
{
case 'W':
case 'w':
--nowSelIndex;
if (nowSelIndex < 0)
nowSelIndex = 0;
break;
case 'S':
case 's':
++nowSelIndex;
if (nowSelIndex > 1)
nowSelIndex = 1;
break;
case 'J':
case 'j':
//开始游戏逻辑
if (nowSelIndex == 0)
{
//将场景ID设置为2
nowSceneID = 2;
isQuitScene = true;
}
//退出游戏
else
{
closeConsole();
}
break;
}
}
游戏场景逻辑
清空场景:
system("cls");
红墙绘制
墙体绘制:
//绘制的颜色
setTextColor(4);
//横向墙体
for (int i = 0; i < w; i+=2)
{
//上方墙体
setCursorPosition(i, 0);
cout << "■";
//下方墙体
setCursorPosition(i, h);
cout << "■";
//中间墙体
setCursorPosition(i, h - 5);
cout << "■";
}
for (int i = 0; i < h; i++)
{
//左侧墙体
setCursorPosition(0, i);
cout << "■";
//右侧墙体
setCursorPosition(w - 2, i);
cout << "■";
}
Boss 属性
Boss 位置与战斗属性:
//位置相关
int bossX = 24;
int bossY = 15;
//战斗属性相关
int bossAtkMin = 7;
int bossAtkMax = 13;
int bossHp = 100;
//boss绘制相关 形状 颜色
string bossIcon = "■";//形状
int bossColor = 2;//绿色
玩家属性
玩家位置与战斗属性:
//位置相关
int playerX = 4;//注意:这个坐标x一定个是个偶数
int playerY = 5;
//战斗属性相关
int playerAtkMin = 8;
int playerAtkMax = 12;
int playerHp = 100;
//player绘制相关 形状 颜色
string playerIcon = "●";
int playerColor = 4 | 2;
int playerInput;
公主属性
公主位置与相关绘制属性:
//位置相关
int princessX = 24;
int princessY = 5;
//player绘制相关 形状 颜色
string princessIcon = "★";
int princessColor = 1;
回合制战斗标识
控制战斗状态:
//是否开战的一个标识
bool isFight = false;
//是否游戏结束 需要跳到结束界面
bool isOver = false;
回合制战斗死循环
//为了避免闪烁 先在这里 将之后用来检测玩家输入的死循环写上
while (true)
{
//绘制Boss和公主
//设置光标位置 和 颜色
setCursorPosition(playerX, playerY);
setTextColor(playerColor);
cout << playerIcon;
//检测玩家输入
playerInput = _getch();
if (isFight)
{
//回合制战斗相关
}
else
{
// 玩家移动相关
}
//检测输入的while循环所在层
if (isOver)
break;
}
Boss和公主显示逻辑
//boss显示相关的逻辑
if (bossHp > 0)
{
setCursorPosition(bossX, bossY);
setTextColor(bossColor);
cout << bossIcon;
}
else
{
setCursorPosition(princessX, princessY);
setTextColor(princessColor);
cout << princessIcon;
}
玩家移动逻辑
玩家输入检测与移动:
setCursorPosition(playerX, playerY);
cout << " ";
switch (playerInput)
{
case 'W':
case 'w':
--playerY;
if (playerY < 1)
playerY = 1;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
++playerY;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
++playerY;
break;
case 'S':
case 's':
++playerY;
if (playerY > h - 6)
playerY = h - 6;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
--playerY;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
--playerY;
break;
case 'A':
case 'a':
playerX -= 2;
if (playerX < 2)
playerX = 2;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
playerX += 2;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
playerX += 2;
break;
case 'D':
case 'd':
playerX += 2;
if (playerX > w - 4)
playerX = w - 4;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
playerX -= 2;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
playerX -= 2;
break;
case 'J':
case 'j':
//判断玩家要在boss周围四方向 才能进入到一个回合制战斗的状态
//并且 boss要是存货状态 才进入回合制战斗
if ((playerX == bossX - 2 && playerY == bossY ||
playerX == bossX + 2 && playerY == bossY ||
playerX == bossX && playerY == bossY - 1 ||
playerX == bossX && playerY == bossY + 1) && bossHp > 0)
{
isFight = true;
setTextColor(4 | 2 | 1);
setCursorPosition(2, h - 4);
cout << "开始和Boss战斗了,按J键继续";
setCursorPosition(2, h - 3);
cout << "玩家的血量为" << playerHp;
setCursorPosition(2, h - 2);
cout << "boss的血量为" << bossHp;
}
//在公主身边按J键 触发相关逻辑
else if ((playerX == princessX - 2 && playerY == princessY ||
playerX == princessX + 2 && playerY == princessY ||
playerX == princessX && playerY == princessY - 1 ||
playerX == princessX && playerY == princessY + 1) && bossHp <= 0)
{
//通关
//切换到结束界面
nowSceneID = 3;
//通过一个标识 来决定是否跳出外层的while检测输入的循环
isOver = true;
gameOverInfo = "游戏通关";
}
break;
}
Boss 战斗逻辑
战斗回合逻辑:
//处理回合制战斗的逻辑
//按J键打一回合
if (playerInput == 'J' || playerInput == 'j')
{
//因为需要每次按了J键才能走一次回合 所以 玩家和怪物的死亡都放倒按j键后来判断
if (playerHp <= 0)
{
//场景id要变成结束场景
nowSceneID = 3;
//跳出输入检测循环
break;
}
else if (bossHp <= 0)
{
//玩家可以结束战斗状态 可以移动了
//怪物应该被擦除掉
setCursorPosition(bossX, bossY);
cout << " ";
isFight = false;
}
//没死的话 正常的回合制战斗逻辑
else
{
//玩家打怪物
//得到一个随机的玩家攻击力
int atk = getRandom(playerAtkMin, playerAtkMax);
//让怪物受到伤害
bossHp -= atk;
//下方更新信息
//打印之前 先擦除掉之前残留的信息 避免显示错误
setCursorPosition(2, h - 3);
cout << " ";
setCursorPosition(2, h - 3);
setTextColor(2);
cout << "你对boss造成了" << atk << "点伤害,boss剩余血量为" << bossHp;
//怪物打玩家
if (bossHp > 0)
{
//随意一个boss的攻击力
atk = getRandom(bossAtkMin, bossAtkMax);
//让玩家受到伤害
playerHp -= atk;
//下方更新信息
//打印之前 先擦除掉之前残留的信息 避免显示错误
setCursorPosition(2, h - 2);
cout << " ";
// boss把玩家打死了 。。。
if (playerHp <= 0)
{
setCursorPosition(2, h - 2);
setTextColor(4);
cout << "非常遗憾,你未能通过boss的试炼,战败了";
gameOverInfo = "游戏失败";
}
//玩家没有被打死 就显示具体伤害信息
else
{
setCursorPosition(2, h - 2);
setTextColor(4 | 2);
cout << "boss对你造成了" << atk << "点伤害,你剩余血量为" << playerHp;
}
}
//boss被打死了
else
{
//擦除下方的所有的显示信息 boss被打死了 应该让玩家去救公主
setCursorPosition(2, h - 4);
cout << " ";
setCursorPosition(2, h - 3);
cout << " ";
setCursorPosition(2, h - 2);
cout << " ";
setCursorPosition(2, h - 4);
setTextColor(1);
cout << "你战胜了boss了,快去营救公主吧";
setCursorPosition(2, h - 3);
cout << "按J键继续前往营救公主";
}
}
}
结束场景逻辑
清空场景并显示结束信息:
//调用擦除的主要目的 是用来清空之前的场景
system("cls");
//显示固定内容
setCursorPosition(w / 2 - 4, 5);
setTextColor(4 | 2 | 1);
cout << "GameOver";
setCursorPosition(w / 2 - 4, 7);
setTextColor(2);
cout << gameOverInfo;
进行选择:
int nowSelEndIndex = 0;
int input;
bool isQuitEndWhile = false;
while (true)
{
if (isQuitEndWhile)
break;
setCursorPosition(w / 2 - 6, 9);
setTextColor(nowSelEndIndex == 0 ? 4 : 7);
cout << "回到开始界面";
setCursorPosition(w / 2 - 4, 11);
setTextColor(nowSelEndIndex == 1 ? 4 : 7);
cout << "退出游戏";
input = _getch();
switch (input)
{
case 'W':
case 'w':
--nowSelEndIndex;
if (nowSelEndIndex < 0)
nowSelEndIndex = 0;
break;
case 'S':
case 's':
++nowSelEndIndex;
if (nowSelEndIndex > 1)
nowSelEndIndex = 1;
break;
case 'J':
case 'j':
if (nowSelEndIndex == 0)
{
nowSceneID = 1;
isQuitEndWhile = true;
}
else
closeConsole();
break;
}
}
4.2 知识点代码
入门实践.cpp
#include <iostream>
#include "CustomConsole.h"
#include <conio.h>
using namespace std;
int main()
{
#pragma region 1 控制台基础设置
//隐藏光标
setCursorVisibility(false);
//控制台的大小
int w = 50;
int h = 30;
setConsoleSize(w, h);
#pragma endregion
#pragma region 2 场景切换
//代表我们当前所处的场景ID
int nowSceneID = 1;
//用来传递数据的
//将游戏场景通关结果 传递给结束场景
string gameOverInfo = "";
//游戏的本质就是死循环
while (true)
{
switch (nowSceneID)
{
//开始场景处理的对应的逻辑
case 1:
{
//调用擦除的主要目的 是用来清空之前的场景
system("cls");
#pragma region 3 开始场景逻辑实现
setCursorPosition(w / 2 - 7, 8);
cout << "韬老狮营救公主";
//当前选择选项的编号
int nowSelIndex = 0;
//是否退出标识
bool isQuitScene = false;
//我们可以在内部再使用死循环来处理开始界面相关的逻辑
while (true)
{
//如果要退出当前场景 就直接退出这个输入break
if (isQuitScene)
break;
//不停的要根据输入 来决定选中谁 来更新他们的颜色信息
setCursorPosition(w / 2 - 4, 13);
//根据当前选中的标签号 来决定 自己是什么颜色
setTextColor(nowSelIndex == 0 ? 4 : 4 | 2 | 1);
cout << "开始游戏";
setTextColor(nowSelIndex == 1 ? 4 : 4 | 2 | 1);
setCursorPosition(w / 2 - 4, 15);
cout << "结束游戏";
int input = _getch();
switch (input)
{
case 'W':
case 'w':
--nowSelIndex;
if (nowSelIndex < 0)
nowSelIndex = 0;
break;
case 'S':
case 's':
++nowSelIndex;
if (nowSelIndex > 1)
nowSelIndex = 1;
break;
case 'J':
case 'j':
//开始游戏逻辑
if (nowSelIndex == 0)
{
//将场景ID设置为2
nowSceneID = 2;
isQuitScene = true;
}
//退出游戏
else
{
closeConsole();
}
break;
}
}
#pragma endregion
break;
}
//游戏场景处理的对应逻辑
case 2:
{
//调用擦除的主要目的 是用来清空之前的场景
system("cls");
#pragma region 4 不变的红墙
//绘制的颜色
setTextColor(4);
//横向墙体
for (int i = 0; i < w; i+=2)
{
//上方墙体
setCursorPosition(i, 0);
cout << "■";
//下方墙体
setCursorPosition(i, h);
cout << "■";
//中间墙体
setCursorPosition(i, h - 5);
cout << "■";
}
for (int i = 0; i < h; i++)
{
//左侧墙体
setCursorPosition(0, i);
cout << "■";
//右侧墙体
setCursorPosition(w - 2, i);
cout << "■";
}
#pragma endregion
#pragma region 5 boss属性相关
//位置相关
int bossX = 24;
int bossY = 15;
//战斗属性相关
int bossAtkMin = 7;
int bossAtkMax = 13;
int bossHp = 100;
//boss绘制相关 形状 颜色
string bossIcon = "■";//形状
int bossColor = 2;//绿色
#pragma endregion
#pragma region 6 玩家属性相关
//位置相关
int playerX = 4;//注意:这个坐标x一定个是个偶数
int playerY = 5;
//战斗属性相关
int playerAtkMin = 8;
int playerAtkMax = 12;
int playerHp = 100;
//player绘制相关 形状 颜色
string playerIcon = "●";
int playerColor = 4 | 2;
int playerInput;
#pragma endregion
#pragma region 8 公主属性相关
//位置相关
int princessX = 24;
int princessY = 5;
//player绘制相关 形状 颜色
string princessIcon = "★";
int princessColor = 1;
#pragma endregion
#pragma region 7 回合制战斗标识
//是否开战的一个标识
bool isFight = false;
//是否游戏结束 需要跳到结束界面
bool isOver = false;
#pragma endregion
//为了避免闪烁 先在这里 将之后用来检测玩家输入的死循环写上
while (true)
{
#pragma region 5 boss绘制相关
//boss显示相关的逻辑
if (bossHp > 0)
{
setCursorPosition(bossX, bossY);
setTextColor(bossColor);
cout << bossIcon;
}
#pragma endregion
#pragma region 8 公主绘制相关
else
{
setCursorPosition(princessX, princessY);
setTextColor(princessColor);
cout << princessIcon;
}
#pragma endregion
//设置光标位置 和 颜色
setCursorPosition(playerX, playerY);
setTextColor(playerColor);
cout << playerIcon;
//检测玩家输入
playerInput = _getch();
if (isFight)
{
#pragma region 7 回合制战斗相关
//处理回合制战斗的逻辑
//按J键打一回合
if (playerInput == 'J' || playerInput == 'j')
{
//因为需要每次按了J键才能走一次回合 所以 玩家和怪物的死亡都放倒按j键后来判断
if (playerHp <= 0)
{
//场景id要变成结束场景
nowSceneID = 3;
//跳出输入检测循环
break;
}
else if (bossHp <= 0)
{
//玩家可以结束战斗状态 可以移动了
//怪物应该被擦除掉
setCursorPosition(bossX, bossY);
cout << " ";
isFight = false;
}
//没死的话 正常的回合制战斗逻辑
else
{
//玩家打怪物
//得到一个随机的玩家攻击力
int atk = getRandom(playerAtkMin, playerAtkMax);
//让怪物受到伤害
bossHp -= atk;
//下方更新信息
//打印之前 先擦除掉之前残留的信息 避免显示错误
setCursorPosition(2, h - 3);
cout << " ";
setCursorPosition(2, h - 3);
setTextColor(2);
cout << "你对boss造成了" << atk << "点伤害,boss剩余血量为" << bossHp;
//怪物打玩家
if (bossHp > 0)
{
//随意一个boss的攻击力
atk = getRandom(bossAtkMin, bossAtkMax);
//让玩家受到伤害
playerHp -= atk;
//下方更新信息
//打印之前 先擦除掉之前残留的信息 避免显示错误
setCursorPosition(2, h - 2);
cout << " ";
// boss把玩家打死了 。。。
if (playerHp <= 0)
{
setCursorPosition(2, h - 2);
setTextColor(4);
cout << "非常遗憾,你未能通过boss的试炼,战败了";
gameOverInfo = "游戏失败";
}
//玩家没有被打死 就显示具体伤害信息
else
{
setCursorPosition(2, h - 2);
setTextColor(4 | 2);
cout << "boss对你造成了" << atk << "点伤害,你剩余血量为" << playerHp;
}
}
//boss被打死了
else
{
//擦除下方的所有的显示信息 boss被打死了 应该让玩家去救公主
setCursorPosition(2, h - 4);
cout << " ";
setCursorPosition(2, h - 3);
cout << " ";
setCursorPosition(2, h - 2);
cout << " ";
setCursorPosition(2, h - 4);
setTextColor(1);
cout << "你战胜了boss了,快去营救公主吧";
setCursorPosition(2, h - 3);
cout << "按J键继续前往营救公主";
}
}
}
#pragma endregion
}
else
{
#pragma region 6 玩家移动相关
setCursorPosition(playerX, playerY);
cout << " ";
switch (playerInput)
{
case 'W':
case 'w':
--playerY;
if (playerY < 1)
playerY = 1;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
++playerY;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
++playerY;
break;
case 'S':
case 's':
++playerY;
if (playerY > h - 6)
playerY = h - 6;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
--playerY;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
--playerY;
break;
case 'A':
case 'a':
playerX -= 2;
if (playerX < 2)
playerX = 2;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
playerX += 2;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
playerX += 2;
break;
case 'D':
case 'd':
playerX += 2;
if (playerX > w - 4)
playerX = w - 4;
//如果和boss重合了 就把玩家拉回原来的位置
else if (playerX == bossX && playerY == bossY && bossHp > 0)
playerX -= 2;
else if (playerX == princessX && playerY == princessY && bossHp <= 0)
playerX -= 2;
break;
case 'J':
case 'j':
//判断玩家要在boss周围四方向 才能进入到一个回合制战斗的状态
//并且 boss要是存货状态 才进入回合制战斗
if ((playerX == bossX - 2 && playerY == bossY ||
playerX == bossX + 2 && playerY == bossY ||
playerX == bossX && playerY == bossY - 1 ||
playerX == bossX && playerY == bossY + 1) && bossHp > 0)
{
isFight = true;
setTextColor(4 | 2 | 1);
setCursorPosition(2, h - 4);
cout << "开始和Boss战斗了,按J键继续";
setCursorPosition(2, h - 3);
cout << "玩家的血量为" << playerHp;
setCursorPosition(2, h - 2);
cout << "boss的血量为" << bossHp;
}
//在公主身边按J键 触发相关逻辑
else if ((playerX == princessX - 2 && playerY == princessY ||
playerX == princessX + 2 && playerY == princessY ||
playerX == princessX && playerY == princessY - 1 ||
playerX == princessX && playerY == princessY + 1) && bossHp <= 0)
{
//通关
//切换到结束界面
nowSceneID = 3;
//通过一个标识 来决定是否跳出外层的while检测输入的循环
isOver = true;
gameOverInfo = "游戏通关";
}
break;
}
#pragma endregion
}
//检测输入的while循环所在层
if (isOver)
break;
}
break;
}
//结束场景处理的对应逻辑
case 3:
{
#pragma region 结束界面逻辑
//调用擦除的主要目的 是用来清空之前的场景
system("cls");
//显示固定内容
setCursorPosition(w / 2 - 4, 5);
setTextColor(4 | 2 | 1);
cout << "GameOver";
setCursorPosition(w / 2 - 4, 7);
setTextColor(2);
cout << gameOverInfo;
//进行选择
int nowSelEndIndex = 0;
int input;
bool isQuitEndWhile = false;
while (true)
{
if (isQuitEndWhile)
break;
setCursorPosition(w / 2 - 6, 9);
setTextColor(nowSelEndIndex == 0 ? 4 : 7);
cout << "回到开始界面";
setCursorPosition(w / 2 - 4, 11);
setTextColor(nowSelEndIndex == 1 ? 4 : 7);
cout << "退出游戏";
input = _getch();
switch (input)
{
case 'W':
case 'w':
--nowSelEndIndex;
if (nowSelEndIndex < 0)
nowSelEndIndex = 0;
break;
case 'S':
case 's':
++nowSelEndIndex;
if (nowSelEndIndex > 1)
nowSelEndIndex = 1;
break;
case 'J':
case 'j':
if (nowSelEndIndex == 0)
{
nowSceneID = 1;
isQuitEndWhile = true;
}
else
closeConsole();
break;
}
}
#pragma endregion
break;
}
}
}
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com