《捕鱼达人》教程3:闪电特效
在上一节中,我们学习了如何为鱼添加波光效果。在本节教程中,我们将深入探讨如何制作攻击时的闪电特效,揭开华丽闪电魔法背后的技术奥秘。
闪电特效的实现步骤
《捕鱼达人》中的闪电特效通过以下三个主要步骤实现:
- 构建三角形条带:这是闪电特效的基础几何结构,为后续的顶点操作提供框架。
- 采用随机函数扰动条带顶点:使用随机函数对条带的顶点进行扰动,使顶点产生不断的小幅变化,从而模拟出闪电的不规则形状。
- 快速反复循环前两个步骤:通过快速循环构建三角形条带和扰动顶点的操作,实现闪电的动态闪烁效果。
主要使用的类
在实现闪电特效的过程中,主要使用了以下三个类:
- VertexVector:用于存储顶点和索引的类,为后续的图形渲染提供数据支持。
- Noise:噪音处理类,负责对顶点进行扰动,使顶点不断产生小幅变化,模拟闪电的不规则形状。
- LightLineRender:实现闪电效果的核心类,封装了闪电效果的实现细节,并提供了相应的参数调节选项,通过使用该类,我们可以轻松实现闪电链的效果。
具体代码实现
创建五星闪电链
我们打开 cpp-empty-test 项目,在 HelloWorld::init 函数中添加以下代码:
// 线条容器
std::vector<LightLineRender::Line> lines;
// 设置线条位置
// 第一段闪电的起点和终点
Vec3 segStart = Vec3(-50, -50, -8);
Vec3 segEnd = Vec3(50, 50, -8);
lines.push_back(LightLineRender::Line(segStart, segEnd, 0));
// 第二段闪电的起点和终点
segStart = Vec3(50, 50, -8);
segEnd = Vec3(-50, 50, -8);
lines.push_back(LightLineRender::Line(segStart, segEnd, 0));
// 第三段闪电的起点和终点
segStart = Vec3(-50, 50, -8);
segEnd = Vec3(50, -50, -8);
lines.push_back(LightLineRender::Line(segStart, segEnd, 0));
// 第四段闪电的起点和终点
segStart = Vec3(50, -50, -8);
segEnd = Vec3(0, 100, -8);
lines.push_back(LightLineRender::Line(segStart, segEnd, 0));
// 第五段闪电的起点和终点
segStart = Vec3(0, 100, -8);
segEnd = Vec3(-50, -50, -8);
lines.push_back(LightLineRender::Line(segStart, segEnd, 0));
// 创建出闪光链
LightLineRender* _lighting = LightLineRender::create();
// 设置不需要强制纹理循环
_lighting->setForceTexLoop(false);
// 设置宽
_lighting->setWidth(80);
// 设置单张纹理长度,调整这个数值可以避免纹理过度拉伸或挤压
_lighting->setTextueLength(100);
// 设置单个面片网格长,越小曲线越平滑,数值过于小可能带来效率问题
_lighting->setStep(10);
// 设置振幅1
_lighting->setAmplitude0(4);
// 设置频率1
_lighting->setFrequency0(500);
// 设置振幅2
_lighting->setAmplitude1(1);
// 设置频率2
_lighting->setFrequency1(400);
// 设置产生噪音的时间系数
_lighting->setTimeFactor(0.5);
// 使用线段容器创建闪电链
_lighting->setLines(lines);
// 使用柏林噪音算法
_lighting->setLineType(LineType::LT_PerlinNosie);
// 设置每帧强制更新重建模型
_lighting->setForceUpdate(true);
// 设置位置
_lighting->setPosition(Vec2(visibleSize.width / 4 + origin.x, visibleSize.height / 2 + origin.y));
// 将闪电链加入到当前层中
this->addChild(_lighting, 0, 10);
通过上述代码,我们使用五条闪电组成了一个五星闪电链,运行后的效果如图所示。
实现触屏闪电击中乌龟效果
我们希望在触屏时,有一条闪电链击中屏幕中央的乌龟,乌龟被击中后翻个身,闪电链渐渐消失。具体实现步骤如下:
- 修改乌龟动作:在
FishLayer层里,将乌龟循环播放的游泳与被击中的两个动作改为只播放游泳。 - 增加两个函数:
// 击中乌龟 void FishLayer::AttackWuGui() { if (m_Animation3D) { // 从1.933秒到2.8秒截取为受伤的动作 m_Hurt = Animate3D::create(m_Animation3D, 1.933f, 2.8f); m_Hurt->retain();
m_Sprite->stopAllActions();
// 让精灵循环播放游泳和受伤的动作 Sequence* pSequence = Sequence::create(m_Hurt, CallFunc::create(std::bind(&FishLayer::ContinueSwim, this)), NULL); m_Sprite->runAction(pSequence); } }
// 继续游动 void FishLayer::ContinueSwim() { if (m_Animation3D) { // 从起始到1.933秒截取为游泳动作 m_Swim = Animate3D::create(m_Animation3D, 0.f, 1.933f); m_Swim->retain();
m_Sprite->stopAllActions();
// 让精灵循环播放游泳动作 Sequence* pSequence = Sequence::create(m_Swim, NULL); m_Sprite->runAction(RepeatForever::create(pSequence)); } }
3. **在 `HelloWorld` 的 `init` 函数尾部增加代码**:
// 设置可以点击 setTouchEnabled(true);
4. **重载 `onToucesBegan` 函数**:
// 重载 onToucesBegan 函数的具体实现代码 // 这里需要根据实际情况补充完整函数体 bool HelloWorld::onTouchesBegan(const std::vector<Touch>& touches, Event event) { // 实现触屏触发闪电击中乌龟的逻辑 return true; }
通过以上步骤,我们就实现了在触屏时闪电链击中乌龟,乌龟被击中后翻个身,闪电链渐渐消失的效果。