CCSprite runAction: crash. - objective-c

I am trying to animate static, like on a tv. I have 5 frames, and I am trying to switch them out very quickly. Every time I run it, I get an unrecognized selector error and a crash. It crashes on [staticSprite runAction:repeat];. I am new at cocos2d.
CCLayer *staticlayer = [[CCLayer alloc]init];
staticlayer.contentSize = CGSizeMake(640, 960);
staticlayer.position = CGPointMake(winSize.width/2, winSize.height/2);
staticlayer.isRelativeAnchorPoint = YES;
NSArray *staticFrames = [[NSArray alloc]initWithObjects:#"static_0.jpg",
#"static_1.jpg",#"static_2.jpg",#"static_3.jpg",#"static_4.jpg",nil];
CCSprite *staticSprite = [CCSprite spriteWithFile:#"static_0.jpg"];
staticSprite.position = ccp(winSize.width/2, winSize.height);
CCAnimation *staticAnimation = [CCAnimation animationWithFrames:staticFrames delay:0.1f];
CCAnimate *staticAnimate = [CCAnimate actionWithAnimation:staticAnimation];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:staticAnimate];
[staticlayer addChild:staticSprite];
[self addChild:staticlayer z:0];
[staticSprite runAction:repeat];

Your Array of frames should be CCSpriteFrame objects (as you have them they are NSString, and does not have the methods provided by a CCSpriteFrame, thus the unrecognized selector). Look up here for a good introductory turorial on sprite animations.

Related

CGRectContainsPoint using shape opposed to frame

So we have our detection here
-(void)checkInFOVWithPlayer:(Player *)player andEnemy:(Player *)enemy {
SKNode *fovNode = [player childNodeWithName:player.playersFOVName];
SKNode *node = [self childNodeWithName:#"enemy"];
CGPoint newPosition = [self convertPoint:node.position toNode:fovNode.parent];
if (CGRectContainsPoint(fovNode.frame, newPosition)) {
[self playerAimAtEnemy:enemy withPlayer:player];
}
}
And our implementation for the field of vision
SKShapeNode *fov = [SKShapeNode node];
UIBezierPath *fovPath = [[UIBezierPath alloc] init];
[fovPath moveToPoint:CGPointMake(0, 0)];
[fovPath addLineToPoint:CGPointMake(fovOpposite *-1, fovDistance)];
[fovPath addLineToPoint:CGPointMake(fovOpposite, fovDistance)];
[fovPath addLineToPoint:CGPointMake(0, 0)];
fov.path = fovPath.CGPath;
fov.lineWidth = 1.0;
fov.strokeColor = [UIColor clearColor];
fov.antialiased = NO;
fov.fillColor = [UIColor greenColor];
fov.alpha = 0.2;
fov.name = #"playerFOV";
[_playerImage addChild:fov];
Now, this works. However, the detection range for the "field of vision" is not actually the boundaries of the BezierPath, it's in fact the CGRect that creates the image.
So, the detection will run, even if it's outside of the visual field of vision.
I'm curious as to whether there's an easy fix for this, as I don't really want to go down physics body paths if I don't need to.
Finally I figured out what was required.
I had to redraw the path and optimise it for each frame, after that;
if (CGPathContainsPoint(fovPath.CGPath, nil, newPosition, NO)) {}
Ended my problems.

AVVideoCompositionCoreAnimationTool not adding all CALayers

Okay, this one has me completed stumped. I'm happy to post other code if you need it but I think this is enough. I cannot for the life of me figure out why things are going wrong. I'm adding CALayers, which contain images, to a composition using AVVideoCompositionCoreAnimationTool. I create an NSArray of all the annotations (see interface below) I want to add and then add them to the animation layer with an enumerator. No matter how many, as far as I can tell, annotations are in the array, the only ones that end up in the outputted video are the ones added by the last loop. Can someone spot what I'm missing?
Here's the interface for the annotations
#interface Annotation : NSObject// <NSCoding>
#property float time;
#property AnnotationType type;
#property CALayer *startLayer;
#property CALayer *typeLayer;
#property CALayer *detailLayer;
+ (Annotation *)annotationAtTime:(float)time ofType:(AnnotationType)type;
- (NSString *)annotationString;
#end
And here's the message that creates the video composition with the animation.
- (AVMutableVideoComposition *)createCompositionForMovie:(AVAsset *)movie fromAnnotations:(NSArray *)annotations {
AVMutableVideoComposition *videoComposition = nil;
if (annotations){
//CALayer *imageLayer = [self layerOfImageNamed:#"Ring.png"];
//imageLayer.opacity = 0.0;
//[imageLayer setMasksToBounds:YES];
Annotation *ann;
NSEnumerator *enumerator = [annotations objectEnumerator];
CALayer *animationLayer = [CALayer layer];
animationLayer.frame = CGRectMake(0, 0, movie.naturalSize.width, movie.naturalSize.height);
CALayer *videoLayer = [CALayer layer];
videoLayer.frame = CGRectMake(0, 0, movie.naturalSize.width, movie.naturalSize.height);
[animationLayer addSublayer:videoLayer];
// TODO: Consider amalgamating this message and scaleVideoTrackTime:fromAnnotations
// Single loop instead of two and sharing of othe offset variables
while (ann = (Annotation *)[enumerator nextObject]) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"opacity"];
animation.duration = 3; // TODO: Three seconds is the currently hard-coded display length for an annotation, should this be a configurable option after the demo?
animation.repeatCount = 0;
animation.autoreverses = NO;
animation.removedOnCompletion = NO;
animation.fromValue = [NSNumber numberWithFloat:1.0];
animation.toValue = [NSNumber numberWithFloat:1.0];
animation.beginTime = time;
// animation.beginTime = AVCoreAnimationBeginTimeAtZero;
ann.startLayer.opacity = 0.0;
ann.startLayer.masksToBounds = YES;
[ann.startLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.startLayer];
ann.typeLayer.opacity = 0.0;
ann.typeLayer.masksToBounds = YES;
[ann.typeLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.typeLayer];
ann.detailLayer.opacity = 0.0;
ann.detailLayer.masksToBounds = YES;
[ann.detailLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.detailLayer];
}
videoComposition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:movie];
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:animationLayer];
}
return videoComposition;
}
I want to stress that the video outputs correctly and I do get the layers appearing at the right time, just not ALL the layers. Very confused and would greatly appreciate your help.
So I was fiddling around trying to figure out what might have caused this and it turns out that it was caused by the layers hidden property being set to YES. By setting it to NO, all the layers appear but then they never went away. So I had to change the animation's autoreverses property to YES and halve the duration.
So I changed the code to this:
while (ann = (Annotation *)[enumerator nextObject]){
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"opacity"];
animation.duration = 1.5; // TODO: Three seconds is the currently hard-coded display length for an annotation, should this be a configurable option after the demo?
animation.repeatCount = 0;
animation.autoreverses = YES; // This causes the animation to run forwards then backwards, thus doubling the duration, that's why a 3-second period is using 1.5 as duration
animation.removedOnCompletion = NO;
animation.fromValue = [NSNumber numberWithFloat:1.0];
animation.toValue = [NSNumber numberWithFloat:1.0];
animation.beginTime = time;
// animation.beginTime = AVCoreAnimationBeginTimeAtZero;
ann.startLayer.hidden = NO;
ann.startLayer.opacity = 0.0;
ann.startLayer.masksToBounds = YES;
[ann.startLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.startLayer];
ann.typeLayer.hidden = NO;
ann.typeLayer.opacity = 0.0;
ann.typeLayer.masksToBounds = YES;
[ann.typeLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.typeLayer];
ann.detailLayer.hidden = NO;
ann.detailLayer.opacity = 0.0;
ann.detailLayer.masksToBounds = YES;
[ann.detailLayer addAnimation:animation forKey:#"animateOpacity"];
[animationLayer addSublayer:ann.detailLayer];
}

Sprite animation cocos2d

How can I animate this sprite?
if ((self = [super initWithSpriteFrameName:#"Boss_ship_5.png" world:world shapeName:#"Boss_ship" maxHp:50 healthBarType:HealthBarTypeRed])) {
I'm trying with this, but with _layer doesn't work...
CCSpriteFrameCache * cache =
[CCSpriteFrameCache sharedSpriteFrameCache];
CCAnimation *animation = [CCAnimation animation];
[animation addSpriteFrame:
[cache spriteFrameByName:#"Boss_ship_5.png"]];
[animation addSpriteFrame:
[cache spriteFrameByName:#"Boss_ship_4.png"]];
animation.delayPerUnit = 0.05;
[_layer runAction:
[CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:animation]]];
Before adding sprites to animation object, you'll need to load the textures into the CCSpriteFrameCache. Please, take a look at
http://www.cocos2d-iphone.org/archives/633
Also, CCAnimation actions are supposed to be used with CCSprites. Which class is _layer object?

Mapview crashes in iOS 6

I'm having a problem when I'm loading map view in iOS 6. But it's working 100% with previous OS versions.
Here's the code:
//.h file
MKMapView *galleryListMap; //map view
NSMutableArray *copyOfAllRecords; //array with locations
And here is the code structure in my .m file. I have synthesized variables and released them in dealloc method.
//this will runs in a background thread and populateMap method will make all the annotations
//[self performSelectorInBackground:#selector(populateMap) withObject:nil];
//here is populateMap method
-(void)populateMap{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSArray *existingpoints = galleryListMap.annotations;
//removes alll the existing points
[galleryListMap removeAnnotations:existingpoints];
//assign point to map view
for(int i = 0; i < [copyOfAllRecords count]; i++) {
Gallery *gallery = (Gallery *)[copyOfAllRecords objectAtIndex:i];//array which has the elements
//create location based on the latitude and longtitude
CGFloat latDelta = gallery.latitude;
CGFloat longDelta = gallery.longitude;
CLLocationCoordinate2D newCoord = {latDelta, longDelta};
//adds the notations
AddressAnnotation *addrAnnotation = [[[AddressAnnotation alloc] initWithCoordinate:newCoord]autorelease];
//assing the location the map
[addrAnnotation setId:i];
[addrAnnotation setTitle:gallery.name];
if([gallery.exhibition length]==0 && !gallery.isResturant){
[addrAnnotation setSubtitle:#""];
}else{
[addrAnnotation setSubtitle:gallery.exhibition];
}
**//gives the exception on this line
[galleryListMap addAnnotation:addrAnnotation];**
}
MKCoordinateRegion region;
MKCoordinateSpan span = MKCoordinateSpanMake(0.2, 0.2);
Gallery *lastGalleryItem = [copyOfAllRecords lastObject];
CLLocationCoordinate2D location = {lastGalleryItem.latitude, lastGalleryItem.longitude};
region.span=span;
region.center=location;
[galleryListMap setRegion:region animated:TRUE];
[galleryListMap regionThatFits:region];
galleryListMap.showsUserLocation = YES;
[pool release];
}
- (MKAnnotationView *) mapView:(MKMapView *)mkmapView viewForAnnotation:(AddressAnnotation *) annotation{
static NSString *identifier = #"currentloc";
if([annotation isKindOfClass:[AddressAnnotation class]]){
MKPinAnnotationView *annView = [[[MKPinAnnotationView alloc]initWithAnnotation:addAnnotation reuseIdentifier:identifier]autorelease];
Gallery *galItem = (Gallery *)[copyOfAllRecords objectAtIndex:annotation.annotationId];
CGRect viewFrame;
UIView *myView;
UIImage *tagImage;
//checks whether the resturant or not
if (galItem.isResturant) {
viewFrame = CGRectMake( 0, 0, 41, 45 );
myView = [[UIView alloc] initWithFrame:viewFrame];
tagImage= [UIImage imageNamed:#"map_restaurant"];
}else{
viewFrame = CGRectMake( 0, 0, 41, 45 );
myView = [[UIView alloc] initWithFrame:viewFrame];
tagImage= [UIImage imageNamed:galItem.mapMarker];
}
UIImageView *tagImageView = [[UIImageView alloc] initWithImage:tagImage];
[myView addSubview:tagImageView];
[tagImageView release];
UIGraphicsBeginImageContext(myView.bounds.size);
[myView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[annView setImage:viewImage];
[myView release];
int recordCount =[copyOfAllRecords count];
if (recordCount != 0 ) {
UIButton *annotationButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[annotationButton addTarget:self action:#selector(showLinks:) forControlEvents:UIControlEventTouchUpInside];
annotationButton.tag = [annotation annotationId];
annView.rightCalloutAccessoryView = annotationButton;
}
if([annotation annotationId]==recordCount-1){
//hides loading screen
//[HUD hide:YES];
self.mapAlreadyLoaded = YES;
}
return annView;
}
return nil;
}
The exception I get is:
*** Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSArrayM: 0x21683870> was mutated while being enumerated.'
*** First throw call stack:
(0x32dc62a3 0x3259897f 0x32dc5d85 0x37c4d33b 0x37c50373 0x86e63 0x37dcc67d 0x36e52311 0x36e521d8)
But if I use:
[self populateMap];
//[self performSelectorInBackground:#selector(populateMap) withObject:nil];
the application works fine.
Any idea why this is happening?
There are a number of reasons this could be happening - the error is telling you that at some point you (or an underlying iOS library) tried to enumerate an array that changed while that process was on-going.
The fact that it works when you populateMap off the main thread and doesn't work when you call it on a secondary thread suggests there's some sort of race condition going on.
Bear in mind that not all of UIKit is thread safe (most of it isn't) - so there might be an issue there. You add the annotations to your map whilst still on a background thread:
[galleryListMap addAnnotation:addrAnnotation];
...this is also the line on which your crash happens. It stands to reason that when you add an annotation to a MapView it probably iterates through all its current annotations to update the display. Because you're making these calls off a background thread this could introduce lots of problems.
Instead, try this:
[galleryListMap performSelectorOnMainThread:#selector(addAnnotation:)
withObject:addrAnnotation
waitUntilDone:YES]
This will force the map view to add the annotation on the main thread. As a general rule, there are only a few things in UIKit that are thread-safe (the apple documentation has a complete list).

Multiple Sprite Actions

I am using Cocos2d engine and I've faced a strange problem.
I have a sprite. Also, I have 2 animations for that sprite. And I want to play one animation when app loads and second, after ccTouchevent is called.
walkAnim = [CCAnimation animation];
dropAnim = [CCAnimation animation];
for( int q=1;q<12;q++){
[walkAnim addFrameWithFilename: [NSString stringWithFormat:#"walkforward_%.2d.png", q]];
[dropAnim addFrameWithFilename: [NSString stringWithFormat:#"drop_%.2d.png", q]];
}
action = [CCAnimate actionWithAnimation:walkAnim];
action.duration = 2;
id act = [CCRepeatForever actionWithAction:action];
[sprite runAction:act];
So, here we see an animating sprite.
[sprite stopAllActions]; //and here my torture begins
I have tried many ways of creating an action:
I've tried to add another AnimateAction, tried to replace the current animation, but everything results in a crash.
[action setAnimation:dropAnim];
and
CCAnimate* animat = [[CCAnimate alloc]initWithDuration:30 animation:dropAnim restoreOriginalFrame:YES];
and
id action = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:dropAnim]];
[player1 runAction:action];
The crash is in [CCAnimate actionWithAnimation:]
+(id) actionWithAnimation: (CCAnimation*)anim
{
return [[[self alloc] initWithAnimation:anim restoreOriginalFrame:YES] autorelease];
}
Thanks!
To launch an action from another method, you have to retain the action Eg: [action retain];
To launch an action from another method, you have to retain the action
Eg: [action retain]; and then do not forget to release it
-(void)create{
for( int q=1;q<12;q++){
[playerWalkAnim addFrameWithFilename: [NSString stringWithFormat:#"walkforward_%.2d.png", q]];
}
playerAction = [CCAnimate actionWithAnimation:playerWalkAnim];
playerAction.duration = 2;
[playerAction retain];
}
-(void)launch{
[player1 runAction:playerAction];
}