Get element in cocos2d vector

So i n my project I need to put some sprites into vector. But I need to interact with elements. So I need to select one element(sprite) from vector. SInce cc2d vector doesn’t overload operator [] , I thought there are 2 ways to to that.
1th using that wierd foor loop for (const String& sprite_name : frames)
but it doesn0t do what I want, cause I need to get previus element of that that I am selecting , etc (vector[a-1], ,...) I also need to select element outside the foor loop.
So I thought of a at() function. Function description.
I use it like vector.at(a)
But the app crahses at the point of usage. I tried just simple code, without any hard lifting, so there were 99,9% no mistakes in the code, but It always chrases when it went to at() function…
SO how else can I do that!? Am I missing sth?

Can you show is the code, please?

I don’t use cocos2d::Vector. I use std::vector instead and basically the same way you describe doing.

If you’re starting a new project then you probably want to look into moving to std::string and using std::vector for those instances as @slackmoehrle mentions. The old-style cocos2d::String class is deprecated.

Otherwise if you need to work with an existing/previous code base then …

Are you defining it with pointers: Vector<String*> frames;?
Is there an ASSERT message when it crashes?
Or does it crash with a bad memory access (EXC_BAD_ACCESS, or similar)?

If it’s not a bad index then my guess is the frames instance has become invalid.

Try and see if this code crashes:

//using cocos2d::Vector;
//using cocos2d::log;
Vector<String*> frames;
String* str = String::create("test"); // or = ccs("test");
frames.pushBack(str);
// this should not crash unless the above failed
String* str1 = frames.at(0);
log("str1 = %s", str1->getCString());
// loop using index (start at 1 to allow for prev string index of `1-1`
for(int i=1; i<frames.size(); ++i) {
  String* str = frames.at(i);
  String* prevStr = frames.at(i-1);
  log("str = %s", str->getCString(), prevStr->getCString());
}
// using weird loop
String* prevStr = null;
for(auto* str : frames) {
  // make sure we've done one iteration to get a valid prevStr
  if(prevStr) log("str = %s", str->getCString(), prevStr->getCString());
  prevStr = str;
}
1 Like

I can’t get on what’s wrong with my code but…
It seems it woud be easyier using std::vector instead (I am familiar with that). But are there any special things I should know?
Or do I just write std::vector<sprite*>.
I usually create sprites using auto sprite1 = Sprite::create
Can I do std::vector<auto> or something?

I already changet the code. But it was working fine (even the foor loop) if I removed the line with the at() function.
But since you say std::vector will work, that’s okay.

std::vector<cocos2d::Sprite*>

is what I do.

1 Like

Tenx, I will try.

If you use std::vector to store array of cocos2d objects, then what case is the cocos2d::Vector used for??

Could you suggest some best practices??

It’s all about automatically managing memory correctly with cocos2d Ref* derived objects. Essentially it’s meant to be used in the same manner as std::vector except that cocos2d::Vector will retain objects when added, pushBack, and release them in the destructor or when removing a single object using methods: eraseObject, popBack, etc.
(as noted, cocos2d::Vector does have different naming scheme in order to make sure developers know they’re using a different container than std::vector)

If you only use the objects that you store inside the vector during a single scope (e.g. within a function) then you can let the default autorelease cleanup at end of the scope.

Similarly, if you want to always use only std:: containers instead you just have to remember to retain/release any objects you store in them that haven’t been retained elsewhere. If you only store nodes that have been added to a Scene or another Node then you don’t have to bother with the retain/release, but you will need to be a little more diligent.

If this is confusing, or doesn’t make sense, I think one can recommend to just use std::vector and learn when and where you need to actually retain/release manually.

There’s probably is a guide (or one should be written) on how memory management works where X::create() autoreleases, addChild retains, release is called when a node is removed and cleaned up, etc.

2 Likes

What would be the iterator for that. These two dont work

	std::vector<cocos2d::Sprite*>Iterator = iter;
	std::vector<cocos2d::Sprite*>Iterator iter;

&
for (iter.cbegin(); iter.end(); iter++)
{
(iter*)
}

std::vector<cocos2d::Sprite*> mySprites;
for ( auto sprite : mySprites) {
   sprite->setColor(Color3B::BLUE);
}
2 Likes

That is the magic dude !!!
Thanks

Anyone know anything about tuples

	std::vector<std::tuple< std::vector<cocos2d::Vec2>, std::vector<cocos2d::Vec2>, std::vector<cocos2d::Vec2>>> wayPointVectorsTuple;
	std::vector<std::tuple< std::vector<cocos2d::Vec2*>, std::vector<cocos2d::Vec2*>, std::vector<cocos2d::Vec2*> > >::iterator iteratorTuple;

for (int i = 0; i < 62; i++) 
{
	std::vector<cocos2d:Vec2> first (i, WayPoints[i][0]);
	std::vector<cocos2d:Vec2> second (i, WayPoints[i][1]);
	std::vector<cocos2d:Vec2> third (i, WayPoints[i][2);
	wayPointVectorsTuple.push_back(std::make_tuple(id, x, y));
}

The for loop has endless errors. How would one do this ?

Thanks

i’d like to see the errors… you are missing some parenthesis and a few other things. You also use * sometimes and then sometimes not

so you want to access elements in the std::tuple?

I have a track with inner, middle and outer Vec2 points for AI to follow. If there hard they will follow inner set of Vec2 Points like so

WayPoints[0][0] = cocos2d::Vec2(-2450 / TIscale, 1000 / TIscale);//ZERO IS MOST TIGHT CORNER
WayPoints[0][1] = cocos2d::Vec2(-2520 / TIscale, 1000 / TIscale);//ONE IS MIDDLE
WayPoints[0][2] = cocos2d::Vec2(-2590 / TIscale, 1000 / TIscale);//TWO IS LEAST TIGHT CORNER

WayPoints[1][0] = cocos2d::Vec2(-2350 / TIscale, 1170 / TIscale);
WayPoints[1][1] = cocos2d::Vec2(-2380 / TIscale, 1200 / TIscale);//WAY POINT 2
WayPoints[1][2] = cocos2d::Vec2(-2420 / TIscale, 1250 / TIscale);

WayPoints[2][0] = cocos2d::Vec2(-1150 / TIscale, 1150 / TIscale);
WayPoints[2][1] = cocos2d::Vec2(-1100 / TIscale, 1200 / TIscale);//WAY POINT 3
WayPoints[2][2] = cocos2d::Vec2(-1050 / TIscale, 1250 / TIscale);

WayPoints[3][0] = cocos2d::Vec2(-1050 / TIscale, 1020 / TIscale);
WayPoints[3][1] = cocos2d::Vec2(-1000 / TIscale, 1050 / TIscale);//WAY POINT 4
WayPoints[3][2] = cocos2d::Vec2(-950 / TIscale, 1080 / TIscale);

Im using Array so far. And it works fine

If its Hard we see this been followed WayPoints[Which ever its on ][ difficulty 0 - 2]. So changing the difficulty setting decides how close to the corner the AI drive

The reason I want it in a Vector is because I can pass that in as a parameters to a AI function. And on different tracks we may have different amount of way points, but always three levels of how close to corner to cut

You may want to try and change your design, but if not, just remember that if you store pointers to objects in containers (vector, etc) then you may invalidate those pointers, so you need to be careful how you use them.
https://stackoverflow.com/questions/23488326/c-stdvector-of-references .

Since it appears your waypoint vectors won’t change once create them you probably don’t need to worry about having copies of Vec2 that reference the same instance of data. If you modify any of them then you’d have to keep both up-to-date or use references/pointers for one of the ‘copies’.

I also think what you really want is one vector<tuple<Vec2,Vec2,Vec2>> actualData; and another container tuple<vector<Vec2>,vector<Vec2>,vector<Vec2>> alternativeLayout;. For the latter reference one I’d probably just separate the last one out into separate vector<Vec2> first,second,third; instead.

Also, note that if you want to modify data after creation you’ll want a reference on the iteration with vectors (again with the warning about invalidating pointers).

for (/* optionally const */ auto& el : myVector) { ... }

You can also look at that stackoverflow post above and use the reference wrapper.


You could also consider malloc’d arrays to allow for run-time sizing on creation since you’ve already got it working with statically sized arrays. Vec2* first = new Vec2[N] // delete [] first. You can probably convert this method into using unique/shared_ptr instead.

(there are some third-party dynamic array container implementations (Boost, others) that you could also look at.)

1 Like

:open_mouth: Ok Ill have to try digest that tomorrow ! Ill be back

:slight_smile:
Your help Is much appreciated