cocos2d-x 3.3 Lua开发 摄像机使用

2015年01月28日 14:05 0 点赞 0 评论 更新于 2025-11-21 15:40

在cocos2d-x 3.3 Lua开发中,需要学习的内容众多,本文将聚焦于摄像机的使用。

1. 为什么要使用Camera

游戏与电影有相似之处,镜头的运用至关重要,例如镜头的远近切换、跟随主角以及场景切换等。通常情况下,2D游戏对Camera的需求不大,因此在Cocos2d-x早期版本中,对Camera的支持不够完善。直到3.3版本,Camera的使用才变得相对容易。此前,一些Camera的效果可以通过其他方式模拟,但这种方式逻辑不够直观,而直接操作Camera则是最理想的解决方案。

先来看Camera Demo的效果图,从常理理解,画面中呈现一个人不断往上移动的效果。游戏实现这种效果有两种方式:

  • 方式一:固定人物位置,将背景向下移动,从而营造出“人物在往上移动”的视觉效果。
  • 方式二:人物向上移动,Camera的位置保持在人物位置下方一定距离处,并跟随人物移动,背景则保持静止,但需要进行拼接处理。

在Cocos2d-x 3.3之前,只能采用类似第一种方式来实现,本质上是一种视觉欺骗。而在3.3版本引入Camera后,我们可以使用第二种方式,这种方式更符合逻辑。

2. 创建Camera

以下是创建Camera的代码示例:

if self._camera == nil then
self._camera = cc.Camera:createOrthographic(GameUtil:VISIBLE_WIDTH(), GameUtil:VISIBLE_HEIGHT(), 0, 1)
self._camera:setCameraFlag(cc.CameraFlag.USER1)
self:addChild(self._camera)
self._camera:setPosition3D(cc.vec3(0, 0, 0))
end

self:setCameraMask(2)

在OpenGL的API中,有两种类型的Camera。一种类似于现实生活中的摄像头,远处的物体看起来较小,近处的物体看起来较大;另一种则是远处和近处的物体大小相同。由于这是2D游戏,我们使用第二种Camera。

createOrthographic函数有4个参数,它们大致规定了Camera的观察范围。在3D空间中,全面观察会消耗大量资源且没有必要,因此Camera有观察范围的概念。这4个参数分别表示宽度、高度、近处和远处。对于2D游戏,只要近处和远处的范围包含0即可。如果游戏场景未能正常显示,需要检查该范围是否包含0。

setCameraFlagsetCameraMask是相互对应的关系,它们决定了哪些物体能够被Camera看到。以下是CameraFlag的枚举定义:

enum class CameraFlag
{
DEFAULT = 1,
USER1 = 1 << 1,
USER2 = 1 << 2,
USER3 = 1 << 3,
USER4 = 1 << 4,
USER5 = 1 << 5,
USER6 = 1 << 6,
USER7 = 1 << 7,
USER8 = 1 << 8,
};

从源码中可以得知,USER1 = 2USER2 = 4 等等。只要将节点的CameraMask设置为与CameraFlag的值相同,该节点对于Camera来说就是可见的。

可以对一个图层的cameramask进行设置,这样图层中的所有节点都会递归地进行设置。设置的时机也非常关键,需要在最后进行设置,以确保前面添加的节点能够生效。

需要注意的是,由于使用了Camera,在游戏中新增物体时,不要忘记为新增物体设置cameramask,否则将无法看到这些物体。

3. 不受Camera限制的节点

观察Demo中的右上角暂停按钮,它的位置是固定的,不会随着Camera的移动而移动。实现这一效果非常简单,只需不设置cameramask即可。可能有人会疑惑,前面提到不设置cameramask就看不到物体,这里为何能看到且位置不变呢?这涉及到Cocos2d-x整个游戏引擎的Camera实现,情况较为复杂,目前尚未完全搞清楚。

4. 背景的拼接

虽然本文主要讨论Camera的使用,但这里也简单提及一下背景的处理。由于使用了Camera,背景可以无需移动。然而,当Camera向上移动时,背景会被甩在后面,导致画面没有背景。因此,背景需要不断改变位置。

当第一张背景的顶部位置低于Camera位置时,就可以将该背景图片移动到所有背景图的最上方。以下是相关的代码实现:

function GameBackgroundLayer:getFirstBgTop()
return (self.allBackGrounds[1]:getPositionY() + self.height * 0.5)
end

function GameBackgroundLayer:moveFirstBgToLast()
local firstBg = self.allBackGrounds[1]
table.remove(self.allBackGrounds, 1)
table.insert(self.allBackGrounds, firstBg)
firstBg:setPositionY(self.allBackGrounds[#(self.allBackGrounds) - 1]:getPositionY() + self.height)
end

function GameObjectsLayer:update(dt)
if(self._camera:getPositionY() >= g_GameMainLayer.backgroundLayer:getFirstBgTop())then
g_GameMainLayer.backgroundLayer:moveFirstBgToLast()
end
end

这里虽然只使用了2张背景图片,但采用了表格来存储,方便后续扩展到3张、4张或更多背景图片。具体实现可参考Demo的源码。

5. 体验Camera的具体使用

这是一个使用Cocos2d-x 3.3中的Camera开发的新游戏,亲自体验一下可以更深入地了解Camera的使用方法。

6. Demo源码下载

CameraTest

作者信息

feifeila

feifeila

共发布了 3994 篇文章