本节将要实现的游戏效果是, 当用户在页面上拖拽了一个炮台后, 炮台会自动发射出子弹, 当飞跃的子弹打中外星人时, 外星人就会从页面上消失, 本节代码完成后效果如下:
这里写图片描述
我们看看代入如何实现. 第一步是构建子弹对象, 代码如下:
- // change 1
- bullet (damageDeal) {
- var obj = new this.cjs.Container()
- obj.addChild(new this.assetsLib.Bullet())
- obj.cache(-25, -25, 50, 50)
- obj.damageDeal = damageDeal | 1
- return obj
- },
- // change 2
- bulletTick (bullet) {
- if (this.cjs.Ticker.getPaused()) {
- return
- }
- bullet.y -= 1.5
- }
bullet 函数构造一个 cjs 容器对象, 然后从资源库中加载子弹图片资源, 并调用 cache 缓存在页面里, damgeDeal 用于设置子弹的攻击力. bulletTick 在时钟循环函数中被调用, 它会不断的修改子弹对象在页面上的 y 坐标, 从而实现子弹在页面上的飞升效果.
图片中发射子弹的炮台是我们以前实现的 castle 对象, 我们要把所有的 castle 对象加入到一个列表中, 这样我们才能知道有多少炮台要发射子弹, 所以代码修改如下:
- castle () {
- var b = this.building()
- b.addChild(new this.assetsLib.Castle())
- b.hp = 300
- b.shield = 5
- b.damageDeal = 2
- b.attackSpeed = 120
- // change 3
- b.tick = 0
- // change 10
- this.castleList.push(b)
- return b
- },
代码用 castleList 数组来记录所有炮台, 其中的 tick 变量用来设置炮台发射子弹的时间间隔. 接着我们要增加一个 castleTick 函数, 在主时钟函数中调用, 代码如下:
- // change 4
- castleTick () {
- if (this.cjs.Ticker.getPaused()) {
- return
- }
- for (var i = 0; i <this.castleList.length; i++) {
- var castle = this.castleList[i]
- castle.tick += 1
- if (castle.tick % castle.attackSpeed === 0) {
- this.summonBullet(castle)
- }
- }
- for (i = 0; i < this.bulletList.length; i++) {
- this.bulletTick(this.bulletList[i])
- }
- },
主时钟循环函数里, 它会反复调用 castleTick 函数, 该函数轮询 castleList 数组, 从中取出炮台对象, 增加炮台对象的 tick 计数器, 一旦计数器达到指定值时, 它会调用 summonBullet 函数创建子弹对象, 然后该函数又会轮询子弹对象数组, 然后调用 blletTick 函数设置页面上子弹对象的 y 坐标, 从而使得子弹产生往上飞的效果. 我们再看 summonBullet 函数的实现:
- // change 5
- summonBullet (castle) {
- var bullet = this.bullet(castle.damageDeal)
- bullet.x = castle.x + Math.random() * 20 - 10
- bullet.y = castle.y
- this.addBullet(bullet)
- },
- // change 7
- addBullet (bullet) {
- this.effectLayer.addChild(bullet)
- this.bulletList.push(bullet)
- },
该函数就是调用原先实现的 bullet 函数创建子弹对象, 并把子弹在页面上的坐标设置成与对应的炮台一致, 然后调用 addBullet 函数把子弹对象加入特效图层和 bulletList 数组. 这里用到的几个变量要在 data() 函数中增加:
- data () {
- return {
- ....
- // change 6
- bulletList: [],
- // change 9
- castleList: []
- }
- }
接着我们要在主轮询函数中添加代码, 驱动上面代码的调用, 在 boardTick 函数中增加如下代码:
- boardTick () {
- ....
- // change 11
- this.castleTick()
- // change 8 轮询敌人队列和子弹队列, 看看两者是否相撞
- for (i = this.enemyList.length - 1; i>= 0; i--) {
- for (var j = this.bulletList.length - 1; j>= 0; j--) {
- var bullet = this.bulletList[j]
- var pos = bullet.localToLocal(0, 0, this.effectLayer)
- rowCol = this.screenToRowCol(pos.x, pos.y)
- if (this.enemyMap[rowCol.col][rowCol.row] !== undefined) {
- var enemyHit = this.enemyMap[rowCol.col][rowCol.row]
- this.enemyDamage(enemyHit, bullet.damageDeal)
- if (enemyHit.hp <= 0) {
- this.enemyMap[rowCol.col][rowCol.row] = undefined
- this.removeItem(this.enemyList, enemyHit)
- this.boardLayer.removeChild(enemyHit)
- }
- this.removeItem(this.bulletList, bullet)
- this.effectLayer.removeChild(bullet)
- }
- }
- }
- },
- ....
- enemyDamage (enemy, damage) {
- enemy.hp -= damage
- },
boardTick 函数会被主循环函数调用, 它会调用 castleTick 函数, 于是炮台对象会不断的创建子弹对象. 然后代码通过两个循环轮询外星人数组和子弹数组, 它从子弹数组中取出子弹对象, 将子弹所在的坐标转换成页面上的行和列, 接着根据行和列到外星人分布图, 也就是 enemyMap 中查询, 如果对应的位置有外星人对象, 那表明子弹击中了外星人. 此时代码调用 enemyDamage 函数计算外星人被击中后会掉多少血, 如果外星人的能力耗尽, 那么 if(enemyHit.hp <=0) 部分的代码会被执行, 于是外星人对象就会从页面上被删除. 同时不管外星人是否被摧毁, 最后的两句代码:
- this.removeItem(this.enemyList, bullet)
- this.effectLayer.removeChild(bullet)
都会把子弹从页面上去除. 完成以上代码后, 图片所示的效果就可以完成了.
来源: http://www.jianshu.com/p/4da6f9223a13