您的位置:首页 > 移动开发 > Cocos引擎

cocos2dx粒子效果的一个有趣的bug

2014-07-23 22:16 211 查看
废话不多说,直入主题。

运行如下代码,效果如下图。

auto ptc = ParticleSun::create();

auto act = Sequence::create(DelayTime::create(2), MoveBy::create(0.1, Vec2(50, 50)), NULL);

ptc->runAction(Repeat::create(act,5));

scene->addChild(ptc);



这是正常情况下的表现,当我们将当前场景放大之后,效果如下

auto ptc = ParticleSun::create();

auto act = Sequence::create(DelayTime::create(2), MoveBy::create(0.1, Vec2(50, 50)), NULL);

ptc->runAction(Repeat::create(act,5));

scene->addChild(ptc);

scene->setScale(1.4f);



粒子的拖尾是喷射出来的,像发射火箭一样。

为什么放大后会出现这样的情况呢?

观察ParticleSystem的update

<pre name="code" class="cpp">// ParticleSystem - MainLoop
void ParticleSystem::update(float dt)
{
CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update");

if (_isActive && _emissionRate)
{
float rate = 1.0f / _emissionRate;
//issue #1201, prevent bursts of particles, due to too high emitCounter
if (_particleCount < _totalParticles)
{
_emitCounter += dt;
}

while (_particleCount < _totalParticles && _emitCounter > rate)
{
this->addParticle();
_emitCounter -= rate;
}

_elapsed += dt;
if (_duration != -1 && _duration < _elapsed)
{
this->stopSystem();
}
}

_particleIdx = 0;

Vec2 currentPosition = Vec2::ZERO;
if (_positionType == PositionType::FREE)  //默认情况下的PositionType是FREE模式
{
currentPosition = this->convertToWorldSpace(Vec2::ZERO);//currentPosition保存的是屏幕坐标系的粒子坐标   }
else if (_positionType == PositionType::RELATIVE)
{
currentPosition = _position;
}

{
while (_particleIdx < _particleCount)
{
tParticle *p = &_particles[_particleIdx];

// life
p->timeToLive -= dt;

if (p->timeToLive > 0)
{
// Mode A: gravity, direction, tangential accel & radial accel
if (_emitterMode == Mode::GRAVITY)
{
Vec2 tmp, radial, tangential;

radial = Vec2::ZERO;
// radial acceleration
if (p->pos.x || p->pos.y)
{
radial = p->pos.getNormalized();
}
tangential = radial;
radial = radial * p->modeA.radialAccel;

// tangential acceleration
float newy = tangential.x;
tangential.x = -tangential.y;
tangential.y = newy;
tangential = tangential * p->modeA.tangentialAccel;

// (gravity + radial + tangential) * dt
tmp = radial + tangential + modeA.gravity;
tmp = tmp * dt;
p->modeA.dir = p->modeA.dir + tmp;

// this is cocos2d-x v3.0
//                    if (_configName.length()>0 && _yCoordFlipped != -1)

// this is cocos2d-x v3.0
tmp = p->modeA.dir * dt * _yCoordFlipped;
p->pos = p->pos + tmp;
}

// Mode B: radius movement
else
{
// Update the angle and radius of the particle.
p->modeB.angle += p->modeB.degreesPerSecond * dt;
p->modeB.radius += p->modeB.deltaRadius * dt;

p->pos.x = - cosf(p->modeB.angle) * p->modeB.radius;
p->pos.y = - sinf(p->modeB.angle) * p->modeB.radius;
p->pos.y *= _yCoordFlipped;
}

// color
p->color.r += (p->deltaColor.r * dt);
p->color.g += (p->deltaColor.g * dt);
p->color.b += (p->deltaColor.b * dt);
p->color.a += (p->deltaColor.a * dt);

// size
p->size += (p->deltaSize * dt);
p->size = MAX( 0, p->size );

// angle
p->rotation += (p->deltaRotation * dt);

//
// update values in quad
//

Vec2    newPos;

if (_positionType == PositionType::FREE || _positionType == PositionType::RELATIVE)
{
Vec2 diff = currentPosition - p->startPos;
//问题的关键在这里,场景放大后,以屏幕坐标系计算得出的diff实际上也被放大了,所以newPos是错误的
newPos = p->pos - diff;
}
else
{
newPos = p->pos;
}

// translate newPos to correct position, since matrix transform isn't performed in batchnode
// don't update the particle with the new position information, it will interfere with the radius and tangential calculations
if (_batchNode)
{
newPos.x+=_position.x;
newPos.y+=_position.y;
}

updateQuadWithParticle(p, newPos);
//updateParticleImp(self, updateParticleSel, p, newPos);

// update particle counter
++_particleIdx;
}
else
{
// life < 0
int currentIndex = p->atlasIndex;
if( _particleIdx != _particleCount-1 )
{
_particles[_particleIdx] = _particles[_particleCount-1];
}
if (_batchNode)
{
//disable the switched particle
_batchNode->disableParticle(_atlasIndex+currentIndex);

//switch indexes
_particles[_particleCount-1].atlasIndex = currentIndex;
}

--_particleCount;

if( _particleCount == 0 && _isAutoRemoveOnFinish )
{
this->unscheduleUpdate();
_parent->removeChild(this, true);
return;
}
}
} //while
_transformSystemDirty = false;
}

// only update gl buffer when visible
if (_visible && ! _batchNode)
{
postStep();
}

CC_PROFILER_STOP_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update");
}




只要将

if (_positionType == PositionType::FREE || _positionType == PositionType::RELATIVE)
{
Vec2 diff = currentPosition - p->startPos;
newPos = p->pos - diff;
}
else
{
newPos = p->pos;
}

改成

if (_positionType == PositionType::FREE)
{
Vec2 diff = convertToNodeSpace(currentPosition) - convertToNodeSpace(p->startPos);
newPos = p->pos - diff;
}
else if(_positionType == PositionType::RELATIVE)
{
Vec2 diff = currentPosition - p->startPos;
newPos = p->pos - diff;
}
else
{
newPos = p->pos;
}
即可解决这个问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息