上周发现了一个简单粗暴变态虐心的小游戏 ,并且。这个游戏代码不多,并且没用框架,很适合初学者学习。于是我花了一周时间学习了代码,并且试着重写了一遍。 下面是我的学习笔记。
代码使用了基于requirejs的模块化开发方式,并且使用grunt做构建。这里不分析这两个功能,只分析功能实现部分的代码。
阅读下文时,建议阅读的同时对照游戏()和代码()。
UI
这个app页面一共就有2个,一个是“开始页”,一个是“游戏页”。其中“游戏页”所有的画面都是用canvas实现的,没有dom。
“游戏页”中又分为两个部分,一个是“切换部分”(每一关开始和结束时的切换画面),一个是“游戏部分”(最核心的部分)。
代码结构
首先先看我画的貌似很不专业的结构图:
模块Scene对应的是“游戏页”,是游戏的核心,其中又分两个核心子模块:
模块Core是游戏中一直在转的圆盘。
模块 BallQuene是旋转圆盘下面那排待发射的球。
模块BeginStage对应的是“开始页”。
模块Switcher对应的是“游戏页”中的“切换部分”。
模块Ball是球,Core 和 BallQuene 都会依赖这个模块。
模块Game封装了模块Scene,Switcher,BeginStage。对外提供了一个start()接口
模块index为app的入口。
代码没有使用MVC结构。其中Core,Switcher,Ball,BallQuene这些模块既负责数据的逻辑,同时也负责视图的绘制。
流程
在index中调用
var Game = require(general/Game); Game.start();
后,游戏启动。游戏启动分为3个步骤:1. 自适应屏幕尺寸。 2. 设置交互事件(其中会监听“开始游戏”事件、“点击屏幕”事件等”)。 3. 开启循环定时器。
开启定时器后,会不断的调用Scene和Switcher的update()和render()函数(这两个函数的功能分别为数据更新和视图渲染)。但是update()和render()里的内容不会每次都执行,Scene和Switcher内部分别维护一个enable属性,只有值为true时,才执行update()和render()里的内容。
每次点击“游戏开始”时,Game会调用Switcher的switchStage()函数,显示转换动画,动画结束时,在switchStage()的回调参数中调用Scene的run()功能,同时传入参数level,游戏开始。
beginStage.on("start", function(){
canvas.style.display = ""; beginStage.hide(); switcher.switchStage(1, function(){ scene.run(level); }); });
游戏开始后,每一帧中都会刷新和渲染Core和BalQuene中的数据。Core中每次update()都会改变内部属性angle,通过angle去控制转盘的旋转。
当点击屏幕时,会调用Scene的shot()方法。shot()会从BallQuene中弹出一个Ball放到Core中,然后会进行一次碰撞检测。此时会发生三种情况:1. 如果通过,则游戏继续。2. 如果失败,则切换到“开始页”中。 3. 如果BallQuene中没有球了,则过关,切换到“开始页”中。切换工作都是通过Switcher的switchStage()方法执行。
写着写着发现,用文字表达逻辑真是很复杂的一件事。本来几行代码就能表达清楚的东西,用文字表述却会多很多。 这里还有很多细节没有写明。欢迎直接看代码或交流讨论。
以上全是引用别人的博文,很想改游戏代码,只是能力不足,有待继续努力。。。