Let's say I have a parent node with N child nodes. They all have scheduled updates on every frame. Whose update: selector gets called first, the child nodes or the parent? Is there any set order?
The visit method in CCNode has the following code:
if(children_) {
ccArray *arrayData = children_->data;
NSUInteger i = 0;
// draw children zOrder < 0
for( ; i < arrayData->num; i++ ) {
CCNode *child = arrayData->arr[i];
if ( [child zOrder] < 0 )
[child visit];
else
break;
}
// self draw
[self draw];
// draw children zOrder >= 0
for( ; i < arrayData->num; i++ ) {
CCNode *child = arrayData->arr[i];
[child visit];
}
So, as you can see, first are visited children whose zOrder is less than zero, then the current node (the children's parent) is drawn, then the rest of children is also visited (note that visiting a node will eventually draw it, according to the criteria just explained).
Related
I tried to add several items to QGraphicsScene, but after calling scene->addItem(new Bonus(Bonus::BonusType::coin, randPoint, pixels, parent)); in application output appears this message: QGraphicsScene::addItem: item has already been added to this scene.What I do wrong?
Code:
for(int i = 0; i < coinsCount; ) {
QPoint randPoint(random() % g->getWidth(),
random() % g->getHeight());
if(g->getType(randPoint) != Graph::wall && !usedPoints.contains(randPoint)) {
scene->addItem(new Bonus(Bonus::BonusType::coin, randPoint, pixels, parent));
usedPoints.push_back(randPoint);
i++;
}
}
You are passing a parent item. If the parent item is already added to the scene, setting it as a parent for the new item will add the latter to the scene as well.
The constructor runs before addItem() so by the time the latter is executed, the item is already in the scene.
Note that this implicitly adds this graphics item to the scene of the
parent. You should not add the item to the scene yourself.
Using cocos2d, I'm trying to replace a sprite (item in my code) with a particle system. This code is placed in my board class. This one works:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = ccpSub(item.position,ccp(160,160));
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
This one doesn't:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = item.position;
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
I tried player with this but without success:
particles.positionType = CCPositionTypeMake(CCPositionUnitUIPoints, CCPositionUnitUIPoints, CCPositionReferenceCornerBottomLeft);
My board is a 320x320 points CCSprite with anchor point set at 0.5, 0.5
When I log my item.position value, I get something relative to the bottom left corner of my board (from 30,30 to 290,290)
Is using ccpSub the correct way ?
When you destroy a node you also destroy all of it's children nodes, you said you add your particle to 'item' then you destroy that 'item', which means you have no particle anymore.
I have a CCLayer which has multiple children (Sprites, CCMenuItemImages ets). And these children are having their children (mostly CCLabel*** or CCMenuItemImages). So I want to fade out the all the grand-children and children of the layer and then once all are faded I want to remove the CCLayer.
I am able to apply fade action to the hierarchy. But if I do [CCLayer removeFromParentWithCleanup:YES], then it removes immediately while still some children are running with fade action.
So my question is how can i remove the parent layer once all the gran-children and children are faded (opacity = 0).
Edit: Here is a code snippet
for(CCNode *node in itemLayer.children)
{
for(CCSprite *sprite in parentLayer.children)
{
for(id item in sprite.children)
[item runAction:[CCFadeTo actionWithDuration:2.5f opacity:0]];
[sprite runAction:[CCFadeTo actionWithDuration:2.5f opacity:0]];
}
}
itemLayer is the Parent CCLayer which has a CCNode *node. node is having children and each children have their children. So I want to remove the node and its parent itemLayer once all the actions completes on children and gran-children. How to do this?
Make your top level container a CCNodeRGBA and set in the init :
self.cascadeColorEnabled=YES;
self.cascadeOpacityEnabled=YES;
self.opacity=255;
When you run a CCFadeAction on that, the node will do all the forklifting of cascading down to children and grand-children. At the end of the fade action,
id fade = [CCFadeTo actionWithDuration:2.5 opacity:0];
id done = [CCCallBlock actionWithBlock:^{
[self removeFromParentAndCleanup:YES];
// plus whatever else you see fit
}];
id seq = [CCSequence actions:fade, done, nil];
[self runAction:seq];
ob cit : from memory, not compiled nor tested, YMMV
hi there I am making a game with Sprite Kit and I have a method which has a NSArray, a for loop and some SKACTIONS. Now, this array has 7 items. the for loop randomly picks up one of the array's content and shows on the screen and using SKActions, that item scales down and another scales up. however, at the bottom of the similuator, it shows that numbers of nodes keep piling up. for example, if one sprite appears, instead of 1 node, 4 nodes shows as the number of nodes at the bottom of Simulator's screen. What do you think might be wrong here?
here is my code.
-(void) ItemMakerMe {
myArray = [[NSMutableArray alloc] initWithObjects:#"item1", #"item2", #"item3", #"item4", #"item5", #"item6", #"MyNull", nil];
NSUInteger arraypicker = arc4random() % [myArray count];
for (int i=0; i < arraypicker; ++i) {
NSString *d1 = [myArray objectAtIndex:i];
sprites = [SKSpriteNode spriteNodeWithImageNamed:d1];
sprites.name = #"items";
sprites.position = CGPointMake(ScalarRandomRange(0, self.size.width/2), ScalarRandomRange(0, self.size.height/2));
sprites.xScale = 0;
sprites.yScale = 0;
[self addChild:sprites];
}
}
-(void) OneItemONLY {
SKAction *appear = [SKAction scaleTo:0.19 duration:0.5];
SKAction *waiter = [SKAction waitForDuration:0.5];
SKAction *scaleDown = [SKAction scaleTo:0.0 duration:0.5];
SKAction *remover = [SKAction removeFromParent];
[sprites runAction:[SKAction sequence:#[appear, waiter, scaleDown, remover]]];
}
Also in the init method I run it like this:
[self runAction:[SKAction repeatActionForever:[SKAction sequence:#[[SKAction performSelector:#selector(ItemMakerMe) onTarget:self],
[SKAction waitForDuration:2.0]]]]];
[self runAction:[SKAction repeatActionForever:[SKAction sequence:#[[SKAction performSelector:#selector(OneItemONLY) onTarget:self],
[SKAction waitForDuration:2.0]]]]];
if I understood correctly, I believe that the for loop runs the action of the last node of i value but still adds the other sprites before the loop ends.
I.E: Lets say the arraypicker has a value of 4, then the for-loop will then select the NSString from the array, initialize the sprites object with the image, name, position, etc and then it is added to self's children, this repeats 4 times but only the last added instance of sprites will have the image you want and will run the actions.
What I mean is that if you only want to select a random value from the array, and set its properties maybe you could remove the for-loop.
Summary: [self addChild:sprites] is adding the same object i times and is causing an increment of nodes.
In cocos2d-x, how can I display the bounding box for all sprites that are children of this layer?
Here's my starting point:
void MyLayer::draw()
{
// super draw
CCLayer::draw();
// Iterate through all nodes of this layer
for ( CCNode* node = ??? )
{
// Make sure the node is a CCSprite
if ( node == CCSprite ??? )
{
CCSprite* sprite = (CCSprite*) node;
ccDrawRect( sprite->boundingBox() ??? );
}
}
}
//put this line at the top of your cpp file
#define CC_VERIFY_TYPE(__OBJECT__,__CLASS_TYPE__) assert(dynamic_cast<__CLASS_TYPE__>(__OBJECT__))
//these lines in your code
CCObject* child;
CCARRAY_FOREACH(m_pChildren, child)
{
CC_VERIFY_TYPE(child,CCSprite*);
CCSprite* sprite = (CCSprite*) child;
CCSize s = sprite->boundingBox().size;
ccDrawRect(sprite->boundingBox().origin, ccpAdd(sprite->boundingBox().origin, (ccp(s.width,s.height))));
}
As you create all sprites in this layer by your own, you can, for example, create simple node, that will draw bounding box of its parent. Then just add instance of this node to any node/sprite you want to see.
Another way is to add all sprites/nodes you want to see in additional array and draw bounding box of each object in this array.