用基数样条做一个循环

Make a loop with cardinal spline

我正在尝试为 sprite 制作动画,它会在路径上运行并且会永远循环。但是CardinalSpline并没有像我想的那样关闭。

以下是示例点(这是一个正方形):

pointsRed->addControlPoint(Vec2(350, 350));
pointsRed->addControlPoint(Vec2(350, 150));
pointsRed->addControlPoint(Vec2(150, 150));
pointsRed->addControlPoint(Vec2(150, 350));
pointsRed->addControlPoint(Vec2(350, 350));

动画创作:

auto redSpline = CardinalSplineTo::create(20, pointsRed, 0);

看起来是这样的:

所以当然动画看起来不太好。我想做一个完美的循环(以恒定速度),在哪里看不到结束或开始。

如果我继续添加相同的点,它会很好地循环,直到它到达故障的尽头,您可以在右上角看到它。

我怎样才能做到这一点?

我唯一想到的是点数太多了,动画刚好一半就开始寻找它或创建一个新的。

要在 AutoCAD 等 CAD 程序中绘制样条曲线,您不仅必须指定点,还必须指定极值点的方向(假想延伸)。方向影响样条曲线从极值点到下一个点的行为。
这里没有指定方向,所以样条的极值点有一个"sharp transition".
尝试添加两个点来表示方向,例如:

pointsRed->addControlPoint(Vec2(300, 360));
pointsRed->addControlPoint(Vec2(350, 350));
pointsRed->addControlPoint(Vec2(350, 150));
pointsRed->addControlPoint(Vec2(150, 150));
pointsRed->addControlPoint(Vec2(150, 350));
pointsRed->addControlPoint(Vec2(350, 350));
pointsRed->addControlPoint(Vec2(360, 300));

我指出了极值点的大概位置。您应该移动它们并确定确切的位置以实现样条曲线的精确叠加。
P.S。或者您可以尝试连接样条曲线不在拐角处和样条曲线的平坦图上,例如在点 (250, 360) 处。

我之前的回答只涉及样条创建。但是现在我用螺旋线让我的粒子旋转,并且知道了最简单的方法可以帮助你。
所以,你的对象需要一个容器,你应该做两件事:旋转容器和在容器上移动对象。我将展示一个以粒子为对象的例子:

Sprite* container = Sprite::create("background.png");
container->setAnchorPoint(Vec2::ANCHOR_MIDDLE); // the container is rotated about its center 
container->setPosition(winSize.width * 0.5f, winSize.height * 0.5f);
container->setOpacity(255); // it’s only for test. After that you can setOpacity(0)
this->addChild(container);

ParticleSystemQuad* particle = ParticleSystemQuad::create("particle_meteor.plist");
// place object 100 pixels above the center of the container
particle->setPosition(container->getBoundingBox().size.width * 0.5f, container->getBoundingBox().size.height * 0.5f + 100);
container->addChild(particle);

container->runAction(RotateBy::create(4.0f, 360));

EaseInOut* easeUp = EaseInOut::create(MoveBy::create(0.4f, Vec2(0, 35)), 2.0f);
EaseInOut* easeDown = EaseInOut::create(MoveBy::create(0.4f, Vec2(0, -35)), 2.0f);
particle->runAction(Sequence::create(DelayTime::create(0.1f),
                                     easeUp,
                                     easeDown,
                                     DelayTime::create(0.2f),
                                     easeUp,
                                     easeDown,
                                     DelayTime::create(0.2f),
                                     easeUp,
                                     easeDown,
                                     DelayTime::create(0.2f),
                                     easeUp,
                                     easeDown,
                                     DelayTime::create(0.1f),
                                     NULL)); // particle «jumps» in corners

这里我只展示了一个翻转,但是你可以让它连续旋转。有程序结果:

和你的splain不一样,但是创作原理应该很清楚了。我认为,您可以减小 MoveBy: 中的距离并尝试 Ease: 以获得更好的结果。

我终于做到了。我不得不稍微更改 cocos2d-x 代码。

所有需要的更改:

在 startWithTarget 中:

_deltaT = (float) 1 / (_points->count() - 1);

至:

_deltaT = (float) 1 / (_points->count());

重新实现了 getControlPointAtIndex:

来自:

Vec2 PointArray::getControlPointAtIndex(ssize_t index)
{
      index = MIN(static_cast<ssize_t>(_controlPoints->size())-1, MAX(index, 0));  
      return *(_controlPoints->at(index));
}

至:

Vec2 PointArray::getControlPointAtIndex(ssize_t index)
{
    ssize_t tIndex = index;
    ssize_t pSize = static_cast<ssize_t>(_controlPoints->size());
    if(tIndex < 0) tIndex += pSize;
    if(tIndex >= pSize) tIndex -= pSize;    
    return *(_controlPoints->at(tIndex));
}

然后样条插值很好,因为它总是有 4 个不同的点可以插值。在第一个和最后一个点被切断之前。