MySQL - C/C++访问MySQL数据库(数据库编程实战-跳转下一关)

跳转下一关

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值