上一节,我们完成了平行背景滚动的效果,这一节我们要在变化背景的前方加入精灵动画以及检测碰撞。我们现在背景的前方加入一个奔跑的小人,打开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>
完成上面代码后,把页面加载起来,可以看到一个小人出现在页面上,点击左箭头,小人处于跑道左边:
点击右箭头,小人处于跑道右边:
接着我们看看如何实现碰撞检测。打开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个像素,于是检测碰撞时,在背景的每一个小图片下移时,我们先检测当前挪动的图片是否是障碍物,并且障碍物所在的位置是否和小人位置一致就可以,这个检测算法可用下图表示:
实框是小人处于左边时的坐标,当我们点击右箭头按钮后,小人会向右边挪动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)处,并且障碍物也处于同样坐标,那么碰撞就发生了,一旦碰撞发生,我们就结束游戏。上面代码完成,加载到页面后,一旦碰撞发生时,效果如下:
最后我们看看,小人跑动时手脚动起来的精灵动画效果是怎么实现的,我们先看看用于在页面上显示小人的背景图片:
我们看到,图片上有两个小人,要实现小人跑动时的动画效果,我们只要在页面上显示小人时,反复在这两个小人形态间切换就可以实现一种动画效果了。所谓精灵动画本质上是一张图片有好几部分组成,然后把单位时间切割成若干部分,在对应时间段内显示图片中的某一部分,于是单位时间内,页面上就显示了图片的不同部分,进而形成一种动画效果,这种显示方式就叫精灵动画。我们看看如何通过代码实现精灵动画。我们要通过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/
来仔细了解他的作用。
上面的代码添加完成后,加载页面,你会看到小人两条腿在不停晃荡,表现出一种在奔跑的生动形象,
至此,整个游戏的设计就完成了,如果你运行起来,会觉得当前游戏很傻逼,因为障碍物始终位于跑道的右边,小人跑动的形象也不是很好看,整个游戏感觉比较粗糙,这个游戏设计的目的其实是为了引入几个重要概念,例如游戏主循环,平行背景移动,碰撞检测,精灵动画等几个概念,掌握这些概念和相关技术后,我们便可以把他们运用到更复杂更强大的游戏设计和开发中。
欢迎关注公众号,让我们一起学习,交流,成长: