用《捕鱼达人3》讲解Cocos引擎3D技术(三):闪电特效

之前我们已经学习了《捕鱼达人3》中Cocos引擎3D技术的实现:加载鱼的模型和播放动画 和 鱼身上的波光处理,今天我们接着学习游戏中如何制作攻击时的闪电特效。 《捕鱼达人》中的闪电,是

(via:Cocos引擎中文站

 

之前我们已经学习了《捕鱼达人3》中Cocos引擎3D技术的实现:加载鱼的模型和播放动画 和 鱼身上的波光处理,今天我们接着学习游戏中如何制作攻击时的闪电特效。

 

《捕鱼达人》中的闪电,是通过以下几个步骤来实现的:

一、构建三角形条带。

二、采用随机函数来扰动条带顶点。

三、快速反复循环一,二步骤。

 

这个过程主要使用到以下三个类:

(1)VertexVector:用于存储顶点和索引的类。

(2)Noise:噪音处理类,用于进行顶点扰动,使顶点不断的小幅变化。

(3)LightLineRender:实现闪电效果的类。

 

具体的代码实现,可以参看注释。我们要关心的是LightLineRender类,它封装了闪电效果,并提供了相应的参数调节选项,我们学会了使用它就可以做出闪电链的效果。

 

我们打开 cpp-empty-test ,在 HelloWorld::init 函数中加入以下代码:

     
  1. //线条容器 
  2. std::vector<LightLineRender::Line> lines; 
  3. //设置线条位置 
  4. //第一段闪电的起点和终点 
  5. Vec3 segStart = Vec3(-50,-50,-8); 
  6. Vec3 segEnd   = Vec3(50,50,-8); 
  7. lines.push_back( LightLineRender::Line( segStart, segEnd, 0 ) ); 
  8. //第二段闪电的起点和终点 
  9. segStart = Vec3(50,50,-8); 
  10. segEnd   = Vec3(-50,50,-8); 
  11. lines.push_back( LightLineRender::Line( segStart, segEnd, 0 ) ); 
  12. //第三段闪电的起点和终点 
  13. segStart = Vec3(-50,50,-8); 
  14. segEnd   = Vec3(50,-50,-8); 
  15. lines.push_back( LightLineRender::Line( segStart, segEnd, 0 ) ); 
  16. //第四段闪电的起点和终点 
  17. segStart = Vec3(50,-50,-8); 
  18. segEnd   = Vec3(0,100,-8); 
  19. lines.push_back( LightLineRender::Line( segStart, segEnd, 0 ) ); 
  20. //第五段闪电的起点和终点 
  21. segStart = Vec3(0,100,-8); 
  22. segEnd   = Vec3(-50,-50,-8); 
  23. lines.push_back( LightLineRender::Line( segStart, segEnd, 0 ) ); 
  24. //创建出闪光链 
  25. LightLineRender*    _lighting = LightLineRender::create(); 
  26. //设置不需要强制纹理循环 
  27. _lighting->setForceTexLoop( false ); 
  28. //设置宽 
  29. _lighting->setWidth( 80 ); 
  30. //设置 单张纹理长度,调整这个数值可以避免纹理过度拉伸或挤压 
  31. _lighting->setTextueLength( 100 ); 
  32. //设置单个面片网格长,越小曲线越平滑,数值过于小可能带来效率问题 
  33. _lighting->setStep( 10 ); 
  34. //设置振幅1 
  35. _lighting->setAmplitude0( 4 ); 
  36. //设置频率1 
  37. _lighting->setFrequency0( 500 ); 
  38. //设置振幅2 
  39. _lighting->setAmplitude1( 1 ); 
  40. //设置频率2 
  41. _lighting->setFrequency1( 400 ); 
  42. //设置产生噪音的时间系数 
  43. _lighting->setTimeFactor( 0.5 ); 
  44. //使用线段容器创建闪电链 
  45. _lighting->setLines( lines ); 
  46. //使用柏林噪音算法 
  47. _lighting->setLineType( LineType::LT_PerlinNosie ); 
  48. //设置每帧强制更新重建模型 
  49. _lighting->setForceUpdate(true); 
  50. //设置位置 
  51. _lighting->setPosition(Vec2(visibleSize.width / 4 + origin.x,visibleSize.height / 2 + origin.y)); 
  52. //将闪电链加入到当前层中。 
  53. this->addChild(_lighting,0,10); 

这样我们完成了使用了五条闪电组成一个五星闪电链不断的闪动。运行后的效果如图所示:

然后我们希望在触屏时能够有一条闪电链击中屏幕中央的乌龟,乌龟被击中后翻个身,闪电链渐渐消失,我们可以这样做:

 

首先我们在 FishLayer 这个层里将乌龟循环播放的游泳与被击中的两个动作改为只播放游泳,然后我们增加两个函数:

     
  1. //击中乌龟 
  2. void    FishLayer::AttackWuGui() 
  3.     if (m_Animation3D) 
  4.     { 
  5.         //从1.933秒到2.8秒截取为受伤的动作 
  6.         m_Hurt = Animate3D::create(m_Animation3D, 1.933f, 2.8f); 
  7.         m_Hurt->retain(); 
  8.   
  9.         m_Sprite->stopAllActions(); 
  10.         //让精灵循环播放游泳和的受伤动作 
  11.         Sequence*   pSequence = Sequence::create(m_Hurt,CallFunc::create( std::bind(&FishLayer::ContinueSwim, this) ),NULL); 
  12.         m_Sprite->runAction(pSequence); 
  13.   
  14.     } 
  15.   
  16. //继续游动 
  17. void    FishLayer::ContinueSwim() 
  18.     if (m_Animation3D) 
  19.     { 
  20.         //从起始到1.933秒截取为游泳动作 
  21.         m_Swim = Animate3D::create(m_Animation3D, 0.f, 1.933f); 
  22.         m_Swim->retain(); 
  23.   
  24.         m_Sprite->stopAllActions(); 
  25.         //让精灵循环播放游泳和的受伤动作 
  26.         Sequence*   pSequence = Sequence::create(m_Swim,NULL); 
  27.         m_Sprite->runAction(RepeatForever::create(pSequence)); 
  28.     } 

然后在 HelloWorld 的 init 函数尾部增加代码:

     
  1. //设置可以点击 
  2. setTouchEnabled( true ); 

 

最后,我们重载一下 onToucesBegan 函数:

     
  1. //触屏事件处理 
  2. void HelloWorld::onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event) 
  3. //屏幕转换到射线 
  4.     kmVec3    tPt; 
  5.     kmVec3    tDir; 
  6.     // 获取点在视图中的坐标 
  7.     CCPoint touchLocation = touches[0]->getLocation(); 
  8.     auto    visibleSize = Director::getInstance()->getVisibleSize(); 
  9.     auto    origin = Director::getInstance()->getVisibleOrigin(); 
  10.     //线条容器 
  11.     std::vector<LightLineRender::Line> lines; 
  12.     //闪电的起点和终点 
  13.     Vec2    tFishPos(Vec2(visibleSize / 2) + origin); 
  14.     tFishPos = m_FishLayer->GetSpritePosition() + origin; 
  15.     Vec3 segStart = Vec3(0,0,-8); 
  16.     Vec3 segEnd   = Vec3(touchLocation.x - tFishPos.x ,touchLocation.y - tFishPos.y ,-8); 
  17.     //取得方向 
  18.     Vec3  dir = segEnd - segStart ; 
  19.     float fLength = dir.length(); 
  20.     dir.normalize(); 
  21.     //顺时针转动45度形成一个偏移点做为第一个闪电链线段。 
  22.     Vec3  rotate_left; 
  23.     Mat4  rotate_left_Mat; 
  24.     kmMat4RotationZ(&rotate_left_Mat,MATH_DEG_TO_RAD(-45)); 
  25.     kmVec3TransformCoord(&rotate_left,&dir,&rotate_left_Mat); 
  26.     rotate_left.normalize(); 
  27.     //逆时针转动45度形成一个偏移点做为第一个闪电链线段。 
  28.     Vec3  rotate_right; 
  29.     Mat4  rotate_right_Mat; 
  30.     kmMat4RotationZ(&rotate_right_Mat,MATH_DEG_TO_RAD(45)); 
  31.     kmVec3TransformCoord(&rotate_right,&dir,&rotate_right_Mat); 
  32.     rotate_right.normalize(); 
  33.   
  34.     //分成三段闪电链 
  35.     Vec3  v1_s = segStart ; 
  36.     Vec3  v1_e = segStart + dir * fLength / 4.0 + rotate_left * (fLength / 6.0); 
  37.   
  38.     Vec3  v2_s = v1_e ; 
  39.     Vec3  v2_e = segStart + dir * fLength / 2.0 + rotate_right * (fLength / 6.0); 
  40.   
  41.     Vec3  v3_s = v2_e ; 
  42.     Vec3  v3_e = segEnd; 
  43.   
  44.     lines.push_back( LightLineRender::Line( v1_s, v1_e, 0 ) ); 
  45.     lines.push_back( LightLineRender::Line( v2_s, v2_e, 0 ) ); 
  46.     lines.push_back( LightLineRender::Line( v3_s, v3_e, 0 ) ); 
  47.     //创建出闪光链 
  48.     LightLineRender*    _lighting = dynamic_cast<LightLineRender*>(getChildByTag(10)); 
  49.     //使用线段容器创建闪电链 
  50.     _lighting->setLines( lines ); 
  51.     _lighting->setPosition(tFishPos); 
  52.     //这一句可以让闪电链在1秒内渐渐消隐。它通过调节Shader中的u_color值从1变为0来实现。 
  53.     _lighting->OpenAlphaToZero(1.0); 
  54.     //击中乌龟,让乌龟翻身。 
  55.     m_FishLayer->AttackWuGui(); 

再次运行后,我们点击屏幕,就可以看到从点击屏幕位置到乌龟位置间会出现一条闪电链击中小乌龟啦!小乌龟摇了摇身体,勇敢的继续前行!

DEMO:

/cms/uploads/soft/140813/4196-140Q31F437.rar
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值