项目实战——推箱子小游戏(引入数据库)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 项目实战——推箱子小游戏(引入数据库)

数据库表设计

用户表


表名

Users

字段名

类型

是否为空

默认值

主、外键

备注

id

int(11)

NOT

1,自增长

PK

用户id

username

varchar(64)

NOT

用户名:英文字符、数字和特殊符号的组合


password

varchar(32)

NOT

密码:英文字符、数字和特殊符号的组合,8-16位

level_id

int

1

当前关卡,关联Levels表中的id


关卡表


表名

Levels

字段名

类型

是否为空

默认值

主、外键

备注


id

int

NOT

1

PK

游戏关卡序号,从1开始

name

varchar(64)

NOT

地图名称


map_row

int

NOT

地图二位组的总行数

map_column

int

NOT

地图二维组的总列数

mysql>  create database box_man;   #创建数据库box_man                                                                                                                      


mysql>                                                                                    


mysql>  create table users(          #创建用户表                                                              


            id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,                            


            username varchar(64) NOT NULL UNIQUE,                                                


            password varchar(32) NOT NULL ,                                                


            level_id int  default 1                                                            


        );                                                                                  


mysql>  create table levels(         #创建关卡表                                                        


            id int NOT NULL PRIMARY KEY default 1,                                                


            name varchar(64) NOT NULL UNIQUE,                                                  


            map_row int  NOT NULL,                                                              


            map_column   int NOT NULL,                                                          


            map_data     varchar(4096) NOT NULL,                                      


            next_level_id  int default 0                                                    


        );                                                                                  


mysql>   insert into users values(1000, 'martin', md5('123456qweQWE'), 1);                    


mysql>   insert into levels values(1, '牛刀小试', 9, 12,                                            


'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',0);        

代码优化

登录认证

database.cpp

#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  "123456qweQWE"


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, level_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  level_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;


}

database.h

#pragma once


#include <string>


using namespace std;


//用户信息


typedef struct _userinfo{


   int id;            //用户id


   string username;   //用户名


   string passwd;     //密码


   int level_id;      //关卡id


}userinfo;


bool fetch_user_info(userinfo &user);

boxman.cpp

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;


}

获取关卡

//database.h


typedef struct _levelinfo {


   int id;            //关卡的id


   string name;       //关卡的名字


   int map_row;       //地图总行数


   int map_column;    //地图总列数


   string  map_data;  //二维地图数据


   int next_level;    //下一关卡的id


}levelinfo;


bool fetch_level_info(levelinfo &level, int level_id);


//database.cpp


/***************************************************


*功能:根据关卡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) {


       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;


}

地图适配

//database.h


bool transform_map_db2array(levelinfo &level, int map[LINE][COLUMN]);


//database.cpp


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;


}


//boxman.cpp


//把数据库中的地图数据转换到map 中


 ret = transform_map_db2array(level, map);

下一关跳转

//database.h


bool update_user_level(userinfo& user, int next_level_id);


//database.cpp


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) {


       printf("数据库更新出错,%s 错误原因: %s\n", sql, mysql_error(&mysql));


       mysql_close(&mysql);


       return false;


   }


   //关闭数据库


   mysql_close(&mysql);


   return true;


}


//boxman.cpp


//...............前面省略N行代码....................


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);


   ::system("pause");


   cleardevice();


}


//...............中间省略N行代码....................


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;


   //quit = true;


}

以下是完整代码实现:

box_man.h

#pragma once
#include <graphics.h>
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
#define START_X 100   //x轴偏移
#define START_Y 150   //y轴偏移
#define WEIGHT 960    //舞台长
#define HEIGHT 768    //舞台宽
#define RATIO 61
#define isValid(pos) pos.x>=0 && pos.x<MAP_X && pos.y>=0 && pos.y<MAP_Y   //判断小人在地图行走后是否有效
#define MAX_REIRY_TIMES 4
#define MAP_X   48    
#define MAP_Y 12
enum _RES
{
  WALL,
  FLOOR,
  BOX_DES,
  MAN,
  BOX,
  HIT,
  ALL
};
enum _DIRECT
{
  UP,
  DOWN,
  LEFT,
  RIGHT
};
struct _POS   //小人坐标
{
  int x;
  int y;
};

box_man.cpp

#include <iostream>
#include <Windows.h>
#include <string>
#include <conio.h>
#include "box_man.h"
#include "database.h"
using namespace std;
int map[MAP_X][MAP_Y] = { 0 };
int hold = 0;
IMAGE pic[ALL];   //资源图片
bool fetch_user_info(userinfo& user);
bool fetch_level_info(levelinfo& level, int level_id);
bool transform_map_dbtoarry(levelinfo& level, int map[MAP_X][MAP_Y]);
bool update_user_level(userinfo& user, int next_level_id);
void changeMap(struct _POS* pos, enum _RES prop)
{
  map[pos->x][pos->y] = prop;
  putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &pic[prop]);
}
struct _POS man;
bool isGameOver()
{
  int i, j;
  if (hold == 1)
  {
    return false;
  }
  for (i = 0; i < MAP_X; i++)
  {
    for (j = 0; j < MAP_Y; j++)
    {
      if (map[i][j] == BOX_DES)
      {
        return false;
      }
    }
  }
  return true;
}
void gameOverScene(IMAGE* bg)
{
  putimage(0, 0, bg);
  settextcolor(WHITE);
  RECT rec = { 0,0,WEIGHT,HEIGHT };
  settextstyle(20, 0, _T("宋体"));
  drawtext(_T("恭喜您~\n通关了!再见"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void gameNextScene(IMAGE* bg)
{
  putimage(0, 0, bg);
  settextcolor(WHITE);
  RECT rec = { 0,0,WEIGHT,HEIGHT };
  settextstyle(20, 0, _T("宋体"));
  drawtext(_T("恭喜您~\n此关挑战成功,任意键跳转到下一关!"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  ::system("pause");
  cleardevice();
}
void gameCotrol(enum _DIRECT direct)
{
  struct _POS next_pos = man;
  struct _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;
  }
  if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR)  //小人前是地板
  {
    if (hold == 0)
    {
      changeMap(&next_pos, MAN);
      changeMap(&man, FLOOR);
      man = next_pos;
    }
    else
    {
      changeMap(&next_pos, MAN);
      changeMap(&man, BOX_DES);
      man = next_pos;
      hold = 0;
    }
  }
  else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX_DES) //小人前是箱子目的地
  {
    changeMap(&next_pos, MAN);
    changeMap(&man, FLOOR);
    man = next_pos;
    hold = 1;
  }
  else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX)   //小人前是箱子
  {
    if (isValid(next_next_pos) && 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;
    }
    else if (isValid(next_next_pos) && map[next_next_pos.x][next_next_pos.y] == FLOOR)    //箱子前面是地板
    {
      if (hold == 1)
      {
        changeMap(&next_next_pos, BOX);
        changeMap(&next_pos, MAN);
        changeMap(&man, BOX_DES);
        man = next_pos;
        hold = 0;
      }
      else
      {
        changeMap(&next_next_pos, BOX);
        changeMap(&next_pos, MAN);
        changeMap(&man, FLOOR);
        man = next_pos;
      }
    }
  }
  else if (isValid(next_next_pos) && map[next_pos.x][next_pos.y] == HIT)    //小人前方箱子和目的地重合
  {
    changeMap(&next_next_pos, BOX);
    changeMap(&next_pos, MAN);
    changeMap(&man, FLOOR);
    man = next_pos;
    hold = 1;
  }
}
bool login(userinfo& user)
{
  int times = 0; //登录次数
  int ret = false;
  do
  {
    cout << "请输入用户名:";
    cin >> user.username;
    cout << "请输入登录密码:";
    cin >> user.passwd;
    if (times > MAX_REIRY_TIMES)
    {
      cout << "输入用户名或密码错误过多!" << endl;
      return false;
    }
    ret = fetch_user_info(user);
  } while (ret == false);
  return ret;
}
void init_game_graph(IMAGE &bg_img)
{
  initgraph(WEIGHT, HEIGHT);
  loadimage(&bg_img, L"blackground.bmp", WEIGHT, HEIGHT, true);
  putimage(0, 0, &bg_img);
  loadimage(&pic[WALL], L"wall_right.bmp", RATIO, RATIO, true);
  loadimage(&pic[FLOOR], L"floor.bmp", RATIO, RATIO, true);
  loadimage(&pic[BOX_DES], L"des.bmp", RATIO, RATIO, true);
  loadimage(&pic[MAN], L"man.bmp", RATIO, RATIO, true);
  loadimage(&pic[BOX], L"box.bmp", RATIO, RATIO, true);
  loadimage(&pic[HIT], L"box.bmp", RATIO, RATIO, true);
}
int main(void)
{
  userinfo user;
  levelinfo level;
  bool ret = false;
  IMAGE bg_img;
  if (!login(user))
  {
    cout << "登录失败" << endl;
  }
  else
  {
    cout << "登录成功!请开始你的表演" << endl;
  }
  //初始化游戏舞台
  init_game_graph(bg_img);
  ::system("pause");
  bool quit = false;
  do
  {
    hold = 0; //每次到新的一关人物肯定不在目的地
    //根据用户所在的关卡id获取关卡数据
    ret = fetch_level_info(level, user.level_id);
    if (!ret)
    {
      cout << "获取关卡数据失败,请重试!" << endl;
      ::system("pause");
      exit(-1);
    }
    else
    {
      cout << "登录成功,用户id:" << user.id << ",您所在的关卡是:" << user.level_id << ",请开始您的表演!" << endl;
    }
    //把数据库中的地图数据转换到map中
    ret = transform_map_dbtoarry(level, map);
    if (!ret)
    {
      cout << "转换地图失败,请重试!" << endl;
      ::system("pause");
      exit(-1);
    }
    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, &pic[map[i][j]]);
      }
    }
    do
    {
      if (_kbhit())
      {
        char ch = _getch();
        if (ch == KEY_UP)
        {
          gameCotrol(UP);
        }
        else if (ch == KEY_DOWN)
        {
          gameCotrol(DOWN);
        }
        else if (ch == KEY_LEFT)
        {
          gameCotrol(LEFT);
        }
        else if (ch == KEY_RIGHT)
        {
          gameCotrol(RIGHT);
        }
        else if (ch == KEY_QUIT)
        {
          quit = false;
        }
        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;
            putimage(0, 0, &bg_img); //显示图片
          }
          break;
        }
      }
      Sleep(100);
    } while (!quit);
  } while (quit == false);
  ::system("pause");
  closegraph();
  return 0;
}

database.cpp

#include <mysql.h>
#include <stdio.h>
#include "database.h"
using namespace std;
#define DB_NAME "box_man"
#define DB_HOST "127.0.0.1"
#define DB_POST 3306
#define DB_USER "root"
#define DB_USER_PASSWD "rfly"
//static bool connect_db(MYSQL& mysql);
bool connect_db(MYSQL& mysql)
{
  mysql_init(&mysql);
  mysql_options(&mysql,MYSQL_SET_CHARSET_NAME,"gbk");
  if (mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_USER_PASSWD, DB_NAME, DB_POST, NULL, 0) == NULL)
  {
    printf("数据库连接失败,错误原因:%s\n", mysql_error(&mysql));
    return false;
  }
  return true;
}
/****************************
*功能:通过用户名和密码获取用户信息
*输入:
*   user - 用户信息结构体
* 
* 返回值:
*   获取成功返回true
*   获取失败返回false
*****************************/
bool fetch_user_info(userinfo& user)
{
  MYSQL mysql;
  MYSQL_RES* res; //查询结果集
  MYSQL_ROW row;  //查询记录行
  char a[256];      //用来保存字符串查询语句
  int ret = false;
  //1.连接数据库
  if (connect_db(mysql) == false) 
  {
    cout << "数据库连接失败" << endl;
    return false;
  }
  snprintf(a, 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, a); //等于0,表示查询成功
  if (ret)
  {
    printf("数据库查询出错,%s 错误原因:%s\n", a, mysql_error(&mysql));
    mysql_close(&mysql);
    return false;
  }
  res = mysql_store_result(&mysql);
  row = mysql_fetch_row(res);
  if (row == NULL)
  {
    cout <<"查询到空数据,失败!" << endl;
    mysql_free_result(res);
    mysql_close(&mysql);
    return false;
  }
  user.id = atoi(row[0]);
  user.level_id = atoi(row[1]);
  cout << "用户名id:" << user.id << "\t" << "用户关卡:" << user.level_id;
  mysql_free_result(res);
  mysql_close(&mysql);
  return true;
}
bool fetch_level_info(levelinfo& level, int level_id)
{
  MYSQL mysql;
  MYSQL_RES* res; //查询结果集
  MYSQL_ROW row;  //查询记录行
  char sql[256];
  bool ret = false;
  if (connect_db(mysql) == false)
  {
    cout << "数据库连接失败" << endl;
    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);
  if (ret)
  {
    printf("数据库查询出错,%s 错误原因:%s\n", sql, mysql_error(&mysql));
    mysql_close(&mysql);
    return false;
  }
  res = mysql_store_result(&mysql);
  row = mysql_fetch_row(res);
  if (row == NULL)
  {
    cout << "查询到空数据,失败!" << endl;
    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]);
  mysql_free_result(res);
  mysql_close(&mysql);
  return true;
}
bool transform_map_dbtoarry(levelinfo& level, int map[MAP_X][MAP_Y])
{
  //1.合法性检查
  if (level.map_row > MAP_X || level.map_column > MAP_Y)
  {
    cout << "给定的地图太大!" << endl;
    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);
    //find找到最后一行,没有'|'返回-1
    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);
  if (row < level.map_row)
  {
    printf("地图行数少于设定,%d(need:%d),终止!\n", row, level.map_row);
    return false;
  }
  return true;
}
/******************************
* 功能:更新用户的关卡id
* 输入:user -将下一关的id赋值给user
* 
*   next_level_id 下一关id
*******************************/
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)
  {
    printf("数据库更新出错,%s 错误原因:%s\n", sql, mysql_error(&mysql));
    mysql_close(&mysql);
    return false;
  }
  return true;
}

database.h

#pragma once 
#include <string>
#include "box_man.h"
#include <iostream>
using namespace std;
typedef struct _userinfo
{
  int id;
  string username;
  string passwd;
  int level_id;
}userinfo;
typedef struct _levelinfo
{
  int id; //关卡的id
  string name; //关卡的名字
  int map_row; //地图的总行数
  int map_column; //地图的总列数
  string map_data; //二维地图的数据
  int next_level; //下一关卡的id
}levelinfo;


相关文章
|
8天前
|
存储 SQL 关系型数据库
数据库mysql项目实战(二)
数据库mysql项目实战(二)
|
8天前
|
存储 SQL 关系型数据库
数据库mysql项目实战 一
数据库mysql项目实战 一
|
8月前
|
前端开发 JavaScript 数据库
uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管
uniapp项目实战系列(1):导入数据库,启动后端服务,开启代码托管
264 2
|
10月前
|
关系型数据库 MySQL 数据库
项目实战12—数据库数据类型不一致导致查询慢
项目实战12—数据库数据类型不一致导致查询慢
66 0
|
10月前
|
JSON 关系型数据库 MySQL
Spring Boot + vue-element 开发个人博客项目实战教程(四、数据库搭建和配置)
Spring Boot + vue-element 开发个人博客项目实战教程(四、数据库搭建和配置)
87 0
|
10月前
|
NoSQL Oracle 安全
|
存储 缓存 数据库
如何在小游戏制作工具中使用云数据库持久保存用户的数据
前言 这可能是你能从网上找到的唯一一篇在微信小游戏制作工具中使用云数据库的教程了。通过这篇教程你将能学会如何在小游戏制作工具中使用云数据库添加,更新和查询玩家的数据。使用云数据库保存玩家数据的好处是,当你每次更新小游戏时,玩家都能够获取到之前保存的游戏数据,继续进行游戏。
277 0
|
存储 JSON 缓存
彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-模板与数据库EP02
书接上回,上次我们搭建好了项目入口文件,同时配置了路由体系,接着就可以配置项目的模板了,这里我们采用Iris内置的模板引擎,事实上,采用模板引擎并不意味着前后端耦合,模板中的数据保持其独立性即可,也就是说模板的数据操作交互方式采用http接口请求的形式,Iris并不参与模板逻辑,只返回Json格式的数据即可。前端集成数据双向绑定机制的框架Vue.js。
彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-模板与数据库EP02
|
数据库 Python
Flask学习与项目实战5:通过SQLAlchemy连接数据库进行ORM模型的简单增删改查
是对于数据库的ORM的框架,直接操作模型,安装命令为pip install SQLAlchemy。 SQLAlchemy是一个独立的ORMR框架,可以独立于FLASK存在,也可以在Django中使用。 Flask-SQLAlchemy是对SQLAlchemy的一个封装,更适合在flask使用。
Flask学习与项目实战5:通过SQLAlchemy连接数据库进行ORM模型的简单增删改查
|
6天前
|
关系型数据库 MySQL API
实时计算 Flink版产品使用合集之可以通过mysql-cdc动态监听MySQL数据库的数据变动吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
82 0