地图转换优化
#include <graphics.h>
#include <iostream>
#include <stdlib.h>
#include <string>
#include <conio.h>
#include "box_man.h"
#include "database.h"
using namespace std;
IMAGE images[ALL];
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = { 0 };
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
// { 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
// { 0, 1, 4, 1, 0, 2, 1, 0, 2, 1, 0, 0 },
// { 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0 },
// { 0, 1, 0, 2, 0, 1, 1, 4, 1, 1, 1, 0 },
// { 0, 1, 1, 1, 0, 3, 1, 1, 1, 4, 1, 0 },
// { 0, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 0 },
// { 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0 },
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
//};
/**********************************************
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* 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("恭喜您~ \n您终于成为了一个合格的搬箱子老司机!"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
/**********************************************
*改变游戏地图视图中一格对应道具并重新显示
*输入:
* 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;
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;
}
int main(void) {
/* 用户身份验证 */
userinfo user;
levelinfo level;
bool ret = false;
if (login(user) == false)
{
cout << "登录失败, 请重新登录!!!" << endl;
::system("pause");
exit(-1);
}
else
{
cout << "登录成功 用户id: " << user.id << ", 你所在的关卡是: " << user.level_id << ", 请开始你的表演!!!" << endl;
::system("pause");
}
/* 根据用户所在关卡id获取关卡数据 */
ret = fetch_level_info(level, user.level_id);
if (!ret)
{
cout << "获取关卡数据失败, 请重试" << endl;
::system("pause");
exit(-2);
}
/* 把数据库中的地图数据转换到map中 */
ret = transform_map_db2array(level, map);
::system("pause");
IMAGE bg_img;
//搭台唱戏
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
loadimage(&bg_img, _T("blackground.bmp"), SCREEN_WIDTH, SCREEN_HEIGHT, true);
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);
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]]);
}
}
//游戏环节
bool quit = false;
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()) {
gameOverScene(&bg_img);
quit = true;
}
}
Sleep(100);
} while (quit == false); //!quit
system("pause");
//游戏结束,释放资源
closegraph();
return 0;
}
#pragma once
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define RATIO 50
//控制键 上、下、左、右 控制方向,'q' 退出
#define KEY_UP 'w' //char 'a'
#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
#define MAX_RETRY_TIMES 4
//#define PROPS enum _PROPS
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
enum _PROPS {
WALL, //墙
FLOOR, //地板
BOX_DES, //箱子目的地
MAN, //小人
BOX, //箱子
HIT, //箱子命中目标
ALL
};
//游戏控制方向
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人所在的二维数组的行
int y; //小人所在的二维数组的列
};
#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_level_info(levelinfo& level, int level_id); /* 获取关卡信息 */
bool transform_map_db2array(levelinfo& level, int map[LINE][COLUMN]); /* 地图转换优化 */
#include "database.h"
#include <mysql.h>
#include <stdio.h>
#define DB_NAME "box_man"
#define DB_HOST "127.0.0.1"
#define DB_PORT 3306
#define DB_USER "root"
#define DB_USER_PASSWD "Wei02032001"
static int debug = 1;
static bool connect_db(MYSQL& mysql);
/************************************
* 功能: 通过用户名和密码从数据库获取用户信息
* 输入:
* user - 用户信息结构体
*
* 返回值:
* 获取成功返回true, 失败 false
************************************/
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 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;
}
/************************************
* 功能: 根据关卡 id 获取完整的关卡信息(如: 地图, 下一关等)
* 输入:
* level - 保存关卡信息的结构体变量
* level_id - 要获取详细关卡信息的关卡 id
*
* 返回值:
* 获取成功返回true, 失败 false
************************************/
bool fetch_level_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[5]);
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);
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 == 1);
if (row < level.map_row)
{
printf("地图行数少于设定, %d(need: %d), 终止! \n", row, level.map_row);
return false;
}
return true;
/*
'0,0,0,0,0,0,0,0,0,0,0,0|
0,1,0,1,1,1,1,1,1,1,0,0|
0,1,4,1,0,2,1,0,2,1,0,0|
0,1,0,1,0,1,0,0,1,1,1,0|
0,1,0,2,0,1,1,4,1,1,1,0|
0,1,1,1,0,3,1,1,1,4,1,0|
0,1,2,1,1,4,1,1,1,1,1,0|
0,1,0,0,1,0,1,1,0,0,1,0|
0,0,0,0,0,0,0,0,0,0,0,0'
*/
}
运行结果:
(略)
结语:
时间: 2020-07-16