推箱子游戏
运行之后的效果如视频所示,在完成游戏后播放音乐
准备工作:建立一个新的文件夹,并在文件夹中任意增加一张背景图片,以及各个部件的照片文件
因为这里用到了贴图技术,要使用graphic.h这个函数,不安装的话是不能在vs里面显示图案的,所以要安装Easy x 这个图形库,下载地址[http://www.easyx.cn/downloads/]
具体下载安装见我的博客这一篇:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/134126314https://mp.csdn.net/mp_blog/creation/editor/134126314
图中用到的资源图形是(借用下面博主的图形音乐资源,代码并不相同,整体代码更好维护):
c/c++推箱子游戏开发基础入门(附全部源码)_堆箱子c++完整代码-CSDN博客
文件的全部代码在最下面:
1.地图初始化----背景色
#define _CRT_SECURE_NO_WARNINGS
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
int main()
{
IMAGE bg_img;//设置图片变量
initgraph(960,768);//设置终端窗口大小
loadimage(&bg_img, _T("bakeground.bmp"), 960, 768, true);//将背景图片赋值到图片变量
putimage(0, 0, &bg_img);//将背景图片刷到终端窗口
system("pause");
return 0;
}
2.初始化界面:
#define _CRT_SECURE_NO_WARNINGS
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;
//定义图片数据
IMAGE images[6];
//游戏地图
int map[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},
};
int main()
{
IMAGE bg_img;//设置图片变量
//搭台唱戏
initgraph(960, 768);//设置终端窗口大小
loadimage(&bg_img, _T("bakeground.bmp"), 960, 768, true);//将背景图片赋值到图片变量
putimage(0, 0, &bg_img);//将背景图片刷到终端窗口
//加载道具图标
loadimage(&images[0], _T("7.bmp"), 61, 61, TRUE);
loadimage(&images[1], _T("0.bmp"), 61, 61, TRUE);
loadimage(&images[2], _T("3.bmp"), 61, 61, TRUE);
loadimage(&images[3], _T("5.bmp"), 61, 61, TRUE);
loadimage(&images[4], _T("4.bmp"), 61, 61, TRUE);
loadimage(&images[0], _T("1.bmp"), 61, 61, TRUE);
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 12; j++)
{
putimage(125+j*61, 120+i*61, &images[map[i][j]]);
}
}
system("pause");
return 0;
}
3.小人移动控制
#define _CRT_SECURE_NO_WARNINGS
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#define RATIO 61 //宏定义
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
#define LINE 9
#define COLUMN 12
#define START_X 125
#define START_Y 120
//控制键 上下左右控制方向,'q'退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
#define isVaile(pos) pos.x>=0&&pos.x<LINE&&pos.y>=0&&pos.y<COLUMN
using namespace std;
//定义道具类型(用枚举类型使用),增加文章可读性
//WALL墙0,FLOOR地板1,BOX_DES目的地2,MAN人3,BOX篮球4,JI篮球命中目标5
enum _PROSE {
WALL,
FLOOR,
BOX_DES,
MAN,
BOX,
JI,
ALL
};
//游戏控制方向
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT
};
//游戏地图 ,可以直接由上面的枚举类型的数值进行替换,这里不做替换
int map[LINE][COLUMN] = {
{WALL,0,0,0,0,0,0,0,0,0,0,0},
{0,FLOOR,0,1,1,1,1,1,1,1,0,0},
{0,1,4,1,0,BOX_DES,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,MAN,1,1,1,4,1,0},
{0,1,2,1,1,BOX,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},
};
//定义图片数据
IMAGE images[ALL];
//存储小人位置
struct _POS {
int x;//小人所在的二维数组的行
int y;//小人所在的二维数组的列
};
struct _POS man;
/*******************************
*改变游戏地图视图中一格对应道具并重新显示
* 输入:
* line---道具在地图数组的行下标
* column---道具在地图数组的列下标
* prop----道具的类型
* 返回值:无
************************************/
void changeMap(struct _POS *pos, enum _PROSE prop) {
map[pos->x][pos->y] = prop;//将此时小人的道具改变
putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &images[prop]);
}
/****************************************
*实现游戏四个方向(上下左右)的控制
* 输入:
* direct---人前进的方向
* 输出:无
********************************************/
void gameControl(enum _DIRECTION direct) {
struct _POS next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
break;
case DOWN:
next_pos.x++;
break;
case LEFT:
next_pos.y--;
break;
case RIGHT:
next_pos.y++;
break;
}
//宏展开isVaile
if (isVaile(next_pos)&& map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(&next_pos, MAN);//小人前进一格
changeMap(&man , FLOOR);
man = next_pos;
}
}
int main()
{
IMAGE bg_img;//设置图片变量
//搭台唱戏
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);//设置终端窗口大小
loadimage(&bg_img, _T("bakeground.bmp"), 960, 768, true);//将背景图片赋值到图片变量
putimage(0, 0, &bg_img);//将背景图片刷到终端窗口
//加载道具图标
loadimage(&images[WALL], _T("WALL.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[JI], _T("JI.bmp"), RATIO, RATIO, TRUE);
//初始化表盘
for (int i = 0; i < LINE; i++)
{
for (int j = 0; j < 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]]);
}
}
//游戏环节
bool quit = false;
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;
}
}
Sleep(100);//0.1s
} while (quit==false);//!quit
system("pause");
return 0;
}
4.功能实现
#define _CRT_SECURE_NO_WARNINGS
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#define RATIO 61 //宏定义
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
#define LINE 9
#define COLUMN 12
#define START_X 125
#define START_Y 120
//控制键 上下左右控制方向,'q'退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
#define isVaile(pos) pos.x>=0&&pos.x<LINE&&pos.y>=0&&pos.y<COLUMN
using namespace std;
//定义道具类型(用枚举类型使用),增加文章可读性
//WALL墙0,FLOOR地板1,BOX_DES目的地2,MAN人3,BOX篮球4,JI篮球命中目标5
enum _PROSE {
WALL,
FLOOR,
BOX_DES,
MAN,
BOX,
JI,
ALL
};
//游戏控制方向
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT
};
//游戏地图 ,可以直接由上面的枚举类型的数值进行替换,这里不做替换
int map[LINE][COLUMN] = {
{WALL,0,0,0,0,0,0,0,0,0,0,0},
{0,FLOOR,0,1,1,1,1,1,1,1,0,0},
{0,1,4,1,0,BOX_DES,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,MAN,1,1,1,4,1,0},
{0,1,2,1,1,BOX,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},
};
//定义图片数据
IMAGE images[ALL];
//存储小人位置
struct _POS {
int x;//小人所在的二维数组的行
int y;//小人所在的二维数组的列
};
struct _POS man;
/*******************************
*改变游戏地图视图中一格对应道具并重新显示
* 输入:
* line---道具在地图数组的行下标
* column---道具在地图数组的列下标
* prop----道具的类型
* 返回值:无
************************************/
void changeMap(struct _POS *pos, enum _PROSE prop) {
map[pos->x][pos->y] = prop;//将此时小人的道具改变
putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &images[prop]);
}
/****************************************
*实现游戏四个方向(上下左右)的控制
* 输入:
* direct---人前进的方向
* 输出:无
********************************************/
void gameControl(enum _DIRECTION 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 (isVaile(next_pos)&& map[next_pos.x][next_pos.y] == FLOOR) {//宏展开isVaile,人的前方是地板
changeMap(&next_pos, MAN);//小人前进一格
changeMap(&man , FLOOR);
man = next_pos;
}
else if (isVaile(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, JI);
changeMap(&next_pos, MAN);//小人前进一格
changeMap(&man, FLOOR);
man = next_pos;
}
}
}
int main()
{
IMAGE bg_img;//设置图片变量
//搭台唱戏
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);//设置终端窗口大小
loadimage(&bg_img, _T("bakeground.bmp"), 960, 768, true);//将背景图片赋值到图片变量
putimage(0, 0, &bg_img);//将背景图片刷到终端窗口
//加载道具图标
loadimage(&images[WALL], _T("WALL.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[JI], _T("JI.bmp"), RATIO, RATIO, TRUE);
//初始化表盘
for (int i = 0; i < LINE; i++)
{
for (int j = 0; j < 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]]);
}
}
//游戏环节
bool quit = false;
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;
}
}
Sleep(100);//0.1s
} while (quit==false);//!quit
//游戏结束,释放资源
closegraph();
system("pause");
return 0;
}
5.游戏结束
/****************************************
*判断游戏是否结束,如果所有篮球目的地都不存在,则表示游戏结束
* 输入:无
* 输出: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 gameOver(IMAGE* bg_img) {
putimage(0, 0, bg_img);
settextcolor(WHITE);//设置文本颜色为白色
RECT rec = { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };//设置一个矩形
settextstyle(20,0,_T("宋体"));//设置字体的位置
drawtext(_T("游戏成功,基尼太美~~~~"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//设置文字字体位置
}
6.优化头文件
7.成功后添加音乐
全部代码文件:
库文件:box_man.h
#pragma once
#define RATIO 61 //宏定义
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
#define LINE 9
#define COLUMN 12
#define START_X 125
#define START_Y 120
//控制键 上下左右控制方向,'q'退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
#define isVaile(pos) pos.x>=0&&pos.x<LINE&&pos.y>=0&&pos.y<COLUMN
//类型定义
typedef enum _DIRECTION DIRECTION;
typedef enum _PROSE PROSE;
typedef struct _POS POS;
//定义道具类型(用枚举类型使用),增加文章可读性
//WALL墙0,FLOOR地板1,BOX_DES目的地2,MAN人3,BOX篮球4,JI篮球命中目标5
enum _PROSE {
WALL,
FLOOR,
BOX_DES,
MAN,
BOX,
JI,
ALL
};
//游戏控制方向
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT
};
//存储小人位置
struct _POS {
int x;//小人所在的二维数组的行
int y;//小人所在的二维数组的列
};
运行程序:box_man.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<graphics.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<conio.h>
#include<MMSystem.h>//播放音乐所需要的头文件
#pragma comment(lib,"winmm.lib")//告诉编译器,加载winmm.lib库文件
#include"box_man.h"
//#define RATIO 61 //宏定义
//#define SCREEN_WIDTH 960
//#define SCREEN_HEIGHT 768
//#define LINE 9
//#define COLUMN 12
//#define START_X 125
//#define START_Y 120
//
控制键 上下左右控制方向,'q'退出
//#define KEY_UP 'w'
//#define KEY_LEFT 'a'
//#define KEY_RIGHT 'd'
//#define KEY_DOWN 's'
//#define KEY_QUIT 'q'
//
//#define isVaile(pos) pos.x>=0&&pos.x<LINE&&pos.y>=0&&pos.y<COLUMN
using namespace std;
类型定义
//typedef enum _DIRECTION DIRECTION;
//typedef enum _PROSE PROSE;
//typedef struct _POS POS;
//
定义道具类型(用枚举类型使用),增加文章可读性
WALL墙0,FLOOR地板1,BOX_DES目的地2,MAN人3,BOX篮球4,JI篮球命中目标5
//enum _PROSE {
// WALL,
// FLOOR,
// BOX_DES,
// MAN,
// BOX,
// JI,
// ALL
//};
//
游戏控制方向
//enum _DIRECTION
//{
// UP,
// DOWN,
// LEFT,
// RIGHT
//};
//游戏地图 ,可以直接由上面的枚举类型的数值进行替换,这里不做替换
int map[LINE][COLUMN] = {
{WALL,0,0,0,0,0,0,0,0,0,0,0},
{0,FLOOR,0,1,1,1,1,1,1,1,0,0},
{0,1,4,1,0,BOX_DES,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,MAN,1,1,1,4,1,0},
{0,1,2,1,1,BOX,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},
};
//定义图片数据
IMAGE images[ALL];
存储小人位置
//struct _POS {
// int x;//小人所在的二维数组的行
// int y;//小人所在的二维数组的列
//
//};
POS man;
/*******************************
*改变游戏地图视图中一格对应道具并重新显示
* 输入:
* line---道具在地图数组的行下标
* column---道具在地图数组的列下标
* prop----道具的类型
* 返回值:无
************************************/
void changeMap(POS *pos, PROSE 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;
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 (isVaile(next_pos)&& map[next_pos.x][next_pos.y] == FLOOR) {//宏展开isVaile,人的前方是地板
changeMap(&next_pos, MAN);//小人前进一格
changeMap(&man , FLOOR);
man = next_pos;
}
else if (isVaile(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, JI);
changeMap(&next_pos, MAN);//小人前进一格
changeMap(&man, FLOOR);
man = next_pos;
}
}
}
/****************************************
*判断游戏是否结束,如果所有篮球目的地都不存在,则表示游戏结束
* 输入:无
* 输出: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 gameOver(IMAGE* bg_img) {
putimage(0, 0, bg_img);
settextcolor(WHITE);//设置文本颜色为白色
RECT rec = { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };//设置一个矩形
settextstyle(20,0,_T("宋体"));//设置字体的位置
drawtext(_T("游戏成功,基尼太美~~~~"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);//设置文字字体位置
//重复播放基尼太美
mciSendString(_T("play 1.mp3 repeat"), 0, 0, 0);//播放音乐
}
int main()
{
IMAGE bg_img;//设置图片变量
//搭台唱戏
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);//设置终端窗口大小
loadimage(&bg_img, _T("bakeground.bmp"), 960, 768, true);//将背景图片赋值到图片变量
putimage(0, 0, &bg_img);//将背景图片刷到终端窗口
//加载道具图标
loadimage(&images[WALL], _T("WALL.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[JI], _T("JI.bmp"), RATIO, RATIO, TRUE);
//初始化表盘
for (int i = 0; i < LINE; i++)
{
for (int j = 0; j < 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]]);
}
}
//游戏环节
bool quit = false;
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()) {
gameOver(&bg_img);
quit = true;
}
}
Sleep(100);//0.1s
} while (quit==false);//!quit
system("pause");
//游戏结束,释放资源
closegraph();
return 0;
}