cocos2d remove tint - cocos2d-iphone

I'm trying to implement a highlight animation to my sprites. The sprite should highlight to a given color and gradually reverse back to its original colors, with the following code:
- (void)highlight {
CCTintTo *tintAction = [CCTintTo actionWithDuration:0.1 red:255 green:255 blue:255];
CCTintTo *tintBackAction = [tintAction reverse];
CCSequence *sequence = [CCSequence actions: tintAction, tintBackAction, nil];
[self runAction:sequence];
}
Now this function raises an exception as CCTintTo doesn't seem to implement 'reverse', which makes sense. Is there any other way to implement removal of an added tint over an interval, using a CCAction?

CCSprite's default color is ccWhite, {255, 255, 255}, so if you
want to make sprite lighter, you'll have to subclass CCSprite/write shader to use additive coloring.
Just tint it back:
CCColor3B oldColor = sprite.color;
CCTintTo *tintTo = [CCTintTo actionWithDuration:t red:r green:g blue:b];
CCTintTo *tintBack = [CCTintTo actionWithDuration:t red:oldColor.r green:oldColor.g blue:oldColor.b];
[sprite runAction:[CCSequence actions: tintTo, tintBack, nil]];

You can store previous color before start tint, then just create CCTintTo with initial RGB values.

For Cocos2dx (C++)
ccColor3B oldColor = sprite->getColor();
CCTintTo* action = CCTintTo::create(0.5f, 127, 255, 127);
CCTintTo* actionReverse = CCTintTo::create(0.5f, oldColor.r, oldColor.g, oldColor.b);;
sprite->runAction(CCSequence::create(action, actionReverse, NULL));
Works fine Kreiri, thanks! I already gave a plus to you:).

Related

Cocos2D CCButton setBackgroundColor not working

I added the following code to the Cocos2D default template's IntroScene:
CCButton *playButton = [CCButton buttonWithTitle:#"Play" fontName:#"HelveticaNeue" fontSize:18.0f];
[playButton setBackgroundColor:[CCColor colorWithWhite:0.7f alpha:1.0f] forState:CCControlStateNormal];
[playButton setBackgroundColor:[CCColor colorWithWhite:0.75f alpha:1.0f] forState:CCControlStateHighlighted];
playButton.positionType = CCPositionTypeNormalized;
playButton.position = ccp(0.5f, 0.35f);
playButton.zoomWhenHighlighted = NO;
playButton.preferredSize = CGSizeMake(222, 46);
[playButton setTarget:self selector:#selector(onSpinningClicked:)];
[self addChild:playButton];
For some reason the button has no background color. Any ideas?
Because you didn't set a color, only brightness (this is what "white" means in the context of CCColor).
Try using a color with this initializer:
CCColor* normalColor = [CCColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0f]
[playButton setBackgroundColor:normalColor forState:CCControlStateNormal];
This will make the button background red.

Syncing sprite animations in cocos2d

Every now and then I add some pulsating sprites to my scene like so:
CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [scene getChildByTag: foo1];
sprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake(0, 0, 128, 128)];
sprite.position = foo2
CCTintTo *a = [CCTintTo actionWithDuration: .5 red:128 green: 128 blue: 128];
CCTintTo *b = [CCTintTo actionWithDuration: .5 red:255 green: 255 blue: 255];
[sprite runAction:[CCRepeatForever actionWithAction:
[CCSequence actionOne: a two: b]]];
[batch addChild: sprite];
I would like to have all my sprites pulsating in sync, how do I go about this?
hmmm ... not easy. The only way i'd see of doing that is to schedule a 'flasherRamp' like so:
in .h
NSMutableArray *flashers;
in .m, init method
flashers = [[NSMutableArray array] retain]; // choose your own ARC flavor, if you retain
// dont forget to release in dealloc
[self schedule:#selector(flasherRamp) interval:1.0f];
in .m, where you create the sprite
foo2.visible=NO;
[flashers addObject foo2];
finally
-(void) flasherRamp {
for (CCSprite *flasher in flashers) {
CCTintTo *a = [CCTintTo actionWithDuration: .5 red:128 green: 128 blue: 128];
CCTintTo *b = [CCTintTo actionWithDuration: .5 red:255 green: 255 blue: 255];
[flasher runAction:[CCRepeatForever actionWithAction:
[CCSequence actionOne: a two: b]]];
flasher.visible=YES;
}
[flashers removeAllObjects];
}
ps. there could be some drift eventually, depending on how long this goes on for.
pps. from a usability perspective, this may not be a good idea if there is some causality between the appearance of the flashing sprites and some 'asynchronous' gaming event that may induce a delay of up to 1 second between the triggering event and the actual appearance of the flasher.
ob cit. : coded from memory, not tested, but should be close.
I would avoid using CCRepeatForever in this case.
Create an enum defining the current tint state (tintGray, tintWhite, tintDone), then create a scheduled selector that checks the state.
Once the state is complete, repeat the actions, but for every child of the batchnode (assuming those are the only children).
To schedule the selector, place the following in your init or other loading method:
// be sure to schedule the interval at a fast enough rate
[self schedule:#selector(tick:) interval:0.1f];
Then define the method as follows:
-(void)tick:(ccTime)dt
{
if(tintState == tintDone)
{
[self unschedule:#selector(tick:)];
[self tinter];
}
}
Then to schedule the tint actions for all sprites:
-(void)tinter
{
// could init and reuse this somewhere else to save on allocs
CCSequence *actions = [CCSequence actions:
[CCCallBlockN actionWithBlock:^(CCNode* node)
{
tintState = tintGray;
}],
[CCTintTo actionWithDuration: .5 red:128 green: 128 blue: 128],
[CCCallBlockN actionWithBlock:^(CCNode* node)
{
tintState = tintWhite;
}],
[CCTintTo actionWithDuration: .5 red:255 green: 255 blue: 255],
[CCCallBlockN actionWithBlock:^(CCNode* node)
{
tintState = tintDone;
}],
nil];
CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [scene getChildByTag: foo1];
for (CCSprite *flasher in batch.children)
{
[flasher stopAllActions];
[flasher runAction:actions];
}
// reschedule tick checking
[self schedule:#selector(tick:) interval:0.1f];
}
Obviously this isn't perfect, as the flag will be driven by the first sprite to complete the tinting, but the delay should be negligible. If you want to make sure they all finish, just change the flag to a running count of the number of sprites, so "tinter" only gets called once tintState is equal to the number of sprites in the batchnode.

put sprites hidden on screen,than fade them in

I need to put some CCsprites on screen that later on will be fade in to screen.
I cant hide them ,because the CCFade action will not work on hidden sprite , or a sprite with opacity=0 .
What i do is put them on screen and fade them out :
[colors[i] runAction:[CCFadeOut actionWithDuration:0]];
[self addChild:colors[i] z:0];
it turned out that fading out in zero time is not unseen, so they appear for a second the moment i add them to CCScene.
How would i put them on screen to be unseen, and than fade them in with CCFadeIn action ?
You can stack actions using a sequence. See the example below from one of my projects :
CCSprite *frame1 = [CCSprite spriteWithSpriteFrame:[frames objectAtIndex:0]];
frame1.flipX = self.flipX;
frame1.scale = self.scaling;
frame1.visible = NO;
frame1.opacity = 255;
frame1.rotation = self.rotation;
frame1.position = self.offset;
animation = [CCAnimation animationWithSpriteFrames:frames delay:(duration / self.numberOfFrames)];
id stall = [CCDelayTime actionWithDuration:delay];
id show = [CCShow action];
id animate = [CCAnimate actionWithAnimation:animation];
id hide = [CCHide action];
id clean = [CCCallBlock actionWithBlock:^{
[frame1 removeFromParentAndCleanup:YES];
}];
id enchiladas = [CCSequence actions:stall, show, animate, hide, clean, nil];
[node addChild:frame1 z:5];
[frame1 runAction:enchiladas];
Similar thing. I want to run an animation that will appear after a set delay time, then vanish and cleanup after itself when complete.
YOU can use sprite.opacity =0; initially
and in actions you can increase the opacity

CCLayerPanZoom won't zoom in or out

I have been having trouble with CCLayerPanZoom for weeks now and finally got close but am still having an issue. I have a tile map that is quite large 8000 pixels x 8000 pixels and what I'd like to to is have the ability to zoom in to about 2.0f and zoom out to about 0.4f. The below code works great in that it lets me pan around my entire tile map and NOT pan past the edges - a common problem with CCLayerPanZoom, however the code will not allow zoom in or out. I have commented out minScale and maxScale for now since neither is working. I have tried changing the location of minScale and maxScale and it doesn't work anywhere. Does anyone have any ideas how to get minScale and maxScale to work so zooming will function?
//PanZoomLayer
_panZoomLayer = [[CCLayerPanZoom node] retain];
[self addChild: _panZoomLayer];
_panZoomLayer.delegate = self;
[_panZoomLayer addChild: _tileMap z :1 tag: kBackgroundTag];
_panZoomLayer.mode = kCCLayerPanZoomModeSheet;
_panZoomLayer.rubberEffectRatio = 0.0f;
CCNode *backgroundZ = [_panZoomLayer getChildByTag: kBackgroundTag];
CGRect boundingRect = CGRectMake(0, 0, 0, 0);
boundingRect.size = [backgroundZ boundingBox].size;
[_panZoomLayer setContentSize: boundingRect.size];
_panZoomLayer.anchorPoint = ccp(0.5f, 0.5f);
_panZoomLayer.position = ccp(0.5f * winSize.width, 0.5f * winSize.height);
_panZoomLayer.panBoundsRect = CGRectMake(0, 0, winSize.width, winSize.height);
_panZoomLayer.minScale = 0.4f;
_panZoomLayer.maxScale = 2.0f;
//end PanZoomLayer
Finally figured it out, by adding the below line to the code above the CCPanZoomLayer finally works great. Hopefully this code hopes others out that have struggled with this cocos2d extension
[[[CCDirector sharedDirector] view] setMultipleTouchEnabled:YES];

cocos2d: Why can't I change a scaled node's position?

I think I'm just understanding scaling/positioning nodes/layers incorrectly. I'm setting up my node like this (node class is derived from CCNode):
-(id) init
{
if ((self = [super init]))
{
// Create parallax background node.
background = [BackgroundNode node];
[self addChild:background z:0];
// Create foreground node.
foreground = [ForegroundLayer node];
[self addChild:foreground z:0];
self.position.y = 500.0f;
self.scaleX = 1.5f;
self.scaleY = 1.5f;
}
return self;
}
It doesn't seem to matter what I set the self.position.y to - the scaled node is always displayed as though it was positioned in the bottom-left of the screen. I've tried playing around with anchorPoint as well, but it doesn't really seem to change anything.
The reason I'm asking is because I'd like to be able to pan vertically when I'm zoomed in - this doesn't seem to really be the right way to accomplish it, though. Any ideas?
self.position.y = 500.0f;
doesn't work. It should be
self.position = ccp(self.position.x, 500.0f);
Please refer to "Cocoa Objective-c Property C structure assign fails".