推箱子(数据库篇)

引言:

推箱子,经典小游戏,带我们回到小时候,来一波“爷童回”。可以在数据库表中设计不一样的关卡,自己设计地图,学习的同时又能体验游戏的乐趣~

实现:

采用C++语言,使用visual studio工具,与数据库进行相连,实现用户登录与获取关卡信息功能。

用户登录后可获取当前已到达哪一关卡,接着从那一关开始继续推箱子。同时加载地图也是通过读取关卡表,支持在表中添加多种不同地图,提升游戏体验。

效果:

推箱子GIF

源代码:

github地址

目录:

一、数据库表设计
二、连接数据库与用户登录
三、初始化游戏界面
四、获取并加载地图数据
五、操作游戏
六、跳转至下一关或结束游戏

一 、数据库表设计

1.1 用户表设计

用户表用来存用户的信息,包括用户id,用户名,密码,关卡id。

字段名 类型 是否为空 备注
id int 主键 自动增长
username varchar(64) 唯一键 用户名(登录时使用)
password varchar(32) NA 密码(用md5加密)
level_id int NA 保存用户所在的关卡

用户表里中保存的关卡id(预设为1表示第一关),当用户下次登录时,从上次玩到的关卡开始继续游戏。

创建语句:

CREATE TABLE user (
  id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  username varchar(64) NOT NULL UNIQUE,
  password varchar(32) NOT NULL,
  level_id int DEFAULT '1');

1.2 关卡表设计

关卡表用来存放地图信息,包括地图id,地图名字,地图行数,地图列数,地图数据,下一关地图id。

字段名 类型 是否为空 备注
id int 主键 地图的id
name varchar(64) NA 地图名字
map_row int NA 地图行数
map_column int NA 地图列数
map_data varchar(32) NA 地图数据
next_level_id int NA 下一关的地图id

其中,通过读取表中的地图数据来加载地图,next_level_id存下一关的地图id,没有下一关存0。

创建语句:

CREATE TABLE levels(
  id int NOT NULL PRIMARY KEY,
  name varchar(64) NOT NULL,
  map_row int NOT NULL,
  map_column int NOT NULL,
  map_data varchar(4096) NOT NULL,
  next_level_id int DEFAULT '0');

二 、连接数据库与用户登录

2.1 连接数据库

创建了一个database文件,用来存放与数据库连接的方法,和需要与数据库交互的一些方法,database.h中为方法的声明,database.cpp中为方法的定义。
以下为连接数据库的方法,只写在database.cpp文件中:

#define DB_HOST "127.0.0.1"
#define DB_USER "root"
#define DB_PASSWD "123456!"
#define DB_NAME "push_box"
#define DB_PORT 3308

/**********************************************
 *功能:连接数据库
 *输入:
	mysql - 句柄,数据库连接的一些需要使用的方法中需用到
 *返回值:
	连接成功返回true,连接失败返回false
***********************************************/
bool connectDB(MYSQL &mysql) {
   
	mysql_init(&mysql);	//初始化句柄

	//设置字符编码
	mysql_options(&mysql,MYSQL_SET_CHARSET_NAME,"gbk");

	//连接数据库
	if (mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_PASSWD, DB_NAME, DB_PORT, NULL, 0) == NULL) {
   
		printf("数据库连接失败,原因:%s",mysql_error(&mysql));
		return false;
	}

	return true;
}

其中, DB_HOST, DB_USER, DB_PASSWD, DB_NAME, DB_PORT都使用了宏定义。

2.2 实现用户登录

database文件中通过getUserInfo方法,用来获取用户信息并进行用户登录认证。

database.h:

#include "box.h"

bool getUserInfo(useInfo &user);

database.cpp:

#include <mysql.h>
#include <stdio.h>
#include "database.h"

//省略上面已写的宏定义与conactDB方法


/**********************************************
 *功能:获取用户信息
 *输入:
	user - 保存用户信息的结构体变量
 *返回值:
	获取成功返回true,获取失败返回false
***********************************************/
bool getUserInfo(useInfo &user) {
   
	MYSQL mysql;
	MYSQL_RES *result; //定义结果集
	MYSQL_ROW row;	//记录结构体
	char sql[256];	//将sql语句存入其中
	int ret;

	//连接到数据库
	if (!connectDB(mysql)) {
   
		return false;
	}
	snprintf(sql,256,"select id,level_id from user where username='%s' and password=md5('%s');", user.name.c_str(), user.pwd.c_str());
	ret=mysql_query(&mysql, sql);	//成功返回0

	if (ret) {
   
		printf("查询数据失败,%s,原因:%s",sql,mysql_error(&mysql));
		mysql_close(&mysql); //关闭数据库
		return false;
	}

	//获取结果
	result = mysql_store_result(&mysql);
	row = mysql_fetch_row(result);	//结果读出

	if (row == NULL) {
   		//没有查询到数据
		mysql_free_result(result);	//释放结果集
		mysql_close(&mysql);	//关闭数据库
		return false;
	}

	user.id = atoi(row[0]);		//atoi将字符串转为int
	user.levelID = atoi(row[1]);

	mysql_free_result(result);	//释放结果集
	mysql_close(&mysql);	//关闭数据库

	return true;
}

其中userInfo为结构体,存放在box.h头文件中,如下所写:

typedef struct _useInfo{
   
	int id;			//用户id
	string name;	//用户名
	string pwd;		//密码
	int levelID;	//关卡id
}useInfo;

从数据库中获取的用户数据会保存到结构体对象中。
同时main方法中的写法如下:

#include <iostream>
#include <string>
#include <Windows.h>
#include <graphics.h>
#include <conio.h>
#include <easyx.h>
#include <mysql.h>
#include "box.h"
#include "database.h"

useInfo user;	//创建user结构体对象

//用户登录方法,有四次输入密码的机会
bool login() {
   
//	useInfo user;
	int times = 0;
	bool ret = false;

	do {
   
		times++;
		cout << "请输入用户名:";
		cin >> user.name;
		cout << "请输入密码:";
		cin >> user.pwd;
		ret = getUserInfo(user);
		if (times > 4) {
   
			break;
		}
		if (ret == false) {
   
			cout << "请重新输入账号/密码!" << endl;
		}
	} while (!ret);

	return ret;
}

int main(){
   
	if (login() == false) {
   
		exit(-1);
	}
	
	return 0;
}

三 、初始化游戏界面

main.cpp文件中,创建了initGame方法,用来初始化窗口大小,加载人、箱子等图片。

更新main.cpp

#include <iostream>
#include <string>
#include <Windows.h>
#include <graphics.h>
#include <conio.h>
#include <easyx.h>
#include <mysql.h>
#include "box.h"
#include "database.h"

useInfo user;	//创建user结构体对象
//創建數組來存放不同種類的圖片
IMAGE img[ALL];
IMAGE bg_img;	//創建圖片對象

//用户登录方法,有四次输入密码的机会
//省略

//初始化游戏界面
void initGame() {
   
//	cleardevice();
	initgraph(BG_WIDTH, BG_HEIGTH);	//初始化窗口大小
	loadimage(&bg_img, _T("blackground.bmp"), BG_WIDTH, BG_HEIGTH, true);	//加載背景圖片
	putimage(0, 0, &bg_img);	//把圖片放到窗口上

	//加載墻,人等圖片
	loadimage(&img[WALL], _T("wall_right.bmp"), IMG_SIZE, IMG_SIZE, true);
	loadimage(&img[FLOOER], _T("floor.bmp"), IMG_SIZE, IMG_SIZE, true);
	loadimage(&img[BOX_DEC], _T("des.bmp"), IMG_SIZE, IMG_SIZE, true);
	loadimage(&img[MAN], _T("man.bmp"), IMG_SIZE, IMG_SIZE, true);
	loadimage(&img[BOX], _T("box.bmp"), IMG_SIZE, IMG_SIZE, true);
	loadimage(&img[HIT], _T("box.bmp"), IMG_SIZE, IMG_SIZE, true);

}

int main(){
   
	if (login() == false) {
   
		exit(-1);
	}
	initGame();
	
	return 0;
}

initGame方法中的窗口大小为宏定义,图片数组中墙、地板等为枚举类型,都定义在box.h文件中:

#pragma once
#include <string>

using namespace std;

#define IMG_SIZE    61
#define BG_WIDTH    800
#define BG_HEIGTH   640

//枚舉道具
enum PROP {
   
	WALL,
	FLOOER,
	BOX_DEC,
	MAN,
	BOX,
	HIT,
	ALL
};

四 、获取并加载地图数据

4.1 获取地图数据

在初始化界面后,需要从数据库中读取地图数据。同样也是在database文件中,通过getLevelInfo来获取关卡信息,如下所写:

//省略头文件,宏定义,conactDB方法和getUserInfo方法

/**********************************************
 *功能:获取关卡信息
 *输入:
	level - 保存关卡信息的结构体变量
	level_id - 传入的关卡id,根据id获取关卡信息
 *返回值:
	获取成功返回true,获取失败返回false
***********************************************/
bool getLevelInfo(levelInfo &level,int level_id) {
   
	MYSQL mysql;
	MYSQL_RES *result; //定义结果集
	MYSQL_ROW row;	//记录结构体
	char sql[256];	//将sql语句存入其中
	int ret;

	//连接到数据库
	if (!connectDB(mysql)) {
   
		return false;
	}
	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) {
   
		printf("查询数据失败,%s,原因:%s", sql, mysql_error(&mysql));
		mysql_close(&mysql); //关闭数据库
		return false;
	}

	//获取结果
	result = mysql_store_result(&mysql);
	row = mysql_fetch_row(result);	//结果读出

	if (row == NULL) {
   		//没有查询到数据
		mysql_free_result(result);	//释放结果集
		mysql_close(&mysql);	//关闭数据库
		return false;
	}

	level.name = row[0];		//atoi将字符串转为int
	level.map_row = atoi(row[1]);
	level.map_column = atoi(row[2]);
	level.map_data = row[3];
	level.next_level = atoi(row[4]);

	mysql_free_result(result);	//释放结果集
	mysql_close(&mysql);	//关闭数据库

	return true;
}

其中levelInfo为结构体,存放在box.h头文件中,如下所写:

typedef struct
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值