闯关游戏看着复杂,拆开也就是几个固定零件。只要理清角色移动、碰撞检测、关卡切换这三件事,一个能玩的闯关游戏就能在两三百行代码里跑起来。我以网页版为例,用的是HTML5的Canvas,这个方案不用装任何软件,浏览器直接能跑。
角色移动最朴素的做法是改坐标。给角色设一个x和y变量,每帧根据键盘状态去加减。按方向键或者WASD,上下左右对应y和x的变化。为了防止角色跑得太飘,需要加上速度限制。比如设maxSpeed为5,每次移动后检查一下,如果速度超过这个值就强行掐掉。跳更简单,设一个verticalSpeed变量,按跳跃键时给它赋一个向上的初值,比如-8,每帧加上重力加速度0.4,y坐标加上这个速度,落地的检测就是看y是否碰到地面。这个参数组合跳起来手感接近超级玛丽的水准,高度约40像素,滞空时间大约0.5秒,你可以在自己机器上试出来。
碰撞检测是闯关游戏的门槛。最省事的方案用网格地图,把一张30x20的关卡地图存在二维数组里,1代表有墙,0代表空地。移动时先把新坐标算出来,然后检查新坐标所在的格子是不是墙。为了防止角色卡进墙里,把角色当作一个宽24高32的矩形,检测时同时检查左上角和右下角的格子。碰到墙就把速度置零,把坐标修正到紧贴墙壁的位置。这个过程叫碰撞反馈,反馈做得好不好直接决定手感生死。
关卡切换,最直观的办法是设一个levelIndex变量,数组里存着多个地图。当角色走到一只旗子或者一扇门前,触发区域的坐标设成关卡地图的一个值,比如3。检测时判断角色是否踩到3这个格子,如果踩到就把levelIndex加一,重新载入对应地图。一个完整的闯关游戏至少要跑到3个关卡才不至于让人觉得空,每关长度控制在20秒左右最合适,玩家反复尝试几次不会烦躁。
把这些要素揉在一起,用一段简单的游戏循环来驱动。requestAnimationFrame确保游戏在60帧刷新,上一帧时间戳保存下来,计算时间差dt,移动和检测都乘上dt把帧率差异消除掉,这样在60Hz和144Hz的显示器上跑起来速度一致。常犯的错误是把移动量直接乘在固定帧率上,导致高刷屏上游戏跑得飞快。用dt处理之后,这个坑就填上了。
再提一个容易忽略的环节:死亡重开。不做这个就不叫闯关。给角色设一个生命值或者只做一条命,碰到尖刺或掉出地图就切换到死亡界面,按任意键回到当前关卡开头。掉出地图的判断最简单,只要y坐标超过地图高度加50,直接死。要是做了生命数,血条画在屏幕左上角,用一套图标区分当前状态。
美术资源不用花心思,先用纯色方块撑起整个画面,地面用深灰色,角色用亮蓝色,敌人用红色方块。等这部分逻辑全部调通了,再考虑替换成图片或粒子效果。直接一上来就抠美术,很容易被资源拖死,最后游戏逻辑反而没写完。
有一款免费引擎叫GDevelop,它把上面的逻辑做成了可视化积木,不写代码也能在半个小时内拼出一个闯关游戏关卡。只要理解了移动、碰撞、切关这三个概念,在图形式界面上拖拽参数反而更直观。但如果你以后想进游戏行业,还是老老实实把代码功底啃下来,脚本语言Lua配合LÖVE引擎也是个练手的好路子,代码量比HTML版本更少,同样跑在电脑上,适合专心研究逻辑。
最后一个建议。不要一开始就堆大量的关卡设计。先做两关,一关用于测试跳跃,一关测试碰撞,自己来回跑几遍,练熟了再动手加敌人、弹跳砖块、机关门。每加一个新元素,就重新跑一遍前两关确认没把旧的弄坏。这个版本控制习惯能给你省下一大截调试时间。
闯关游戏本质就是一个地图编辑器配一套规则解释器。地图编辑器负责把数组里的数字变成可见的方块,规则解释器负责让玩家、敌人、道具按流程彼此交互。你不需要什么高深算法,只要把上面说到的零件一个个调通,一个能让人投入半小时的闯关游戏就这么攒出来了。