I am using AtlasSpriteManager and AltasSprite to create frame by fram animation with 1 one file. I wanna write something that at first show a simple picture, without any animation and for example when I touch it, it shows some animation and return to the first position and frame. I just can't show the first frame without animation using this code :
Sprite *checker = [Sprite spriteWithFile:#"test.png"];
float frameWidth = [checker boundingBox].size.width / frameNumber;
float frameHeight = [checker boundingBox].size.height;
AtlasSpriteManager *mgr = [AtlasSpriteManager spriteManagerWithFile:fileName];
AtlasSprite *sprite = [AtlasSprite spriteWithRect:CGRectMake(pos.x, pos.y, frameWidth, frameHeight) spriteManager:mgr];
sprite.position = ccp(pos.x, pos.y);
[mgr addChild:sprite];
[layer addChild:mgr];
AtlasAnimation* animation = [AtlasAnimation animationWithName:#"Animation" delay:delay];
assert( animation != nil );
for(int i = 0; i < frameNumber; i++){
[animation addFrameWithRect:CGRectMake(i * frameWidth, 0, frameWidth, frameHeight)];
}
id action = [Animate actionWithAnimation:animation];
assert( action != nil );
id repeatAction;
if(repeatNumber == 0){
repeatAction = [RepeatForever actionWithAction:action];
}else{
repeatAction = [Repeat actionWithAction:action times:repeatNumber];
}
[sprite runAction:repeatAction];
any idea how to do that?
thanx in advance
Updated Answer
I don't think I understood your question as you intended it.
As I understand now, you have a sprite whih you have an animation for. But when the animation is finished, it doesn't return to the frame that you want the sprite to be set to when standing still.
In our code you use actionWithAnimation:, have you tried setting that to actionWithAnimation:restoreOrigionalFrame: and then set restoreOrigionalFrame part to YES?
That should render the animation, but then when it stops, return to the frame it was before the animation.
Alternatively, you can make the action run, then when it stops, return to a certain frame manually by calling setTextureRect: on the AtlasSprite.
[sprite setTextureRect:CGRectMake( x, y, width, height )];
below this marker is my old answer:
The code that you have now will animate it immediately.
If you want the animation to start on touch, you'll have to check for touches. Then add the code to start the animation in the method that receives the touch.
There is sample code on how to use touches in the cocos2d download.
Basically: make your sprite a TargetedTouchDelegate (or create a new object to do that, but that's a bit of a hassle) and implement -(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
I think that you need CallFunc action combined with Sequence action.
From your code:
}
.....
.....
id action = [Animate actionWithAnimation:animation];
assert( action != nil );
id repeatAction;
if(repeatNumber == 0){
repeatAction = [RepeatForever actionWithAction:action];
}else{
repeatAction = [Repeat actionWithAction:action times:repeatNumber];
}
id actionCallFunc = [CallFunc actionWithTarget:self selector:#selector(resetSprite)];
id actionSequence = [Sequence actions: repeatAction, actionCallFunc, nil];
[sprite runAction:repeatAction];
....
}
-(void)resetSprite{
[sprite runAction:repeatAction];
}
First will be executed your repeatAction and when it ends the actionCallFunc will be executed calling resetSprite method where you can do what you want with your sprite.
Related
I have two sprites one is added as the child of CCSpriteBatchNode and the other as the child of CCParallaxNode. Is there any method to detect their collision? I have used the following code.
-(void)CheckCollition:(CCSprite *)Opp_Obs Opponent:(CCSprite *) H_man
{
// NSLog(#"inside check collision");
CGRect b_rect=[Opp_Obs boundingBox];
CGPoint p_position=[H_man position];
if (CGRectContainsPoint(b_rect,p_position))
{
NSLog(#"collision with opponent");
// Zoom Animation with Points
CCScaleBy *zzomscal=[CCScaleTo actionWithDuration:.2 scale:.12];
CCRotateTo * rotLeft = [CCRotateBy actionWithDuration:0.2 angle:360];
CCCallFunc *ccfun=[CCCallFunc actionWithTarget:self selector:#selector(zoomComplete)];
CCSequence * zzomseq = [CCSequence actions:zzomscal,rotLeft,ccfun, nil];
[H_man runAction:zzomseq];
}
else
{
NSLog(#"no collision");
}
}
But here the control never enters into the loop. Is there any other solution? Anyone please help me.
Set a breakpoint and compare the values of rect and position. One of them may be zero, or way off.
In the latter case you may need to convert the bbox origin and position to world coordinates first in order to compare them. This is the case when the sprites' parents are moving too (parent position != 0,0).
I've hit a wall here. I know how to move an Image using "CGAffineTransformMakeTranslation" and I also know how to scale an image using"CGAffineTransformMakeScale" but for the life of me, I can't seem to get one Image to do both of these and stay that way. It scales to the desired size for about a split second and then immediately reverts to its original size and moves to the desired location. What I need is for the image to get big, STAY big, and then move to a new location (while permanently staying its new size).
Here is what I've got going on in my .m file:
-(IBAction)PushZoomButton {
[UIWindow animateWithDuration:1.5
animations:^{
JustinFrame.transform = CGAffineTransformMakeScale(2.0, 2.0);
JustinFrame.transform = CGAffineTransformMakeTranslation(10.0, 10.0);}];
[UIWindow commitAnimations];}
Any help with this would be appreciated!
you can use CGAffineTransformConcat, for instance:
JustinFrame.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(2.0, 2.0), CGAffineTransformMakeTranslation(10.0, 10.0));
You may need to adapt the translation to (5, 5) since you have doubled the scale
The second transform you set overrides the first one. You need to concat both transform actions into one, as Luis said. Another way of writing that would be:
CGAffineTransform transform = CGAffineTransformMakeScale(2.0, 2.0);
transform = CGAffineTransformTranslate(transform, 10, 10);
JustinFrame.transform = transform;
You may need to look into CoreAnimation, basically what UIView animation is controlling under the hood. If you set up a CAAnimation, then what you want to achieve is done with the fillMode property of the animation.
Here's some example code to make a UIView look like it's opening like a door (copy pasted some code I have, but perhaps you could modify it and find it useful):
- (void) pageOpenView:(UIView *)viewToOpen duration:(NSTimeInterval)duration pageTurnDirection:(PageTurnDirection) p{
// Remove existing animations before stating new animation
[viewToOpen.layer removeAllAnimations];
// Make sure view is visible
viewToOpen.hidden = NO;
// disable the view so it’s not doing anythign while animating
viewToOpen.userInteractionEnabled = NO;
float dir = p == 0 ? -1.0f : 1.0f; // for direction calculations
// create an animation to hold the page turning
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
transformAnimation.removedOnCompletion = NO;
transformAnimation.duration = duration;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CATransform3D startTransform = CATransform3DIdentity;
if (p == NEXT_PAGE) {
// orig values
startTransform.m34 = 0.001f;
}else {
// orig values
startTransform.m34 = -0.001f;
}
// start the animation from the current state
transformAnimation.fromValue = [NSValue valueWithCATransform3D:startTransform];
// this is the basic rotation by 90 degree along the y-axis
CATransform3D endTransform = CATransform3DMakeRotation(3.141f/2.0f,
0.0f,
dir,
0.0f);
// these values control the 3D projection outlook
if (p == NEXT_PAGE) {
endTransform.m34 = 0.001f;
endTransform.m14 = -0.0015f;
}else {
endTransform.m34 = -0.001f;
endTransform.m14 = 0.0015f;
}
transformAnimation.toValue = [NSValue valueWithCATransform3D:endTransform];
// Create an animation group to hold the rotation
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
// Set self as the delegate to receive notification when the animation finishes
theGroup.delegate = self;
theGroup.duration = duration;
// CAAnimation-objects support arbitrary Key-Value pairs, we add the UIView tag
// to identify the animation later when it finishes
[theGroup setValue:[NSNumber numberWithInt:[(BODBookPageView *)viewToOpen pageNum]] forKey:#"animateViewPageNum"]; //STEPHEN: We set the tag to the page number
[theGroup setValue:[NSNumber numberWithInt: p] forKey:#"PageTurnDirection"];
[theGroup setValue:[NSNumber numberWithBool:YES] forKey:#"isAnimationMidpoint"]; // i.e. is this the first half of page-turning or not?
// Here you could add other animations to the array
theGroup.animations = [NSArray arrayWithObjects:transformAnimation, nil];
theGroup.removedOnCompletion = NO; // THIS LINE AND THE LINE BELOW WERE CRUCIAL TO GET RID OF A VERY HARD TO FIND/FIX BUG.
theGroup.fillMode = kCAFillModeForwards; // THIS MEANS THE ANIMATION LAYER WILL STAY IN THE STATE THE ANIMATION ENDED IN, THEREBY PREVENTING THAT ONE FRAME FLICKER BUG.
// Add the animation group to the layer
[viewToOpen.layer addAnimation:theGroup forKey:#"flipViewOpen"];
}
I have a small game that works perfectly when compiling, howevery every second time I
compile it, it gives me the error:
-(void) addHeroCar{
CGSize screenSize = [CCDirector sharedDirector].winSize;
sprite = [CCBodySprite spriteWithFile:#"carNew.png"];
sprite.world = self;
sprite.physicsType = kDynamic;
sprite.collisionType = kBoxCollisionType;
sprite.collidesWithType = kBoxCollisionType | kWallCollisionType;
sprite.position = ccp(screenSize.width / 2, [sprite boundingBox].size.height / 2);
sprite.density = 0.7f;
sprite.friction = 0.3f;
[sprite addBoxWithName:#"box"];
[self addChild:sprite z:1 tag:HERO_TAG];
sprite.fixed = YES;
}
and the debugger shows me the following errors:
-(void) addChild: (CCNode*) child z:(int)z tag:(int) aTag
{
NSAssert( child != nil, #"Argument must be non-nil");
Im using a cocos2d + box2d wrapper from an other developer, just FYI.
Any suggestions?
Regards,
Mirza
So i have the action build to make my frog jump but i have 5 images and i want to run them in the order 1,2,3,4,5,4,3,2,1 using the coordinates. I only want to loop them once everytime the from jumps.
Thanks
while defining your image you can use the following code:
CCAnimation* anim = [CCAnimation animationWithName:#"frog"];
CCSpriteFrame* frames[5];
CGRect Rect;
// some code to initialize Rect position
for(int i=0;i<5;i++)
{
frames[i] = [CCSpriteFrame frameWithTexture:#"frog.png" rect:Rect];
// some code to move Rect so that it will mark next frame;
}
for(int i=0;i<5;i++)
[anim addFrame:frames[i]];
for(int i=3;i>=0;i--)
[anim addFrame:frames[i]];
use ccanimation and ccspritebatchnodefile
save your image sequence in spritesheet
I have 10 CCSprite images. They are continues images. I am using,
CCSprite *playerH = [CCSprite spriteWithFile:#"Player_01.png" ];
playerH.position = ccp(playerH.contentSize.width/2, windowSize.height/2);
[self addChild:playerH z:1];
CCAnimation* animation = [CCAnimation animationWithName:#"dance" delay:0.20f];
for( int i = 1; i < 11; i++ )
{
[animation addFrameWithFilename: [NSString stringWithFormat:#"Player_%02d.png", i]];
}
NSLog(#"k VALUE: k: %d",k);
id actionA = [CCAnimate actionWithAnimation: animation restoreOriginalFrame:NO];
id actionD = [CCDelayTime actionWithDuration:5.0f];
id actionC = [CCCallFunc actionWithTarget:self selector:#selector(enemyEntranceScreen:)];
id seqActionPlayer = [CCSequence actions:actionA, actionD, actionC, nil];
[playerH runAction: seqActionPlayer];
But the animation is not continues. I have changed the animation delay time. but, I can see only three images appearing. How can we know how much time interval should we keep in animation.
Is there any relationship between this and the frame rate
[[CCDirector sharedDirector] setAnimationInterval:1.0/60];
[[CCDirector sharedDirector] setDisplayFPS:YES];
Thank you.
I got my animation smoothly. I think it depends on the
[[CCDirector sharedDirector] setAnimationInterval:1.0/60];
[[CCDirector sharedDirector] setDisplayFPS:YES];
Previously the setAnimationInterval value is 60.0/60. I changed it to 1.0/60. I could find all the images when the value is 1.0/60. I adjusted the animation time delay between the images.
But, when setAnimationInterval is 60.0/60 even I set the value of animation delay to 1second, I could not see all the 10 images displayed.
But, I need some clarification on the setAnimationInterval:
Thank You.