this is probably a very quick and easy answer for someone, but I'm having a hard time figuring it out as a noob. I'm trying to run my CCAnimation and then run a second action that removes the animation from the screen upon completion. Before I can get to that point I'm getting a "Incompatible pointer types sending 'CCAction *' to parameter of type 'CCFiniteTimeAction *'" error. I suspect I need to use something besides CCRepeat to run my animation, but I'm not sure what to replace it with. Thank you!!
NSMutableArray *crabAnimFrames = [NSMutableArray array];
for (int i=1; i<=10; i++) {
[crabAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"bashCrab%d.png",i]]];
}
CCAnimation *crabAnim = [CCAnimation animationWithSpriteFrames:crabAnimFrames delay:0.1f];
CGSize winSize = [CCDirector sharedDirector].winSize;
float randomOffset = CCRANDOM_X_Y(-winSize.height * 0.25, winSize.height * 0.25);
render.node = [CCSprite spriteWithSpriteFrameName:#"bashCrab1.png"];
render.node.position = ccp(winSize.width * 0.25, winSize.height * 0.5 + randomOffset);
render.crabWalk = [CCRepeat actionWithAction:[CCAnimate actionWithAnimation:crabAnim] times:1];
[_batchNode addChild:render.node];
[render.node runAction:[CCSequence actions:render.crabWalk, nil]];
How is crabWalk defined? If it is CCAction* change it to CCFiniteTimeAction*.
Related
I have some strange error happening with my game. How anyone can help me to get solve form this.
I have a runner game and hero is collecting coins while running ,when hero touches the coin,now I am showing a particle effect created with the help of particle maker.and it's working fine. But last day I purchased a software and it gives us really good particle effects but it can only export as pngs. so I made sprite sheet and instead of previous particle animation I put this on the contact listener code for showing this effect when hero touches the coin. Unfortunately it is not showing anything. Here is my previous code :
-(void) checkHeroAndCoins {
float fDelta = 0;
if(m_hero->m_bMagnet)
fDelta = iDevPixelX(30);
for(Coin *coin in m_drawLayer.children){
if([coin isKindOfClass:[Coin class]]){
CGRect rCoin = CGRectMake(coin.position.x - coin.contentSize.width * coin.scaleX / 2.0f - fDelta,
coin.position.y - coin.contentSize.height * coin.scaleY / 2.0f - fDelta,
coin.contentSize.width * coin.scaleX + fDelta * 2, coin.contentSize.height * coin.scaleY + fDelta * 2);
CGRect rHero = CGRectMake(m_hero.position.x - m_hero.contentSize.width * m_hero.scaleX / 2.0f, m_hero.position.y, m_hero.contentSize.width * m_hero.scaleX, m_hero.contentSize.height * m_hero.scaleY);
if(CGRectIntersectsRect(rCoin, rHero)){
coin.tag = DELETED_TAG;
g_nCoin++;
[[AppDelegate getDelegate] playSystemEffect:E_COIN];
// this below code is to show the particle effect and its working perfect
CCParticleSystem *effect = [ARCH_OPTIMAL_PARTICLE_SYSTEM particleWithFile:#"arroweffect.plist"];
[self addChild:effect];
effect.position = ccp(self.contentSize.width * self.scaleX / 2, self.contentSize.height * self.scaleY / 2.0f);
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
effect.scale *= 2;
}
}
}
[[AppDelegate getDelegate] saveSetting];
}
But after I put sprite sheet as animation to show the effect , it is not working , I tried my best but not able to solve this. this is my code for the sprite sheet animation :
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: #"coinsprite.plist"];
//load the sprite sheet into a CCSpriteBatchNode object. If you're adding a new sprite
//to your scene, and the image exists in this sprite sheet you should add the sprite
//as a child of the same CCSpriteBatchNode object otherwise you could get an error.
CCSpriteBatchNode *parrotSheet12 = [CCSpriteBatchNode batchNodeWithFile:#"coinsprite.png"];
//add the CCSpriteBatchNode to your scene
[self addChild:parrotSheet12];
//load each frame included in the sprite sheet into an array for use with the CCAnimation object below
NSMutableArray *flyAnimFrames12 = [NSMutableArray array];
for(int i = 1; i <=30; ++i) {
[flyAnimFrames12 addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"coins%04d.png", i]]];
}
//Create the animation from the frame flyAnimFrames array
CCAnimation *flyAnim12 = [CCAnimation animationWithFrames:flyAnimFrames12 delay:1.0f];
//create a sprite and set it to be the first image in the sprite sheet
CCSprite * dragont2 = [CCSprite spriteWithSpriteFrameName:#"coins0000.png"];
//set its position to be dead center, i.e. screen width and height divided by 2
[dragont2 setPosition:ccp(600,600)];
//[self moveRandom:theParrot];
//create a looping action using the animation created above. This just continuosly
//loops through each frame in the CCAnimation object
CCAction *flyAction12 = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:flyAnim12 restoreOriginalFrame:NO]];
//start the action
[dragont2 runAction:flyAction12];
//add the sprite to the CCSpriteBatchNode object
[parrotSheet12 addChild:dragont2];
problem got solved
-(void) coinanimationeffect:(CGPoint) ptPos {
m_gamecoinffect = [CCSprite spriteWithSpriteFrameName:#"coins0001.png"];
[self addChild:m_gamecoinffect];
CCAnimate *coineffect = [CCAnimate actionWithSpriteSequence:#"coins%04d.png" numFrames:30 delay:0.01f restoreOriginalFrame:NO];
[m_gamecoinffect runAction:[CCRepeatForever actionWithAction:coineffect]];
m_gamecoinffect.position = ptPos;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
m_gamecoinffect.scale *= 2;
}
added this function
and call that function in
-(void) checkHeroAndCoins {
float fDelta = 0;
if(m_hero->m_bMagnet)
fDelta = iDevPixelX(30);
for(Coin *coin in m_drawLayer.children){
if([coin isKindOfClass:[Coin class]]){
CGRect rCoin = CGRectMake(coin.position.x - coin.contentSize.width * coin.scaleX / 2.0f - fDelta,
coin.position.y - coin.contentSize.height * coin.scaleY / 2.0f - fDelta,
coin.contentSize.width * coin.scaleX + fDelta * 2, coin.contentSize.height * coin.scaleY + fDelta * 2);
CGRect rHero = CGRectMake(m_hero.position.x - m_hero.contentSize.width * m_hero.scaleX / 2.0f, m_hero.position.y, m_hero.contentSize.width * m_hero.scaleX, m_hero.contentSize.height * m_hero.scaleY);
if(CGRectIntersectsRect(rCoin, rHero)){
coin.tag = DELETED_TAG;
g_nCoin++;
[[AppDelegate getDelegate] playSystemEffect:E_COIN];
[self coinanimationeffect:ccp(coin.position.x, coin.position.y)];
}
}
}
[[AppDelegate getDelegate] saveSetting];
}
Problem
As of right now, I've just realised a pretty major design flaw in my application..
So, the problem is:
A rifle shot is fired, and lands based on no trajectory as of right now, I'm toying with the idea. However, the bullets land and their marks are left as nodes.
-(void)applyShot:(int) posX with:(int) posY {
SKSpriteNode *impact = [[SKSpriteNode alloc] initWithColor:[UIColor grayColor] size:CGSizeMake(2, 2)];
impact.zPosition = 1;
impact.userInteractionEnabled = NO;
impact.position = CGPointMake(posX , posY);
[backgroundImage addChild:impact];
}
And posX / posY are sent this way.
//Find difference between centre and background moved distance.
CGPoint positionNow = CGPointMake(backgroundImage.position.x, backgroundImage.position.y);
CGPoint positionPrev = CGPointMake(0.5, 0.5);
float xdiff = positionNow.x - positionPrev.x;
float ydiff = positionNow.y - positionPrev.y;
//Calculate ydrop
int newYDrop = yDrop * 10;
//
CGPoint newPositionOne = CGPointMake(0.5 - xdiff, 0.5 - ydiff);
newPositionOne = CGPointMake((newPositionOne.x + [self myRandom:15 withFieldLower:-15]), (newPositionOne.y - newYDrop));
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(secondsDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void){
[self applyShot:newPositionOne.x with:newPositionOne.y];
});
Which seems to work fine, until I started toying with zoom.
Now, this application basically is a 1080p image for the reticle, and the background enlarges to give the (zoom) effect, then the background is touch-dragged/inverted to give the reticle moving effect.
Then I managed to get it to fire exactly where the crosshair was, which was good.. Then I started toying with zoom and noticed this.
So if it's not too easy to notice, the (bullet hits) are the grey marks, however, when you enlarge the backgroundImage they aren't tied to it. so they remain the same spread.
Solution
Now what I need is to either,
A: tie the nodes to the backgroundImage
B: enlarge the spread to the same factor as the enlargement.
But I'm pretty confused at how to achieve this.
Additional problem
When calibrating the drop, the drop will remain a burden no matter of the zoom as of right now. so if it's a 1 mil-dot drop on 6x zoom, it's also a 1 mil-dot drop at 10x zoom or 1x zoom ( I keep saying zoom when I mean enlargement )
How can I achieve a calibration for drop intensity no matter what enlargement the background image is at?
Thanks for reading and confusing yourself with my dire problems, it's appreciated!
What I've Tried
saving the children to a mutable array, then recreating them after a zoom change;
//recreate children
[backgroundImage removeAllChildren];
for (int i=0; i < [shotsHitX count]; i++) {
double posX = ([shotsHitX[i] doubleValue] / 5) * rifleZoom;
double posY = ([shotsHitY[i] doubleValue] / 5) * rifleZoom;
SKSpriteNode *impact = [[SKSpriteNode alloc] initWithColor:[UIColor grayColor] size:CGSizeMake(2, 2)];
impact.zPosition = 1;
impact.userInteractionEnabled = NO;
impact.position = CGPointMake(posX , posY);
[shotsHitX addObject:[NSNumber numberWithDouble:posX]];
[shotsHitY addObject:[NSNumber numberWithDouble:posY]];
[backgroundImage addChild:impact];
}
//end recreate children
Crash with memory error.
not so good at this!
[backgroundImage removeAllChildren];
for (int i=0; i < [shotsHitX count]; i++) {
double posX = ([shotsHitX[i] doubleValue] / 5) * rifleZoom;
double posY = ([shotsHitY[i] doubleValue] / 5) * rifleZoom;
SKSpriteNode *impact = [[SKSpriteNode alloc] initWithColor:[UIColor grayColor] size:CGSizeMake(2, 2)];
impact.zPosition = 1;
impact.userInteractionEnabled = NO;
impact.position = CGPointMake(posX , posY);
[backgroundImage addChild:impact];
}
//end recreate children
Works, however, now It doesn't just seem quite right..
I think the problem is when the initial zoom goes in it works, then when it reverts it's mixing zoom shots in the array with old shots.. Here we go again, MORE ARRAYS.
//recreate children
[backgroundImage removeAllChildren];
for (int i=0; i < [shotsHitRem count]; i+= 2) {
double posX = ([shotsHitRem[i] doubleValue] / 5) * rifleZoom;
double posY = ([shotsHitRem[i+1] doubleValue] / 5) * rifleZoom;
SKSpriteNode *impact = [[SKSpriteNode alloc] initWithColor:[UIColor grayColor] size:CGSizeMake(2, 2)];
impact.zPosition = 1;
impact.userInteractionEnabled = NO;
impact.position = CGPointMake(posX , posY);
[backgroundImage addChild:impact];
//add olds m4
if ([shotsHitM4 count] > 0) {
posX = ([shotsHitM4[i] doubleValue] / 2) * rifleZoom;
posY = ([shotsHitM4[i+1] doubleValue] / 2) * rifleZoom;
impact.position = CGPointMake(posX, posY);
[backgroundImage addChild:impact];
}
}
//end recreate children
Now I crash attempting to add a sknode which already has a parent
Confusing as it should removeAllChildren before looping
Well after some major messing around
[backgroundImage setScale:rifleZoom];
Programming is my favourite, oh yeah.. Five hours, Oh yeah.. For one line, oh yeah!
I wasn't scaling before, I was creating a new cgsize. and that was my problem.
I now have the issue of scaling and trying to render a new centrepoint as it still remembers the centrepoint of scale = 1 and scale = 2, nightmare.
I have created an application similar to Candy Crush Saga application using Cocos2d V3 in iPhone and iPad. I want the ray animation on candy. The ray should passed in different directions and at different distance. I have attached the Image for the reference.
I have also the sequence of animation Images of ray like,
Could any one can assist me how this can be done ?
To find the angle of rotation:
CGPoint difference = ccpSub(targetCloud.position, sourceCloud.position);
CGFloat rotationRadians = ccpToAngle(difference);
CGFloat rotationDegrees = -CC_RADIANS_TO_DEGREES(rotationRadians);
rotationDegrees -= 90.0f;
CGFloat rotateByDegrees = rotationDegrees - targetCloud.rotation;
To find the scale :
float dist = ccpDistance(targetCloud.position,sourceCloud.position);
CCSprite *line = [CCSprite spriteWithImageNamed:#"0_light.png"];
float scale = dist / line.boundingBox.size.width;
To create the animation :
-(CCActionSequence *)createRayAnimationFrom:(CGPoint)startPosition atAngle:(float)angle toScale:(float)scale
{
//Using Texture packer
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode batchNodeWithFile:#"light.pvr.ccz"];
[self addChild:batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"light.plist"];
CCSprite *raySprite = [CCSprite spriteWithSpriteFrameName:#"0_light.png"];
raySprite.position = startPosition;
raySprite.anchorPoint = ccp(0.5, 0.0);
[batchNode addChild:raySprite];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=12;i++)
{
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:#"%d_light.png",i]];
[animFrames addObject:frame];
}
CCAnimation *animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.1f;
animation.restoreOriginalFrame = YES;
CCActionAnimate *animAction = [CCActionAnimate actionWithAnimation:animation];
CCActionSequence *animSequence = [CCActionSequence actions:[CCActionRotateBy actionWithDuration:0.1 angle:angle],[CCActionScaleBy actionWithDuration:0.1 scaleX:1.0f scaleY:scale],animAction,[CCActionCallBlock actionWithBlock:^{
[CCActionRemove action];
}], nil];
[raySprite runAction:animSequence];
}
You have to call this function for each target cloud:
[self createRayAnimationFrom:sourceCloud atAngle:rotateByDegrees toScale:scale];
I have to animate(dancing) a character(guy) for about 6-7 seconds i.e 500-600 frames. I have done animation before by creating spritesheets using zwoptex and then loading it with CCSpriteFrameCache && CCSpriteBatchNode with the help of The Great Ray Wenderlich. But in this case frames are heavy in number i am not sure if iOS device will be able to sustain it. What is the best process to animate all these frames with as little overhead as possible. Can i change the fps while animating? any idea anyone??
Here I put code That use for add Animated Image Without use TexturePacker:
CCSprite *dog = [CCSprite spriteWithFile:#"dog1.gif"];
dog.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dog z:2];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=5;i++)
{
NSString* file = [NSString stringWithFormat:#"dog%d.gif", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[animFrames addObject:frame];
}
CCAnimation * animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.07f;
animation.restoreOriginalFrame = YES;
CCAnimate *animAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
[dog runAction:animAction];
Try with This code, I'm not sure might be helpful in your case:
I have an accelerometer that I use to shift layers of UIImageviews slightly, to get some depth perception.
Here is the code I use to instantiate the animations and accelerometer inside my viewdidload method.
UIAccelerometer *accelerator = [UIAccelerometer sharedAccelerometer];
accelerator.delegate = self;
accelerator.updateInterval = 0.1f;
animateLayer0 = [CABasicAnimation animationWithKeyPath:#"position"];
animateLayer1 = [CABasicAnimation animationWithKeyPath:#"position"];
animateLayer2 = [CABasicAnimation animationWithKeyPath:#"position"];
animateLayer0.duration = 0.1;
animateLayer0.fillMode = kCAFillModeForwards;
animateLayer0.removedOnCompletion = false;
animateLayer1.duration = 0.1;
animateLayer1.fillMode = kCAFillModeForwards;
animateLayer1.removedOnCompletion = false;
animateLayer2.duration = 0.1;
animateLayer2.fillMode = kCAFillModeForwards;
animateLayer2.removedOnCompletion = false;
Here is the accelerometer function's code:
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
self.difference = 0 - acceleration.y;
if (fabsf(self.difference) > 0.01) {
for (int i = 0; i < self.accLayerPoints0.count; i++) {
NSValue *val = [self.accLayerPoints0 objectAtIndex:i];
CGPoint origin = [val CGPointValue];
float x = origin.x + (acceleration.y * ACC_LAYER0_THRESHOLD);
[animateLayer0 setToValue:[NSValue valueWithCGPoint:CGPointMake(x, origin.y)]];
UIImageView *layer0 = [self.accLayerObjects0 objectAtIndex:i];
[layer0.layer addAnimation:animateLayer0 forKey:nil];
}
for (int i = 0; i < self.accLayerPoints1.count; i++) {
NSValue *val = [self.accLayerPoints1 objectAtIndex:i];
CGPoint origin = [val CGPointValue];
float x = origin.x + (acceleration.y * ACC_LAYER1_THRESHOLD);
[animateLayer1 setToValue:[NSValue valueWithCGPoint:CGPointMake(x, origin.y)]];
UIImageView *layer0 = [self.accLayerObjects1 objectAtIndex:i];
[layer0.layer addAnimation:animateLayer1 forKey:nil];
}
for (int i = 0; i < self.accLayerPoints2.count; i++) {
NSValue *val = [self.accLayerPoints2 objectAtIndex:i];
CGPoint origin = [val CGPointValue];
float x = origin.x + (acceleration.y * ACC_LAYER2_THRESHOLD);
[animateLayer2 setToValue:[NSValue valueWithCGPoint:CGPointMake(x, origin.y)]];
UIImageView *layer0 = [self.accLayerObjects2 objectAtIndex:i];
[layer0.layer addAnimation:animateLayer2 forKey:nil];
}
}
}
My problem is after a while the ipad starts having performance issues, starts lagging.
I've used the Allocations tool to verify that it is the code in the accelerometer function that's causing the issue.
Is there a way to release the objects thats not in use anymore or clean the code?
I'm using ARC so I'm not sure how the cleaning works.
I don't think allocations are your problem. I'll bet if you use the time profiler, you'll see you're blocking the main thread with all that accelerometer activity. You are doing all this in a number of very tight loops for every single accelerometer event, which is probably WAY more than you realize.
Consider putting the position computations in a background queue and updating the positions of the UI objects on the main thread (this part is required, since it's generally not safe to update UI from a background queue). Do this by dispatching the actual UI update commands to the main queue. Maybe create a funnel point (-updateUIWithDictionaryContainingComputedPositionsForEachLayer:, called on the main queue with your background-computed values).
It's doubtful also that you need every single accelerometer event. Throttle the processing (Grand Central Dispatch can help there too, or a simple countdown-restart-if-new-event NSTimer) so not every single event is processed. You'll need to experiment to find the perceptual 'sweet spot' as a balance between smooth-looking animation and efficient responsiveness, but I'll bet the number of updates needed for a smooth visual effect is MUCH LOWER than the number of accelerometer events you're processing.