1、Camera3DDemo
//.h
#include "cocos2d.h"
#include <string>
USING_NS_CC;
#include <string>
namespace cocos2d {
class Sprite3D;
class Delay;
}
enum State
{
State_None = 0,
State_Idle = 0x01,
State_Move = 0x02,
State_Rotate = 0x04,
State_Speak = 0x08,
State_MeleeAttack = 0x10,
State_RemoteAttack = 0x20,
State_Attack = 0x40,
};
enum class CameraType
{
FreeCamera=0,
FirstCamera=1,
ThirdCamera=2,
};
class Camera3DTestDemo : public Layer
{
public:
CREATE_FUNC(Camera3DTestDemo);
Camera3DTestDemo(void);
virtual ~Camera3DTestDemo(void);
virtual void onEnter() override;
virtual void onExit() override;
void addNewSpriteWithCoords(Vec3 p,std::string fileName,bool playAnimation=false,float scale=1.0f,bool bindCamera=false);
void onTouchesBegan(const std::vector<Touch*>& touches, cocos2d::Event *event);
void onTouchesMoved(const std::vector<Touch*>& touches, cocos2d::Event *event);
void onTouchesEnded(const std::vector<Touch*>& touches, cocos2d::Event *event);
void SwitchViewCallback(Ref* sender,CameraType cameraType);
void updateCamera(float fDelta);
void move3D(float elapsedTime);
void updateState(float elapsedTime);
bool isState(unsigned int state,unsigned int bit) const;
bool onTouchesZoomOut(Touch* touch, Event* event);
void onTouchesZoomOutEnd(Touch* touch, Event* event);
bool onTouchesZoomIn(Touch* touch, Event* event);
void onTouchesZoomInEnd(Touch* touch, Event* event);
bool onTouchesRotateLeft(Touch* touch, Event* event);
void onTouchesRotateLeftEnd(Touch* touch, Event* event);
bool onTouchesRotateRight(Touch* touch, Event* event);
void onTouchesRotateRightEnd(Touch* touch, Event* event);
protected:
std::string _title;
Layer* _layer3D;
Sprite3D* _sprite3D;
Vec3 _targetPos;
CameraType _cameraType;
MenuItem* _incRot;
MenuItem* _decRot;
unsigned int _curState;
Camera* _camera;
MoveTo* _moveAction;
bool _bZoomOut;
bool _bZoomIn;
bool _bRotateLeft;
bool _bRotateRight;
Label* _RotateRightlabel;
Label* _RotateLeftlabel;
Label* _ZoomInlabel;
Label* _ZoomOutlabel;
};
.cpp
#include "Camera3DDemo.h"
#include <algorithm>//包含STL库的算法
#include "VisibleRect.h"
class DrawLine3D: public Node
{
public:
//静态创建函数
static DrawLine3D* create();
//画线函数,参数1:起点;参数2:终点;参数3:线段颜色
void drawLine(const Vec3 &from, const Vec3 &to, const Color4F &color);
void clear()
{
_buffer.clear();
}
//真正的绘图函数
void onDraw(const Mat4 &transform, uint32_t flags);
//绘制节点
virtual void draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) override;
CC_CONSTRUCTOR_ACCESS:
DrawLine3D()
{
}
virtual ~DrawLine3D()
{
}
virtual bool init();
protected:
//自定义线段存放的结构体
struct V3F_C4B
{
Vec3 vertices;//线段端点坐标
Color4B colors; //线段颜色
};
//存放线段数据的容器
std::vector<V3F_C4B> _buffer;
//启动自定义绘图
CustomCommand _customCommand;
private:
//CC_DISALLOW_COPY_AND_ASSIGN宏的作用是定义一个类,禁止拷贝和赋值(=)运算符重载功能。
CC_DISALLOW_COPY_AND_ASSIGN(DrawLine3D);
};
DrawLine3D* DrawLine3D::create()
{
//nothrow创建对象失败返回0
auto ret = new (std::nothrow) DrawLine3D();
//对象创建成功
if (ret && ret->init())
return ret;
//对象创建失败
CC_SAFE_DELETE(ret);
return nullptr;
}
bool DrawLine3D::init()
{
//设置节点着色程序
setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_COLOR));
return true;
}
//画线函数
void DrawLine3D::drawLine(const Vec3 &from, const Vec3 &to, const Color4F &color)
{
Color4B col = Color4B(color);//线段颜色
DrawLine3D::V3F_C4B vertex;
vertex.vertices = from;//起点信息
vertex.colors = col;
_buffer.push_back(vertex);
vertex.vertices = to;//终点信息
_buffer.push_back(vertex);
}
//绘制节点函数
void DrawLine3D::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
_customCommand.init(_globalZOrder);
调用真正的绘图函数onDraw
_customCommand.func = CC_CALLBACK_0(DrawLine3D::onDraw, this, transform, flags);
//将着色器程序加入renderer对象
renderer->addCommand(&_customCommand);
}
//真正的调用OpenGL接口绘图,涉及OpenGL知识,暂不了解
void DrawLine3D::onDraw(const Mat4 &transform, uint32_t flags)
{
auto glProgram = getGLProgram();//返回当前节点的GLProgram (shader)
glProgram->use();//调用glUseProgram()函数,使用shader绘图
glProgram->setUniformsForBuiltins(transform);
glEnable(GL_DEPTH_TEST);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B), &(_buffer[0].vertices));
glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_COLOR);
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B), &(_buffer[0].colors));
glDrawArrays(GL_LINES, 0, static_cast<int>(_buffer.size()));
glDisable(GL_DEPTH_TEST);
}
enum
{
IDC_NEXT = 100,
IDC_BACK,
IDC_RESTART
};
Camera3DTestDemo::Camera3DTestDemo(void)
: Layer()
, _camera(nullptr)
, _incRot(nullptr)
, _decRot(nullptr)
,_bZoomOut(false)
,_bZoomIn(false)
,_bRotateLeft(false)
,_bRotateRight(false)
{
}
Camera3DTestDemo::~Camera3DTestDemo(void)
{
}
//旋转视角回调函数
void Camera3DTestDemo::SwitchViewCallback(Ref* sender, CameraType cameraType)
{
//如果当前视角等于要转换的视角,则直接返回
if(_cameraType==cameraType)
{
return ;
}
_cameraType = cameraType;
//如果摄像机类型等于自由视角
if(_cameraType==CameraType::FreeCamera)
{
_camera->setPosition3D(Vec3(0, 130, 130) + _sprite3D->getPosition3D());
_camera->lookAt(_sprite3D->getPosition3D(), Vec3(0,1,0));
_RotateRightlabel->setColor(Color3B::WHITE);
_RotateLeftlabel->setColor(Color3B::WHITE);
_ZoomInlabel->setColor(Color3B::WHITE);
_ZoomOutlabel->setColor(Color3B::WHITE);
}
//如果摄像机类型为第一视角
else if(_cameraType==CameraType::FirstCamera)
{
Vec3 newFaceDir;
//返回逆世界仿射变换矩阵。像素的矩阵。并获取Forward矩阵,参数为目标向量
_sprite3D->getWorldToNodeTransform().getForwardVector(&newFaceDir);
//目标向量标准化,将Vec3对象的x,y,z转化为分数,且x的平方+y的平方+z的平方=1
newFaceDir.normalize();
_camera->setPosition3D(Vec3(0,35,0) + _sprite3D->getPosition3D());
//设置相机的视图矩阵,参数1:target位置,参数2:向上的向量
_camera->lookAt(_sprite3D->getPosition3D() + newFaceDir*50, Vec3(0, 1, 0));
_RotateRightlabel->setColor(Color3B::WHITE);
_RotateLeftlabel->setColor(Color3B::WHITE);
_ZoomInlabel->setColor(Color3B::GRAY);
_ZoomOutlabel->setColor(Color3B::GRAY);
}
//如果摄像机的类型为第三视角
else if(_cameraType==CameraType::ThirdCamera)
{
_camera->setPosition3D(Vec3(0, 130, 130) + _sprite3D->getPosition3D());
//设置相机的视图矩阵。
_camera->lookAt(_sprite3D->getPosition3D(), Vec3(0,1,0));
_RotateRightlabel->setColor(Color3B::GRAY);
_RotateLeftlabel->setColor(Color3B::GRAY);
_ZoomInlabel->setColor(Color3B::WHITE);
_ZoomOutlabel->setColor(Color3B::WHITE);
}
}
void Camera3DTestDemo::onEnter()
{
Layer::onEnter();
_sprite3D=nullptr;
//注册事件
auto s = Director::getInstance()->getWinSize();
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(Camera3DTestDemo::onTouchesBegan, this);
listener->onTouchesMoved = CC_CALLBACK_2(Camera3DTestDemo::onTouchesMoved, this);
listener->onTouchesEnded = CC_CALLBACK_2(Camera3DTestDemo::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
//创建新的层,用于加载3D精灵和线段
auto layer3D=Layer::create();
addChild(layer3D,0);
_layer3D=layer3D;
_curState=State_None;
//添加精灵参数依次为:Vec3向量,精灵文件路径,是否执行动作,缩放系数,是否绑定摄像机
addNewSpriteWithCoords( Vec3(0,0,0),"girl.c3b",true,0.2f,true);
TTFConfig ttfConfig("fonts/arial.ttf", 30);
//依次添加4个Label对象到对应的Node节点上,并对4个Label对象注册监听事件
auto containerForLabel1 = Node::create();
_ZoomOutlabel = Label::createWithTTF(ttfConfig,"zoom out");
_ZoomOutlabel->setPosition(s.width-150, VisibleRect::top().y-30);
containerForLabel1->addChild(_ZoomOutlabel);
addChild(containerForLabel1, 10);
auto listener1 = EventListenerTouchOneByOne::create();
listener1->setSwallowTouches(true);
listener1->onTouchBegan = CC_CALLBACK_2(Camera3DTestDemo::onTouchesZoomOut, this);
listener1->onTouchEnded = CC_CALLBACK_2(Camera3DTestDemo::onTouchesZoomOutEnd, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, _ZoomOutlabel);
auto containerForLabel2 = Node::create();
_ZoomInlabel = Label::createWithTTF(ttfConfig,"zoom in");
_ZoomInlabel->setPosition(s.width-150, VisibleRect::top().y-100);
containerForLabel2->addChild(_ZoomInlabel);
addChild(containerForLabel2, 10);
auto listener2 = EventListenerTouchOneByOne::create();
listener2->setSwallowTouches(true);
listener2->onTouchBegan = CC_CALLBACK_2(Camera3DTestDemo::onTouchesZoomIn, this);
listener2->onTouchEnded = CC_CALLBACK_2(Camera3DTestDemo::onTouchesZoomInEnd, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener2, _ZoomInlabel);
auto containerForLabel3 = Node::create();
_RotateLeftlabel = Label::createWithTTF(ttfConfig,"rotate left");
_RotateLeftlabel->setPosition(s.width-150, VisibleRect::top().y-170);
containerForLabel3->addChild(_RotateLeftlabel);
addChild(containerForLabel3, 10);
auto listener3 = EventListenerTouchOneByOne::create();
listener3->setSwallowTouches(true);
listener3->onTouchBegan = CC_CALLBACK_2(Camera3DTestDemo::onTouchesRotateLeft, this);
listener3->onTouchEnded = CC_CALLBACK_2(Camera3DTestDemo::onTouchesRotateLeftEnd, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener3, _RotateLeftlabel);
auto containerForLabel4 = Node::create();
_RotateRightlabel = Label::createWithTTF(ttfConfig,"rotate right");
_RotateRightlabel->setPosition(s.width-150, VisibleRect::top().y-240);
containerForLabel4->addChild(_RotateRightlabel);
addChild(containerForLabel4, 10);
auto listener4 = EventListenerTouchOneByOne::create();
listener4->setSwallowTouches(true);
listener4->onTouchBegan = CC_CALLBACK_2(Camera3DTestDemo::onTouchesRotateRight, this);
listener4->onTouchEnded = CC_CALLBACK_2(Camera3DTestDemo::onTouchesRotateRightEnd, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener4, _RotateRightlabel);
//设置摄像机视角菜单选项,并回调转换视角函数
auto label1 = Label::createWithTTF(ttfConfig,"free ");
auto menuItem1 = MenuItemLabel::create(label1, CC_CALLBACK_1(Camera3DTestDemo::SwitchViewCallback,this,CameraType::FreeCamera));
auto label2 = Label::createWithTTF(ttfConfig,"third person");
auto menuItem2 = MenuItemLabel::create(label2, CC_CALLBACK_1(Camera3DTestDemo::SwitchViewCallback,this,CameraType::ThirdCamera));
auto label3 = Label::createWithTTF(ttfConfig,"first person");
auto menuItem3 = MenuItemLabel::create(label3, CC_CALLBACK_1(Camera3DTestDemo::SwitchViewCallback,this,CameraType::FirstCamera));
auto menu = Menu::create(menuItem1, menuItem2, menuItem3, nullptr);
menu->setPosition(Vec2::ZERO);
menuItem1->setPosition(VisibleRect::left().x+100, VisibleRect::top().y-50);
menuItem2->setPosition(VisibleRect::left().x+100, VisibleRect::top().y -100);
menuItem3->setPosition(VisibleRect::left().x+100, VisibleRect::top().y -150);
addChild(menu, 0);
//设置自定义更新器,时间间隔为0.0秒
schedule(CC_SCHEDULE_SELECTOR(Camera3DTestDemo::updateCamera), 0.0f);
if (_camera == nullptr)
{
//初始化相机
_camera=Camera::createPerspective(60, (GLfloat)s.width/s.height, 1, 1000);
_camera->setCameraFlag(CameraFlag::USER1);
_layer3D->addChild(_camera);
}
//首先执行视角切换回调函数,先切换到第三视角
SwitchViewCallback(this,CameraType::ThirdCamera);
//创建3D画线类对象
DrawLine3D* line =DrawLine3D::create();
//draw x
for( int j =-20; j<=20 ;j++)
{
//将线段信息存入vector,调用draw绘图,实质是onDraw进行绘制
line->drawLine(Vec3(-100, 0, 5*j),Vec3(100,0,5*j),Color4F(1,0,0,1));
}
//draw z
for( int j =-20; j<=20 ;j++)
{
//将线段信息存入vector,调用draw绘图,实质是onDraw进行绘制
line->drawLine(Vec3(5*j, 0, -100),Vec3(5*j,0,100),Color4F(0,0,1,1));
}
//draw y //绘制y轴方向的两条线段
line->drawLine(Vec3(0, -50, 0),Vec3(0,0,0),Color4F(0,0.5,0,1));
line->drawLine(Vec3(0, 0, 0),Vec3(0,50,0),Color4F(0,1,0,1));
_layer3D->addChild(line);
//设置mask,使得其对相机可见
_layer3D->setCameraMask(2);
}
//onExit函数,退出当前层时执行
void Camera3DTestDemo::onExit()
{
Layer::onExit();
if (_camera)
{
_camera = nullptr;
}
}
//添加精灵,参数1:精灵坐标,参数2:精灵文件路径,参数3:是否执行动作,参数4:缩放系数,参数5:是否绑定摄像机
void Camera3DTestDemo::addNewSpriteWithCoords(Vec3 p,std::string fileName,bool playAnimation,float scale,bool bindCamera)
{
//创建3D精灵
auto sprite = Sprite3D::create(fileName);
_layer3D->addChild(sprite);
float globalZOrder=sprite->getGlobalZOrder();
//设置精灵的坐标和全局Z轴顺序
sprite->setPosition3D( Vec3( p.x, p.y,p.z) );
sprite->setGlobalZOrder(globalZOrder);
if(playAnimation)
{
//首先通过骨骼节点创建骨骼动画
auto animation = Animation3D::create(fileName,"Take 001");
if (animation)
{
//执行3D动画
auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
}
//如果绑定摄像机,将sprite赋值给_sprite3D对象
if(bindCamera)
{
_sprite3D=sprite;
}
sprite->setScale(scale);
}
//多点触摸
void Camera3DTestDemo::onTouchesBegan(const std::vector<Touch*>& touches, cocos2d::Event *event)
{
for ( auto &item: touches )
{
auto touch = item;
auto location = touch->getLocation();
}
}
//多点触摸移动,即点击线段区域,精灵移动过去
void Camera3DTestDemo::onTouchesMoved(const std::vector<Touch*>& touches, cocos2d::Event *event)
{
if(touches.size()==1)
{
auto touch = touches[0];
//获取第一个触摸点的OpenGL坐标系的坐标,原点在屏幕左下角。
//补充:屏幕坐标系,原点在屏幕左上角
//世界坐标系:与OpenGL坐标系一致,位于屏幕左下角
//节点坐标系:父节点的左下角,与OpenGL一致
auto location = touch->getLocation();
Point newPos = touch->getPreviousLocation()-location;
if(_cameraType==CameraType::FreeCamera || _cameraType==CameraType::FirstCamera)
{
Vec3 cameraDir;
Vec3 cameraRightDir;
//返回世界仿射变换矩阵。矩阵单位是像素。并获取Forward矩阵,参数为目标向量。注意逆世界仿射变换矩阵
_camera->getNodeToWorldTransform().getForwardVector(&cameraDir);
//将返回的矩阵向量规范化
cameraDir.normalize();
//将返回的矩阵向量y轴赋值为0
cameraDir.y=0;
//返回正确的举证向量的世界仿射变化矩阵
_camera->getNodeToWorldTransform().getRightVector(&cameraRightDir);
//向量规范化
cameraRightDir.normalize();
//向量y轴赋值0
cameraRightDir.y=0;
Vec3 cameraPos= _camera->getPosition3D();
cameraPos+=cameraDir*newPos.y*0.1f;
cameraPos+=cameraRightDir*newPos.x*0.1f;
//重新设置摄像机的3D坐标
_camera->setPosition3D(cameraPos);
//如果精灵存在,且相机的类型为第一视角,执行下面代码
if(_sprite3D && _cameraType==CameraType::FirstCamera)
{
//设置精灵的3D坐标,并保存当前精灵坐标值,用于更新任务运动状态
_sprite3D->setPosition3D(Vec3(_camera->getPositionX(),0,_camera->getPositionZ()));
_targetPos=_sprite3D->getPosition3D();
}
}
}
}
//3D精灵移动
void Camera3DTestDemo::move3D(float elapsedTime)
{
if(_sprite3D)
{
//获取当前精灵的3D坐标
Vec3 curPos= _sprite3D->getPosition3D();
//计算原来坐标与新坐标的向量
Vec3 newFaceDir = _targetPos - curPos;
//将y轴赋值为0,并将新向量规范化
newFaceDir.y = 0.0f;
newFaceDir.normalize();
//计算偏移
Vec3 offset = newFaceDir * 25.0f * elapsedTime;
curPos+=offset;
//设置精灵的新坐标
_sprite3D->setPosition3D(curPos);
offset.x=offset.x;
offset.z=offset.z;
if(_cameraType==CameraType::ThirdCamera)
{
//如果摄像机的类型为第三视角,同时更新摄像机的3D坐标
Vec3 cameraPos= _camera->getPosition3D();
cameraPos.x+=offset.x;
cameraPos.z+=offset.z;
_camera->setPosition3D(cameraPos);
}
}
}
//判断精灵的状态
void Camera3DTestDemo::updateState(float elapsedTime)
{
if(_sprite3D)
{
Vec3 curPos= _sprite3D->getPosition3D();
Vec3 curFaceDir;
//返回世界仿射变换矩阵。矩阵单位是像素。并获取Forward矩阵,参数为目标向量。注意逆世界仿射变换矩阵
_sprite3D->getNodeToWorldTransform().getForwardVector(&curFaceDir);
curFaceDir=-curFaceDir;
curFaceDir.normalize();
Vec3 newFaceDir = _targetPos - curPos;
newFaceDir.y = 0.0f;
newFaceDir.normalize();
//计算两个向量的点积,通过返回的值判断精灵运动方向和是否停止
float cosAngle = std::fabs(Vec3::dot(curFaceDir,newFaceDir) - 1.0f);
//返回两个向量的平方距离
float dist = curPos.distanceSquared(_targetPos);
if(dist<=4.0f)
{
if(cosAngle<=0.01f)
_curState = State_Idle;
else
_curState = State_Rotate;
}
else
{
if(cosAngle>0.01f)
_curState = State_Rotate | State_Move;
else
_curState = State_Move;
}
}
}
void Camera3DTestDemo::onTouchesEnded(const std::vector<Touch*>& touches, cocos2d::Event *event)
{
for ( auto &item: touches )
{
auto touch = item;
auto location = touch->getLocationInView();
if(_camera)
{
if(_sprite3D && _cameraType==CameraType::ThirdCamera && _bZoomOut == false && _bZoomIn == false && _bRotateLeft == false && _bRotateRight == false)
{
Vec3 nearP(location.x, location.y, -1.0f), farP(location.x, location.y, 1.0f);
auto size = Director::getInstance()->getWinSize();
_camera->unproject(size, &nearP, &nearP);
_camera->unproject(size, &farP, &farP);
Vec3 dir(farP - nearP);
float dist=0.0f;
float ndd = Vec3::dot(Vec3(0,1,0),dir);
if(ndd == 0)
dist=0.0f;
float ndo = Vec3::dot(Vec3(0,1,0),nearP);
dist= (0 - ndo) / ndd;
Vec3 p = nearP + dist * dir;
if( p.x > 100)
p.x = 100;
if( p.x < -100)
p.x = -100;
if( p.z > 100)
p.z = 100;
if( p.z < -100)
p.z = -100;
_targetPos=p;
}
}
}
}
void onTouchesCancelled(const std::vector<Touch*>& touches, cocos2d::Event *event)
{
}
//更新视图
void Camera3DTestDemo::updateCamera(float fDelta)
{
if(_sprite3D)
{
if( _cameraType==CameraType::ThirdCamera)
{
//摄像机类型为第三视角,判断精灵的运动状态
updateState(fDelta);
//如果精灵正在行走
if(isState(_curState,State_Move))
{
//使精灵和相机为行走状态
move3D(fDelta);
//如果行走在转身
if(isState(_curState,State_Rotate))
{
Vec3 curPos = _sprite3D->getPosition3D();
Vec3 newFaceDir = _targetPos - curPos;
newFaceDir.y = 0;
newFaceDir.normalize();
Vec3 up;
_sprite3D->getNodeToWorldTransform().getUpVector(&up);
up.normalize();
Vec3 right;
Vec3::cross(-newFaceDir,up,&right);
right.normalize();
Vec3 pos = Vec3(0,0,0);
Mat4 mat;
mat.m[0] = right.x;
mat.m[1] = right.y;
mat.m[2] = right.z;
mat.m[3] = 0.0f;
mat.m[4] = up.x;
mat.m[5] = up.y;
mat.m[6] = up.z;
mat.m[7] = 0.0f;
mat.m[8] = newFaceDir.x;
mat.m[9] = newFaceDir.y;
mat.m[10] = newFaceDir.z;
mat.m[11] = 0.0f;
mat.m[12] = pos.x;
mat.m[13] = pos.y;
mat.m[14] = pos.z;
mat.m[15] = 1.0f;
//设置额外的节点变换矩阵
_sprite3D->setAdditionalTransform(&mat);
}
}
}
//如果执行缩小动作
if(_bZoomOut == true)
{
if(_camera)
{
//摄像机类型为第三视角
if(_cameraType == CameraType::ThirdCamera)
{
Vec3 lookDir = _camera->getPosition3D() - _sprite3D->getPosition3D();
Vec3 cameraPos = _camera->getPosition3D();
//求得相机与精灵的空间距离
if(lookDir.length() <= 300)
{
//相机位置增加,且不改变相机与精灵的相对位置
cameraPos += lookDir.getNormalized();
_camera->setPosition3D(cameraPos);
}
}
//如果是自由视角
else if(_cameraType == CameraType::FreeCamera)
{
Vec3 cameraPos = _camera->getPosition3D();
if(cameraPos.length() <= 300)
{
//相机距离增加
cameraPos += cameraPos.getNormalized();
_camera->setPosition3D(cameraPos);
}
}
}
}
//如果是放大效果
if(_bZoomIn == true)
{
if(_camera)
{
//相机是第三视角
if(_cameraType == CameraType::ThirdCamera)
{
Vec3 lookDir = _camera->getPosition3D() - _sprite3D->getPosition3D();
Vec3 cameraPos = _camera->getPosition3D();
if(lookDir.length() >= 50)
{
//相机与精灵的距离大于50,才会执行下面操作
//相机位置增加
cameraPos -= lookDir.getNormalized();
_camera->setPosition3D(cameraPos);
}
}
//如果为自由视角
else if(_cameraType == CameraType::FreeCamera)
{
Vec3 cameraPos = _camera->getPosition3D();
if(cameraPos.length() >= 50)
{
//相机位置增加
cameraPos -= cameraPos.getNormalized();
_camera->setPosition3D(cameraPos);
}
}
}
}
//如果是左转效果
if(_bRotateLeft == true)
{
//如果相机类型为自由视角和第一视角
if(_cameraType==CameraType::FreeCamera || _cameraType==CameraType::FirstCamera)
{
//y轴增加旋转
Vec3 rotation3D= _camera->getRotation3D();
rotation3D.y+= 1;
_camera->setRotation3D(rotation3D);
}
}
//如果是右转效果
if(_bRotateRight == true)
{
if(_cameraType==CameraType::FreeCamera || _cameraType==CameraType::FirstCamera)
{
//摄像机类型为自由视角和第一视角,y轴减少旋转
Vec3 rotation3D= _camera->getRotation3D();
rotation3D.y-= 1;
_camera->setRotation3D(rotation3D);
}
}
}
}
//判断精灵的运动状态
bool Camera3DTestDemo::isState(unsigned int state,unsigned int bit) const
{
return (state & bit) == bit;
}
//缩小触摸事件
bool Camera3DTestDemo::onTouchesZoomOut(Touch* touch, Event* event)
{
auto target = static_cast<Label*>(event->getCurrentTarget());
//将触摸点的位置转化为节点坐标位置
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
//如果触摸在节点内
if (rect.containsPoint(locationInNode))
{
_bZoomOut = true;
return true;
}
return false;
}
//缩小触摸结束
void Camera3DTestDemo::onTouchesZoomOutEnd(Touch* touch, Event* event)
{
_bZoomOut = false;
}
//放大触摸事件
bool Camera3DTestDemo::onTouchesZoomIn(Touch* touch, Event* event)
{
auto target = static_cast<Label*>(event->getCurrentTarget());
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
//如果在节点内,设置放大判断值为true
if (rect.containsPoint(locationInNode))
{
_bZoomIn = true;
return true;
}
return false;
}
//放大触摸结束
void Camera3DTestDemo::onTouchesZoomInEnd(Touch* touch, Event* event)
{
_bZoomIn = false;
}
//左转触摸
bool Camera3DTestDemo::onTouchesRotateLeft(Touch* touch, Event* event)
{
auto target = static_cast<Label*>(event->getCurrentTarget());
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
//设置左转触摸为true
if (rect.containsPoint(locationInNode))
{
_bRotateLeft = true;
return true;
}
return false;
}
void Camera3DTestDemo::onTouchesRotateLeftEnd(Touch* touch, Event* event)
{
//左转触摸结束,恢复判断值为false
_bRotateLeft = false;
}
//右转触摸
bool Camera3DTestDemo::onTouchesRotateRight(Touch* touch, Event* event)
{
auto target = static_cast<Label*>(event->getCurrentTarget());
Vec2 locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
//设置右转触摸判断值为true;
if (rect.containsPoint(locationInNode))
{
_bRotateRight = true;
return true;
}
return false;
}
//触摸结束,恢复右转判断触摸值为false
void Camera3DTestDemo::onTouchesRotateRightEnd(Touch* touch, Event* event)
{
_bRotateRight = false;
}
2、使用
在HelloWorld的createScene中,直接创建Camera3DDemo的Layer对象,加入Scene