Update sprites from array

I have created an array which produces 4 sprites (clouds), but when i try to make them move in the update() method, only the first one spawned moves, the rest appear but are not moving…any suggestions would be greatly appreciated.

i don’t fetch the sprites from a batch, i create() one with every iteration.

show us the code…

sure, here it goes:

in init()

auto clouds = Array::createWithCapacity(4);
clouds->retain();

for (int i = 0; i < 4; i++)
{
	cloud = Sprite::create("clouds_1.png");
	cloud->setPosition(Vec2(visibleSize.width / 4 + i * 300, visibleSize.height / 1.2));
	this->addChild(cloud);
	clouds->addObject(cloud);
}

and inside the update() method:

cloud->setPositionX(cloud->getPositionX() - dt * 10);

the sprite is declared in the .h file of the scene

  1. use Vectors

  2. it looks like you are re-using cloud over and over, shouldn’t you be creating a new local cloud in the for loop?

for (int i = 0; i < 4; i++)
{
	auto cloud = Sprite::create("clouds_1.png");
	cloud->setPosition(Vec2(visibleSize.width / 4 + i * 300, visibleSize.height / 1.2));
	this->addChild(cloud);
	clouds->addObject(cloud);
}

I haven’t really grasped the context of vectors yet, perhaps you would like to give a heads-up on the matter, and secondly, you mean initialize 4 sprites and attach the texture in each or i completely misunderstood your comment?

Cocos2d-x moved to Vectors more so than Arrays in v3. Arrays are still useful but I think I see most everyone using Vectors instead.

What happens when you replace your for with mine?

if i use your for loop it breaks. the cloud sprite is declared in the .h file.

oh, right, you need to remove that and in update() loop though the array, cast to a Sprite, move it.

send me your “clouds_1.png”. I might not be able to finish this before I leave though but I’ll surely finish it in the morning.

sure here it is Clouds.zip (21.7 KB)

This works

in .h:

std::vector<Sprite*> clouds;

in .cpp:

// put this where your for loop is now
for (int i = 0; i < 4; i++)
    {
        auto cloud = Sprite::create("clouds_1.png");
        cloud->setPosition(Vec2(_visibleSize.width / 4 + i * 300, _visibleSize.height / 1.2));
        this->addChild(cloud, 1);
        clouds.push_back(cloud);
    }

// edit your current update()
void HelloWorld::update(float dt)
{
    for (int i = 0; i < clouds.size(); i++)
    {
        auto cloud = clouds.at(i);
        
        cloud->setPositionX(cloud->getPositionX() - dt * 10);
    }
}
1 Like

Vectors make only sense, if you need dynamic growing. If the amount of clouds is fixed and known, arrays are the better choice.

It does not reuse the cloud instance, but only the cloud pointer. This is perfectly fine, as the pointer points to the newly created instance, which gets added to the array.

This does not mean, they are using the correct container. Always use the correct one for your purpose, and not just blindly use a vector.

Don’t do that, as this will waste resources, as you are fetching the object in the container with bounds checking, instead using it directly.

Use an iterator to iterate over the objects in the container or use direct access and apply the position change.

Also use pre-increment in case your compiler does not optimize out the temporary variable.

Somewhat off topic, but hoping for some advice…

I tend to use

for (auto floorPoint: this->terrainFloorPoints)
{
	...
}

to iterate - just because it is cleaner looking code to me.

But when I try to debug this in AppCode or XCode it just freezes if I try to step through the loop…

I guess what I’m interested in knowing (as a somewhat C++ novice) is whether there’s anything “wrong” with doing iteration like that - or should I use something like

    Vector<TerrainPoint*>::iterator terrainFloorIterator;
	for (terrainFloorIterator = ++terrainFloorPoints.begin();
	     terrainFloorIterator != terrainFloorPoints.end();
	     terrainFloorIterator++)
    {
    }

As long as the compiler is C++11 compliant it should work without problems.
Could be some IDE/Debugger bug.

Why are you pre-incrementing the iterator? Do you want to start at the second item?

Use pre-increment instead of post-increment.

No. Besides it’s only available in C++11, it generates basically the same code.

Standard 6.5.4.1:
For a range-based for statement of the form
for ( for-range-declaration : expression ) statement
let range-init be equivalent to the expression surrounded by parentheses
( expression )
and for a range-based for statement of the form
for ( for-range-declaration : braced-init-list ) statement
let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to

{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }

sorry - probably picked a poor example; in this case yes, I have the first location stored, and iterate from the second onward.

Awesome - that’s what i had assumed, but didn’t really know. It’s much easier (for me) to read (and type!) so I’d prefer to keep using it - just wish XCode and AppCode would debug it correctly!

Thanks for the info!

Can you enlighten us why if the amount of elements is known or fixed you choose array? Why not just reserve a vector for that many spots to allocate the space and use a vector?

Don’t do that, as this will waste resources, as you are fetching the object in the container with bounds checking, instead using it directly.

Use an iterator to iterate over the objects in the container or use direct access and apply the position change.
[/quote]
ok, you got me here direct access would be better given there is such a small number of elements. An Iterator if there are more than just a handful.

So

int j = i++; // j will contain i, i will be incremented.

Vs:

int j = ++i; // i will be incremented, and j will contain i+1.

You are saying to use ++i; but isn’t there no difference until you assign the result like above?

An array is a strict linear sequence and efficient in the terms of storage size. The size is compile-time constant and cause of that, there is no no memory or time overhead.
If you choose a vector, the space is layed out at run-time. Special memory handling appears and the container implementation might choose to create more entries than you need. This speeds up the insertion of future items, cause the vector does not has to be reallocated to make space for the new items.
It depends on the implementation. E.g. allocating a vector for 10 elements, allocates space for 15 elements under the hood.

Direct access is always at least as fast as an iterator. It does not depend on the amount of elements.
Use [] instead of .at if you want to speed it up or don’t need bounds checking.
Using iterators are just more convenient.

i will be incremented and j will contain i. j will have the same value as i.

There is a difference, cause it will always assign the result. You are assigning it to a temporary.

i++; this is implicit(temporary) assigning, as the value of i will be stored in a temporary variable, cause the original value of i can be used/assigned prior to incrementing. After the assignment to the temporary variable, i will be incremented in place.

++i; there is no temporary variable needed, as it will increment i in place. You cannot use/assign the value prior to incrementing, cause the increment operation happens at first.

So do we get taught c++ wrong, back in the mid 90’s when I was going through school we were always taught i++ when using loops, especially.

So should one really be doing:

for (int i=0; i < 5; ++i)

I should go see what the Stroustrup book says about it.

Edit: Also, using @Maxxx code from above, you are saying to do this:

Vector<TerrainPoint*>::iterator terrainFloorIterator;

for (terrainFloorIterator = terrainFloorPoints.begin();
	     terrainFloorIterator != terrainFloorPoints.end();
	     ++terrainFloorIterator)
{

 }

You can use both, cause the outcome is the same as ++i, but no need to escpecially use i++ in loops. The increment and assignment is done in the loop header.
The difference is just in the memory and operations used.

Every for loop is transformed to a while loop by the compiler. Good/clever compilers are optimizing the i++ into ++i.

If you ant to spare that temp variable and be more clear on the increment, yes.
The outcome is the same as using i++, but ++i is more clear. It boils down to personal taste.

It does no go into the implementation details, just explains that i++ will keep the original value prior to increment the value of i.

It does no go into the details, cause this is not really C++ specific, as many languages use the same feature and the compiler does the same under the hood.

Yes. Same outcome, but without using a temporary.