在之前写程序设计的大作业时,在哔哩哔哩上跟着一个视频的学习的成果【第一个练习的】
今天整理文件的时候看到的,就发出来一下【CSDN和B站都有详细教程】
不是大项目,只有两个界面
这个代码只有两百行不到,但通过这个把基本的运行逻辑什么的掌握了,然后写自己的完整的游戏设计
经典的推箱子玩法,玩家需要控制一个小人,将箱子推到指定的目标位置,直到通关
#include<graphics.h>
#include<conio.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650 //屏幕宽高
#define RATIO 50 //道具比例
#define START_X 100
#define START_Y 100
#define LINE 9
#define COLUMN 12
//控制键上下左右,退出键
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'
//#define KEY_UNDO 'u' // 撤回键
//#define KEY_RESTART 'r' // 重玩键
#define isvalid(pos) (pos.x>=0 && pos.x<LINE && pos.y>=0 && pos.y<COLUMN)
//确保下标不会越界,移动的前提
enum _PROPS
{
WALL,//墙0
FLOOR,//地板1
BOX_DES,//箱子目的地2
MAN,//小人3
BOX,//箱子4
HIT,//箱子的正确位置5
GameOver,//通关界面6
ALL //7数组个数
};
// 显高级枚举法,暂时不想改
typedef enum _PROPS PROPS;//定义别名
//游戏控制方向,枚举变量
enum _DIRECTION
{
UP,
DOWN,
LEFT,
RIGHT,
};
typedef enum _DIRECTION DIRECTION;//用类型定义作简化
//0:墙 ,1:地板,2:目的地,3:小人,4:箱子,5:正确位置的箱子
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,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},
};
IMAGE images[ALL];
struct _POS
{
int x;//小人所在的二维数组的行
int y;//小人所在的二维数组的列
};
typedef struct _POS POS;//POS小人的坐标的数据类型
POS man; //小人的实时位置,包含小人的坐标
//
void ChangeMap(POS* pos, PROPS prop)
{
map[pos->x][pos->y] = prop;//位置 数组要改
putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &images[prop]);//视图
}
/********************
实现上下左右控制
输入:
输出
********************/
void GameControl(DIRECTION direct) //void没有返回值,方向类型定义变量
{
POS next_pos = man;//小人下一个的位置,变量初始化
POS next_next_pos = man;//小人下下个的位置
switch (direct) //switch判断方向
{
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 (isvalid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR)
{
ChangeMap(&next_pos, MAN);//
ChangeMap(&man, FLOOR);//人原来的位置
man = next_pos;//小人的实时位置
}
//如果人前进一步是 箱子 ,并且箱子前面next_next_pos是地板或者箱子目的地,则推着箱子走
//
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] == FLOOR)
{
ChangeMap(&next_next_pos,BOX);
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] == BOX_DES)
{
ChangeMap(&next_next_pos, HIT);//箱在目的地
ChangeMap(&next_pos, MAN);
ChangeMap(&man, FLOOR);
man = next_pos;
}
}
}
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;
}
//游戏结束
void GameOverScene(IMAGE* bg)
{
putimage(0, 0, bg);
settextcolor(RED);
RECT rec = { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };//跟屏幕同宽高
settextstyle(80, 0, "楷体");
drawtext("恭喜您成功通关", & rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
int main(void)
{
//定义一个表示图片的变量
IMAGE bg_img;
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);//屏幕宽高
//定义一个表示图片的变量
IMAGE gameoverscene;
//设置成功背景
loadimage(&gameoverscene, "GameOverScene.png", SCREEN_WIDTH, SCREEN_HEIGHT, true);//true表示图片自适应
//设置背景
loadimage(&bg_img, "beijing.png", SCREEN_WIDTH, SCREEN_HEIGHT, true);//true表示图片自适应
putimage(0, 0, &bg_img);
//物件图片
loadimage(&images[0], "wall.png", RATIO, RATIO, true);//墙
loadimage(&images[1], "floor.png", RATIO, RATIO, true);//地板
loadimage(&images[2], "des.png", RATIO, RATIO, true);//目的地
loadimage(&images[3], "man.png", RATIO, RATIO, true);//小人
loadimage(&images[4], "box.png", RATIO, RATIO, true);//箱子
loadimage(&images[5], "box.png", RATIO, RATIO, true);//正确位置的箱子
for (int i = 0;i < 9;i++)
{
for (int j = 0;j < 12;j++)
{
if (map[i][j] == MAN)
{
man.x = i;
man.y = j;//x行,y列
}//小人的位置
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
bool quit = false;//游戏结束条件
//热键控制
do
{
if (_kbhit()) //_kbnit(),_grtch()关于按键的函数
{//判断是否有按键,如果有按键按
char ch = _getch();
if (ch == KEY_UP)//w
{
GameControl(UP);//游戏控制
}
else if (ch == KEY_DOWN)//s
{
GameControl(DOWN);
}
else if (ch == KEY_LEFT)//a
{
GameControl(LEFT);
}
else if (ch == KEY_RIGHT)//d
{
GameControl(RIGHT);
}
else if (ch == KEY_QUIT) //q
{
quit = true;
}
else if (ch == KEY_QUIT) //q
{
quit = true;
}
if (IsGameover())//判断游戏是否结束,所有的2全没了
{
GameOverScene(& gameoverscene);
}
}
Sleep(100);//100ms,0.1s
//在没有按键的情况下让CPU休息一下,降低CPU率
} while (quit == false);
system("pause");
return 0;
}
是一个简单的推箱子游戏的实现,使用了 graphics.h
库来进行图形显示。
功能简单明了。
- 游戏地图的初始化
游戏地图是一个二维数组,包含墙壁、地板、箱子、目的地等不同的元素。通过 map
数组表示,不同的整数值代表不同的元素。
int map[9][12] = {
{0,0,0,0,0,0,0,0,0,0,0,0}, // 0代表墙
{0,1,0,1,1,1,1,1,1,1,0,0}, // 1代表地板
{0,1,4,1,0,2,1,0,2,1,0,0}, // 4代表箱子,2代表目的地
// ...
};
0
表示墙壁1
表示地板2
表示箱子目的地3
表示小人4
表示箱子5
表示正确放置的箱子
- 结构体与枚举类型
-
PROPS
枚举定义了不同的游戏元素类型(如墙、地板、箱子等)。 -
DIRECTION
枚举定义了小人的移动方向(上、下、左、右)。 -
POS
结构体用来表示位置,包含x
和y
两个成员,分别表示二维数组的行列。
- 游戏控制和移动逻辑
GameControl
函数是控制小人移动的核心。根据输入的方向(上下左右),更新小人的位置,并处理箱子的推送逻辑。具体逻辑如下:
-
如果小人前进的方向是地板,则小人可以移动。
-
如果小人前进的方向是箱子,且箱子后方是地板或目的地,箱子可以被推移。
- 游戏结束判断
IsGameover
函数用来判断游戏是否结束,判断标准是所有目的地(BOX_DES
)上是否都有箱子。
- 图形显示
使用 putimage
函数显示图像,加载各类图像(如墙壁、地板、箱子等),并通过 ChangeMap
函数来更新游戏地图的显示。
- 用户输入与游戏循环
游戏通过 _kbhit()
和 _getch()
检测用户的按键输入。如果按下控制键(如 w
, a
, s
, d
),则调用 GameControl
函数进行相应的移动操作。如果按下退出键(q
),则退出游戏。
把这些东西理解后就可以自己扩写改造了,
我最后的大作业就是基于最简单的推箱子游戏进行改动,增加其他的功能进行功能扩展
这里的图片来源于网络,可能按照自己的想法更改
完整文件我上传到这了,下载可以直接运行
游戏设计:推箱子【easyx图形界面/c语言】资源-CSDN文库
自己看用上面代码然后自己整加图片素材也可以正常运行
图像加载
游戏中的每个对象(如墙、地板、小人、箱子等)都通过图像来表示。我们使用loadimage
函数将图像加载到内存,并通过图形界面显示出来。
loadimage(&images[0], "wall.png", RATIO, RATIO, true); // 加载墙壁图像
loadimage(&images[1], "floor.png", RATIO, RATIO, true); // 加载地板图像
loadimage(&images[2], "des.png", RATIO, RATIO, true); // 加载目标图像
loadimage(&images[3], "man.png", RATIO, RATIO, true); // 加载小人图像
loadimage(&images[4], "box.png", RATIO, RATIO, true); // 加载箱子图像
""里就是图片对应的图片路径
loadimage(&images[4], "box.png", RATIO, RATIO, true);
"box.png"
是图像文件的路径,它是一个名为 box.png
的图像文件。
图像文件可以是多种格式,比如 .png
, .jpg
等,这里使用的是 .png
格式。box.png
应该是存放在程序的工作目录下,或者是通过相对/绝对路径进行访问。
这里是直接存储在代码所在的文件夹
如果想现有运行效果,针对导入图片的一些代码加入自己的图片路径即可