cocos2d-x游戏开发 跑酷(五) 跳起和下蹲动作 手势识别

来源:互联网 发布:房屋平面图设计软件 编辑:程序博客网 时间:2024/05/02 02:19

转载请注明出处:http://blog.csdn.net/dawn_moon/article/details/22051929

人物已经可以跑动起来了,但是还仅仅只是一个单调的跑动,还会跑出屏幕。先实现一个无限滚动背景。


实现滚动背景有几个方式:

1.人物位置不动,背景滚动。我之前的天天飞翔是用的这种,不过那个背景移动是用的动画,两张图片重复动作滚动。还有之前的雷电,也是背景滚动。不过实现有点区别,是循环改变背景的Y坐标来实现的。

2.人物移动,当前层跟随人物,使用CCFollow。详细用法有兴趣可以自己搜索。

3.人物移动,摄像机跟随。这里用的就是第三种方式。


先解释一下CCCamera摄像机的概念:

OpenGL有个视点转换函数gluLookAt函数,原型:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);  

第一组eyex, eyey,eyez 相机在世界坐标的位置
第二组centerx,centery,centerz 目标参考物体在世界坐标的位置
第三组upx,upy,upz 相机竖直方向在世界坐标中的方向向量


你把相机想象成为你自己的脑袋:
第一组数据就是脑袋的位置
第二组数据就是眼睛看的物体的位置
第三组就是头顶朝向的方向(因为你可以歪着头看同一个物体)。

CCCamera的概念跟这个类似。

为什么调整eyez的值可以实现缩放。Z值就是摄像机离物体距离,拿眼睛看一个物体,离物体远,看起来物体小,离物体近,物体看起来大。

这里我们不调整eyez的值,因为不做缩放,用默认就好。

需要调整摄像机X坐标和参考目标的X坐标,让摄像机跟随人物移动:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. mLastEyeX = mRunner->getRunnerPX() - mRunner->getOffsetPx();  
  2. CCCamera* camera = this->getCamera();  
  3. float eyeZ = CCCamera::getZEye();  
  4. camera->setEyeXYZ(mLastEyeX, 0, eyeZ);  
  5. camera->setCenterXYZ(mLastEyeX, 0, 0);  

我用手势控制人物跳起和蹲下,但是我懒的弄那个手势识别的库就直接用了SimpleRecognizer,识别上下左右的滑动,向上滑动就跳起,向下滑动就蹲下。先来看动作,Runner.cpp里面:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::initAction()  
  2. {  
  3.     CCArray* animateFrames = CCArray::create();  
  4.     char str[50] = {0};  
  5.     for (int i = 0; i != 8; ++i) {  
  6.         sprintf(str, "runner%d.png", i);  
  7.         animateFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(str));  
  8.     }  
  9.     CCAnimation* animationRunning = CCAnimation::createWithSpriteFrames(animateFrames, 0.1);  
  10.     // 设置无限循环  
  11.     animationRunning->setLoops(-1);  
  12.     // 循环动画貌似可以不设置这个  
  13.     animationRunning->setRestoreOriginalFrame(true);  
  14.     // running animation 命名  
  15.     CCAnimationCache::sharedAnimationCache()->addAnimation(animationRunning, "running");  
  16.       
  17.     // jumpUpAction  
  18.     animateFrames->removeAllObjects();  
  19.     for (int i = 0; i != 4; ++i) {  
  20.         sprintf(str, "runnerJumpUp%d.png",i);  
  21.         animateFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(str));  
  22.     }  
  23.     CCAnimation* animationJumpUp = CCAnimation::createWithSpriteFrames(animateFrames, 0.2);  
  24.     // 动画完毕停在最后一帧  
  25.     animationJumpUp->setRestoreOriginalFrame(false);  
  26.     // jumpUp animation 命名  
  27.     CCAnimationCache::sharedAnimationCache()->addAnimation(animationJumpUp, "jumpUp");  
  28.       
  29.     // jumpDownAction  
  30.     animateFrames->removeAllObjects();  
  31.     for (int i = 0; i != 2; ++i) {  
  32.         sprintf(str, "runnerJumpDown%d.png",i);  
  33.         animateFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(str));  
  34.     }  
  35.     CCAnimation* animationJumpDown = CCAnimation::createWithSpriteFrames(animateFrames, 0.3);  
  36.     animationJumpDown->setRestoreOriginalFrame(false);  
  37.     // jumpDown animation 命名  
  38.     CCAnimationCache::sharedAnimationCache()->addAnimation(animationJumpDown, "jumpDown");  
  39.       
  40.     // crouchAction  
  41.     animateFrames->removeAllObjects();  
  42.     animateFrames->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("runnerCrouch0.png"));  
  43.     CCAnimation* animationCrouch = CCAnimation::createWithSpriteFrames(animateFrames,0.3);  
  44.     animationCrouch->setRestoreOriginalFrame(false);  
  45.     // crouch animation 命名  
  46.     CCAnimationCache::sharedAnimationCache()->addAnimation(animationCrouch, "crouch");  
  47.       
  48. }  

生产序列帧的流程:

-- 生成单帧

-- 将序列帧存入数组

-- 用帧数组生成CCAnimation

-- 将animation存入缓存,取别名(用的时候通过名字取出即可)


这里值得注意的是需要设置帧间隔和是否恢复第一帧(setRestoreOriginalFrame)

setRestoreOriginalFrame这个函数看名字有点难理解,不过我试过后发现是恢复第一帧,就是说如果设为true,那么动画播放完毕后就会停留在第一帧,如果设为false则停在最后一帧。


动作初始化完毕后,要用的时候通过名字调用:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::runAction(const char *action)  
  2. {  
  3.     // 通过名字获取animation  
  4.     CCAnimation* animation = CCAnimationCache::sharedAnimationCache()->animationByName(action);  
  5.     mRunner->runAction(CCAnimate::create(animation));  
  6. }  

我们要为人物添加跳起和蹲下的动作,由于人物和一个物理刚体关联,就需要对物体的初始化做相应修改。人物跑动和人物蹲下的中心坐标是不一样的,同时其物理性状大小也不一样,修改如下:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::initShape(const char* type)  
  2. {  
  3.     // 如果物体已经有一个形状则删掉  
  4.     if(mBody->GetFixtureList())  
  5.     {  
  6.         mBody->DestroyFixture(mBody->GetFixtureList());  
  7.     }  
  8.     if (strcmp(type,"running") == 0)  
  9.     {  
  10.         // 人物站立,中心改变,调整位置  
  11.         mBody->SetTransform(b2Vec2(mBody->GetPosition().x, (GROUND_HEIGHT + mRunnerSize.height / 2) / RATIO), mBody->GetAngle());  
  12.           
  13.         // 定义runner的形状,一个box,参数是半宽高  
  14.         mShape.SetAsBox(mRunnerSize.width / 2 / RATIO, mRunnerSize.height / 2 / RATIO);  
  15.           
  16.   
  17.     }else  
  18.     {  
  19.         // 由于人物下蹲的大小和站立大小不一致,所以要下调位置  
  20.         mBody->SetTransform(b2Vec2(mBody->GetPosition().x, (GROUND_HEIGHT + mCrouchSize.height / 2) / RATIO) ,mBody->GetAngle());  
  21.           
  22.         // 定义runner下蹲的形状,一个box,参数是半宽高  
  23.         mShape.SetAsBox(mCrouchSize.width / 2 / RATIO, mCrouchSize.height / 2 / RATIO);  
  24.     }  
  25.     b2FixtureDef fixDef;  
  26.     fixDef.friction = 0.0f;  
  27.     fixDef.shape = &mShape;  
  28.     mBody->CreateFixture(&fixDef);  
  29. }  

好了,只要识别向上的手势就跳起,向下滑动就蹲下,看跳起和蹲下的函数:
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::jump()  
  2. {  
  3.     if (mState == RunnerStateRunning) {  
  4.         float impulse = mBody->GetMass() * 10;  
  5.         // 根据物体质量,施加一个向上的力,人物就会跳起  
  6.         mBody->ApplyLinearImpulse(b2Vec2(0, impulse), mBody->GetWorldCenter());  
  7.         mState = RunnerStateJumpUp;  
  8.         mRunner->stopAllActions();  
  9.         runAction("jumpUp");  
  10.         SimpleAudioEngine::sharedEngine()->playEffect(jumpmusic);  
  11.     }  
  12. }  
  13.   
  14. void Runner::crouch()  
  15. {  
  16.     if (mState == RunnerStateRunning) {  
  17.         this->initShape("crouch");  
  18.         mRunner->stopAllActions();  
  19.         runAction("crouch");  
  20.         mState = RunnerStateCrouch;  
  21.         scheduleOnce(schedule_selector(Runner::loadNormal), 1.5);  
  22.         SimpleAudioEngine::sharedEngine()->playEffect(crouchmusic);  
  23.     }  
  24. }  

人物蹲下后怎样恢复跑动的状态呢,直接1.5秒后调用loadNormal函数就好:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::loadNormal()  
  2. {  
  3.     initShape("running");  
  4.     mRunner->stopAllActions();  
  5.     runAction("running");  
  6.     mState = RunnerStateRunning;  
  7. }  

人物跳起的动作分jumpUp和jumpDown,怎么样区分?

判断人物在Y轴上的速度分量,给物体一个向上的力,物体会在单步时间段内加速到指定速度,由于重力加速度的存在,Y轴速度会递减。这里的做法是,当物体速度小于0.1时开始到达顶点,那么切换状态到RunnerStateJumpDown同时切换jumpDown的动画。在RunnerStateJumpDown状态时,如果Y轴速度变为0,就是到达地面了。

毫无疑问,这些迭代要写在update函数里面:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void Runner::update(float dt)  
  2. {  
  3.     b2Vec2 vel = mBody->GetLinearVelocity();  
  4.     if (mState == RunnerStateJumpUp) {  
  5.         if (vel.y < 0.1) {  
  6.             mState = RunnerStateJumpDown;  
  7.             mRunner->stopAllActions();  
  8.             runAction("jumpDown");  
  9.         }  
  10.     }  
  11.       
  12.     if (mState == RunnerStateJumpDown) {  
  13.         if (vel.y == 0) {  
  14.             mState = RunnerStateRunning;  
  15.             mRunner->stopAllActions();  
  16.             runAction("running");  
  17.         }  
  18.     }  
  19.       
  20. }  

好了,这些都做完了,在PlayScene.cpp里面修改update函数

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void PlayScene::update(float dt)  
  2. {  
  3.     // 物理世界的迭代函数  
  4.     mWorld->Step(dt, 10, 8);  
  5.   
  6.     // 移动相机实现滚动地图  
  7.     mLastEyeX = mRunner->getRunnerPX() - mRunner->getOffsetPx();  
  8.     CCCamera* camera = this->getCamera();  
  9.     float eyeZ = CCCamera::getZEye();  
  10.     camera->setEyeXYZ(mLastEyeX, 0, eyeZ);  
  11.     camera->setCenterXYZ(mLastEyeX, 0, 0);  
  12.       
  13.     // runner状态迭代  
  14.     mRunner->update(dt);  
  15. }  

看下效果:

0 0
原创粉丝点击