Cocos2d-x 3.3版本中加入了相机这个类,该类在3D游戏中是必不可少的,在3D立体游戏中,往往需要视野角度的变化,通过相机的变换才能观察和体验整个游戏世界。
CCCamera类基本使用
在游戏中一般有两种类型的相机:一种是透视相机,它在3D游戏中十分常见;另一种是正交相机,它没有透视相机的近大远小的效果而是相机内任何位置的物体大小比例都是一样的。
上图是透视相机的原理图,一般来说,我们通过以下代码创建:
_camera = Camera::createPerspective(60, (GLfloat)s.width/s.height, 1, 1000);
上面的代码就是创建了一个透视投影的相机,下面我来说明下参数的意义:第一个参数是FOV,即视场角(field of view),它可以理解为你的视线左右能看多宽(以角度计)第二个就是上述所有的宽高比,最后两个是相机的近裁面和远裁面,这个也很好理解,距离相机比近裁面还要近的,比远裁面还要远的,都不会被渲染到。
上图是正交相机的原理图,一般来说,我们通过以下代码创建:
_camera = Camera::createOrthographic(s.width, s.height, 1,1000);
上面的代码就是创建了一个正交投影的相机,下面我来说明下参数的意义:第一个参数是相机的宽度,第二个就是相机的高度,最后两个是相机的近裁面和远裁面,这个也很好理解,距离相机比近裁面还要近的,比远裁面还要远的,都不会被渲染到。这个和透视相机是一样的。
接下来,我们需要对相机设置一个标记位(FLAG),这样可以让相机与其他的相机区分开来–在一些游戏的应用中,通常不仅仅只有一个相机,如果有多个相机的话,那么我们要标记一个物体,到底是要被哪一个相机所”看到”,这时候,我们就需要设置它的CameraMask来与相机的Flag对应:
_layer3D->setCameraMask(2);
_camera->setCameraFlag(CameraFlag::USER1);
这样_layer3D就能被_camera看到。
注意到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,
};
Node中有个_cameraMask的属性,当相机的_cameraFlag & _cameraMask为true时,该Node可以被该相机看到。所以在上述相机的创建代码中,camera的CameraFlag设置为CameraFlag::USER1,并且该layer的CameraMask为2,则表示该layer只能被CameraFlag::USER1相机看到。如果你设置的精灵的cameraMask是3的话,它也是能被cameraFlag为CameraFlag::USER1和CameraFlag::USER2的相机看到的。我们还要注意如果你的精灵是在layer设置cameraMask之后添加的,它是不会被看到的,还需要手动再设置精灵的cameraMask。不要以为这样就可以了,最后我们还要把相机添加到场景中,不然我们还是看不到效果的,一定要记住呀,下图就是把相机加到场景中的代码:
_layer3D->addChild(_camera);
这样,通过设置相机的位置,角度等参数就能实现不同视角观察游戏世界。
CCCamera类源码分析
下面是CCCamera.h文件内容:
#ifndef _CCCAMERA_H__
#define _CCCAMERA_H__
#include "2d/CCNode.h"
#include "3d/CCFrustum.h"
#include "renderer/CCQuadCommand.h"
#include "renderer/CCCustomCommand.h"
#include "renderer/CCFrameBuffer.h"
NS_CC_BEGIN
class Scene;
class CameraBackgroundBrush;
/**
相机标识,每个Node中有个_cameraMask的属性,当相机的_cameraFlag & _cameraMask为true时,该Node可以被该相机看到。
*/
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,
};
/**
定义一个相机类,该类继承于Node。
*/
class CC_DLL Camera :public Node
{
/**
友元类有场景类,导演类以及事件分发类。
*/
friend class Scene;
friend class Director;
friend class EventDispatcher;
public:
;/**
枚举类标记:透视相机和正交相机。
*/
enum class Type
{
PERSPECTIVE = 1,
ORTHOGRAPHIC = 2
};
public:
;/**
创建一个透视相机。
参数:
fieldOfView 透视相机的可视角度 (一般是在40-60度之间).
aspectRatio 相机的长宽比(通常会使用视窗的宽度除以视窗的高度)。
nearPlane 近平面的距离。
farPlane 远平面的距离。
*/
static Camera* createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane);
/**
创建一个正交相机。
参数:
zoomX 沿x轴的正交投影的缩放因子(正交投影的宽度)。
zoomY 沿y轴的正交投影的缩放因子(正交投影的高度)。
nearPlane 近平面的距离。
farPlane 远平面的距离。
*/
static Camera* createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane);
/**
创建默认的相机,相机的类型取决于Director::getProjection,默认的相机深度是0
*/
static Camera* create();
/**
获取相机类型。
*/
Camera::Type getType() const { return _type; }
/**
获取和设置相机标识。类型为枚举类和无符号短整型。
*/
CameraFlag getCameraFlag() const { return (CameraFlag)_cameraFlag; }
void setCameraFlag(CameraFlag flag) { _cameraFlag = (unsigned short)flag; }
/**
使相机看着目标
参数:
target 目标的位置
up 相机向上的向量,通常这是Y轴
*/
virtual void lookAt(const Vec3& target, const Vec3& up = Vec3::UNIT_Y);
/**
获取相机的投影矩阵。
返回:
相机投影矩阵。
*/
const Mat4& getProjectionMatrix() const;
/**
获取相机的视图矩阵。
返回:
相机视图矩阵。
*/
const Mat4& getViewMatrix() const;
/**
得到视图投影矩阵。
*/
const Mat4& getViewProjectionMatrix() const;
/*
把指定坐标点从世界坐标转换为屏幕坐标。 原点在GL屏幕坐标系的左下角。
参数:
src 世界的位置。
返回:
屏幕的位置。
*/
Vec2 project(const Vec3& src) const;
/*
把指定坐标点从3D世界坐标转换为屏幕坐标。 原点在GL屏幕坐标系的左下角。
参数:
src 3D世界的位置。
返回:
GL屏幕空间的位置。
*/
Vec2 projectGL(const Vec3& src) const;
/**
把指定坐标点从屏幕坐标转换为世界坐标。 原点在GL屏幕坐标系的左下角。
参数:
src 屏幕的位置。
返回:
世界的位置。
*/
Vec3 unproject(const Vec3& src) const;
/**
把指定坐标点从屏幕坐标转换为3D世界坐标。 原点在GL屏幕坐标系的左下角。
参数
src GL屏幕空间的位置。
返回
3D世界的位置。
*/
Vec3 unprojectGL(const Vec3& src) const;
/**
把指定坐标点从屏幕坐标转换为世界坐标。 原点在GL屏幕坐标系的左下角。
参数
size 使用的视窗大小。
src 屏幕的位置。
dst 世界的位置。
*/