八、相机锁定
到目前为止,我们已经将级别限制到了浏览器窗口的大小。这对于概念验证来说没问题,但是真实的关卡需要比我们目前所能提供的更多的空间。
我已经计划了一些事情来克服这个限制。首先,我们要将摄像机锁定到玩家,这样它会随着玩家的移动而移动。然后,我们将增加级别的大小,以便它可以是我们需要的任何大小。
用照相机包装
PixiJS 不支持任何自由移动的摄像机来渲染场景,但是我们不需要。我们可以将渲染器或场景包装在 HTML 元素中并移动,而不是移动渲染器或场景。我们需要改变嵌入游戏的方式:
<div class="camera"></div>
<div class="focus-target">click to focus</div>
------
.camera, .focus-target {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.focus-target {
padding: 25px;
text-align: center;
}
------
game.addEventListenerTo(window)
game.addRendererTo(document.querySelector(".camera"))
game.animate()
这些都出自 http://codepen.io/assertchris/pen/WGzkym
。
我们首先创建一个占据整个屏幕空间的摄像机。然后,不是将场景附加到document.body
,而是将其附加到.camera
。这让我们有能力以有趣的方式改造.camera
:
animate() {
requestAnimationFrame(this.animate)
this.state.renderer = this.renderer
this.state.stage = this.stage
this.state.objects.forEach((object) => {
object.animate(this.state)
})
if (this.player) {
const offsetLeft = Math.round(
this.player.rectangle.x - (window.innerWidth / 2)
) * -1
const offsetTop = Math.round(
this.player.rectangle.y - (window.innerHeight / 2)
) * -1
this.element.style = `
transform:
scale(1.2)
translate(${offsetLeft}px)
translateY(${offsetTop}px)
`
}
this.renderer.render(this.stage)
}
// ...later
const player = new Player(
new PIXI.Sprite.fromImage(
"path/to/sprites/player-idle.png",
),
new PIXI.Rectangle(
Math.round(window.innerWidth / 2),
Math.round(window.innerHeight / 2),
44,
56,
),
)
game.addObject(player)
game.player = player
这是出自 http://codepen.io/assertchris/pen/WGzkym
。
我们需要稍微不同地创建player
对象。我们没有直接把它加到game
上,而是声明它是一个常量。我们仍然把它添加到game
,但是我们也把它作为一个属性分配。
这意味着我们可以在Game.animate
中引用它。我们得到玩家的x
和y
坐标,然后减去半个屏幕的innerWidth
和innerHeight
,这样玩家就会大致在屏幕的中央。
然后我们使用 CSS 转换将.camera
向左和向上移动我们刚刚计算的量。我们也可以把相机放大一点,这样东西看起来会稍微放大一点(见图 8-1 )。由于这段代码在Game.animate
中,所以每次渲染玩家时都会更新,也就是说它会随着玩家的移动而移动。
图 8-1。
Zoomed and locked
增长水平
这导致了一个有趣的发现。当玩家站在我的平台上然后跳跃时,他们穿过渲染场景的顶部(然后消失)。这是因为场景的高度是固定的(与窗口高度相同)。
为了解决这个问题,我们需要改变我们定义游戏尺寸的方式,以及我们在游戏中放置物体的方式:
constructor(w, h) {
this.w = w
this.h = h
this.state = {
"keys": {},
"clicks": {},
"mouse": {},
"objects": [],
}
this.animate = this.animate.bind(this)
}
newRenderer() {
return new PIXI.autoDetectRenderer(
this.w, this.h, this.newRendererOptions(),
)
}
// ...later
const width = window.innerWidth
const height = window.innerHeight + 200
const game = new Game(
width,
height,
)
game.addObject(
new Box(
new PIXI.extras.TilingSprite.fromImage(
"path/to/sprites/floor-tile.png",
width,
64,
),
new PIXI.Rectangle(
0,
height - 64,
width,
64,
),
),
)
// ...remaining object definitions
这是出自 http://codepen.io/assertchris/pen/WGzkym
。
我们更改Game
来接受width
和height
构造函数参数。然后,我们使用与提供给game
相同的宽度和高度,而不是到处使用window.innerWidth
和window.innerHeight
。
到目前为止,我们已经相对于屏幕边缘添加了游戏对象。这使得我们可以很容易地改变宽度和高度,而不必重新定位所有的游戏对象。现在我们需要用width
和height
常量替换先前(全局)宽度和高度的所有实例。
我们唯一没有删除全局引用的地方是我们刚刚添加的摄像机锁定代码。这些需要相对于窗口(而不是整个级别的大小),所以它们可以保持原样。
摘要
在这一章中,我们学习了如何将我们的层次扩展到窗口之外。既然我们可以将相机锁定在玩家身上,我们就可以创建庞大的迷宫和令人敬畏的城堡。
花些时间考虑如何改善每个关卡的背景和边框,这样它们就不会像我的一样空了。也许你想创建动画背景来表达每一层的基调和位置。
版权属于:月萌API www.moonapi.com,转载请注明出处