Image material and source code
Download link
Database SQL statements
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 'The id of the next level, 0 means pass the level', primary key(id) ); insert into users values(1,'Jack',md5(123456),1); insert into levels values(1,'Test → First level',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,'The Jedi Strong → The Second Level',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,'The Strong Man from Heaven → The Third Level',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,'Resurrection from the Death → BOSS Pass',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);
Operate database C++ code
#pragma once #include<string> using namespace std; #define LINE 48 #define COLUMN 48 typedef struct _userinfo { //The string is initially empty here _userinfo() :id(0), username(""), password(""), level_id(0) {}; int id; // User ID string username; string password; // 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; // Level id string name; // Level name int map_row; // Number of rows of map int map_column; //Number of map columns string map_data; // 2D map data int next_level; //Next level 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);
Remember to change your username and password
#include"" #include<> #include<> // Will use C's interface #define DB_NAME "box_man" //Database name#define DB_HOST "127.0.0.1" //IP address#define DB_PORT 3306 //Port number#define DB_USER "root" //User name#define DB_USER_PASSWORD "123456" //Password /********************************************* *Function: Database link * Input: * mysql - database access handle * * Return value: * true - Connection is successful * false - Connection failed ***************************************/ bool connect_db(MYSQL& mysql) { //1. Initial database handle mysql_init(&mysql); //2. Set character encoding (set for handle) //Windows supports Chinese, generally the gbk character set on Windows, gbk contains Chinese simplified and traditional Chinese, and simplified Chinese is gbk2312 mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "gbk"); //3.Connect the database // Handle, host, username, password, database, port number, ——— if (mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_USER_PASSWORD, DB_NAME, DB_PORT, NULL, 0) == NULL) { printf("Database connection failed, error reason: %s\n", mysql_error(&mysql)); return false; } return true; } /********************************************* *Function: Obtain user information through username and password * Input: * user - user information structure * * Return value: * Get success and return true, fail false ***************************************/ bool fetch_user_info(userinfo& user) { MYSQL mysql; //Define a handle, and access to mysql is through this handle (that is, a collection) MYSQL_RES* res; // Query result set MYSQL_ROW row; // If there are multiple resultsets, you can use row to get it char sql[256]; bool ret = false; //1.Connect the database if (connect_db(mysql) == false) { return false; } //2. Set SQL query statement //snprintf function, let's format the mutable parameters (...) into a string according to format and copy the string into str. Size is the maximum number of characters to be written. If size exceeds size, it will be truncated. snprintf(sql, 256, "select id,level_id from users where username='%s' and password = md5('%s');", .c_str(), .c_str()); ret = mysql_query(&mysql, sql); //mysql query, successfully returned 0 if (ret) { printf("The database query error occurred, %s error reason: %s\n", sql, mysql_error(&mysql)); // Close the database mysql_close(&mysql); return false; } //3. Obtain the found results res = mysql_store_result(&mysql); //row gets a row of records in the result set, and then accesses the data in the record through the subscript. If there are multiple rows in the result set, you can get it through the while(row = mysql_fetch_row(res)){ } loop row = mysql_fetch_row(res); if (row == NULL) { //No record was found //1. Release the result set mysql_free_result(res); //1. Close the database mysql_close(&mysql); return false; } = atoi(row[0]); // String to integer user.level_id = atoi(row[1]); //4. Return the result mysql_free_result(res); mysql_close(&mysql); return true; } /************************************************ *Function: Obtain complete level information based on level id (such as: map, next level, etc.) * Input: * level - The structure that saves level information * level_id - get level id * Return value: * -1 - An error occurred in database connection or query * 0 - The search result is empty * 1 - Search successfully ******************************************/ int fetch_level_info(levelinfo& level, int level_id) { MYSQL mysql; //Define a handle, and access to mysql is through this handle (that is, a collection) MYSQL_RES* res; // Query result set MYSQL_ROW row; // If there are multiple resultsets, you can use row to get it char sql[256]; bool ret = false; //1.Connect the database if (connect_db(mysql) == false) { return -1; } //2. Write SQL statement 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 query, successfully returned 0 if (ret) { printf("The database query error occurred, %s error reason: %s\n", sql, mysql_error(&mysql)); // Close the database mysql_close(&mysql); return -1; } //3. Obtain the found results res = mysql_store_result(&mysql); //row gets a row of records in the result set, and then accesses the data in the record through the subscript. If there are multiple rows in the result set, you can get it through the while(row = mysql_fetch_row(res)){ } loop row = mysql_fetch_row(res); if (row == NULL) { //No record was found //1. Release the result set mysql_free_result(res); //1. Close the database mysql_close(&mysql); return 0; } = level_id; = 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 uses printf output, and using .c_str() can return a pointer to const char* //printf("level id: %d name: %s map row: %d map column: %d map data: %s next level: %d\n", , .c_str(), level.map_row, level.map_column, level.map_data.c_str(), level.next_level); //4. Return the result mysql_free_result(res); mysql_close(&mysql); return 1; } /********************************************* *Function: Convert the obtained level data to map array * Input: * level - level data * map - 2D map array * * Return value: * false - Conversion failed * true - Conversion was successful ***************************************/ bool transform_map_db2array(levelinfo& level, int map[][COLUMN]) { if (level.map_row > LINE || level.map_column > COLUMN) { printf("The map is too large, please reset\n"); return false; } if (level.map_data.length() < 1) { printf("The map data is incorrect, please reset it!\n"); return false; } long long start = 0, end = 0; int row = 0, column = 0; do { /********************************************* *find returns the value of size_t type, and size_t is 8 bytes in 64 bits, so here is set to start and end to long long type (there will be a "data loss" warning if it is not set). Of course, you can also simply and roughly modify the warning settings ***************************************/ end = level.map_data.find('|', start); if (end == -1) { end = level.map_data.length(); } //Legality check, end=level.map_data.length at the end, start=end+1 if (start >= end) break; string line = level.map_data.substr(start, end - start); //printf("get-line:%s\n", line.c_str()); // Analyze the row data: 0,1,0,1,1,1,1,1,1,1,1,0,0 char* next_token = NULL; //Convert line to const char* (a string in C language), strtok_s will modify the value in line to follow a specific character, so you need to convert line.c_str() to char * // The first parameter of strtok_s is the string to be split (required to be a char* type); the second parameter is split by a certain character (the comma will be changed to the ending character of "," which means that the original string will be modified, so the original const char* needs to be converted to char*); the third parameter is this interface // If necessary, it is used for positioning function. //printf("%p\n", &line[2]); char* item = strtok_s((char*)line.c_str(), ",", &next_token); column = 0; //printf("%p", next_token); //::system("pause"); //If the number of data in a certain row is unnecessary, the number of map columns is controlled to only read level.map_column-1 while (item&&column<level.map_column) { map[row][column] = atoi(item); column++; //You can write NULL when using the strtok_s interface first parameter. It should be that the next_token parameter was recorded when it was last used for positioning function. The position given by the string was recorded. item = strtok_s(NULL, ",", &next_token); } //Legality check if (column < level.map_column) { // The number of data in a row is smaller than the number of columns in this map printf("The map data parsing error, terminated!\n"); return false; } row++; // If the number of columns is unnecessary, just discard it if (row >= level.map_row) { break; } start = end + 1; } while (1 == 1); //If the number of columns is redundant, the error will be reported directly if (row < level.map_row) { printf("The map row count is less than the setting, terminate!"); return false; } return true; } /********************************************* *Function: Update user game progress information * Input: * user - User information * next_level_id - game progress * * Return value: * Get success and return true, fail false ***************************************/ bool update_user_level(userinfo& user, int next_level_id) { MYSQL mysql; //Define a handle, and access to mysql is through this handle (that is, a collection) char sql[256]; bool ret = false; //1.Connect the database if (connect_db(mysql) == false) { return false; } //2. Write SQL statement snprintf(sql, 256, "update users set level_id=%d where id=%d", next_level_id, ); ret = mysql_query(&mysql, sql); if (ret) { printf("The database update error occurred, %s error reason: %s\n", sql, mysql_error(&mysql)); // Close the database mysql_close(&mysql); return false; } user.level_id = next_level_id; mysql_close(&mysql); return true; } /********************************************* *Function: Reset user game progress information * Input: * user - User information * * Return value: * false - Reset failed * true - Reset successfully ***************************************/ bool resiting_data(userinfo& user) { MYSQL mysql; //Define a handle, and access to mysql is through this handle (that is, a collection) char sql[256]; bool ret = false; //1.Connect the database if (connect_db(mysql) == false) { return false; } //2. Write SQL statement snprintf(sql, 256, "update users set level_id=1 where id=%d", ); ret = mysql_query(&mysql, sql); //3.Judge query results if (ret) { printf("The database update error occurred, %s error reason: %s\n", sql, mysql_error(&mysql)); // Close the database mysql_close(&mysql); return false; } user.level_id = 1; //4. Close the database mysql_close(&mysql); return true; }
Push box game code
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, //wall FLOOR, //floor BOX_DES,//Box destination MAN, //The little man BOX, //box HIT, //The box hits the target MAN_DES, //People stand on the target VECTOR //Performance pictures}; enum _DIRECTION { UP, DOWN, LEFT, RIGHT }; struct _POS { int x; //The number of rows in the two-dimensional array where the villain is located int y; //The number of columns in the two-dimensional array where the villain is located};
box_man.cpp
#include<> #include<iostream> #include<> #include<string> #include<> //??? #include"box_man.h" #include"" using namespace std; int map[LINE][COLUMN] = { 0 }; POS man; IMAGE images[9]; /****************************************** * Function: Determine whether the game ends * Input: * none * Output: * true - Not ended * flase - end ***************************************/ 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; } /****************************************** * Function: Load the end game picture * Input: * none * Output: * none ***************************************/ void show_over() { cleardevice(); IMAGE game_over; loadimage(&game_over, _T(""), SCREEN_WIDTH, SCREEN_HEIGHT, true); putimage(0, 0, &game_over); } /****************************************** * Function: Change map information at the specified location Display the specified picture * Input: * next_pos - specify location * prop - specify the picture * Output: * none ***************************************/ 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]); } /****************************************** * Function: Display the specified picture at the specified location * Input: * next_pos - specify location * prop - specify the picture * Output: * none ***************************************/ void changeMap2(POS* next_pos, PROPS prop) { putimage(START_X + next_pos->y * RATIO, START_Y + next_pos->x * RATIO, &images[prop]); } /****************************************** * Function: Control the movement of the villain in the specified direction * Input: * direct - specify direction * Output: * none ***************************************/ 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; } // Macro expand next_pos.x > 0 && next_pos.x < LINE && next_pos.y>0 && next_pos.y < COLUMN // The floor is ahead of people if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR) { //The destination is under the feet of a person if (map[][] == BOX_DES) { changeMap(&next_pos, MAN); changeMap2(&man, BOX_DES); } else { changeMap(&man, FLOOR); changeMap(&next_pos, MAN); } man = next_pos; } // In front of the person is a box 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) { // The front of the box is the floor changeMap(&next_next_pos, BOX); changeMap(&next_pos, MAN); if (map[][] == 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) { // The destination is in front of the box changeMap(&next_next_pos, HIT); changeMap(&next_pos, MAN); if (map[][] == BOX_DES) { changeMap(&man, BOX_DES); } else { changeMap(&man, FLOOR); } man = next_pos; } } //The destination is ahead else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX_DES) { //The little man is also the destination if (map[][] == BOX_DES) { changeMap2(&next_pos, MAN_DES); changeMap(&man, BOX_DES); } else { changeMap(&man, FLOOR); changeMap2(&next_pos, MAN_DES); } man = next_pos; } //The box hit point ahead is else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == HIT) { if (map[next_next_pos.x][next_next_pos.y] == FLOOR) { // The front of the box is the floor changeMap(&next_next_pos, BOX); changeMap(&next_pos, BOX_DES); changeMap2(&next_pos, MAN_DES); //The destination is under the feet of a person if (map[][] == 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) { // The destination is in front of the box changeMap(&next_next_pos, HIT); changeMap(&next_pos, BOX_DES); changeMap2(&next_pos, MAN_DES); //The destination is under the feet of a person if (map[][] == BOX_DES) { changeMap(&man, BOX_DES); } else { changeMap(&man, FLOOR); } man = next_pos; } } } /****************************************** * Function: User login * Input: * user - User information * Output: * false - Login failed * true - Login successfully ***************************************/ bool login(userinfo& user) { int times = 0; bool ret = false; do { cout << "Please enter the username:"; cin >> ; cout << "Please enter your password:"; cin >> ; ret = fetch_user_info(user); times++; if (times >= MAX_RETRY_TIMES) break; if (ret == false) { cout << "Login failed, please re-enter!" << endl; } } while (!ret); return ret; } /****************************************** * Function: Load game material * Input: * none * Output: * none ***************************************/ void init_graph() { initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); loadimage(&images[WALL], _T("wall_right.bmp"), RATIO, RATIO, true); loadimage(&images[FLOOR], _T(""), RATIO, RATIO, true); loadimage(&images[BOX_DES], _T(""), RATIO, RATIO, true); loadimage(&images[MAN], _T(""), RATIO, RATIO, true); loadimage(&images[BOX], _T(""), 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(""), 6*RATIO, 6*RATIO, true); } /****************************************** * Function: Display the specified map * Input: * level - specify map * Output: * none ***************************************/ void show_images(levelinfo& level) { cleardevice(); // Clear the screen every time the picture is posted IMAGE bg_img; //The last parameter of the width and height of the picture is "whether to stretch" loadimage(&bg_img, _T(""), 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) { = i; = j; } if (map[i][j] == BG_IMAGE) continue; putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]); } } const char* str = .c_str(); setbkmode(TRANSPARENT); setfont(RATIO, 0, _T("Chinese Kaiyi")); setcolor(WHITE); outtextxy(200, 25, str); } /****************************************** * Function: Load the PNG image and remove the transparent part * Input: * none * Output: * none ***************************************/ void drawAlpha(IMAGE* picture, int picture_x, int picture_y) //x is the X coordinate of the loading picture, and y is the Y coordinate{ // Variable initialization DWORD* dst = GetImageBuffer(); // GetImageBuffer() function is used to obtain the video memory pointer of the drawing device. EASYX comes with its own DWORD* draw = GetImageBuffer(); DWORD* src = GetImageBuffer(picture); //Get picture memory pointer int picture_width = picture->getwidth(); //Get the width of the picture, EASYX comes with its own int picture_height = picture->getheight(); //Get the height of the picture, EASYX comes with its own int graphWidth = getwidth(); //Get the width of the drawing area, EASYX comes with its own int graphHeight = getheight(); //Get the height of the drawing area, EASYX comes with its own int dstX = 0; //The angle mark of pixels in the video memory // Implement transparent maps Formula: Cp=αp*FP+(1-αp)*BP, Bayes theorem to calculate the probability of point color for (int iy = 0; iy < picture_height; iy++) { for (int ix = 0; ix < picture_width; ix++) { int srcX = ix + iy * picture_width; //The angle mark of pixels in the video memory int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA is transparency int sr = ((src[srcX] & 0xff0000) >> 16); //Get R in RGB 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; //The angle mark of pixels in the video memory 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) //Formula: 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 } } } } /****************************************** * Function: Load the "Congratulations" picture * Input: * none * Output: * none ***************************************/ void promot_over() { setbkmode(TRANSPARENT); drawAlpha(&images[VECTOR], 250, 130); // Load the PNG image and remove the transparent part Sleep(1100); } /****************************************** * Function: Sleep * Input: * interval - sleep time * Output: * none ***************************************/ void wait(int interval) { int count = interval / 10; for (int i = 0; i < count; ++i) { Sleep(10); if (_kbhit()) return; } } /****************************************** * Function: Game control * Input: * level - retaining wall level data * user - User information * Output: * none ***************************************/ void game_operation(levelinfo& level, userinfo& user) { bool quit = false; do { //Judge whether there are buttons if (_kbhit()) { //Unbuffered read 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()) { //Update the user's next level level information (the user directly jumps to the next level after passing the level) update_user_level(user, level.next_level); quit=true; } } wait(100); } while (quit == false); } /****************************************** * Function: Make judgment based on the return result of "Get level data from user ID" * Input: * result - Return result (-1: Failed to obtain 0: The user has passed the level 1: Successful to obtain) * level - level data * user - User information * Output: * none ***************************************/ void judge_by_result(int result, levelinfo& level, userinfo& user) { if (result == 1) { return; } else if (result == -1) { closegraph(); cout << "Failed to get level data, please try again!" << endl; std::system("pause"); exit(-1); } else if (result == 0) { show_over(); do { //Judge whether there are buttons if (_kbhit()) { //Unbuffered read 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() { //User authentication userinfo user; levelinfo level; if (!login(user)) { cout << "Login failed, please log in again!" << endl; ::system("pause"); exit(-1); } init_graph(); //Loop (read the level → user operation) do { //Load level data based on user information int result = fetch_level_info(level, user.level_id); judge_by_result(result, level, user); //Convert level data to map game map transform_map_db2array(level, map); //Load game pictures show_images(level); //The little man moves game_operation(level, user); //Congratulations on passing the promot_over(); } while (1); std::system("pause"); closegraph(); return 0; }
This is the article about C language + MySQL box push game that introduces this. For more related C languages, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!