How to loop the animation of road?

Hi everyone, I have a problem with animation of the road. The road sprite is initialized by a log picture of the road which goes left while the program works. But then the picture ends and I have to start moving it from the beginning, and I did it, but the animation twitches and the return to the beginning is noticeable. I don’to know if there is the way to do it smoothly.
The road moves this way (in function Update()):

if ((road->getPositionX() - coefSpeed * delta) <= origin.x)
                road->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 4 + origin.y));
            else
                road->setPositionX(road->getPositionX() - coefSpeed *delta);

Class Action and Cocos Creator are avoid to use, unfortunately.

One way to handle this is to use 2 instances of the road image that both move together, attached end to end. Say they start off as AB, and the road is scrolling right to left. When A is off the screen, move it’s position so it’s behind B, so it becomes BA, and then when B moves off the screen, then move B to be behind A, so it becomes AB again, and so on.

You’ll never see any gaps or flickers, since everything is done outside the visible area.

Yeah, the sprite of road is initialized by a picture made of three glued copies of one picture. Maybe I have to make two sprites initialized by the picture of road?

I understand it, but I don’t understand how to do it. Should I create two sprites? And then how to make the program “understand” when A is outside the screen? Maybe it should be connected with Position

You may need more than 2 sprites, because it all depends on the sprite width, the screen width, and the speed at which you’re moving the sprites.

For instance, if the screen is 1920 pixels wide, and your sprite is 500 pixels, then you would need at least 6 sprites. The reason is simple:

500 pixels x 4 = 2000 pixels. This means that 4 sprites will be visible on screen at any given time, and the sprites off the screen are the ones you’re shifting. Say the sprites are A, B, C, D, E, F, then this is how they would work:

ABCDEF
BCDEFA
CDEFAB
DEFABC
etc etc.

Updating them would be something like this (untested):

void update(float delta)
{
    // assuming road sprites are scrolling to the left of the screen
    // assuming each section of the road is 500 pixels wide
    const auto sectionWidth = 500;
    
    // calculate the offset to move the road by
    for (auto&& road : roadSection)
    {
        road->setPositionX(road->getPositionX() - offset);
        // Check if this section of the road is outside the visible area on the left side of the screen
        if (road->getBoundingBox().getMaxX() < 0)
        {
            road->setPositionX(road->getPositionX() + (sectionWidth * roads.size()));  // position the current section so it is on the other side of the screen
        }
    }
}

Now the sprite of the road is three times wider than the visible width of the screen. So, I think, I should split it into 3 sprites with width = vizible width.

What do you mean “road section”? Is it one of the sprites (A, B, C,…etc)?

Yes, A to F is a section of the road, so in my example each would be a road sprite.

Я сделал это, но такое ощущение, что создается только один спрайт, первый. Когда он заканчивается, за ним следует пустота для расстояния, равного sectionWidth * roadSection.size (). Мне кажется, я неправильно инициализирую. Вы можете взглянуть, пожалуйста?
In init():
Vector<Sprite*> roadSection; const int sectionWidth = 1800; roadSection.reserve(3); roadSection.pushBack(Sprite::create("longroad.png")); roadSection.pushBack(Sprite::create("longroad.png")); roadSection.pushBack(Sprite::create("longroad.png")); if ((*roadSection.begin()) == nullptr) { problemLoading("'longroad.png'"); } else { // position the sprite on the center of the screen (*roadSection.begin())->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 4 + origin.y)); this->addChild(*roadSection.begin(), 0); }
In update():
for (auto&& road : roadSection) { road->setPositionX(road->getPositionX() - coefSpeed*delta); if (road->getBoundingBox().getMaxX() < 0) { road->setPositionX(road->getPositionX() + sectionWidth*roadSection.size()); } }
CoefSpeed ​ is the offset.

It’s a little hard to read your post with the code formatted as it is. Try to use block formatting, with 3 backtick characters before and after the code block.

You need to initialise all the pieces of the road, and also add them to the scene, not just the first.

Vector<Sprite*> roadSections; 
const int sectionWidth = 1800; 
roadSections.reserve(3); 
roadSections.pushBack(Sprite::create("longroad.png")); 
roadSections.pushBack(Sprite::create("longroad.png")); 
roadSections.pushBack(Sprite::create("longroad.png")); 
if ((*roadSections.begin()) == nullptr) 
{ 
    problemLoading("'longroad.png'"); 
} 
else 
{ 
    // set the position for all sections and add them to the scene
    auto xPosition = visibleSize.width / 2 + origin.x;
    for (auto&& roadSection : roadSections) 
    {
        roadSection->setPosition(xPosition, visibleSize.height / 4 + origin.y);
        xPosition += roadSection->getContentSize().width;  // or you can use xPosition += sectionWidth;
        addChild(roadSection);
    }
}
1 Like

Oh god, it finally works! Thanks a lot for your detailed explanations and patience, you’re my savior :blue_heart:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.