在之前写程序设计的大作业时,在哔哩哔哩上跟着一个视频的学习的成果【第一个练习的】
今天整理文件的时候看到的,就发出来一下【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,//墙0FLOOR,//地板1BOX_DES,//箱子目的地2MAN,//小人3BOX,//箱子4HIT,//箱子的正确位置5GameOver,//通关界面6ALL //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
库来进行图形显示。
功能简单明了。
1. 游戏地图的初始化
游戏地图是一个二维数组,包含墙壁、地板、箱子、目的地等不同的元素。通过 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
表示正确放置的箱子
2. 结构体与枚举类型
-
PROPS
枚举定义了不同的游戏元素类型(如墙、地板、箱子等)。 -
DIRECTION
枚举定义了小人的移动方向(上、下、左、右)。 -
POS
结构体用来表示位置,包含x
和y
两个成员,分别表示二维数组的行列。
3. 游戏控制和移动逻辑
GameControl
函数是控制小人移动的核心。根据输入的方向(上下左右),更新小人的位置,并处理箱子的推送逻辑。具体逻辑如下:
-
如果小人前进的方向是地板,则小人可以移动。
-
如果小人前进的方向是箱子,且箱子后方是地板或目的地,箱子可以被推移。
4. 游戏结束判断
IsGameover
函数用来判断游戏是否结束,判断标准是所有目的地(BOX_DES
)上是否都有箱子。
5. 图形显示
使用 putimage
函数显示图像,加载各类图像(如墙壁、地板、箱子等),并通过 ChangeMap
函数来更新游戏地图的显示。
6. 用户输入与游戏循环
游戏通过 _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
应该是存放在程序的工作目录下,或者是通过相对/绝对路径进行访问。
这里是直接存储在代码所在的文件夹
如果想现有运行效果,针对导入图片的一些代码加入自己的图片路径即可