废话不多说,直接进入正题,这篇文章主要为大家讲解一下一个类似【Z-Type】的html5小游戏的开发思路。

【Z-Type】不知大家是否有玩过,Impactjs 的一个演示demo。一个需要99$的html5游戏框架。咱们暂且先不管他实现的思路,以下我们按自己的思路来一步步实现。

以下实例基于AlloyTeam团队游戏底层库【Laro】 实现.

【演示Demo】 (Firefox3.4+,Chrome10+,safari10+ 测试通过)

=======================================================

【Stpe 1】游戏主循环和CanvasReander

游戏初始化的时候,我们先做两件事:

  • 获取Laro提供的用于canvas渲染的canvas render实例,里面封装了大部分常用的canvas 游戏常用的方法。
  • 开始循环,重绘

接下来,主循环开始,我们在主循环里可以先做两件事,一个update 用于处理每次循环数据方面的更新。 一个 draw ,用来做每帧的重绘。

接下来,开始考虑游戏主流程的逻辑编码,这里我们使用有限状态机FSM来处理游戏主流程。

【Stpe 2】游戏主流程

关于有限状态机,简单的理解可以理解为一种switch case 的升级版,基于事件驱动的状态分支管理方式。适用于一些典型的基于事件驱动的模型,比如说游戏,或者是一些富操作的app。详细可以google或者百科一下。

状态与状态之间尽量解耦,状态之间的消息传递和转换通过他们的宿主来处理。

于是,我们暂且先把这个游戏流程分为3块。

  1. 资源loading,初始化
  2. 游戏主场景
  3. 游戏结束Game Over

关于状态机的使用方式,我这里有一个简单的Demo ,对于每个状态都抛出了enter,leave,update,transition等事件,状态宿主有onStateChange状态改变的监听。

 

我们状态机主流程初始化的时候,进入第一个资源Loading 状态,这时候,我们可以在loading 的state class 里面来处理资源加载状态的一些情况。

上面抛出了

  • enter:进入状态时触发
  • leave:离开状态时触发
  • update:每帧数据更新
  • draw: 每帧的绘制
  • transition:转换判断,在每次update之后触发

还有一些别的事件,详细请参考源码和文档。 每个状态的update和draw方法会有他们的状态宿主统一派发。

所以只需要在主循环里面的update和draw里面加上这个fsm宿主的update和draw的调用即可。

【Step 3】游戏主场景-飞船和敌人的绘制

进入游戏主场景状态之后,我们可以看到,主场景绘制也可以分为下面几个方面:

  • 后面网格背景的动态绘制
  • 飞船,包括射击动作的处理
  • 敌人,敌人头上的文字,还有被击中状态的处理

动态网格背景很简单,让背景绘制的坐标不断向上移动就可以了

飞船,因为需要处理的逻辑可能比较多,我们用一个新建的类来处理。同时,飞船必定也会有多种状态间的切换,比如:普通静止的状态,射击的状态,被撞毁的状态等等。

所以,飞船这里我们又可以利用一个状态机来处理飞船自身的一些状态切换管理。

然后,在游戏主场景状态里面的update和draw里面去派发调用这个Ship的update和draw即可。

敌人的绘制也一样,可以独立一个 负责 敌人的类, 只不过可能需要多个敌人在同一个场景里面,那么按照不同的条件生成多个实例即可。基本思路一致。这里就不细说。

【Step 4】键盘事件响应,激光的射出

键盘事件,很常见,这里就不详述,监听键盘事件,判断当前的按键符不符合当前射击条件,这里的条件跟游戏规则挂钩。

我这里设计的游戏规则是这样的。

  • 当前所有敌人都是“满血”状态时,这里由于是打字游戏,所以这里的满血状态指的每一个敌人的 word 都是完整的,没被消除过字母。这时候,根据当前的按键情况,遍历word 列表的 首字母,如果遇到符合条件的,那么射击,否则表示按键失误,没有匹配的单词。
  • 当有单词被击中之后,这个单词就变红,意味着你只能继续把这个单词完全打完之后才能打别的单词。

我们按照这个规则处理是否射击的判断,也就简单了,假如有符合条件的判断,那么我们添加一个“激光”类的实例到当前需要渲染的激光列表里面。

在游戏主场景 的update 和draw 里面对这个激光 列表进行遍历 update 和draw即可。

激光击中之后,消失,移除这个激光渲染列表。

【Step 5】激光击中的判断和击中效果绘制

由于我们是打字游戏,所以只要激光射出,就一定会中,至于激光在什么时候消失,我们可以做个粗略的 碰撞检测 即可,比如激光当前 位置 和 所射击敌人的位置 距离 的绝对值 小于多少 就判定 为击中…

因为并不需要判定 精确击中,所以这种逻辑基本也能满足需求。

那么判定激光击中之后,将当前激光移除渲染列表,同时可以在击中敌人周围加上一些 击中的效果, 比如说一些 飞舞的光圈等等。

当然,这些都是增加体验的效果,不是必需。

【Step 6】体验的丰富,音效处理

当然,想要更好的体验,可以考虑在射击可击中的时候加上音效的播放,这一点可以直接使用html5 的audio来处理。需要注意的几个点是:

  • firefox,chrome,safari等浏览器能够支持的音频格式都不太一致,需要有个适配兼容
  • firefox下面如果不开始play的时候,他不会自动帮你预加载资源,所以做资源预加载时,firefox下最好先 play(),再pause() 一下,可以绕过去。
  • 另外,资源预加载时,如果为了保证音频完整可用之后再使用,最好使用canplaythrough事件来做回调。

============================

好吧,大致的思路就写到这里,感兴趣的同学可以直接查看demo源码,当然,代码里面有一些处理的不够好的地方,因为仅作演示而已。

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2012/05/how-to-make-typeshot/

  1. zhengfei 2012 年 9 月 4 日

    楼主 源码里少了个world.js啊

  2. 匿名 2012 年 7 月 10 日

    我是firefox13 为什么总是无法导入laro module?

  3. Aki_konata 2012 年 5 月 31 日

    话说Laro里面那个module的概念是怎样的?感觉不是很明白的说。和register名空间有什么不同?

  4. DeadFire 2012 年 5 月 24 日

    还个字体吧,i和l实在分不清楚。

发表评论