上一节,我们完成了平行背景滚动的效果,这一节我们要在变化背景的前方加入精灵动画以及检测碰撞。我们现在背景的前方加入一个奔跑的小人,打开gamescenecomponent.vue,在style标签里添加代码如下:

#player {
  position: absolute;
  width: 100px;
  height: 100px;
  background-image: url(../../static/images/running.png);
  bottom: 100px;
}

#player.lane1{-webkit-transform: translate3d(100px, 0, 0);}
#player.lane2{-webkit-transform: translate3d(200px, 0, 0);}

接着我们在script标签里添加代码,让前方小人根据键盘按键变换位置,添加代码如下:

init () {
        this.startOver()
        window.onkeyup = this.handleKeyUp
      },
      handleKeyUp (e) {
        if (e.keyCode === 37) {
          this.isOnLane1 = true
        } else if (e.keyCode === 39) {
          this.isOnLane1 = false
        }

        return false
      },

当keyCode的值是37时,表示键盘左箭头按键被按下,当keyCode的值是39时,表示键盘右箭头按键被按下。最后我们调整一下template中的代码:

<template>
  <div id="game-scene" class="scene">
    <div id="floor" class="floor" :style="backgroundStyle">
    <div v-for="tile in tiles">
      <div :class="tile.class" :style="tile.style">
    </div>

    <div id="player" :class="{lane1: isOnLane1,
                                lane2: !isOnLane1}">
    </div>

      </div>
    </div>
  </div>
</template>

完成上面代码后,把页面加载起来,可以看到一个小人出现在页面上,点击左箭头,小人处于跑道左边:

VUE+WebPack游戏设计:实现碰撞检测和动画精灵_精灵动画


点击右箭头,小人处于跑道右边:

VUE+WebPack游戏设计:实现碰撞检测和动画精灵_WebPack_02

接着我们看看如何实现碰撞检测。打开gamecontainer.vue,在style标签中,我们能看到如下代码:

#game {
    width: 480px;
    height: 600px;
    margin: 0 auto;
    border-radius: 8px;
    text-align: center;
    position: relative;
    overflow: hidden;
  }

也就是说,整个游戏场景的高度是600个像素,前面我们定义的player属性中,设置bottom属性为100,有就是小人图片的底部距离游戏场景底部有100个像素的位置,也就是底部位于游戏场景下标为500px的地方,由于小人图片的像素高度是100px,因此小人图片的起始点始终位于游戏场景400px处。障碍物的图片宽度和高度都是100px, 在上节实现的背景滚动功能里,每个一个时间段,我们会把页面背景的小图片下移100个像素,于是检测碰撞时,在背景的每一个小图片下移时,我们先检测当前挪动的图片是否是障碍物,并且障碍物所在的位置是否和小人位置一致就可以,这个检测算法可用下图表示:

VUE+WebPack游戏设计:实现碰撞检测和动画精灵_游戏设计_03

实框是小人处于左边时的坐标,当我们点击右箭头按钮后,小人会向右边挪动100个像素,处于x坐标是200px处,当障碍物背景图片往下移动到坐标是x=200px, y = 400px时,那么碰撞就发生了,根据这个原理,我们添加一下代码实现碰撞检测功能,在style标签中添加如下代码:

createTile (type, x, y) {
        var tile = {}
        tile.class = 'tile tile-' + type
        tile.x = x
        tile.y = y
        tile.style = 'transform: translate3d(' + x + 'px, ' + y + 'px, 0)'
        if (type === 100) {
          tile.isBlock = true
        }
        this.tiles.push(tile)
      }

在创建背景图片时,我们给tile增加了isBlock变量,如果当前创建的背景图片时障碍物,也就是type的值是100时,我们把isBlock设置成true,在style标签中继续添加如下代码:

moveTilesDown () {
        for (var i = 0; i < this.tiles.length; i++) {
          this.tiles[i].y += this.TILE_HEIGHT
          if (this.tiles[i].y > this.BOUNDARY) {
            this.tiles.splice(i, 1)
          } else {
            this.checkCollision(this.tiles[i])
          }
        }
      },
      checkCollision (tile) {
        if (tile.isBlock) {
          if (tile.y === 400) {
            if ((tile.x === this.TILE_WIDTH && this.isOnLane1 === true) || (tile.x === this.TILE_WIDTH * 2 && this.isOnLane1 === false)) {
              console.log('collision')
              this.isGameOver = true
              Constant.Event.$emit(Constant.MSG_SHOW_GAMEOVER_SCENE)
            }
          }
        }
      }

moveTilesDown函数是上一节实现的,它的作用是把组成背景的小图片往下挪动,形成背景移动的效果,每移动组成背景的一小块图片时,调用checkCollision判断碰撞是否发生,判断的办法就是先看当前背景图片是否是障碍物,如果是,再判断图片移动后的位置是否跟前面讲解过的坐标重合,如果小人处于左边,也就是坐标(100px, 400px)处,或者处于右边也就是坐标(200px, 400px)处,并且障碍物也处于同样坐标,那么碰撞就发生了,一旦碰撞发生,我们就结束游戏。上面代码完成,加载到页面后,一旦碰撞发生时,效果如下:

VUE+WebPack游戏设计:实现碰撞检测和动画精灵_游戏设计_04

最后我们看看,小人跑动时手脚动起来的精灵动画效果是怎么实现的,我们先看看用于在页面上显示小人的背景图片:

VUE+WebPack游戏设计:实现碰撞检测和动画精灵_精灵动画_05

我们看到,图片上有两个小人,要实现小人跑动时的动画效果,我们只要在页面上显示小人时,反复在这两个小人形态间切换就可以实现一种动画效果了。所谓精灵动画本质上是一张图片有好几部分组成,然后把单位时间切割成若干部分,在对应时间段内显示图片中的某一部分,于是单位时间内,页面上就显示了图片的不同部分,进而形成一种动画效果,这种显示方式就叫精灵动画。我们看看如何通过代码实现精灵动画。我们要通过css3提供的功能实现精灵动画,所以需要在style标签里增加代码:

@-webkit-keyframes running {
  from {background-position: 0px;}
  to   {background-position: -200px;}
}

#player {
  position: absolute;
  width: 100px;
  height: 100px;
  background-image: url(../../static/images/running.png);
  bottom: 100px;
  -webkit-animation-name: running;
  -webkit-animation-duration: .4s;
  -webkit-animation-timing-function: steps(2, end);
  -webkit-animation-iteration-count: infinite;
}

@-webkit-keyframes 用于定义动画流程,running动画有两个流程,第一步是从背景图片最左边的坐标值为0处,在页面上显示图案,根据player的css定义,它的宽度是100px,也就是执行第一步时,将背景图片宽度为0px到100px这部分图案贴到页面上,也就是上面两个小人中左边抬起右脚的那个小人图案,第二步则是把背景图左移动200px后,把剩余部分显示到页面上,从上面的背景图看到,第一个小人和第二个小人间有一个间隔,这个间隔是100px,所以挪动200px后,正好是第二个小人开始的位置,webkit-animation-timing-function用于表示显示以怎样的时序来显示背景图的不同部分,step(2,end)的意思把把动画显示总时间0.4s分成两部分,那意味着背景图中第一个小人在页面上存在0.2秒,然后第二个小人在页面上存在0.2秒,这个流程不断的重复,step函数的第二个参数解释起来比较麻烦,大家可通过链接:https://idiotwu.me/understanding-css3-timing-function-steps/
来仔细了解他的作用。

上面的代码添加完成后,加载页面,你会看到小人两条腿在不停晃荡,表现出一种在奔跑的生动形象,

至此,整个游戏的设计就完成了,如果你运行起来,会觉得当前游戏很傻逼,因为障碍物始终位于跑道的右边,小人跑动的形象也不是很好看,整个游戏感觉比较粗糙,这个游戏设计的目的其实是为了引入几个重要概念,例如游戏主循环,平行背景移动,碰撞检测,精灵动画等几个概念,掌握这些概念和相关技术后,我们便可以把他们运用到更复杂更强大的游戏设计和开发中。

欢迎关注公众号,让我们一起学习,交流,成长: