C語(yǔ)言+MySQL實(shí)現(xiàn)推箱子游戲
圖片素材及源碼
數(shù)據(jù)庫(kù)SQL語(yǔ)句
create database box_man if not exists;
use box_man;
create table users (
id int not null auto_increment,
username varchar(64) not null,
password varchar(32) not null,
level_id int default 1,
primary key(id),
unique key username(username)
);
create table levels(
id int not null auto_increment,
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 comment '下一關(guān)的id,0代表通關(guān)',
primary key(id)
);
insert into users
values(1,'Jack',md5(123456),1);
insert into levels
values(1,'小試牛刀→第一關(guān)',8,10,'-1,0,0,0,0,0,0,0,-1,-1|-1,0,2,2,2,2,1,0,-1,-1|0,0,0,2,2,2,4,0,0,0|0,1,1,4,0,4,1,4,1,0|0,1,4,4,1,1,0,4,1,0|0,1,1,1,3,0,1,1,1,0|0,0,0,0,1,1,1,0,0,0,|-1,-1,-1,0,0,0,0,0,-1,-1',2),
(2,'絕地強(qiáng)者→第二關(guān)',6,6,'0,0,0,0,0,0|0,2,2,1,1,0|0,4,4,1,3,0|0,2,1,4,0,0|0,1,1,1,0,-1|0,0,0,0,0,-1',3),
(3,'天外強(qiáng)人→第三關(guān)',8,10,'-1,-1,0,0,0,0,0,0,-1,-1|0,0,0,1,1,1,0,0,0,0|0,1,1,1,4,1,4,1,1,0|0,1,4,1,1,1,4,1,3,0|0,0,0,4,4,0,0,0,0,0,|-1,-1,0,1,1,2,2,0,-1,-1|-1,-1,0,2,2,2,2,0,-1,-1|-1,-1,0,0,0,0,0,0,-1,-1',4),
(4,'死而復(fù)生→BOSS關(guān)',8,8,'-1,0,0,0,0,0,0,-1|-1,0,2,1,2,2,0,-1|-1,0,2,1,4,2,0,-1|0,0,0,1,1,4,0,0|0,1,4,1,1,4,1,0|0,1,0,4,0,0,1,0|0,1,1,1,3,1,1,0|0,0,0,0,0,0,0,0',0);
操作數(shù)據(jù)庫(kù)C++代碼
database.h
#pragma once
#include<string>
using namespace std;
#define LINE 48
#define COLUMN 48
typedef struct _userinfo {
//這里將字符串初始為空
_userinfo() :id(0), username(""), password(""), level_id(0) {};
int id; // 用戶(hù)id
string username;
string password; // 密碼
int level_id;
}userinfo;
typedef struct _levelinfo {
_levelinfo() :id(0), name(""), map_row(0), map_column(0), map_data(""), next_level(0) {};
int id; // 關(guān)卡id
string name; // 關(guān)卡名字
int map_row; // 地圖行數(shù)
int map_column; //地圖列數(shù)
string map_data; // 二維地圖數(shù)據(jù)
int next_level; //下一關(guān)卡id
}levelinfo;
bool fetch_user_info(userinfo& user);
int fetch_level_info(levelinfo& level, int level_id);
bool transform_map_db2array(levelinfo& level, int map[][COLUMN]);
bool update_user_level(userinfo& user, int next_level_id);
bool resiting_data(userinfo& user);database.cpp
記得更改自己的用戶(hù)名和密碼
#include"database.h"
#include<mysql.h>
#include<stdio.h> // 會(huì)使用C的接口
#define DB_NAME "box_man" //數(shù)據(jù)庫(kù)名
#define DB_HOST "127.0.0.1" //IP地址
#define DB_PORT 3306 //端口號(hào)
#define DB_USER "root" //用戶(hù)名
#define DB_USER_PASSWORD "123456" //密碼
/******************************
*功能:數(shù)據(jù)庫(kù)鏈接
* 輸入:
* mysql - 數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)句柄
*
* 返回值:
* true - 連接成功
* false - 連接失敗
*****************************/
bool connect_db(MYSQL& mysql) {
//1.初始數(shù)據(jù)庫(kù)句柄
mysql_init(&mysql);
//2.設(shè)置字符編碼(為句柄設(shè)置)
//windows支持中文,在windows上一般是gbk字符集,gbk包含中文簡(jiǎn)體和繁體,簡(jiǎn)體是gbk2312
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "gbk");
//3.連接數(shù)據(jù)庫(kù)
//句柄,主機(jī),用戶(hù)名,密碼,數(shù)據(jù)庫(kù),端口號(hào),——,——
if (mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_USER_PASSWORD, DB_NAME, DB_PORT, NULL, 0) == NULL) {
printf("數(shù)據(jù)庫(kù)連接失敗,錯(cuò)誤原因:%s\n", mysql_error(&mysql));
return false;
}
return true;
}
/******************************
*功能:通過(guò)用戶(hù)名和密碼獲取用戶(hù)信息
* 輸入:
* user - 用戶(hù)信息結(jié)構(gòu)體
*
* 返回值:
* 獲取成功返回true,失敗false
*****************************/
bool fetch_user_info(userinfo& user) {
MYSQL mysql; //定義一個(gè)句柄,對(duì)mysql的訪(fǎng)問(wèn)都是通過(guò)這個(gè)句柄(就是一個(gè)集合)
MYSQL_RES* res; // 查詢(xún)的結(jié)果集
MYSQL_ROW row; // 如果結(jié)果集有多條,可以使用row獲取
char sql[256];
bool ret = false;
//1.連接數(shù)據(jù)庫(kù)
if (connect_db(mysql) == false) {
return false;
}
//2.設(shè)置SQL查詢(xún)語(yǔ)句
//snprintf函數(shù),設(shè)將可變參數(shù)(...)按照 format 格式化成字符串,并將字符串復(fù)制到 str 中,size 為要寫(xiě)入的字符的最大數(shù)目,超過(guò) size 會(huì)被截?cái)唷?
snprintf(sql, 256, "select id,level_id from users where username='%s' and password = md5('%s');", user.username.c_str(), user.password.c_str());
ret = mysql_query(&mysql, sql); //mysql查詢(xún),成功返回0
if (ret) {
printf("數(shù)據(jù)庫(kù)查詢(xún)出錯(cuò),%s錯(cuò)誤原因:%s\n", sql, mysql_error(&mysql));
// 關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return false;
}
//3.獲取查到的結(jié)果
res = mysql_store_result(&mysql);
//row獲得結(jié)果集里的一行記錄,再通過(guò)下標(biāo)訪(fǎng)問(wèn)記錄里的數(shù)據(jù),如果結(jié)果集有多行時(shí)可以通過(guò) while(row = mysql_fetch_row(res)){ }循環(huán)獲得
row = mysql_fetch_row(res);
if (row == NULL) { //沒(méi)有查到記錄
//1.釋放結(jié)果集
mysql_free_result(res);
//1.關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return false;
}
user.id = atoi(row[0]); // 字符串轉(zhuǎn)整數(shù)
user.level_id = atoi(row[1]);
//4.返回結(jié)果
mysql_free_result(res);
mysql_close(&mysql);
return true;
}
/*********************************
*功能:根據(jù)關(guān)卡id獲取完整的關(guān)卡信息(如:地圖,下一關(guān)等)
* 輸入:
* level - 保存關(guān)卡信息的結(jié)構(gòu)體
* level_id - 獲取關(guān)卡id
* 返回值:
* -1 - 數(shù)據(jù)庫(kù)連接或查詢(xún)出錯(cuò)
* 0 - 查找結(jié)果為空
* 1 - 查找成功
*********************************/
int fetch_level_info(levelinfo& level, int level_id) {
MYSQL mysql; //定義一個(gè)句柄,對(duì)mysql的訪(fǎng)問(wèn)都是通過(guò)這個(gè)句柄(就是一個(gè)集合)
MYSQL_RES* res; // 查詢(xún)的結(jié)果集
MYSQL_ROW row; // 如果結(jié)果集有多條,可以使用row獲取
char sql[256];
bool ret = false;
//1.連接數(shù)據(jù)庫(kù)
if (connect_db(mysql) == false) {
return -1;
}
//2.編寫(xiě)SQL語(yǔ)句
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); //mysql查詢(xún),成功返回0
if (ret) {
printf("數(shù)據(jù)庫(kù)查詢(xún)出錯(cuò),%s錯(cuò)誤原因:%s\n", sql, mysql_error(&mysql));
// 關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return -1;
}
//3.獲取查到的結(jié)果
res = mysql_store_result(&mysql);
//row獲得結(jié)果集里的一行記錄,再通過(guò)下標(biāo)訪(fǎng)問(wèn)記錄里的數(shù)據(jù),如果結(jié)果集有多行時(shí)可以通過(guò) while(row = mysql_fetch_row(res)){ }循環(huán)獲得
row = mysql_fetch_row(res);
if (row == NULL) { //沒(méi)有查到記錄
//1.釋放結(jié)果集
mysql_free_result(res);
//1.關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return 0;
}
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]);
//string用printf輸出,使用.c_str()可以返回一個(gè)const char* 的指針
//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);
//4.返回結(jié)果
mysql_free_result(res);
mysql_close(&mysql);
return 1;
}
/******************************
*功能:將獲得的關(guān)卡數(shù)據(jù)轉(zhuǎn)換到map地圖數(shù)組中
* 輸入:
* level - 關(guān)卡數(shù)據(jù)
* map - 二維地圖數(shù)組
*
* 返回值:
* false - 轉(zhuǎn)換失敗
* true - 轉(zhuǎn)換成功
*****************************/
bool transform_map_db2array(levelinfo& level, int map[][COLUMN]) {
if (level.map_row > LINE || level.map_column > COLUMN) {
printf("地圖過(guò)大,請(qǐng)重新設(shè)置\n");
return false;
}
if (level.map_data.length() < 1) {
printf("地圖數(shù)據(jù)有誤,請(qǐng)重新設(shè)置!\n");
return false;
}
long long start = 0, end = 0;
int row = 0, column = 0;
do {
/******************************
*find返回size_t類(lèi)型值,size_t在64位下是8字節(jié)長(zhǎng)度,因此這里把start和end設(shè)置成long long類(lèi)型(不設(shè)置會(huì)有“數(shù)據(jù)丟失”警告)。當(dāng)然也可以簡(jiǎn)單粗暴的修改警告設(shè)置
******************************/
end = level.map_data.find('|', start);
if (end == -1) {
end = level.map_data.length();
}
//合法性檢查,結(jié)束時(shí)end=level.map_data.length,start=end+1
if (start >= end)
break;
string line = level.map_data.substr(start, end - start);
//printf("get-line:%s\n", line.c_str());
// 對(duì)行數(shù)據(jù)進(jìn)行解析:0,1,0,1,1,1,1,1,1,1,0,0
char* next_token = NULL;
//line轉(zhuǎn)為const char*(C語(yǔ)言中的字符串),strtok_s會(huì)修改line里的值,按照某個(gè)特定字符,所以需要將line.c_str()轉(zhuǎn)為char *
// strtok_s第一個(gè)參數(shù)是要劈開(kāi)的字符串(要求是一個(gè)char *類(lèi)型的);第二個(gè)參數(shù)是按某個(gè)字符劈開(kāi)(會(huì)把“,”逗號(hào)變成‘\0'結(jié)束符,也就是說(shuō)會(huì)修改原來(lái)字符串,所以要把原來(lái)的const char*轉(zhuǎn)為char*);第三個(gè)參數(shù)是這個(gè)接口
// 需要的,用來(lái)做定位功能,
//printf("%p\n", &line[2]);
char* item = strtok_s((char*)line.c_str(), ",", &next_token);
column = 0;
//printf("%p", next_token);
//::system("pause");
//如果某行數(shù)據(jù)個(gè)數(shù)多余這個(gè)地圖列數(shù),控制只讀取level.map_column-1個(gè)
while (item&&column<level.map_column) {
map[row][column] = atoi(item);
column++;
//再使用strtok_s接口第一個(gè)參數(shù)可以寫(xiě)NULL,應(yīng)該是next_token參數(shù)上一次做定位功能時(shí)已經(jīng)記錄了要劈開(kāi)字符串給的某個(gè)位置
item = strtok_s(NULL, ",", &next_token);
}
//合法性檢查
if (column < level.map_column) { // 某行的數(shù)據(jù)個(gè)數(shù)小于這個(gè)地圖的列數(shù)
printf("地圖數(shù)據(jù)解析出錯(cuò),終止!\n");
return false;
}
row++;
//列數(shù)多余的話(huà)直接舍棄
if (row >= level.map_row) {
break;
}
start = end + 1;
} while (1 == 1);
//列數(shù)多余則直接報(bào)錯(cuò)
if (row < level.map_row) {
printf("地圖行數(shù)少于設(shè)定,終止!");
return false;
}
return true;
}
/******************************
*功能:更新用戶(hù)游戲進(jìn)度信息
* 輸入:
* user - 用戶(hù)信息
* next_level_id - 游戲進(jìn)度
*
* 返回值:
* 獲取成功返回true,失敗false
*****************************/
bool update_user_level(userinfo& user, int next_level_id) {
MYSQL mysql; //定義一個(gè)句柄,對(duì)mysql的訪(fǎng)問(wèn)都是通過(guò)這個(gè)句柄(就是一個(gè)集合)
char sql[256];
bool ret = false;
//1.連接數(shù)據(jù)庫(kù)
if (connect_db(mysql) == false) {
return false;
}
//2.編寫(xiě)SQL語(yǔ)句
snprintf(sql, 256, "update users set level_id=%d where id=%d", next_level_id, user.id);
ret = mysql_query(&mysql, sql);
if (ret) {
printf("數(shù)據(jù)庫(kù)更新出錯(cuò),%s錯(cuò)誤原因:%s\n", sql, mysql_error(&mysql));
// 關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return false;
}
user.level_id = next_level_id;
mysql_close(&mysql);
return true;
}
/******************************
*功能:重置用戶(hù)游戲進(jìn)度信息
* 輸入:
* user - 用戶(hù)信息
*
* 返回值:
* false - 重置失敗
* true - 重置成功
*****************************/
bool resiting_data(userinfo& user) {
MYSQL mysql; //定義一個(gè)句柄,對(duì)mysql的訪(fǎng)問(wèn)都是通過(guò)這個(gè)句柄(就是一個(gè)集合)
char sql[256];
bool ret = false;
//1.連接數(shù)據(jù)庫(kù)
if (connect_db(mysql) == false) {
return false;
}
//2.編寫(xiě)SQL語(yǔ)句
snprintf(sql, 256, "update users set level_id=1 where id=%d", user.id);
ret = mysql_query(&mysql, sql);
//3.判斷查詢(xún)結(jié)果
if (ret) {
printf("數(shù)據(jù)庫(kù)更新出錯(cuò),%s錯(cuò)誤原因:%s\n", sql, mysql_error(&mysql));
// 關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return false;
}
user.level_id = 1;
//4.關(guān)閉數(shù)據(jù)庫(kù)
mysql_close(&mysql);
return true;
}推箱子游戲代碼
box_man.h
#pragma once
#define RATIO 40
#define SCREEN_WIDTH 740
#define SCREEN_HEIGHT 500
#define START_X 50
#define START_Y 75
#define KEY_UP 'W'
#define KEY_LEFT 'A'
#define KEY_RIGHT 'D'
#define KEY_DOWN 'S'
#define KEY_OUT 'Q'
#define GAME_AGAIN 'R'
#define MAX_RETRY_TIMES 4
#define BG_IMAGE -1
#define isValid(next_pos) next_pos.x > 0 && next_pos.x < LINE && next_pos.y>0 && next_pos.y < COLUMN
typedef enum _PROPS PROPS;
typedef enum _DIRECTION DIRECTION;
typedef struct _POS POS;
enum _PROPS {
WALL, //墻
FLOOR, //地板
BOX_DES,//箱子目的地
MAN, //小人
BOX, //箱子
HIT, //箱子命中目標(biāo)
MAN_DES, //人站在目標(biāo)上
VECTOR //通關(guān)圖片
};
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人所在二維數(shù)組的行數(shù)
int y; //小人所在二維數(shù)組的列數(shù)
};box_man.cpp
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string>
#include<conio.h> //???
#include"box_man.h"
#include"database.h"
using namespace std;
int map[LINE][COLUMN] = { 0 };
POS man;
IMAGE images[9];
/*****************************
* 功能:判斷游戲是否結(jié)束
* 輸入:
* 無(wú)
* 輸出:
* true - 未結(jié)束
* flase - 結(jié)束
*****************************/
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;
}
/*****************************
* 功能:加載游戲結(jié)束圖片
* 輸入:
* 無(wú)
* 輸出:
* 無(wú)
*****************************/
void show_over() {
cleardevice();
IMAGE game_over;
loadimage(&game_over, _T("gameover.png"), SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &game_over);
}
/*****************************
* 功能:在指定位置更改地圖信息 顯示指定圖片
* 輸入:
* next_pos - 指定位置
* prop - 指定圖片
* 輸出:
* 無(wú)
*****************************/
void changeMap(POS* next_pos, PROPS prop) {
map[next_pos->x][next_pos->y] = prop;
putimage(START_X + next_pos->y * RATIO, START_Y + next_pos->x * RATIO, &images[prop]);
}
/*****************************
* 功能:在指定位置顯示指定圖片
* 輸入:
* next_pos - 指定位置
* prop - 指定圖片
* 輸出:
* 無(wú)
*****************************/
void changeMap2(POS* next_pos, PROPS prop) {
putimage(START_X + next_pos->y * RATIO, START_Y + next_pos->x * RATIO, &images[prop]);
}
/*****************************
* 功能:控制小人向指定方向移動(dòng)
* 輸入:
* direct - 指定方向
* 輸出:
* 無(wú)
*****************************/
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;
}
//宏展開(kāi)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) {
//人的腳下是目的地
if (map[man.x][man.y] == BOX_DES) {
changeMap(&next_pos, MAN);
changeMap2(&man, BOX_DES);
}
else {
changeMap(&man, FLOOR);
changeMap(&next_pos, MAN);
}
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);
if (map[man.x][man.y] == BOX_DES) {
changeMap(&man, BOX_DES);
}
else {
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);
if (map[man.x][man.y] == BOX_DES) {
changeMap(&man, BOX_DES);
}
else {
changeMap(&man, FLOOR);
}
man = next_pos;
}
}
//前方是目的地
else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX_DES) {
//小人腳下也是目的地
if (map[man.x][man.y] == BOX_DES) {
changeMap2(&next_pos, MAN_DES);
changeMap(&man, BOX_DES);
}
else {
changeMap(&man, FLOOR);
changeMap2(&next_pos, MAN_DES);
}
man = next_pos;
}
//前方是箱子命中點(diǎn)
else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == HIT) {
if (map[next_next_pos.x][next_next_pos.y] == FLOOR) { // 箱子的前方是地板
changeMap(&next_next_pos, BOX);
changeMap(&next_pos, BOX_DES);
changeMap2(&next_pos, MAN_DES);
//人的腳下是目的地
if (map[man.x][man.y] == BOX_DES) {
changeMap(&man, BOX_DES);
}
else {
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, BOX_DES);
changeMap2(&next_pos, MAN_DES);
//人的腳下是目的地
if (map[man.x][man.y] == BOX_DES) {
changeMap(&man, BOX_DES);
}
else {
changeMap(&man, FLOOR);
}
man = next_pos;
}
}
}
/*****************************
* 功能:用戶(hù)登錄
* 輸入:
* user - 用戶(hù)信息
* 輸出:
* false - 登錄失敗
* true - 登錄成功
*****************************/
bool login(userinfo& user) {
int times = 0;
bool ret = false;
do {
cout << "請(qǐng)輸入用戶(hù)名:";
cin >> user.username;
cout << "請(qǐng)輸入密碼:";
cin >> user.password;
ret = fetch_user_info(user);
times++;
if (times >= MAX_RETRY_TIMES)
break;
if (ret == false) {
cout << "登錄失敗,請(qǐng)重新輸入!" << endl;
}
} while (!ret);
return ret;
}
/*****************************
* 功能:加載游戲素材
* 輸入:
* 無(wú)
* 輸出:
* 無(wú)
*****************************/
void init_graph() {
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
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.jpg"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box_des.jpg"), RATIO, RATIO, true);
loadimage(&images[MAN_DES], _T("man_des.bmp"), RATIO, RATIO, true);
loadimage(&images[VECTOR], _T("vector.png"), 6*RATIO, 6*RATIO, true);
}
/*****************************
* 功能:顯示指定地圖
* 輸入:
* level - 指定地圖
* 輸出:
* 無(wú)
*****************************/
void show_images(levelinfo& level) {
cleardevice(); // 每次貼圖清屏一下
IMAGE bg_img;
//圖片的寬,高最后一個(gè)參數(shù)“是否拉伸”
loadimage(&bg_img, _T("bgimage.png"), SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img);
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;
}
if (map[i][j] == BG_IMAGE)
continue;
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
const char* str = level.name.c_str();
setbkmode(TRANSPARENT);
setfont(RATIO, 0, _T("華文楷體"));
setcolor(WHITE);
outtextxy(200, 25, str);
}
/*****************************
* 功能:載入PNG圖并去透明部分
* 輸入:
* 無(wú)
* 輸出:
* 無(wú)
*****************************/
void drawAlpha(IMAGE* picture, int picture_x, int picture_y) //x為載入圖片的X坐標(biāo),y為Y坐標(biāo)
{
// 變量初始化
DWORD* dst = GetImageBuffer(); // GetImageBuffer()函數(shù),用于獲取繪圖設(shè)備的顯存指針,EASYX自帶
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(picture); //獲取picture的顯存指針
int picture_width = picture->getwidth(); //獲取picture的寬度,EASYX自帶
int picture_height = picture->getheight(); //獲取picture的高度,EASYX自帶
int graphWidth = getwidth(); //獲取繪圖區(qū)的寬度,EASYX自帶
int graphHeight = getheight(); //獲取繪圖區(qū)的高度,EASYX自帶
int dstX = 0; //在顯存里像素的角標(biāo)
// 實(shí)現(xiàn)透明貼圖 公式: Cp=αp*FP+(1-αp)*BP , 貝葉斯定理來(lái)進(jìn)行點(diǎn)顏色的概率計(jì)算
for (int iy = 0; iy < picture_height; iy++)
{
for (int ix = 0; ix < picture_width; ix++)
{
int srcX = ix + iy * picture_width; //在顯存里像素的角標(biāo)
int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); //獲取RGB里的R
int sg = ((src[srcX] & 0xff00) >> 8); //G
int sb = src[srcX] & 0xff; //B
if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
{
dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在顯存里像素的角標(biāo)
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db
}
}
}
}
/*****************************
* 功能:載入“恭喜通關(guān)”圖片
* 輸入:
* 無(wú)
* 輸出:
* 無(wú)
*****************************/
void promot_over() {
setbkmode(TRANSPARENT);
drawAlpha(&images[VECTOR], 250, 130); // 載入PNG圖并去透明部分
Sleep(1100);
}
/*****************************
* 功能:休眠
* 輸入:
* interval - 休眠時(shí)間
* 輸出:
* 無(wú)
*****************************/
void wait(int interval) {
int count = interval / 10;
for (int i = 0; i < count; ++i) {
Sleep(10);
if (_kbhit())
return;
}
}
/*****************************
* 功能:游戲控制
* 輸入:
* level - 擋墻關(guān)卡數(shù)據(jù)
* user - 用戶(hù)信息
* 輸出:
* 無(wú)
*****************************/
void game_operation(levelinfo& level, userinfo& user) {
bool quit = false;
do {
//判斷是否有按鍵按下
if (_kbhit()) {
//無(wú)緩沖讀取
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 == GAME_AGAIN) {
fetch_level_info(level, user.level_id);
transform_map_db2array(level, map);
show_images(level);
}
else if (ch == KEY_OUT) {
closegraph();
exit(0);
}
if (isGameOver()) {
//更新用戶(hù)下一關(guān)關(guān)卡信息(用戶(hù)通關(guān)后直接跳轉(zhuǎn)下一關(guān))
update_user_level(user, level.next_level);
quit=true;
}
}
wait(100);
} while (quit == false);
}
/*****************************
* 功能:根據(jù)“由用戶(hù)ID獲取關(guān)卡數(shù)據(jù)”的返回結(jié)果進(jìn)行判斷
* 輸入:
* result - 返回結(jié)果(-1:獲取失敗 0:用戶(hù)已通關(guān) 1:獲取成功)
* level - 關(guān)卡數(shù)據(jù)
* user - 用戶(hù)信息
* 輸出:
* 無(wú)
*****************************/
void judge_by_result(int result, levelinfo& level, userinfo& user) {
if (result == 1) {
return;
}
else if (result == -1) {
closegraph();
cout << "獲取關(guān)卡數(shù)據(jù)失敗,請(qǐng)重試!" << endl;
std::system("pause");
exit(-1);
}
else if (result == 0) {
show_over();
do {
//判斷是否有按鍵按下
if (_kbhit()) {
//無(wú)緩沖讀取
char ch = _getch();
if (ch == KEY_OUT) {
closegraph();
exit(0);
}
else if (ch == GAME_AGAIN) {
if (!resiting_data(user)) {
std::system("pause");
closegraph();
exit(0);
}
break;
}
}
Sleep(50);
} while (1);
fetch_level_info(level, user.level_id);
}
}
int main() {
//用戶(hù)身份驗(yàn)證
userinfo user;
levelinfo level;
if (!login(user)) {
cout << "登錄失敗,請(qǐng)重新登錄!" << endl;
::system("pause");
exit(-1);
}
init_graph();
//循環(huán)(讀取關(guān)卡→用戶(hù)操作)
do {
//根據(jù)用戶(hù)信息加載關(guān)卡數(shù)據(jù)
int result = fetch_level_info(level, user.level_id);
judge_by_result(result, level, user);
//將關(guān)卡數(shù)據(jù)數(shù)據(jù)轉(zhuǎn)換到map游戲地圖中
transform_map_db2array(level, map);
//加載游戲圖片
show_images(level);
//小人移動(dòng)
game_operation(level, user);
//恭喜通關(guān)
promot_over();
} while (1);
std::system("pause");
closegraph();
return 0;
}到此這篇關(guān)于C語(yǔ)言+MySQL實(shí)現(xiàn)推箱子游戲的文章就介紹到這了,更多相關(guān)C語(yǔ)言 MySQL推箱子內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++編譯報(bào)錯(cuò):||error: ld returned 1 exit 
這篇文章主要介紹了C++編譯報(bào)錯(cuò):||error: ld returned 1 exit status|的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
QT5實(shí)現(xiàn)簡(jiǎn)單的TCP通信的實(shí)現(xiàn)
本文主要介紹了QT5實(shí)現(xiàn)簡(jiǎn)單的TCP通信的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
詳解設(shè)計(jì)模式中的模板方法模式及在C++中的使用
這篇文章主要介紹了設(shè)計(jì)模式中的模板方法模式及在C++中的使用,模板方法將邏輯封裝到一個(gè)類(lèi)中,并采取組合(委托)的方式解決這個(gè)問(wèn)題,需要的朋友可以參考下2016-03-03
C++ 中的虛函數(shù)表及虛函數(shù)執(zhí)行原理詳解
這篇文章主要介紹了C++ 中的虛函數(shù)表及虛函數(shù)執(zhí)行原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
C語(yǔ)言對(duì)磁盤(pán)文件進(jìn)行快速排序簡(jiǎn)單實(shí)例
這篇文章主要介紹了C語(yǔ)言對(duì)磁盤(pán)文件進(jìn)行快速排序簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06
Qt進(jìn)程和線(xiàn)程QProcess和QThread的使用
本文主要介紹了Qt進(jìn)程和線(xiàn)程QProcess和QThread的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件
這篇文章主要為大家詳細(xì)介紹了VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08

