简体   繁体   English

与基数样条线循环

[英]Make a loop with cardinal spline

I'm trying to make an animation for a sprite, which will go on path and it will loop forever. 我正在尝试为sprite制作动画,该动画将继续前进并永远循环。 But CardinalSpline doesn't close up as I thought. 但是CardinalSpline并没有像我想的那样关闭。

Here are example points (it's a square): 这是示例点(它是一个正方形):

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));

Animation creation: 动画制作:

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

It looks like that: 看起来像这样:

在此处输入图片说明

So of course animation doesn't look too good. 因此,动画当然看起来不太好。 I want to make a perfect loop (with constant speed), where cannot be seen where's an end or start. 我想做一个完美的循环(以恒定的速度),在哪里看不到终点或起点。

If I will continue adding the same points it will loop nice until it reaches the end where's an breakdown, which you can see on top right corner. 如果我继续添加相同的点,它将很好地循环播放,直到到达故障点为止,您可以在右上角看到该点。

How can I achieve this? 我该如何实现?

Only thing, which comes to my mind is too double amount of points and at exactly half of animation seek it to the begging or create a new one. 我想到的唯一一件事是要点的数量过多,动画的一半恰好找它乞讨或创建一个新的对象。

Finally I did it. 最后我做到了。 I had to change cocos2d-x code a bit. 我不得不稍微更改cocos2d-x代码。

All needed changes: 所有需要的更改:

in startWithTarget: 在startWithTarget中:

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

to: 至:

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

Reimplemented getControlPointAtIndex: 重新实现了getControlPointAtIndex:

from: 从:

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

to: 至:

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));
}

Then spline is interpolating well, because it always has 4 different points to interpolate. 然后,样条曲线可以很好地进行插值,因为它总是有4个不同的点可以插值。 Before that first and last point were cut off. 在此之前,第一个和最后一个点被切断。

To draw a spline in CAD programs such as AutoCAD, you must specify not only points, but also the direction (imaginary extension) for the extreme points. 要在CAD程序(例如AutoCAD)中绘制样条曲线,不仅必须指定点,还必须指定极限点的方向(虚构延伸)。 Direction affects the behavior of the spline from the extreme point to the next. 方向会影响样条曲线从端点到下一端点的行为。
Here the direction is not specified, so the extreme point of the spline has a "sharp transition". 此处未指定方向,因此样条曲线的极点具有“尖锐过渡”。
Try to add two points to indicate the direction, for example: 尝试添加两个点以指示方向,例如:

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));

I pointed out the approximate position of the extreme points. 我指出了极端点的大概位置。 You should to move them and determine the exact position to achieve precise overlay of a spline. 您应该移动它们并确定精确位置以实现样条线的精确覆盖。
PS Or you can try to connect the spline is not at the corner and on a flat plot of the spline, for example at the point (250, 360). PS或者您可以尝试连接样条线不在角部和样条线的平面图上,例如在点(250,360)处。

My previous answer concerned only spline creation. 我以前的答案只涉及样条线的创建。 But now I made my particle rotation by spiral, and know the simplest way which can help you. 但是现在我使粒子旋转成螺旋状,并且知道可以帮助您的最简单方法。
So, you need a container for your's object, and you should make two things: rotate container and move object on container. 因此,您需要一个用于对象的容器,并且应该做两件事:旋转容器和在容器上移动对象。 I will show an example with particle as object: 我将展示一个以粒子为对象的示例:

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

Here I show only one turnover, but you can get it to rotate continuously. 在这里,我仅显示一个营业额,但您可以使其连续旋转。 There is result of program: 有程序的结果:

It is not same as your splain, but the principle of the creation should be clear. 它与您的原作不同,但创建原理应明确。 I think, you can decrease the distance in MoveBy: and experiment with Ease: for a better results. 我认为,您可以在MoveBy:减小距离,并尝试Ease:以获得更好的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM