目录
- 一、模型调整
- (一)模型定义
- (二)模型实现
- 1.电脑自动完成部分
- 2.SDL图形显示
- 2.1拿起放下盘子的函数
- 2.2左右移动手指的函数
- 二、处理用户输入,进行人机分流
- 三、总结
- 四、源码下载
上篇文章使用C++语言实现汉诺塔游戏电脑自动完成的步骤,还没有实现用户交互,无多少可玩性,本篇继续探索,加入方向键交互功能。
一、模型调整
(一)模型定义
这里更新的知识点包括:类的静态变量、类的构造函数。
//汉诺塔柱子,将大部分属性静态化
class Stick {
public:
deque<int> plates; //柱子放置盘子的栈
int x, y; //柱子底中心位置
static int width, height; //柱子宽、高
static unsigned char r, g, b; //柱子颜色
static int pside, pheight; //盘子边长、厚度
static unsigned char pr, pg, pb; //盘子颜色
Stick(int x, int y, int width, int height, unsigned char r, unsigned char g, unsigned char b,
int pside, int pheight, unsigned char pr, unsigned char pg, unsigned char pb); //构造函数
void show(SDL_Renderer*); //在指定渲染器绘制画面
};
//定义静态变量
int Stick::width; int Stick::height;
unsigned char Stick::r; unsigned char Stick::g; unsigned char Stick::b;
int Stick::pside; int Stick::pheight;
unsigned char Stick::pr; unsigned char Stick::pg = pg; unsigned char Stick::pb = pb;
//默认构造函数,柱子在左边沿位置,宽6,高300,棕色,盘子边长40、厚10、天蓝色
Stick::Stick(int x = 0, int y = 300, int width = 6, int height = 300,
unsigned char r = 95, unsigned char g = 60, unsigned char b = 10,
int pside = 40, int pheight = 10, unsigned char pr = 0, unsigned char pg = 255, unsigned char pb = 255):x(x), y(y) {
Stick::width = width; Stick::height = height;
Stick::r = r; Stick::g = g; Stick::b = b;
Stick::pside = pside; Stick::pheight = pheight;
Stick::pr = pr; Stick::pg = pg; Stick::pb = pb;
}
//整个汉诺塔模型,新增手指、空中盘子2个变量,新增upPlate、downPlate、leftFiger、rightFinger4个成员函数
//更新了显示函数,使用户可以设置刷新频率
class Hanoi {
private:
SDL_Renderer * render; // 内置窗口渲染器指针
Finger finger; //手指
int airPlate; //空中的盘子号
public:
Stick sticks[3]; //3根柱子
Hanoi(SDL_Renderer *, int, int); //构造函数
bool movePlate(int a, int b); //将1个盘子从a柱移到b柱
void movePlates(int a, int b, int count); //将count个盘子从a柱移到b柱
bool upPlate(); //从手指处拾起1个盘子
bool downPlate(); //在手指处放下1个盘子
void leftFinger(); //手指左移1下
void rightFinger(); //手指右移1下
void show(); //在窗口绘制画面
void show(int); //在窗口以指定时间间隔绘制画面
};
//手指颜色默认未拿起时为蓝色,在第0根柱子上
Hanoi::Hanoi(SDL_Renderer *render, int n, int index=0): render(render), finger({index, 0, 0, 255}) {
//初始化空中无盘子
airPlate = 0;
//初始化第0根柱子,盘子从n到1压栈
for (int i = n; i >0; i--) {
sticks[0].plates.push_back(i);
}
//明确3根柱子位置
sticks[0].x = 200; sticks[1].x = 400, sticks[2].x = 600;
}
//手指模型
typedef struct Finger {
int index; //柱号
unsigned char r, g, b; //手指颜色
} Finger;
(二)模型实现
1.电脑自动完成部分
这里更新的知识点包括:移动圆盘前后SDL显示、手指状态显示
bool Hanoi::movePlate(int a, int b) {
int plateA, plateB; //2根柱子顶端的盘子
plateA = this->sticks[a].plates.back();
if (!this->sticks[b].plates.empty()) {
plateB = this->sticks[b].plates.back();
if (plateA > plateB) return false;
}
//小盘子可以放在大盘子上
this->finger.index = a;
this->finger.r = 255; this->finger.b = 0; //让手指变红成拿起圆盘状态
this->show();
this->sticks[a].plates.pop_back();
this->sticks[b].plates.push_back(plateA);
this->finger.index = b;
this->finger.r = 0; this->finger.b = 255; //让手指变蓝成旆圆盘状态
this->show(); //显示
return true;
}
2.SDL图形显示
这里更新的知识点包括:SDL事件捕获与响应
SDL_Event event;
while(true) {
SDL_PollEvent(&event); //等待事件
// cout << event.type << " " << flush;
if (event.type == SDL_QUIT) { // 退出
break;
} else if (event.type == SDL_KEYDOWN) { // 按键
//防抖
while(true) {
SDL_PollEvent(&event); //等待事件
if ((event.type == SDL_KEYUP)) break;
}
switch (event.key.keysym.sym) { //检测按了哪个方向键
case SDLK_UP:
hanoi.upPlate();
break;
case SDLK_DOWN:
hanoi.downPlate();
break;
case SDLK_LEFT:
hanoi.leftFinger();
break;
case SDLK_RIGHT:
hanoi.rightFinger();
break;
}
}
hanoi.show(20); //20毫秒刷新一次
2.1拿起放下盘子的函数
bool Hanoi::upPlate() {
if (this->sticks[this->finger.index].plates.empty() || this->airPlate) return false; //柱子为空或已经有空中盘子
// 弹出圆盘
this->airPlate = this->sticks[this->finger.index].plates.back();
this->sticks[this->finger.index].plates.pop_back();
// 手指变红
this->finger.r = 255; this->finger.b = 0;
return true;
}
bool Hanoi::downPlate() {
//空中无圆盘或下方圆盘小都不能放
if (this->airPlate == 0) return false;
if (this->sticks[this->finger.index].plates.size() > 0 && this->sticks[this->finger.index].plates.back() < this->airPlate)
return false;
// 压入圆盘
this->sticks[this->finger.index].plates.push_back(this->airPlate);
this->airPlate = 0;
// 手指变蓝
this->finger.r = 0; this->finger.b = 255;
return true;
}
2.2左右移动手指的函数
void Hanoi::leftFinger() {
this->finger.index = (this->finger.index + 2) % 3;
}
void Hanoi::rightFinger() {
this->finger.index = (this->finger.index + 1) % 3;
}
二、处理用户输入,进行人机分流
放置在main函数中:
int n; //汉诺塔层数
int mode; //游戏模式
while (true) {
cout << "请输入汉诺塔层数:" << flush;
cin >> n;
cout << "选择模式:1:电脑完成,2:玩家完成" << endl;
cin >> mode;
if (mode != 1 && mode !=2) {
cout << "模式错误" << endl;
} else {
//初始化SDL部分
//...
//初始化汉诺塔部分
Hanoi hanoi(render, n);
hanoi.show(); //修复刚启动黑屏bug
if (mode == 1) { //电脑自动完成部分
hanoi.movePlates(0, 2, n);
} else { //mode == 2,用户交互部分
//进行事件捕获与响应
//...
}
//SDL销毁部分
//...
}
}
三、总结
本篇文章摘记了使用C++语言实现汉诺塔游戏电脑自动完成和用户交互功能的步骤,希望大家有所收获,如有好的建议欢迎留言,谢谢大家!
四、源码下载
C++实现图形化汉诺塔游戏源代码