跳转下一关
MySQL数据库
只要一过关, leve_id = 2, 需要调整, 再运行就会从 level_id = 2, 开始(运行后)
#pragma once
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define RATIO 50
#define MAX_RETRY_TIMES 4
/* 控制键 上 下 左 右 控制方向 */
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
//#define LINE 9
//#define COLUMN 12
#define START_X 100
#define START_Y 100
enum _PROPS /* 道具 */
{
WALL, /* 墙 */
FLOOR, /* 地板 */
BOX_DES, /* 箱子的目地 */
MAN, /* 小人 */
BOX, /* 箱子 */
HIT, /* 箱子命中目标 */
ALL
};
/* 游戏控制方向 */
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS /* 位置 */
{
int x; /* 小人所在二维数组的行 */
int y; /* 小人所在二维数据在列 */
};
typedef enum _PROPS PROPS; /* 道具 */
typedef enum _DIRECTION DIRECTION; /* 控制方向 */
typedef struct _POS POS; /* 道具的位置 */
#define isValid(pos) pos.x>=0 && pos.x<LINE && pos.y>=0 && pos.y < COLUMN
#include "box_man.h"
#include <iostream>
#include <stdlib.h>
#include <string>
#include <conio.h>
#include <graphics.h>
#include "box_man.h"
#include "database.h"
using namespace std;
IMAGE images[ALL];
struct _POS man; /* 小人在二维数组的位置 */
int map[LINE][COLUMN] = { 0 };
//{
// {WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL},
// {WALL, FLOOR, WALL, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, WALL, WALL},
// {WALL, FLOOR, BOX, FLOOR, WALL, BOX_DES, FLOOR, WALL, BOX_DES, FLOOR, WALL, WALL},
// {WALL, FLOOR, WALL, FLOOR, WALL, FLOOR, FLOOR, WALL, FLOOR, FLOOR, FLOOR, WALL},
// {WALL, FLOOR, WALL, BOX_DES, WALL, FLOOR, FLOOR, BOX, FLOOR, FLOOR, FLOOR, WALL},
// {WALL, FLOOR, FLOOR, FLOOR, WALL, MAN, FLOOR, FLOOR, FLOOR, BOX, FLOOR, WALL},
// {WALL, FLOOR, BOX_DES, FLOOR, FLOOR, BOX, FLOOR, FLOOR, FLOOR, FLOOR, FLOOR, WALL},
// {WALL, FLOOR, WALL, WALL, FLOOR, WALL, FLOOR, FLOOR, WALL, WALL, FLOOR, WALL},
// {WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL, WALL},
//};
/*****************************************************
* 判断游戏是否结束, 如果不存在任何一个箱子目的地, 就代表游戏结束
* 输入: 无
* 返回值:
* true - 游戏结束 false - 游戏继续
*****************************************************/
bool isGameOver()
{
for (int i = 0; i < LINE; i++)
{
for (int j = 0; j < COLUMN; j++)
{
if (map[i][j] == BOX_DES)
{
return false;
}
}
}
return true;
}
/***************************************************
* 功能: 游戏结束场景, 在玩家通过后显示
* 输入:
* bg - 背景图片变量的指针
* 返回值: 无
***************************************************/
void gameOverScene(IMAGE* bg)
{
putimage(0, 0, bg);
settextcolor(WHITE);
RECT rec = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
settextstyle(20, 0, _T("宋体"));
drawtext(_T("恭喜你, 通关了!!!"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void gameNextScene(IMAGE* bg)
{
putimage(0, 0, bg);
settextcolor(WHITE);
RECT rec = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
settextstyle(20, 0, _T("宋体"));
drawtext(_T("恭喜你\n 此关挑战成功, 任意键跳转到下一关"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
cleardevice();
}
/*************************************************
* 功能: 改变游戏地图视图中一格对应的道具并重新显示
* 输入:
* pos - 道具在地图数组的行列下标
* prop - 道具的类型
* 返回值: 无
*************************************************/
void changeMap(POS* pos, PROPS prop)
{
map[pos->x][pos->y] = prop;
putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &images[prop]);
}
/**********************************************
* 功能: 实现游戏四个方向 (上, 下, 左, 右) 的控制
* 输入:
* direct - 人前进的方向
* 输出: 无
**********************************************/
void gameControl(DIRECTION direct)
{
POS next_pos = man; /* man 类型(结构体) 与 next_pos 相同 */
POS next_next_pos = man;
switch (direct)
{
case UP:
next_pos.x--;
next_next_pos.x -= 2;
break;
case DOWN:
next_pos.x++;
next_next_pos.x += 2;
break;
case LEFT:
next_pos.y--;
next_next_pos.y -= 2;
break;
case RIGHT:
next_pos.y++;
next_next_pos.y += 2;
break;
}
/* 宏展开 next_pos.x >= 0 && next_pos.x < LINE && next_pos.y >= 0 && next_pos.y < COLUMN */
if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR) /* 人的前方是地板 */
{
changeMap(&next_pos, MAN);
changeMap(&man, FLOOR);
man = next_pos;
}
else if (isValid(next_next_pos) && map[next_pos.x][next_pos.y] == BOX)
{
if (map[next_next_pos.x][next_next_pos.y] == FLOOR)
{
changeMap(&next_next_pos, BOX);
changeMap(&next_pos, MAN); /* 小人前进一格 */
changeMap(&man, FLOOR);
man = next_pos;
}
else if (map[next_next_pos.x][next_next_pos.y] == BOX_DES)
{
changeMap(&next_next_pos, HIT);
changeMap(&next_pos, MAN);
changeMap(&man, FLOOR);
man = next_pos;
}
}
}
bool login(userinfo& user)
{
int times = 0;
bool ret = false;
do {
cout << "请输入用户名: ";
cin >> user.username;
cout << "请输入密码: ";
cin >> user.passwd;
/* 返回 bool, 成功返回 true, 失败返回 false */
ret = fetch_user_info(user);
times++;
if (times >= MAX_RETRY_TIMES)
{
break;
}
if (ret == false)
{
cout << "登录失败, 请重新输入!" << endl;
}
} while (!ret);
return ret;
}
void init_game_graph(IMAGE &bg_img)
{
/* 搭台 */
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
loadimage(&bg_img, _T("blackground.bmp"), SCREEN_WIDTH, SCREEN_HEIGHT);
putimage(0, 0, &bg_img);
/* 加载道具 */
loadimage(&images[WALL], _T("wall_right.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
}
int main(void)
{
/* 用户身份验证 */
userinfo user;
levelinfo level;
IMAGE bg_img;
bool ret = false;
if (login(user) == false)
{
cout << "登录失败" << endl;
::system("pause");
exit(-1);
}
else
{
cout << "登录成功" << endl;
::system("pause");
}
///* 根据用户所在关卡id获取关卡数据 */
//ret = fetch_lever_info(level, user.level_id);
//if (ret == false)
//{
// cout << "获取关卡数失败, 请重试" << endl;
// ::system("pause");
// exit(-2);
//}
//else
//{
// cout << "登录成功 用户名: " << user.username << " ,所在关卡: " << user.level_id << endl;
//}
/* 初始化, 加载 */
init_game_graph(bg_img);
/* 游戏环节 */
bool quit = false;
do {
/* 根据用用户所在的关卡 id 获取关卡数据 */
ret = fetch_lever_info(level, user.level_id);
if (ret == false)
{
cout << "获取关卡数据失败, 请重试! " << endl;
::system("pause");
exit(-1);
}
else
{
cout << "登录成功 用户名: " << user.username << " ,所在关卡: " << user.level_id << endl;
}
/* 把数据库中的地图数据转换到map中 */
ret = transform_map_db2array(level, map);
if (ret == false)
{
cout << "把数据库中的地图数据转换到map中--失败!!!" << endl;
::system("pause");
exit(-2);
}
for (int i = 0; i < level.map_row; i++)
{
for (int j = 0; j < level.map_column; j++)
{
if (map[i][j] == MAN)
{
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
do
{
if (_kbhit())
{
char ch = _getch();
if (ch == KEY_UP)
{
gameControl(UP);
}
else if (ch == KEY_DOWN)
{
gameControl(DOWN);
}
else if (ch == KEY_LEFT)
{
gameControl(LEFT);
}
else if (ch == KEY_RIGHT)
{
gameControl(RIGHT);
}
else if (ch == KEY_QUIT)
{
quit = true;
}
if (isGameOver())
{
if (level.next_level < 1)
{
gameOverScene(&bg_img);
quit = true;
break;
}
gameNextScene(&bg_img);
/* 更新用户下一关的关卡信息 */
if (update_user_level(user, level.next_level))
{
user.level_id = level.next_level;
}
break;
//gameOverScene(&bg_img);
//quit = true;
}
}
Sleep(100);
} while (quit == false);
} while (quit == false);
::system("pause");
closegraph();
return 0;
}
#pragma once
#include <string>
using namespace std;
#define LINE 48
#define COLUMN 48
/* 用户信息 */
typedef struct _userinfo
{
int id; /* 用户 id */
string username; /* 用户名 */
string passwd; /* 密码 */
int level_id; /* 关卡 id */
}userinfo;
/* 关卡信息 */
typedef struct _levelinfo
{
int id; /* 关卡id */
string name; /* 关卡的名字 */
int map_row; /* 地图的总行数 */
int map_column; /* 地图的总列数 */
string map_data; /* 二维地图数据 */
int next_level; /* 下一关的id*/
}levelinfo;
bool fetch_user_info(userinfo& user);
bool fetch_lever_info(levelinfo& level, int level_id);
bool transform_map_db2array(levelinfo& level, int map[LINE][COLUMN]);
bool update_user_level(userinfo& user, int next_level_id);
#include "database.h"
#include <mysql.h>
#include <stdio.h>
#define DB_NAME "box_man_v1"
#define DB_HOST "127.0.0.1"
#define DB_PORT 3306
#define DB_USER "root"
#define DB_USER_PASSWD "Wei02032001"
static int debug = 1;
bool connect_db(MYSQL& mysql)
{
/* 1. 初始化数据库句柄 */
mysql_init(&mysql);
/* 2. 设置字符编码 */
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "gbk");
/* 3. 连接数据库 */
if (mysql_real_connect(&mysql,
DB_HOST, DB_USER, DB_USER_PASSWD, DB_NAME, DB_PORT, NULL, 0) == NULL)
{
printf("数据库连接出错, 错误原因: %s \n", mysql_error(&mysql));
return false;
}
return true;
}
bool fetch_user_info(userinfo& user)
{
MYSQL mysql;
MYSQL_RES* res; /* 查询结果集 */
MYSQL_ROW row; /* 记录结构体 */
char sql[256];
bool ret = false;
/* 1. 连接数据库 */
if (connect_db(mysql) == false)
{
return false;
}
/* 2. 根据用户名和密码获取用户信息(id, leve_id) */
snprintf(sql, 256, "select id, level_id from users where username='%s' and password = md5('%s');",
user.username.c_str(), user.passwd.c_str());
ret = mysql_query(&mysql, sql); /* 成功返回0 */
if (ret)
{
printf("数据库查询出错, %s 错误原因: %s \n", sql, mysql_error(&mysql));
mysql_close(&mysql);
return false;
}
/* 3. 获取结果 */
res = mysql_store_result(&mysql);
row = mysql_fetch_row(res);
if (row == NULL) /* 没有查找到记录 */
{
mysql_free_result(res);
mysql_close(&mysql);
return false;
}
user.id = atoi(row[0]);
user.level_id = atoi(row[1]);
printf("userid: %d leve_id: %d\n", user.id, user.level_id); /* 打印id */
/* 4. 返回结果 */
/* 释放结果集 */
mysql_free_result(res);
/* 关闭数据库 */
mysql_close(&mysql);
return true;
}
bool fetch_lever_info(levelinfo& level, int level_id)
{
MYSQL mysql;
MYSQL_RES* res; /* 查看结果集 */
MYSQL_ROW row; /* 记录结构体 */
char sql[256];
bool ret = false;
/* 1. 连接到数据库 */
if (connect_db(mysql) == false)
{
return false;
}
/* 2. 根据关卡 id 查询数据库获取关卡地图信息 */
snprintf(sql, 256,
"select name, map_row, map_column, map_data, next_level_id from levels where id = %d;",
level_id);
ret = mysql_query(&mysql, sql); /* 成功返回0 */
if (ret != 0)
{
printf("数据库查询出错, %s 错误原因: %s \n", sql, mysql_error(&mysql));
mysql_close(&mysql);
return false;
}
/* 3. 获取结果 */
res = mysql_store_result(&mysql);
row = mysql_fetch_row(res);
if (row == NULL) /* 没有查找到记录 */
{
mysql_free_result(res);
mysql_close(&mysql);
return false;
}
level.id = level_id;
level.name = row[0];
level.map_row = atoi(row[1]);
level.map_column = atoi(row[2]);
level.map_data = row[3];
level.next_level = atoi(row[4]);
if (debug)
{
printf("level id: %d name: %s map row: %d map column: %d map data: %s next level: %d\n",
level.id, level.name.c_str(), level.map_row,
level.map_column, level.map_data.c_str(), level.next_level);
}
/* 释放结果集 */
mysql_free_result(res);
/* 关闭数据库 */
mysql_close(&mysql);
return true;
}
bool transform_map_db2array(levelinfo& level, int map[LINE][COLUMN])
{
if (level.map_row > LINE || level.map_column > COLUMN)
{
printf("地图过大, 请重新设置\n");
return false;
}
if (level.map_data.length() < 1)
{
printf("地图数据有误, 请重新设置! \n");
return false;
}
int start = 0, end = 0;
int row = 0, column = 0;
do
{
end = level.map_data.find('|', start); /* 在数组或者向量中,找到一个数,返回它的下标 */
if (end < 0)
{
end = level.map_data.length();
}
if (start >= end)
{
break;
}
string line = level.map_data.substr(start, end - start); /* 获得字符串map_data中从第start位开始的长度为end - start的字符串*/
printf("get line: %s\n", line.c_str());
/* 对行地图数据进行解析 */
char* next_token = NULL;
char* item = strtok_s((char*)line.c_str(), ",", &next_token);
column = 0;
while (item && column < level.map_column)
{
printf("%s ", item);
map[row][column] = atoi(item);
column++;
item = strtok_s(NULL, ",", &next_token);
}
if (column < level.map_column)
{
printf("地图数据解析出错, 终止! \n");
return false;
}
printf("\n");
row++;
if (row >= level.map_row)
{
break;
}
start = end + 1;
} while (1);
if (row < level.map_row)
{
printf("地图行数小于设定, %d(need: %d), 终止! \n", row, level.map_row);
return false;
}
return true;
}
bool update_user_level(userinfo& user, int next_level_id)
{
MYSQL mysql;
MYSQL_RES* res; /* 查询结果集 */
MYSQL_ROW row; /* 记录结构体 */
char sql[256];
bool ret = false;
/* 1. 连接到数据库 */
if (connect_db(mysql) == false)
{
return false;
}
/* 2. 根据用户 id 更新下关的 level_id */
snprintf(sql, 256, "update users set level_id = %d where id = %d;", next_level_id, user.id);
ret = mysql_query(&mysql, sql);
if (ret != 0)
{
printf("数据库更新出错, %s 错误原因: %s\n", sql, mysql_error(&mysql));
mysql_close(&mysql);
return false;
}
/* 关闭数据库 */
mysql_close(&mysql);
return true;
}
具体操作
(略)
结语:
可以继续优化, 下次一定!!!
时间: 2020-07-17