cocos2d: change CCMenuItemImage when mouse passes over? - cocos2d-iphone

Does anyone know of an easy way to animate a CCMenuItem when the mouse passes over it.
I have read this thread:
Cocos2d CCMenuItem animation upon selection
which seems to cover Cocoa Touch but does not work for me with OS X.
The cocos2d reference lists this method of CCMenuItemImage: which I used this way:
CCMenuItem *beginButtonMenuItem = [CCMenuItemImage itemWithNormalImage:#"BeginButton3.png"
selectedImage:#"BeginButtonSel3.png"
target:self
selector:#selector(beginButtonPressed:)];
However that menu item does not respond by changing the image when the mouse passes over, only when clicked.
the CCMenuItem reference has this method:
(void) selected, stating "The item was selected (not activated), similar to "mouse-over""
but has no sample code ...
Can anyone help implement this?
Thanks

I found it to be quite easy to make the CCMenu change any CCMenuItem to the selected state when the mouse passes over it, giving it a hover effect. First, make sure you've set [window_ setAcceptsMouseMovedEvents:YES];
Then add this function to CCMenu.m (perhaps just after ccMouseDragged definition):
- (BOOL) ccMouseMoved:(NSEvent *)event {
if( ! _visible || ! _enabled)
return NO;
CCMenuItem *currentItem = [self itemForMouseEvent:event];
if(!currentItem) {
if(_highlightedItem != _selectedItem) {
[_highlightedItem unselected];
}
[_highlightedItem release];
_highlightedItem = nil;
return NO;
}
if (currentItem != _highlightedItem) {
[_highlightedItem unselected];
_highlightedItem = currentItem;
[_highlightedItem retain];
[_highlightedItem selected];
}
return YES;
}

Related

Cocos2d - Actions and Animations are not paused

When I do this:
[gameLayer pauseSchedulerAndActions];
Most of the game pauses, but the sprites that are undergoing this action do not pause spinning:
[sprite runAction:[CCRepeatForever actionWithAction:[CCRotateBy actionWithDuration:5.0 angle: 360]]];
Also, those sprites that are running CCAnimations do not stop animating:
CCAnimation *theAnim = [CCAnimation animationWithSpriteFrames:theFrames delay:0.1];
CCSprite *theOverlay = [CCSprite spriteWithSpriteFrameName:#"whatever.png"];
self.theAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:theAnim]];
How can I get these to pause when the game is paused? I would expect “pauseSchedulerAndActions” to pause actions, but that doesn’t seem to be the case.
pauseSchedulerAndActions is not recursive, so it will only affect actions and schedules on the node you are pausing, not it's children.
if your scene/layer is shallow, you could probably just get away with looping through the layer's children and calling (pause/resume)SchedulerAndActions on each, otherwise, if you have a deeper graph, you'll probably want to call it recursively. I wrote up a small test and this worked for me:
-(void) pauseSchedulerAndActions: (BOOL) pause forNodeTree:(id)parentNode shouldIncludeParentNode:(BOOL)includeParent
{
if(includeParent)
{
(pause) ? [parentNode pauseSchedulerAndActions] : [parentNode resumeSchedulerAndActions];
}
for( CCNode *cnode in [parentNode children] )
{
(pause) ? [cnode pauseSchedulerAndActions] : [cnode resumeSchedulerAndActions];
if(cnode.children.count > 0)
{
[self pauseSchedulerAndActions:pause forNodeTree:cnode shouldIncludeParentNode:NO]; // on recurse, don't process parent again
}
}
}
so in your case you could try calling this method and passing in your gameLayer
Try [[CCDirector sharedDirector] pause]; It should pause all animations and movements.

How to Detect the CCSprite Touchevent getBoundingbox equals of CCTouches

I am new to COCOS2d. I am using ccsprite with animation as a button. Now i am struggle to detect the CCTouches and CCsprite getbounding box are equals for click event.
From this way you can achieve what you need and write this code in CCtouches___() :
ArrayList<CCSprite> animation= new ArrayList<CCSprite>();
CGPoint location = CCDirector.sharedDirector().convertToGL(CGPoint.ccp(event.getX(), event.getY()));
for (CCSprite target : animation){
if(CGRect.containsPoint((target.getBoundingBox()), location)){
//here what you want
}

cocos2d scene retaining issue

There is a scene in my application which has only two labels and a menu item. When I load this scene using replaceScene method it stays for 3-4 seconds and then gets disappeared or released. I want to keep it until cancel button is pressed. How can I do it? code is:
#implementation MyLayer
+ (id)myScene {
CCScene *aScene = [CCScene node];
MYLayer *myLayer = [MyLayer node];
[aScene addChild:myLayer];
return aScene;
}
- (id) init {
if (self = [super init]) {
//labels and menu here
}
return self;
}
And I am calling it from another scene like this:
[[CCDirector sharedDirector] replaceScene: [MyLayer myScene]];
Maybe the problem is that it's your first scene. Then you should use runWithScene method of CCDirector.
did you try replacing that scene with a "empty" init function to see if it still releases itself? It might be because of the amount of textures you are putting into memory
I did have sort of similar problems before because the images used in the new scene is too big and got auto purged by my app delegate, thus returning me an empty scene sometimes

Cocos2d: Preloading animation causes a crash

I am trying to preload an animation in the init method of my layer. I then call the animation if the screen is touched. The app crashes with no error message as soon as I touch the screen and seems it is to do with calling the preloaded animation. I would like to do it this way as it seems expensive to create the animation every time the screen is touched - which does seems to work though. Any tips greatly appreciated.
Sample Code:
In my header:
#interface Test : CCLayer {
NSMutableArray *wake;
CCSprite* ani;
CCAnimate *animate;
}
#end
In my implementation:
-(id) init {
if( (self=[super init])) {
// enable touches
self.isTouchEnabled = YES;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"ani.plist" texture:[[CCTexture2D alloc] initWithImage:[UIImage imageNamed:#"ani.png"]]];
ani = [CCSprite spriteWithSpriteFrameName:#"ani1.png"]; //comes from .plist file
ani.anchorPoint=ccp(0,0);
ani.position = ccp(700,65);
[self addChild:ani z:30];
wake = [NSMutableArray array];
for(int i = 1; i <= 4; i++) {
[wake addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"ani%d.png",i]]];
}
animate = [CCAnimate actionWithAnimation:[CCAnimation animationWithFrames:wake delay:1.0f] restoreOriginalFrame:FALSE];
}
return self;
}
Handling the touch:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// run the animation
[ani runAction:animate];
}
Animations in Cocos2d are not designed to be reused. You need to create a new one every time.
Problem solved by creating properties for the array and animation on the class using nonatomic,retain.
You only need to retain the animation but the array can be local.
self.myAnimation = [[CCAnimation animationWithFrames:myAniFramesArray delay:0.1f] retain];
Remember to make the property nonatomic, retain as stated by Chev and to release any objects you retain in the appropriate dealloc method.

Cocos2d - Changing animations after one is over

I've got a CCSprite with three animations: idle, walk and attack. I want to switch between idle and walk depending on whether or not the sprite is moving (if the joystick is beeing used). All of this works great.
For the attacking animation, I want it to run once, and then return to the previous animation when done (ex.: idle) how do I detect when the animation is done?
thanks,
Dave
Alright, so here's what i've done, and it works, although I have no clue if its the right or the best way:
1) store the current animation.
2) If the currentAnimation is attacking, do nothing.
3) when switching between animations, if the new animation is attacking, run a sequence on the sprite, the second action being a callback to a "onDoneAttacking"
4) in the callback, change the current animation
But this isn't veery smooth and it doesn't allow to attack very fast.
Here's what it looks like:
-(void) changeAnimation:(NSString*)name forTime:(int) times {
if(currentAnimation != #"attack" )
{
CCFiniteTimeAction *action = [CCAnimate actionWithAnimation:[self animationByName:name]];
CCRepeat *repeatAction = [CCRepeat actionWithAction:action times:1];
if(name == #"attack") {
id doneAttacking = [CCCallFunc actionWithTarget:self selector:#selector(onDoneAttacking)];
[self runAction:[CCSequence actionOne:repeatAction two:doneAttacking]];
}
else {
[self runAction:repeatAction];
}
currentAnimation = name;
}
}
-(void) onDoneAttacking {
currentAnimation = #"idle";
}