1.飞行棋游戏控制台实践
1.1 知识点
需求分析
理清小项目的功能需求
本项目是一个简单的飞行棋小游戏,包含以下功能需求:
- 控制台初始化:设置控制台大小,隐藏光标。
- 多个场景:包括开始场景、游戏场景和结束场景。
- 开始场景逻辑:玩家可以选择开始游戏或退出游戏。
- 游戏场景逻辑:玩家和电脑轮流扔骰子,根据骰子的点数在格子上移动,遇到不同类型的格子触发相应的事件。
- 结束场景逻辑:游戏结束,显示胜利者并提供返回主菜单的选项。
原型图
整理流程图
流程图应包括以下主要部分:
- 控制台初始化:初始化控制台,设置游戏的屏幕尺寸和相关配置。
- 场景选择:玩家在开始场景选择开始游戏或退出游戏。
- 游戏场景:在游戏场景中,玩家和电脑依次扔骰子,移动到相应的格子,触发格子的效果。
- 结束场景:游戏结束,显示游戏结果。
Visio
可以使用 Visio 工具绘制流程图,将各场景逻辑、格子类型、玩家与电脑的交互等流程可视化。
控制台基础设置
定义控制台初始化函数,设置控制台的大小并隐藏光标,提供一个清晰的游戏界面。
void consoleInit(int w, int h)
{
//控制台大小
setConsoleSize(w, h);
//隐藏光标
setCursorVisibility(false);
}
主函数中调用
int main()
{
int w = 50;
int h = 30;
consoleInit(w, h);
}
多个场景
游戏包括三个主要场景:开始场景、游戏场景和结束场景。通过 E_SceneType
枚举管理场景切换。
enum E_SceneType
{
Begin, // 开始场景
Game, // 游戏场景
End, // 结束场景
};
主函数中进行选择进行选择,声明beginOrEndScene和gameScene函数,等一下再实现
int main()
{
//...
E_SceneType nowSceneType = Begin;
while (true)
{
//根据当前场景ID来决定更新哪一个场景的逻辑
switch (nowSceneType)
{
case Begin:
//开始场景逻辑
//先把之前的内容清理掉
system("cls");
//我们将开始场景逻辑封装到了函数当中
beginOrEndScene(w, h, nowSceneType);
break;
case Game:
//游戏场景逻辑
//先把之前的内容清理掉
system("cls");
gameScene(w, h, nowSceneType);
break;
case End:
//结束场景逻辑
//先把之前的内容清理掉
system("cls");
beginOrEndScene(w, h, nowSceneType);
break;
}
}
}
开始场景和结束逻辑实现
在开始场景中,玩家可以选择开始游戏或退出游戏。以下是实现该场景的核心逻辑。
//颜色枚举 用来设置颜色 方便阅读
enum E_Color
{
Blue = 1,
Green = 2,
Red = 4,
White = 7,
};
//开始场景选择索引
enum E_SceneIndex
{
One,
Two,
};
void beginOrEndScene(int w, int h, E_SceneType& nowSceneType)
{
//显示不会一直更新变化的内容
setCursorPosition(nowSceneType == Begin ? w / 2 - 3 : w / 2 - 4, 8);
setTextColor(White);
cout << (nowSceneType == Begin ? "飞行棋" : "游戏结束");
//表示当前选择的是哪个选项
E_SceneIndex nowSelIndex = One;
//是否退出开始场景循环
bool isQuitBegin = false;
//开始场景的逻辑循环
while (true)
{
//开始游戏
setCursorPosition(nowSceneType == Begin ? w / 2 - 4 : w / 2 - 5, 13);
setTextColor(nowSelIndex == One ? Red : White);
cout << (nowSceneType == Begin ? "开始游戏" : "回到主菜单");
//退出游戏
setCursorPosition(w / 2 - 4, 15);
setTextColor(nowSelIndex == Two ? Red : White);
cout << "退出游戏";
//输入信息的askii码
int input = _getch();
switch (input)
{
case 'W':
case 'w':
//由于这里只有两个选项 所以它可以直接设置类型
//如果超过两个 就应该像C++入门当中一样去进行+-运算
//判断当前选中的是哪个索引了
nowSelIndex = One;
break;
case 'S':
case 's':
nowSelIndex = Two;
break;
case 'J':
case 'j':
//选中谁 处理不同的逻辑
switch (nowSelIndex)
{
case One:
//开始游戏 就应该切换场景类型
//当选择第一个选项 如果是开始场景 就应该前往游戏场景
//否则前往开始场景
nowSceneType = nowSceneType == Begin ? Game : Begin;
isQuitBegin = true;
break;
case Two:
closeConsole();
break;
}
break;
}
//和while循环配对的break
//只有当我们选择开始游戏后 才会跳出开始场景循环
//来到主循环当中
if (isQuitBegin)
break;
}
}
游戏场景逻辑实现
游戏场景函数
绘制红墙,地图和玩家
//游戏场景逻辑处理
void gameScene(int w, int h, E_SceneType& nowSceneType)
{
//绘制不变的内容
//红墙 文字提示 等等
drawWall(w, h);
//绘制地图信息
Map map = Map(14, 3, 80);
map.draw();
//绘制玩家和电脑
Player player = Player(0, E_PlayerType::Player);
Player computer = Player(0, E_PlayerType::Computer);
drawPlayer(player, computer, map);
while (true)
{
//玩家扔骰子逻辑
if (playerRandomMove(w, h, player, computer, map, nowSceneType))
break;
//电脑扔骰子逻辑
if (playerRandomMove(w, h, computer, player, map, nowSceneType))
break;
}
}
不变的红墙
游戏场景中有不变的红墙作为边界。
void drawWall(int w, int h)
{
//绘制红墙
//设置为红色
setTextColor(Red);
//横向
for (int i = 0; i < w; i += 2)
{
//第一排红墙
setCursorPosition(i, 0);
cout << "■";
//最底部的红墙
setCursorPosition(i, h - 1);
cout << "■";
//另外两行墙体
setCursorPosition(i, h - 6);
cout << "■";
setCursorPosition(i, h - 11);
cout << "■";
}
//竖向
for (int i = 0; i < h; i++)
{
//最左边
setCursorPosition(0, i);
cout << "■";
//最右边
setCursorPosition(w - 2, i);
cout << "■";
}
//下方提示内容绘制
setCursorPosition(2, h - 10);
setTextColor(White);
cout << "□:普通格子";
setCursorPosition(2, h - 9);
setTextColor(Blue);
cout << "‖:暂停,一回合不动";
setCursorPosition(26, h - 9);
setTextColor(Red);
cout << "●:炸弹,倒退5格";
setCursorPosition(2, h - 8);
setTextColor(Red | Green);
cout << "¤:时空隧道,随机倒退,暂停,换位置";
setCursorPosition(2, h - 7);
setTextColor(Red | Blue);
cout << "★:玩家";
setCursorPosition(10, h - 7);
setTextColor(Green | Blue);
cout << "▲:电脑";
setCursorPosition(20, h - 7);
setTextColor(White);
cout << "◎:玩家和电脑重合";
setCursorPosition(2, h - 5);
setTextColor(White);
cout << "按任意键开始扔色子";
}
格子类型枚举和格子结构体
格子类型包括普通格子、炸弹、暂停和时空隧道。每个格子都有对应的坐标和类型。
//格子的类型
enum E_Grid_Type
{
Normal,//普通格子
Boom,//炸弹
Pause,//暂停
Tunnel,//时空隧道
};
//位置结构体
struct Vector2
{
int x;
int y;
Vector2()
{
x = 0;
y = 0;
}
Vector2(int x, int y) : x(x), y(y) {}
};
//格子结构体
struct Grid
{
E_Grid_Type type;//格子的类型
Vector2 pos;//格子的位置
Grid()
{
type = Normal;
pos = {};
}
Grid(int x, int y, E_Grid_Type type)
{
pos = { x, y };
this->type = type;
}
//根据格子类型和位置 绘制格子
void draw()
{
//设置格子所在的位置 去进行颜色设置会图像绘制
setCursorPosition(pos.x, pos.y);
//根据格子的位置 去绘制对应类型的颜色的图像
switch (type)
{
case Normal:
setTextColor(White);
cout << "□";
break;
case Boom:
setTextColor(Red);
cout << "●";
break;
case Pause:
setTextColor(Blue);
cout << "‖";
break;
case Tunnel:
setTextColor(Red | Green);
cout << "¤";
break;
}
}
};
地图结构体
地图由多个格子组成,每个格子的位置和类型是动态生成的。
struct Map
{
Grid* grids = nullptr;//格子数组首地址
int gridNum;//格子数组数量
//传入 地图的起始位置 以及 有多少个格子
Map(int x, int y, int num)
{
gridNum = num;//记录格子数量
grids = new Grid[gridNum];//动态在堆上分配格子数组
//表示x变化的次数
int indexX = 0;
//表示y变化的次数
int indexY = 0;
//x的步长
int stepNum = 2;
//对地图信息进行初始化
int randomNum;
for (int i = 0; i < gridNum; i++)
{
//初始化每一个格子信息
//初始化格子类型
randomNum = getRandom(0, 100);
//普通格子 85% 或者 这个格子是第一个或者最后一个格子 那么就必须是普通格子
if (randomNum < 85 || i == 0 || i == gridNum - 1)
grids[i].type = Normal;
//炸弹 5%
else if (randomNum >= 85 && randomNum < 90)
grids[i].type = Boom;
//暂停 5%
else if (randomNum >= 90 && randomNum < 95)
grids[i].type = Pause;
//时空隧道 5%
else
grids[i].type = Tunnel;
//初始化格子位置
grids[i].pos = Vector2(x, y);
if (indexX == 10)
{
//加Y
y += 1;
++indexY;
//Y变化结束
if (indexY == 2)
{
//y加了2次过后 就应该进行下一轮变化了
indexX = 0;
indexY = 0;
//步长反向
stepNum = -stepNum;
}
}
else
{
//X变化
x += stepNum;
++indexX;
}
}
}
~Map()
{
if (grids != nullptr)
{
delete[] grids;
grids = nullptr;
}
}
//绘制地图
void draw()
{
//通过循环命令自己管理的格子们去执行一个绘制的行为
for (int i = 0; i < gridNum; i++)
{
//调用格子数组中每一个格子的绘制方法
grids[i].draw();
}
}
};
玩家和电脑结构体
玩家和电脑在游戏中的位置由 Player
结构体管理。
//玩家电脑枚举
enum class E_PlayerType
{
Player,//玩家
Computer,//电脑
};
struct Player
{
//玩家类型
E_PlayerType type;
//当前所在格子位置
int nowIndex;
//是否暂停
bool isPause;
Player(int index, E_PlayerType type) : nowIndex(index), type(type)
{
isPause = false;
}
void draw(Map& mapInfo)
{
//所在的位置
//获取到地图信息
Grid grid = mapInfo.grids[nowIndex];
setCursorPosition(grid.pos.x, grid.pos.y);
//根据类型去绘制图像和颜色
switch (type)
{
case E_PlayerType::Player:
setTextColor(Red | Blue);
cout << "★";
break;
case E_PlayerType::Computer:
setTextColor(Green | Blue);
cout << "▲";
break;
}
}
};
要对玩家进行绘制
void drawPlayer(Player& player, Player& computer, Map& map)
{
//重合时
if (player.nowIndex == computer.nowIndex)
{
//绘制重合时的图像
//得到位置
Grid grid = map.grids[player.nowIndex];
setCursorPosition(grid.pos.x, grid.pos.y);
setTextColor(White);
cout << "◎";
}
//不重合时
else
{
player.draw(map);
computer.draw(map);
}
}
扔骰子
玩家和电脑通过扔骰子来决定在格子上移动。
//擦除提示位置的信息
void clearInfo(int w, int h)
{
//擦除之前显示的提示信息
for (int j = 5; j >= 2; j--)
{
for (int i = 2; i < w - 2; i++)
{
setCursorPosition(i, h - j);
cout << " ";
}
}
}
bool randomMove(int w, int h, Player& player, Player& otherPlayer, Map& map)
{
//擦除之前显示的提示信息
clearInfo(w, h);
//根据扔色子的对象决定提示信息的文本颜色
setTextColor(player.type == E_PlayerType::Player ? Red | Blue : Green | Blue);
//暂停相关逻辑
if (player.isPause)
{
//提示暂停相关
setCursorPosition(2, h - 5);
cout << "处于暂停状态," << (player.type == E_PlayerType::Player ? "你" : "电脑") << "需要暂停过一回合";
setCursorPosition(2, h - 4);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
//直接不扔色子 直接返回
//提示暂停
player.isPause = false;
return false;
}
//随机扔骰子
int randomNum = getRandom(1, 6);
//让对象移动对应随机扔出的步数
player.nowIndex += randomNum;
//提示扔了多少点数
setCursorPosition(2, h - 5);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "扔出的点数为:" << randomNum;
//移动 判断所在格子是什么 处理对应逻辑
if (player.nowIndex >= map.gridNum - 1)
{
//如果超过了终点 就应该拉回来
player.nowIndex = map.gridNum - 1;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "恭喜你,你率先到达了终点" : "很遗憾,电脑率先到达了终点");
setCursorPosition(2, h - 3);
cout << "请按任意键结束游戏";
//应该结束游戏了 到达了终点
return true;
}
else
{
//没有到终点,就判断当前对象所在格子是什么格子
//处理对应逻辑
Grid grid = map.grids[player.nowIndex];
switch (grid.type)
{
case Normal:
//不处理任何逻辑
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到达了一个安全位置";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Boom:
player.nowIndex -= 5;
//遇到炸弹 最多退掉起点 不能比起点还小
if (player.nowIndex < 0)
player.nowIndex = 0;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "踩到了炸弹,退后5格";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Pause:
//暂停一回合
//必须添加一个暂停标识 才能知道下一回合需要暂停
//不能扔色子
player.isPause = true;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到了暂停点,你需要暂停一回合";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Tunnel:
//随机 退5格 暂停一回合 交换位置
randomNum = getRandom(1, 3);
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到达了时空隧道";
setCursorPosition(2, h - 3);
//退5格
if (randomNum == 1)
{
player.nowIndex -= 5;
if (player.nowIndex < 0)
player.nowIndex = 0;
cout << "触发了退5格";
}
//暂停
else if (randomNum == 2)
{
player.isPause = true;
cout << "触发了暂停一回合";
}
//交换位置
else
{
int temp = player.nowIndex;
player.nowIndex = otherPlayer.nowIndex;
otherPlayer.nowIndex = temp;
cout << "触发了交换位置";
}
setCursorPosition(2, h - 2);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
}
}
//默认就没有到达终点
return false;
}
bool playerRandomMove(int w, int h, Player& player, Player& otherPlayer, Map& map, E_SceneType& nowSceneType)
{
//玩家扔骰子逻辑
//检测输入
_getch();
//扔骰子的逻辑
bool isGameOver = randomMove(w, h, player, otherPlayer, map);
//绘制地图
map.draw();
//绘制玩家
drawPlayer(player, otherPlayer, map);
//判断是否要结束游戏
if (isGameOver)
{
nowSceneType = End;
_getch();
}
return isGameOver;
}
1.2 知识点代码
基础实践.cpp
#include <iostream>
#include <conio.h>
#include "CustomConsole.h"
using namespace std;
#pragma region 1 控制台初始化
void consoleInit(int w, int h)
{
//控制台大小
setConsoleSize(w, h);
//隐藏光标
setCursorVisibility(false);
}
#pragma endregion
#pragma region 2 场景选择相关
enum E_SceneType
{
Begin,//开始场景
Game,//游戏场景
End,//结束场景
};
#pragma endregion
#pragma region 3 开始场景逻辑相关 and 9 结束场景逻辑相关
//颜色枚举 用来设置颜色 方便阅读
enum E_Color
{
Blue = 1,
Green = 2,
Red = 4,
White = 7,
};
//开始场景选择索引
enum E_SceneIndex
{
One,
Two,
};
void beginOrEndScene(int w, int h, E_SceneType& nowSceneType)
{
//显示不会一直更新变化的内容
setCursorPosition(nowSceneType == Begin ? w / 2 - 3 : w / 2 - 4, 8);
setTextColor(White);
cout << (nowSceneType == Begin ? "飞行棋" : "游戏结束");
//表示当前选择的是哪个选项
E_SceneIndex nowSelIndex = One;
//是否退出开始场景循环
bool isQuitBegin = false;
//开始场景的逻辑循环
while (true)
{
//开始游戏
setCursorPosition(nowSceneType == Begin ? w / 2 - 4 : w / 2 - 5, 13);
setTextColor(nowSelIndex == One ? Red : White);
cout << (nowSceneType == Begin ? "开始游戏" : "回到主菜单");
//退出游戏
setCursorPosition(w / 2 - 4, 15);
setTextColor(nowSelIndex == Two ? Red : White);
cout << "退出游戏";
//输入信息的askii码
int input = _getch();
switch (input)
{
case 'W':
case 'w':
//由于这里只有两个选项 所以它可以直接设置类型
//如果超过两个 就应该像C++入门当中一样去进行+-运算
//判断当前选中的是哪个索引了
nowSelIndex = One;
break;
case 'S':
case 's':
nowSelIndex = Two;
break;
case 'J':
case 'j':
//选中谁 处理不同的逻辑
switch (nowSelIndex)
{
case One:
//开始游戏 就应该切换场景类型
//当选择第一个选项 如果是开始场景 就应该前往游戏场景
//否则前往开始场景
nowSceneType = nowSceneType == Begin ? Game : Begin;
isQuitBegin = true;
break;
case Two:
closeConsole();
break;
}
break;
}
//和while循环配对的break
//只有当我们选择开始游戏后 才会跳出开始场景循环
//来到主循环当中
if (isQuitBegin)
break;
}
}
#pragma endregion
#pragma region 游戏场景逻辑
#pragma region 4 不变的红墙逻辑相关
void drawWall(int w, int h)
{
//绘制红墙
//设置为红色
setTextColor(Red);
//横向
for (int i = 0; i < w; i += 2)
{
//第一排红墙
setCursorPosition(i, 0);
cout << "■";
//最底部的红墙
setCursorPosition(i, h - 1);
cout << "■";
//另外两行墙体
setCursorPosition(i, h - 6);
cout << "■";
setCursorPosition(i, h - 11);
cout << "■";
}
//竖向
for (int i = 0; i < h; i++)
{
//最左边
setCursorPosition(0, i);
cout << "■";
//最右边
setCursorPosition(w - 2, i);
cout << "■";
}
//下方提示内容绘制
setCursorPosition(2, h - 10);
setTextColor(White);
cout << "□:普通格子";
setCursorPosition(2, h - 9);
setTextColor(Blue);
cout << "‖:暂停,一回合不动";
setCursorPosition(26, h - 9);
setTextColor(Red);
cout << "●:炸弹,倒退5格";
setCursorPosition(2, h - 8);
setTextColor(Red | Green);
cout << "¤:时空隧道,随机倒退,暂停,换位置";
setCursorPosition(2, h - 7);
setTextColor(Red | Blue);
cout << "★:玩家";
setCursorPosition(10, h - 7);
setTextColor(Green | Blue);
cout << "▲:电脑";
setCursorPosition(20, h - 7);
setTextColor(White);
cout << "◎:玩家和电脑重合";
setCursorPosition(2, h - 5);
setTextColor(White);
cout << "按任意键开始扔色子";
}
#pragma endregion
#pragma region 5 格子枚举和格子结构体相关
//格子的类型
enum E_Grid_Type
{
Normal,//普通格子
Boom,//炸弹
Pause,//暂停
Tunnel,//时空隧道
};
//位置结构体
struct Vector2
{
int x;
int y;
Vector2()
{
x = 0;
y = 0;
}
Vector2(int x, int y) : x(x), y(y) {}
};
//格子结构体
struct Grid
{
E_Grid_Type type;//格子的类型
Vector2 pos;//格子的位置
Grid()
{
type = Normal;
pos = {};
}
Grid(int x, int y, E_Grid_Type type)
{
pos = { x, y };
this->type = type;
}
//根据格子类型和位置 绘制格子
void draw()
{
//设置格子所在的位置 去进行颜色设置会图像绘制
setCursorPosition(pos.x, pos.y);
//根据格子的位置 去绘制对应类型的颜色的图像
switch (type)
{
case Normal:
setTextColor(White);
cout << "□";
break;
case Boom:
setTextColor(Red);
cout << "●";
break;
case Pause:
setTextColor(Blue);
cout << "‖";
break;
case Tunnel:
setTextColor(Red | Green);
cout << "¤";
break;
}
}
};
#pragma endregion
#pragma region 6 地图结构体相关
struct Map
{
Grid* grids = nullptr;//格子数组首地址
int gridNum;//格子数组数量
//传入 地图的起始位置 以及 有多少个格子
Map(int x, int y, int num)
{
gridNum = num;//记录格子数量
grids = new Grid[gridNum];//动态在堆上分配格子数组
//表示x变化的次数
int indexX = 0;
//表示y变化的次数
int indexY = 0;
//x的步长
int stepNum = 2;
//对地图信息进行初始化
int randomNum;
for (int i = 0; i < gridNum; i++)
{
//初始化每一个格子信息
//初始化格子类型
randomNum = getRandom(0, 100);
//普通格子 85% 或者 这个格子是第一个或者最后一个格子 那么就必须是普通格子
if (randomNum < 85 || i == 0 || i == gridNum - 1)
grids[i].type = Normal;
//炸弹 5%
else if (randomNum >= 85 && randomNum < 90)
grids[i].type = Boom;
//暂停 5%
else if (randomNum >= 90 && randomNum < 95)
grids[i].type = Pause;
//时空隧道 5%
else
grids[i].type = Tunnel;
//初始化格子位置
grids[i].pos = Vector2(x, y);
if (indexX == 10)
{
//加Y
y += 1;
++indexY;
//Y变化结束
if (indexY == 2)
{
//y加了2次过后 就应该进行下一轮变化了
indexX = 0;
indexY = 0;
//步长反向
stepNum = -stepNum;
}
}
else
{
//X变化
x += stepNum;
++indexX;
}
}
}
~Map()
{
if (grids != nullptr)
{
delete[] grids;
grids = nullptr;
}
}
//绘制地图
void draw()
{
//通过循环命令自己管理的格子们去执行一个绘制的行为
for (int i = 0; i < gridNum; i++)
{
//调用格子数组中每一个格子的绘制方法
grids[i].draw();
}
}
};
#pragma endregion
#pragma region 7 玩家枚举和玩家结构体相关
//玩家电脑枚举
enum class E_PlayerType
{
Player,//玩家
Computer,//电脑
};
struct Player
{
//玩家类型
E_PlayerType type;
//当前所在格子位置
int nowIndex;
//是否暂停
bool isPause;
Player(int index, E_PlayerType type) : nowIndex(index), type(type)
{
isPause = false;
}
void draw(Map& mapInfo)
{
//所在的位置
//获取到地图信息
Grid grid = mapInfo.grids[nowIndex];
setCursorPosition(grid.pos.x, grid.pos.y);
//根据类型去绘制图像和颜色
switch (type)
{
case E_PlayerType::Player:
setTextColor(Red | Blue);
cout << "★";
break;
case E_PlayerType::Computer:
setTextColor(Green | Blue);
cout << "▲";
break;
}
}
};
#pragma endregion
#pragma region 7 玩家和电脑绘制相关
void drawPlayer(Player& player, Player& computer, Map& map)
{
//重合时
if (player.nowIndex == computer.nowIndex)
{
//绘制重合时的图像
//得到位置
Grid grid = map.grids[player.nowIndex];
setCursorPosition(grid.pos.x, grid.pos.y);
setTextColor(White);
cout << "◎";
}
//不重合时
else
{
player.draw(map);
computer.draw(map);
}
}
#pragma endregion
#pragma region 8 扔骰子相关逻辑
//擦除提示位置的信息
void clearInfo(int w, int h)
{
//擦除之前显示的提示信息
for (int j = 5; j >= 2; j--)
{
for (int i = 2; i < w - 2; i++)
{
setCursorPosition(i, h - j);
cout << " ";
}
}
}
bool randomMove(int w, int h, Player& player, Player& otherPlayer, Map& map)
{
//擦除之前显示的提示信息
clearInfo(w, h);
//根据扔色子的对象决定提示信息的文本颜色
setTextColor(player.type == E_PlayerType::Player ? Red | Blue : Green | Blue);
//暂停相关逻辑
if (player.isPause)
{
//提示暂停相关
setCursorPosition(2, h - 5);
cout << "处于暂停状态," << (player.type == E_PlayerType::Player ? "你" : "电脑") << "需要暂停过一回合";
setCursorPosition(2, h - 4);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
//直接不扔色子 直接返回
//提示暂停
player.isPause = false;
return false;
}
//随机扔骰子
int randomNum = getRandom(1, 6);
//让对象移动对应随机扔出的步数
player.nowIndex += randomNum;
//提示扔了多少点数
setCursorPosition(2, h - 5);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "扔出的点数为:" << randomNum;
//移动 判断所在格子是什么 处理对应逻辑
if (player.nowIndex >= map.gridNum - 1)
{
//如果超过了终点 就应该拉回来
player.nowIndex = map.gridNum - 1;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "恭喜你,你率先到达了终点" : "很遗憾,电脑率先到达了终点");
setCursorPosition(2, h - 3);
cout << "请按任意键结束游戏";
//应该结束游戏了 到达了终点
return true;
}
else
{
//没有到终点,就判断当前对象所在格子是什么格子
//处理对应逻辑
Grid grid = map.grids[player.nowIndex];
switch (grid.type)
{
case Normal:
//不处理任何逻辑
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到达了一个安全位置";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Boom:
player.nowIndex -= 5;
//遇到炸弹 最多退掉起点 不能比起点还小
if (player.nowIndex < 0)
player.nowIndex = 0;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "踩到了炸弹,退后5格";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Pause:
//暂停一回合
//必须添加一个暂停标识 才能知道下一回合需要暂停
//不能扔色子
player.isPause = true;
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到了暂停点,你需要暂停一回合";
setCursorPosition(2, h - 3);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
case Tunnel:
//随机 退5格 暂停一回合 交换位置
randomNum = getRandom(1, 3);
setCursorPosition(2, h - 4);
cout << (player.type == E_PlayerType::Player ? "你" : "电脑") << "到达了时空隧道";
setCursorPosition(2, h - 3);
//退5格
if (randomNum == 1)
{
player.nowIndex -= 5;
if (player.nowIndex < 0)
player.nowIndex = 0;
cout << "触发了退5格";
}
//暂停
else if (randomNum == 2)
{
player.isPause = true;
cout << "触发了暂停一回合";
}
//交换位置
else
{
int temp = player.nowIndex;
player.nowIndex = otherPlayer.nowIndex;
otherPlayer.nowIndex = temp;
cout << "触发了交换位置";
}
setCursorPosition(2, h - 2);
cout << "请按任意键,让" << (player.type == E_PlayerType::Player ? "电脑" : "你") << "开始扔骰子";
break;
}
}
//默认就没有到达终点
return false;
}
bool playerRandomMove(int w, int h, Player& player, Player& otherPlayer, Map& map, E_SceneType& nowSceneType)
{
//玩家扔骰子逻辑
//检测输入
_getch();
//扔骰子的逻辑
bool isGameOver = randomMove(w, h, player, otherPlayer, map);
//绘制地图
map.draw();
//绘制玩家
drawPlayer(player, otherPlayer, map);
//判断是否要结束游戏
if (isGameOver)
{
nowSceneType = End;
_getch();
}
return isGameOver;
}
#pragma endregion
//游戏场景逻辑处理
void gameScene(int w, int h, E_SceneType& nowSceneType)
{
//绘制不变的内容
//红墙 文字提示 等等
drawWall(w, h);
//绘制地图信息
Map map = Map(14, 3, 80);
map.draw();
//绘制玩家和电脑
Player player = Player(0, E_PlayerType::Player);
Player computer = Player(0, E_PlayerType::Computer);
drawPlayer(player, computer, map);
while (true)
{
//玩家扔骰子逻辑
if (playerRandomMove(w, h, player, computer, map, nowSceneType))
break;
//电脑扔骰子逻辑
if (playerRandomMove(w, h, computer, player, map, nowSceneType))
break;
}
}
#pragma endregion
int main()
{
#pragma region 1 控制台初始化
int w = 50;
int h = 30;
consoleInit(w, h);
#pragma endregion
#pragma region 2 场景选择相关
E_SceneType nowSceneType = Begin;
while (true)
{
//根据当前场景ID来决定更新哪一个场景的逻辑
switch (nowSceneType)
{
case Begin:
//开始场景逻辑
//先把之前的内容清理掉
system("cls");
//我们将开始场景逻辑封装到了函数当中
beginOrEndScene(w, h, nowSceneType);
break;
case Game:
//游戏场景逻辑
//先把之前的内容清理掉
system("cls");
gameScene(w, h, nowSceneType);
break;
case End:
//结束场景逻辑
//先把之前的内容清理掉
system("cls");
beginOrEndScene(w, h, nowSceneType);
break;
}
}
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com