原文:Cameras in Love2D Part 1: The Basics ,请自备梯子。

这是几篇关于如何在 LÖVE引擎中创建摄像机的博客中的第一篇。本部分将会设计创建一个摄像机的基本原理。第二部分会涉及视差卷动和创建图层。那么,现在开始!

更新:我已经完成第三部分的写作,包含了如何限定摄像机的活动范围。

函数

我们所需要的函数是以下这些:

Love2D(我从现在开始会使用这个名字,因为它打字更容易)有一个变换栈,在一个栈中有一些独立的变换信息。love.graphics.push可以将当前的变换压入栈顶,然后在它下面插入一个新的变换,可以这么说。love.graphics.pop丢弃当前的变换,然后设置当前的变换到栈上那个之前的变换。让我们来看一些ASCII绘图:

Starting:
|-----------|
| Default   |
|-----------|

love.graphics.push:
|-----------|
| Default   |       ^ pushed up
|-----------|
|-----------|
| New       |       <- pushed under
|-----------|

love.graphics.pop:
|-----------|         |-----------|
| Default   |         | New       |  -> discarded
|-----------|         |-----------|

现在,translatescale,和 rotate 改变了当前变换中的信息。传给 translatexy 参数会加到每个绘制到屏幕的 xy 座标中。每个 xy 座标会乘上传给 scale 的值。最后,每个给定的位置(一个x/y向量)会被传给 rotate 的值转动,屏幕的左上角作为旋转中心。

有了上面的解释,你可以像这样创建一个最简单的摄像机:

function love.draw()
  love.graphics.translate(-x, -y)
  -- drawend

这里 translate 按照默认的变换进行操作。变换栈每帧都会重置,所以我们必须每一帧都要应用我们的改变。我们可以这样来实现一个更复杂些的摄像机:

function love.draw()
  love.graphics.rotate(-rotation) -- this is in radians
  love.graphics.scale(1 / zoom, 1 / zoom)
  love.graphics.translate(-x, -y)
end

-rotation-x-y让 所有的位置“留在原处”,如果它们不随摄像机一起移动的话。传给scale 的值小于1使摄像机拉近,大于1的值使摄像机远离。

camera 模块

让我们把这些组织起来做成一个camera 模块。这是模块的代码:

camera = {}
camera.x = 0
camera.y = 0
camera.scaleX = 1
camera.scaleY = 1
camera.rotation = 0

function camera:set()
  love.graphics.push()
  love.graphics.rotate(-self.rotation)
  love.graphics.scale(1 / self.scaleX, 1 / self.scaleY)
  love.graphics.translate(-self.x, -self.y)
end

function camera:unset()
  love.graphics.pop()
end

function camera:move(dx, dy)
  self.x = self.x + (dx or 0)
  self.y = self.y + (dy or 0)
end

function camera:rotate(dr)
  self.rotation = self.rotation + dr
end

function camera:scale(sx, sy)
  sx = sx or 0
  self.scaleX = self.scaleX * sx
  self.scaleY = self.scaleY * (sy or sx)
end

function camera:setPosition(x, y)
  self.x = x or self.x
  self.y = y or self.y
end

function camera:setScale(sx, sy)
  self.scaleX = sx or self.scaleX
  self.scaleY = sy or self.scaleY
end

camera 模块是一个 table,包含了它需要被定位的信息。关键函数是 setunsetset 应用 camera 模块中的信息并且为它创建一个新的变换(为了支持在一帧中有多个视图)。unset 只是使用 pop 移除最近的变换。剩下的函数只是简单的帮助调整 camera 中的属性。

你可以把这段代码放在 love.draw 中来使用这个摄像机:

function love.draw()
  camera:set()
  -- draw stuff
  camera:unset()
end

然后在更新阶段你可以改变摄像机的位置,缩放,或者旋转。

camera.x = 50
camera:scale(3) -- zoom by 3

鼠标

现在,如果你想在游戏世界中用鼠标来进行交互的话,你还需要使用 love.mouse.getX/Y/Position() 的返回值来调整座标。你可以重新定义这些方法,或者给 camera 模块添加一些新的函数。

function camera:mousePosition()
  return love.mouse.getX() * self.scaleX + self.x, love.mouse.getY() * self.scaleY + self.y
end

它会根据鼠标的座标计算缩放和移动。如果你想把转动也计算在内,你需要做一些向量转动的计算。想了解这方面的东西,就去看 HUMP的vector类

总结

那么感谢你的阅读。我希望你学到了一些东西,请将你的想法写在评论框中告诉我。我们第二部分见!



blog comments powered by Disqus