目录
项目分析
墙:0,地板:1,箱子目的地:2,小人:3,箱子:4,箱子命中目标:5
地图初始化
背景图片
#include <iostream>
#include <graphics.h>
#include <MMsystem.h>
#include <Windows.h>
using namespace std;
IMAGE BG_IMAGE;
#define WIDE 650
#define HEITH 650
//设置窗口初始化,背景
void initGraph() {
initgraph(WIDE, HEITH);
loadimage(&BG_IMAGE, "推箱子图片素材/blackground.bmp", WIDE, HEITH,true);//设置图片为窗口大小
putimage(0, 0, &BG_IMAGE);
}
int main(void) {
initGraph();
system("pause");//设置初始化的屏幕不一闪而逝
return 0;
}
游戏场景图片:
#define MAP_WIDE 50 //方块宽
#define MAP_HEIGTH 50 //方块高
#define MAP_ROWS 9 //数组行数
#define MAP_COLS 12 //数组列数
#define RADIO 50 //每行乘这个比例就加载一个图片
#define MAP_X 100 //图片开始地方偏移量x
#define MAP_Y 100 //图片开始地方偏移量y
enum MyEnum{
wall, //墙
Floor, //地板
des, //目的地
man, //小人
box, //箱子
hit, //命中
all //用来表示图片数组的大小
};
IMAGE MAP_IMAGE[all];//场景图片
void map() {
int a[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,地板:1,箱子目的地:2,小人:3,箱子:4,箱子命中目标:5
loadimage(&MAP_IMAGE[wall], "推箱子图片素材/wall_right.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[Floor], "推箱子图片素材/floor.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[des], "推箱子图片素材/des.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[man], "推箱子图片素材/man.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[box], "推箱子图片素材/box.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[hit], "推箱子图片素材/box.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
for (int i = 0; i < MAP_ROWS; i++){
for (int j = 0; j < MAP_COLS; j++) {
putimage( MAP_X + j*RADIO, MAP_Y + i*RADIO, &MAP_IMAGE[a[i][j]]);
}
}
}
热键控制
按键设置
但是一直执行循环块很占用CPU,消耗很大很严重资源(使用sleep(),在用户没有按键的时候,CPU休息)
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'r'
#define KEY_QUIT 'q'
#include <conio.h>
void control() {
bool quit = false;
do
{
if (_kbhit()) {//判断用户是否按键
char ch = _getch();//直接从键盘获取字符,不经过输入缓冲区
if (ch == KEY_UP) {
//get_control(KEY_UP);
}
else if (ch == KEY_DOWN) {
//get_control(KEY_DOWN);
}
else if (ch == KEY_LEFT) {
//get_control(KEY_LEFT);
}
else if (ch == KEY_RIGHT) {
//get_control(KEY_RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
}
Sleep(50);//在用户没有按键的时候,CPU休息)
} while (quit ==false);
}
确定人物位置
//实现人物行动
enum MyEnum1 {
UP,
DOWN,
RIGHT,
LEFT
};
struct position {
int x;
int y;
};
typedef enum MyEnum1 keybord;
typedef struct position pos;
pos MAN;
void get_control(keybord control) {
pos next_pos, next_next_pos;
switch (control) {
case UP:
next_pos.x = MAN.x - 1;
next_next_pos.x = MAN.x - 2;
break;
case DOWN:
next_pos.x = MAN.x + 1;
next_next_pos.x = MAN.x + 2;
break;
case LEFT:
next_pos.y = MAN.y - 1;
next_next_pos.y = MAN.y - 2;
break;
case RIGHT:
next_pos.y = MAN.y + 1;
next_next_pos.y = MAN.y + 2;
break;
}
}
//void map()函数内需要添加
/*
if (a[i][j] == man) {//记录小人的初始位置
MAN.x = i;
MAN.y = j;
}
*/
实现人物移动(非箱子,目的地)
//实现小人移动
void mapChange(pos* pos, enum MyEnum prop) {
a[pos->x][pos->y] = prop;
putimage(MAP_X + pos->y * RADIO, MAP_Y + pos->x * RADIO, &MAP_IMAGE[prop]);
}
//在void get_control(keybord control)
/*
//小人前面如果是地板,人就前进一步,站到next_pos的位置
if (a[next_pos.x][next_pos.y] == Floor) {
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
}
*/
推箱子控制
//人前进一步是箱子则判断箱子前的道具,即next_next_pos,如果是地板和箱子目的地,推着箱子走
if (a[next_pos.x][next_pos.y] == box) {
//下下个是地板
if (a[next_next_pos.x][next_next_pos.y] == Floor) {
mapChange(&next_next_pos, box);
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
//下下个是目的地
}else if (a[next_next_pos.x][next_next_pos.y] == des) {
mapChange(&next_next_pos, hit);
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
}
}
游戏结束
bool gameOver() {
for (int i = 0; i < MAP_ROWS; i++) {
for (int j = 0; j < MAP_COLS; j++) {
if (a[i][j]==des) {
return false;
}
}
}
return true;
}
void gameOverScien() {
putimage(0, 0, &BG_IMAGE);
settextcolor(RGB(255, 255, 0));
settextstyle(90, 0, "微软雅黑");//这里可能会有字符集的问题,上上篇发过解决方法
rectangle(300, 297, 570, 300);//设置矩形框
outtextxy(300, 300, "游戏结束");;//添加文字
}
最终代码
#include <iostream>
#include <graphics.h>
#include <MMsystem.h>
#include <Windows.h>
#include <conio.h>
using namespace std;
IMAGE BG_IMAGE;
#define WIDE 800
#define HEITH 650
//按键
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
//end按键
//实现人物行动
enum MyEnum1 {
UP,
DOWN,
RIGHT,
LEFT
};
struct position {
int x;
int y;
};
typedef enum MyEnum1 keybord;
typedef struct position pos;
pos MAN;
//end 人物移动
int a[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},
};
//道具
#define MAP_WIDE 50 //方块宽
#define MAP_HEIGTH 50 //方块高
#define MAP_ROWS 9 //数组行数
#define MAP_COLS 12 //数组列数
#define RADIO 50 //每行乘这个比例就加载一个图片
#define MAP_X 100 //图片开始地方偏移量x
#define MAP_Y 100 //图片开始地方偏移量y
enum MyEnum {
wall, //墙
Floor, //地板
des, //目的地
man, //小人
box, //箱子
hit, //命中
all //用来表示图片数组的大小
};
IMAGE MAP_IMAGE[all];//场景图片
//end 道具
//设置窗口初始化,背景
void initGraph() {
initgraph(WIDE, HEITH);
loadimage(&BG_IMAGE, "推箱子图片素材/blackground.bmp", WIDE, HEITH, true);//设置图片为窗口大小
putimage(0, 0, &BG_IMAGE);
}
void map() {
//墙:0,地板:1,箱子目的地:2,小人:3,箱子:4,箱子命中目标:5
loadimage(&MAP_IMAGE[wall], "推箱子图片素材/wall_right.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[Floor], "推箱子图片素材/floor.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[des], "推箱子图片素材/des.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[man], "推箱子图片素材/man.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[box], "推箱子图片素材/box.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
loadimage(&MAP_IMAGE[hit], "推箱子图片素材/box.bmp", MAP_WIDE, MAP_HEIGTH, TRUE);
for (int i = 0; i < MAP_ROWS; i++) {
for (int j = 0; j < MAP_COLS; j++) {
if (a[i][j] == man) {//记录小人的初始位置
MAN.x = i;
MAN.y = j;
}
putimage(MAP_X + j * RADIO, MAP_Y + i * RADIO, &MAP_IMAGE[a[i][j]]);
}
}
}
//实现小人移动
void mapChange(pos* pos, enum MyEnum prop) {
a[pos->x][pos->y] = prop;
putimage(MAP_X + pos->y * RADIO, MAP_Y + pos->x * RADIO, &MAP_IMAGE[prop]);
}
void get_control(keybord control) {
pos next_pos = MAN, next_next_pos=MAN;
switch (control) {
case UP:
next_pos.x = MAN.x - 1;
next_next_pos.x = MAN.x - 2;
break;
case DOWN:
next_pos.x = MAN.x + 1;
next_next_pos.x = MAN.x + 2;
break;
case LEFT:
next_pos.y = MAN.y - 1;
next_next_pos.y = MAN.y - 2;
break;
case RIGHT:
next_pos.y = MAN.y + 1;
next_next_pos.y = MAN.y + 2;
break;
}
//小人前面如果是地板,人就前进一步,站到next_pos的位置
if (a[next_pos.x][next_pos.y] == Floor) {//做合法性判断
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
}
//人前进一步是箱子则判断箱子前的道具,即next_next_pos,如果是地板和箱子目的地,推着箱子走
if (a[next_pos.x][next_pos.y] == box) {
//下下个是地板
if (a[next_next_pos.x][next_next_pos.y] == Floor) {
mapChange(&next_next_pos, box);
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
//下下个是目的地
}else if (a[next_next_pos.x][next_next_pos.y] == des) {
mapChange(&next_next_pos, hit);
mapChange(&next_pos, man);
mapChange(&MAN, Floor);
MAN = next_pos;
}
}
}
bool gameOver() {
for (int i = 0; i < MAP_ROWS; i++) {
for (int j = 0; j < MAP_COLS; j++) {
if (a[i][j]==des) {
return false;
}
}
}
return true;
}
void gameOverScien() {
putimage(0, 0, &BG_IMAGE);
settextcolor(RGB(255, 255, 0));
settextstyle(90, 0, "微软雅黑");//这里可能会有字符集的问题,上上篇发过解决方法
rectangle(300, 297, 570, 300);//设置矩形框
outtextxy(300, 300, "游戏结束");;//添加文字
}
void control() {
bool quit = false;
do{
if (_kbhit()) {//判断用户是否按键
char ch = _getch();//直接从键盘获取字符,不经过输入缓冲区
if (ch == KEY_UP) {
get_control(UP);
}
else if (ch == KEY_DOWN) {
get_control(DOWN);
}
else if (ch == KEY_LEFT) {
get_control(LEFT);
}
else if (ch == KEY_RIGHT) {
get_control(RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
if (gameOver()) {
gameOverScien();
}
}
Sleep(50);
} while (quit ==false);
}
int main(void) {
//初始化
initGraph();
//加载场景图片
map();
//实现热键控制人物
control();
system("pause");//设置初始化的屏幕不一闪而逝
return 0;
}
合法性判断:
#define isValues(pos) (pos.x>=0 &&pos.x<MAP_COLS &&pos.y>=0&&pos.y<MAP_ROWS)