发布时间:2023-11-29 16:05:58 浏览量:145次
经典的推箱子是一个很古老的游戏了,相信大家都不陌生。其目的是在训练我们的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。
我们将编写推箱子游戏,玩家键盘控制游戏角色将所有黄色箱子推到白色方块处,效果如图所示:
操作方法:方向键↑↓←→控制移动推箱子,将箱子推到对应位置。
首先学习字符串与字符数组的概念,并应用字符数组初始化关卡数据;然后利用键盘控制游戏角色移动,实现地图元素更新和游戏胜利的判断;接着利用三维字符数组,实现多关卡的游戏;最后学习基于文件的关卡数据读取,利用枚举类型改进游戏代码。
源码:
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define B_SIZE 60 // 方块大小
#define B_NUM 8 // 方块个数,一共8*8个方块
struct Player // 结构体,用于记录玩家位置
{
int i;
int j;
};
Player player; // 玩家全局变量
enum Element // 定义枚举类型,小方块所有的可能的种类
{
wall,target,box,empty,achieved,role
};
// 用于存储地图数据,用枚举类型实现
Element level[B_NUM][B_NUM] =
{{wall,wall,wall,wall,wall,wall,wall,wall},
{wall,wall,wall,target,box,empty,empty,wall},
{wall,empty,empty,empty,empty,empty,empty,wall},
{wall,empty,empty,empty,empty,empty,empty,wall},
{wall,empty,empty,empty,empty,empty,empty,wall},
{wall,role,empty,box,target,wall,wall,wall},
{wall,empty,empty,empty,empty,wall,wall,wall},
{wall,wall,wall,wall,wall,wall,wall,wall}};
int targetNum,achievedNum; // 目标位置个数、完成目标个数
void startup() // 初始化函数
{
initgraph(B_NUM*B_SIZE,B_NUM*B_SIZE); // 新开一个画面
setbkcolor(RGB(150,150,150)); // 灰色背景
BeginBatchDraw(); // 开始批量绘图
int i,j;
targetNum = 0; // 目标个数,初始为0
// 对二维数组遍历
for (i=0;i<B_NUM;i++)
for (j=0;j<B_NUM;j++)
{
if (level[i][j]==role) // 找到地图中player位置
{
player.i = i; // 设定player位置
player.j = j; //
level[i][j]=empty; // 把地图元素变成空白empty
}
else if (level[i][j]==target || level[i][j]==achieved ) // 如果元素是target或achieved
targetNum++; // 目标个数+1
}
}
void show() // 绘制函数
{
int i,j;
cleardevice(); // 以背景颜色清空屏幕
// 遍历关卡二维数组数据
for (i=0;i<B_NUM;i++)
{
for (j=0;j<B_NUM;j++)
{
if (level[i][j]==empty) // empty 元素是空白区域
{
setfillcolor(RGB(150,150,150)); // 绘制灰色地面
setlinecolor(RGB(150,150,150));
fillrectangle(j*B_SIZE,i*B_SIZE,(j+1)*B_SIZE,(i+1)*B_SIZE);
}
else if (level[i][j]==wall) // wall 元素是墙
{
setfillcolor(RGB(155,0,0));
setlinecolor(RGB(150,150,150)); // 绘制淡红色、灰色线的方框
fillrectangle(j*B_SIZE,i*B_SIZE,(j+1)*B_SIZE,(i+1)*B_SIZE);
}
else if (level[i][j]==box) // box 元素是可移动的箱子
{
setfillcolor(RGB(255,255,0)); // 绘制一个黄色的方块
setlinecolor(RGB(150,150,150));
fillrectangle(j*B_SIZE,i*B_SIZE,(j+1)*B_SIZE,(i+1)*B_SIZE);
}
else if (level[i][j]==target) // target 元素是目标
{
setfillcolor(RGB(250,250,250)); // 绘制一个白色的小方块
fillrectangle((j+0.3)*B_SIZE,(i+0.3)*B_SIZE,
(j+0.7)*B_SIZE,(i+0.7)*B_SIZE);
}
else if (level[i][j]==achieved) // achieved 元素是已完成目标
{
setlinecolor(RGB(150,150,150));
setfillcolor(RGB(255,255,0)); // 绘制一个黄色的方块
fillrectangle(j*B_SIZE,i*B_SIZE,(j+1)*B_SIZE,(i+1)*B_SIZE);
setfillcolor(RGB(250,250,250)); // 绘制一个白色的小方块
fillrectangle((j+0.3)*B_SIZE,(i+0.3)*B_SIZE,
(j+0.7)*B_SIZE,(i+0.7)*B_SIZE);
}
}
}
// 以下绘制玩家,绘制一个人脸图案
i = player.i;
j = player.j;
setfillcolor(RGB(255,0,0));
fillcircle((j+0.5)*B_SIZE,(i+0.5)*B_SIZE,0.4*B_SIZE);//一个红色圆脸
setfillcolor(RGB(80,80,80));
setlinecolor(RGB(80,80,80));
fillcircle((j+0.3)*B_SIZE,(i+0.45)*B_SIZE,0.08*B_SIZE);//两个黑色眼睛
fillcircle((j+0.7)*B_SIZE,(i+0.45)*B_SIZE,0.08*B_SIZE);
setlinestyle(PS_SOLID,3);
line((j+0.35)*B_SIZE,(i+0.7)*B_SIZE,(j+0.65)*B_SIZE,(i+0.7)*B_SIZE);//深灰色嘴巴
setlinestyle(PS_SOLID,1);
if (achievedNum==targetNum) // 如完成目标个数==目标个数
{
setbkmode(TRANSPARENT); // 透明显示文字
settextcolor(RGB(0,255,255)); // 设置字体颜色
settextstyle(80, 0, _T("宋体")); // 设置字体大小、样式
outtextxy(80,200,_T("游戏胜利")); // 显示游戏胜利文字
}
FlushBatchDraw(); // 开始批量绘制
}
void update() // 每帧更新运行
{
if(kbhit() && (achievedNum<targetNum) ) // 如果按键,并且游戏没有胜利
{
char input = getch(); // 获取按键
if (input=='a' || input=='s' || input=='d' || input=='w') // 如果是有效按键
{
int goal_i = player.i; // 移动的目标位置
int goal_j = player.j;
int goalNext_i = goal_i; // 目标位置再向前的一个位置
int goalNext_j = goal_j;
// 根据用户的不同按键输入,获得目标位置、再向前的一个位置
if (input=='a') // 向左
{
goal_j = player.j -1 ; // 目标位置在玩家位置的左边
goalNext_j = goal_j-1; // 目标的下一个位置,在其再左边
}
else if (input=='d') // 向右
{
goal_j = player.j +1 ; // 目标位置在玩家位置的右边
goalNext_j = goal_j+1; // 目标的下一个位置,在其再右边
}
else if (input=='s') // 向下
{
goal_i = player.i+1; // 目标位置在玩家位置的下边
goalNext_i = goal_i+1; // 目标的下一个位置,在其再下边
}
else if (input=='w') // 向上
{
goal_i = player.i-1; // 目标位置在玩家位置的上边
goalNext_i = goal_i-1; // 目标的下一个位置,在其再上边
}
// 根据不同地图元素的情况,判断如何移动角色和更新地图元素
if (level[goal_i][goal_j]==empty || level[goal_i][goal_j]==target )
{ // 如果目标位置是empty,或者target
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
}
else if (level[goal_i][goal_j]==box && level[goalNext_i][goalNext_j]==empty )
{ // 如果目标位置是box,再前面一个是empty
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j]=empty; // 目标位置变成empty
level[goalNext_i][goalNext_j]=box; // 再前面变成box
}
else if (level[goal_i][goal_j]==box && level[goalNext_i][goalNext_j]==target)
{ // 如果目标位置是box,再前面一个是target
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = empty; // 目标位置变成empty
level[goalNext_i][goalNext_j] = achieved; // 再前面变成achieved
}
else if (level[goal_i][goal_j]==achieved && level[goalNext_i][goalNext_j]== empty)
{ // 如果目标位置是achieved,再前面一个是empty
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = target; // 目标位置变成target
level[goalNext_i][goalNext_j] = box; // 再前面变成box
}
else if (level[goal_i][goal_j]==achieved && level[goalNext_i][goalNext_j]== target)
{ // 如果目标位置是achieved,再前面一个是target
player.i = goal_i; // 玩家移动到目标位置
player.j = goal_j;
level[goal_i][goal_j] = target; // 目标位置变成target
level[goalNext_i][goalNext_j] = achieved; // 再前面变成achieved
}
else // 其他情况都推不动
return; // 不做任何处理,函数直接返回
}
achievedNum = 0; // 完成目标个数,初始为0
int i,j;
for (i=0;i<B_NUM;i++) // 对二维数组遍历
for (j=0;j<B_NUM;j++) //
if (level[i][j]==achieved) // 如果元素是achieved
achievedNum++; // 完成目标个数+1
}
}
int main() // 主函数
{
startup(); // 初始化
while (1) // 游戏主循环
{
show(); // 绘制
update(); // 更新
}
return 0;
}
主要讲解了字符串与字符数组、文件读写、枚举类型等语法知识,实现了推箱子游戏。读者可以尝试在本章代码基础上继续改进:
1、实现多关卡的选择界面;
2、实现某一步移动的撤销功能(类似于下棋游戏中的悔棋功能);
3、实现按'h'键后进行提示,播放正确步骤动画的功能;
4、实现一个图形编辑器,并将设计的关卡信息保存为txt文件。
作者:童晶
希望对大家有帮助!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!
对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!
热门资讯
探讨游戏引擎的文章,介绍了10款游戏引擎及其代表作品,涵盖了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戏设计领域和数字艺术教育的重要性,欢迎点击咨询报名。
游戏中玩家将面临武侠人生的挣扎抉择,战或降?杀或放?每个抉定都将触发更多爱恨纠葛的精彩奇遇。《天命奇御》具有多线剧情多结局,不限主线发展,高自由...
3. B站视频剪辑软件「必剪」:免费、炫酷特效,小白必备工具
B站视频剪辑软件「必剪」,完全免费、一键制作炫酷特效,适合新手小白。快来试试!
4. 手机游戏如何开发(如何制作传奇手游,都需要准备些什么?)
如何制作传奇手游,都需要准备些什么?提到传奇手游相信大家都不陌生,他是许多80、90后的回忆;从起初的端游到现在的手游,说明时代在进步游戏在更新,更趋于方便化移动化。而如果我们想要制作一款传奇手游的
5. 3D动画软件你知道几个?3ds Max、Blender、Maya、Houdini大比拼
当提到3D动画软件或动画工具时,指的是数字内容创建工具。它是用于造型、建模以及绘制3D美术动画的软件程序。但是,在3D动画软件中还包含了其他类型的...
三昧动漫对于著名ARPG游戏《巫师》系列,最近CD Projekt 的高层回应并不会推出《巫师4》。因为《巫师》系列在策划的时候一直定位在“三部曲”的故事框架,所以在游戏的出品上不可能出现《巫师4》
一、声音优化在绝地求生游戏中能够提前听到脚步声往往能提前取得战机,主要有两种方法:1、利用SoundLock软件,软件的功能主要是限制最大音量。百度搜索...
UI设计师、动画设计师、特效设计师每一个职位的功能和负责的方面都不同。所以,3D美术这方面需要大量的人才。但是要成为一个3D游戏建模师,也不是那么...
众所周知,虚幻引擎5(下面简称UE5)特别占用存储空间,仅一个版本安装好的文件就有60G,这还不包括我们在使用时保存的工程文件和随之产生的缓存文件。而...
想让你的3D打印模型更坚固?不妨尝试一下Cura参数设置和设计技巧,让你轻松掌握!
最新文章