iOS SpriteKit animation not working - ios

I am new to the iOS native game development. I am trying to create animation using some frames for Ideal state for the character. I am following tutorial from the Ray's Website. Look like I am doing everything fine but I can't see animation in working. Only first frame (default) is visible all the time. I debug the code & it's indeed visiting blinking player method where all 3 frames are also present, but nothing happening on screen.
It will be great if someone can guide/help me identify the issue.
#implementation GameScene
{
NSArray *_playerBlinkFrames;
}
// Player
SKNode *_player;
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
[self createPlayer];
}
return self;
}
- (void) createPlayer
{
SKTextureAtlas *playerAnimatedAtlas = [SKTextureAtlas atlasNamed:#"Assets"];
_player = [SKNode node];
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Idle"];
[_player addChild:sprite];
[sprite setName:#"Ball"];
NSMutableArray *blinkFrames = [NSMutableArray array];
SKTexture *temp = [playerAnimatedAtlas textureNamed:#"Idle.png"];
SKTexture *temp2 = [playerAnimatedAtlas textureNamed:#"Blink.png"];
SKTexture *temp3 = [playerAnimatedAtlas textureNamed:#"LookRight.png"];
[blinkFrames addObject:temp];
[blinkFrames addObject:temp2];
[blinkFrames addObject:temp3];
_playerBlinkFrames = blinkFrames;
_player.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:_player];
[self blinkingPlayer];
}
-(void)blinkingPlayer
{
[_player runAction:[SKAction repeatActionForever:
[SKAction animateWithTextures:_playerBlinkFrames
timePerFrame:0.3f
resize:NO
restore:YES]] withKey:#"blinkingInPlacePlayer"];
return;
}
Thanks.

Try this:
// Player
SKSpriteNode *_player;
//..//
SKTextureAtlas *playerAnimatedAtlas = [SKTextureAtlas atlasNamed:#"Assets"];
NSMutableArray *blinkFrames = [NSMutableArray array];
SKTexture *temp = [playerAnimatedAtlas textureNamed:#"Idle.png"];
SKTexture *temp2 = [playerAnimatedAtlas textureNamed:#"Blink.png"];
SKTexture *temp3 = [playerAnimatedAtlas textureNamed:#"LookRight.png"];
[blinkFrames addObject:temp];
[blinkFrames addObject:temp2];
[blinkFrames addObject:temp3];
_playerBlinkFrames = blinkFrames;
SKTexture *tempSprite = _playerBlinkFrames[0];
_player = [SKSpriteNode spriteNodeWithTexture:tempSprite];
I've not tested it, but i think you have create a SKNode player covered by a spritenode.
let me know

Related

How to detect SKSpriteNode Contact but do not react?

I have two SKSpriteNode first Hero
+(id)hero
{
NSMutableArray *walkFrames = [NSMutableArray array];
SKTextureAtlas *heroAnimatedAtlas = [SKTextureAtlas atlasNamed:#"HeroImages"];
int numImages = (int)heroAnimatedAtlas.textureNames.count;
for (int i=1; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"hero%d", i];
SKTexture *temp = [heroAnimatedAtlas textureNamed:textureName];
[walkFrames addObject:temp];
}
Hero *hero = [Hero spriteNodeWithTexture:walkFrames[0]];
hero.heroWalkingFrames = walkFrames;
hero.name =#"Hero";
hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hero.size];
hero.physicsBody.categoryBitMask = heroCategory;
hero.physicsBody.categoryBitMask = obstacleCategory | groundCategory | homeCategory | ~goodiesCategory;
return hero;
}
and second is Coin
SKSpriteNode *coin = [SKSpriteNode spriteNodeWithImageNamed:#"coin"];
coin.size = CGSizeMake(10,10);
coin.position = CGPointMake(100,100);
coin.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:coin.size];
coin.physicsBody.contactTestBitMask = coinCategory;
coin.physicsBody.dynamic=NO;
coin.name = #"coin";
[self.world addChild:coin];
And I am able to get collision detection by
if([contact.bodyA.node.name isEqual: #"coin"] || [contact.bodyB.node.name isEqual: #"coin"])
{
//[self LevelComplete];
SKNode* coinNode ;
if ([contact.bodyA.node.name isEqual: #"coin"]) {
coinNode=contact.bodyA.node;
}
else{
coinNode=contact.bodyB.node;
}
[coinNode removeFromParent];
NSLog(#"Coin touched");
}
Now my problem is every time hero jump and touch the coin it will go down to ground instead to continue jump and reach the height that it should, I know I am missing something here but don't know what it is, So anyone can please show me the right direction to correct this effect .
Create an extra "nilCategory" and set the collisionBitMask of your coin..
coin.physicsBody.collisionBitMask = nilCategory;

game crashes with SIGKILL when running animation on custom SKSpriteNode

I'm encountering a very weird error causing my app to crash. I have created a custom SKSpriteNode called heroSpriteNode. Here is my initialization:
(id) init
{
if (self = [super init])
{
[self loadAnimations];
SKTexture *temp = self.gorillaStandingFrames[0];
self = [heroSpriteNode spriteNodeWithTexture:temp];
[self setUpHeroDetails];
}
return self;
}
The error is occurring when attempting to run an action on "self" the custom SkSpriteNode, like this:
-(void)jump
{
NSLog(#"Jump Tap!");
if(self.isOnTheGround)
{
self.physicsBody.velocity = CGVectorMake(0, 0);
self.physicsBody.angularVelocity = 0;
self.timedJump=NO;
[self.physicsBody applyImpulse:CGVectorMake(0, 350)];
[self removeActionForKey:#"walkingInPlaceBear"];
[self jumpingGorilla2]; // HERE IS THE ERROR
self.isOnTheGround=NO;
self.isRunning=NO;
self.isStanding=NO;
self.jumpFixTimer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:#selector(flipTimedJumpBoolean) userInfo:nil repeats:NO];
}
}
I know this animation (and other animations I run) is the issue, because when I comment out that line the game runs fine.
Here is how I am loading the textures and creating an action:
-(void)loadJumpAnimation2
{
NSMutableArray *jumpFrames = [NSMutableArray array];
SKTextureAtlas *gorillaAnimatedAtlas = [SKTextureAtlas atlasNamed:#"mainCharJump"];
int numImages = gorillaAnimatedAtlas.textureNames.count;
for (int i=2; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"j%d", i];
SKTexture *temp = [gorillaAnimatedAtlas textureNamed:textureName];
[jumpFrames addObject:temp];
}
self.gorillaFlyingJump = jumpFrames;
}
-(void)jumpingGorilla2
{
[self runAction:[SKAction repeatActionForever:
[SKAction animateWithTextures:self.gorillaFlyingJump
timePerFrame:0.25f
resize:NO
restore:YES]] withKey:#"jump"];
return;
}
When it crashes there is no crash report in the logger, only a popup message in Xcode that is of type: 9 SIGKILL. It seems like this could be a memory issue related to how the animation frames are being stored? The animations ran fine on a standard SkSpriteNode, then after refactoring much of the code into a custom SkSpriteNode, I can no longer apply animations. Any ideas? Thank you.
UPDATE:
I've created another class to try to isolate the issue I'm having, I will post the code below with comments.
Here is the entire test class I created:
#import "heroTestNode.h"
#implementation heroTestNode
- (id) init
{
if (self = [super init])
{
[self loadAnimations];
SKTexture *temp = self.gorillaWalkingFrames[0];
self = [heroTestNode spriteNodeWithTexture:temp];
}
return self;
}
-(void)loadAnimations
{
NSMutableArray *walkFrames = [NSMutableArray array];
SKTextureAtlas *gorillaAnimatedAtlas = [SKTextureAtlas atlasNamed:#"mainCharRun2"];
int numImages = gorillaAnimatedAtlas.textureNames.count;
NSLog(#"Here are how many animation frames: %d", numImages);
for (int i=1; i <= numImages; i++) {
NSString *textureName = [NSString stringWithFormat:#"r%d", i];
SKTexture *temp = [gorillaAnimatedAtlas textureNamed:textureName];
[walkFrames addObject:temp];
}
self.gorillaWalkingFrames = walkFrames;
}
-(void)walkingGorilla // running this is causing the SIGKILL 9 crash
{
[self runAction:[SKAction repeatActionForever:
[SKAction animateWithTextures:self.gorillaWalkingFrames
timePerFrame:0.1
resize:NO
restore:YES]] withKey:#"test"];
return;
}
#end
Here is the interface:
#import <SpriteKit/SpriteKit.h>
#interface heroTestNode : SKSpriteNode
#property NSMutableArray *gorillaWalkingFrames;
-(void)walkingGorilla;
#end
And finally, here is how I am instantiating it:
heroTestNode *test = [[heroTestNode alloc] init];
test.position = CGPointMake((self.frame.size.width/2)+30,self.frame.size.height/3);
[self addChild:test];
[test walkingGorilla]; // this is causing the SIGKILL 9 crash
This causes the it to freeze "compressing" the view into the bottom left corner of my iPad and going unresponsive. I have no idea what would be causing this.

end game not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm using a tutorial to create a game where if the rocketship is hit by an asteroid, the ship will show an image using SKEmitterNode and will blink then play a sound. This part of the game is working, however the game will not end. How do I fix this error?
Here's my code where I believe the error is
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
// SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blink];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
}
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition: reveal];
}
}
}
The game is not ending because you are not calling the end-game transition in case of the collsion between the spaceship and asteroid as you do in the case where the collision is between the projectile and the asteroid.
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (asteroidCategory | shipCategory)) {
SKNode *asteroid, *spaceship;
if (contact.bodyA.categoryBitMask == shipCategory) {
spaceship = contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
spaceship = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self runAction:[SKAction playSoundFileNamed:#"explosion_large.caf" waitForCompletion:NO]];
SKAction *blink = [SKAction sequence:#[[SKAction fadeOutWithDuration:0.1],
[SKAction fadeInWithDuration:0.1]]];
SKAction *blinkForTime = [SKAction repeatAction:blink count:6];
[self.spaceship runAction:blinkForTime];
NSString *explosionPath = [[NSBundle mainBundle] pathForResource:#"RocketFlame" ofType:#"sks"];
SKEmitterNode *explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:explosionPath];
CGVector emitterVector = CGVectorMake(spaceship.frame.size.width * 2.0, 0);
explosion.particlePositionRange = emitterVector;
[self.spaceship addChild:explosion];
[self asteroid:(SKSpriteNode *) asteroid didCollideWithasteroid:(SKSpriteNode *) spaceship]; //What does this do?
[self runAction:[SKAction sequence:#[[SKAction waitForDuration:3.0], [SKAction runBlock:^{
[self gameEndedWithSuccess:NO];
}]]]];
}
else if (collision == (projectileCategory| asteroidCategory)) {
SKNode *Projectile, *asteroid;
if (contact.bodyA.categoryBitMask == asteroidCategory) {
Projectile= contact.bodyA.node;
asteroid = contact.bodyB.node;
}
else {
Projectile = contact.bodyB.node;
asteroid = contact.bodyA.node;
}
[self projectile:(SKSpriteNode *) Projectile didCollideWithasteroid:(SKSpriteNode *) asteroid];
self.asteroidsDestroyed++;
if (self.asteroidsDestroyed > 30) {
[self gameEndedWithSuccess:YES];
}
}
}
-(void) gameEndedWithSuccess:(BOOL)success
{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:success];
[self.view presentScene:gameOverScene transition: reveal];
}

EXEC_BAD_ACCESS on SKAction

I'm developing a Spritekit game.
I recevie an EXEC_BAD_ACCESS exception when touchind a node i try to run an action
This function catches the touch
-(void)selectNodeForTouch:(CGPoint)location {
SKNode *touchedNode = (SKNode *)[self nodeAtPoint:location];
NSLog(#"touched : %#",touchedNode.name);
if([[touchedNode name] isEqualToString:#"piece"]){
Piece *piece = (Piece *)[self nodeAtPoint:location];
if ([piece isRotated])
[piece rotateToFront];
else
[piece rotateToBack];
}
}
The object Piece Method rotateBack:
-(void)rotateToBack{
SKAction *rotationToBack = [SKAction animateWithTextures:[self animationFrames] timePerFrame:0.11];
[self runAction:rotationToBack withKey:#"rotation-to-back"];
[self setRotated:YES];
};
[self animationFrames] is a NSMutable array converted into NSArray with
[self setAnimationFrames:[NSArray arrayWithArray:frames]];
Finally frames is an the NSMutableArray containing some SKTextures
The executions brokes on animation execution.
In the Piece class
Change this line:
NSString *imageName = [NSString stringWithFormat:#"%#-1%#",[self baseImageName],imageResolution];
to
NSString *imageName = [NSString stringWithFormat:#"%#-1",[self baseImageName]];

iOS SpriteKit animation does not appear

I'm loading an animation using textures from a TextureAtlas.
But the animation does not appear on screen.
I appears only when I NSLog the Textures! Looks like a bug.
Does somebody made similar experience?
SKTextureAtlas *atlas = [SKTextureAtlas atlasWithRetinaCorrection:spriteSheetName_];
if ([atlas.textureNames count] == 0) return;
NSArray *r = [self getSprites:WEAPON_FIREANIMATION ofDict:atlas.textureNames];
if ([r count] == 0)return;
SKSpriteNode *firstSprite = (SKSpriteNode*)[self childNodeWithName:tFIRSTSPRITE];
[firstSprite removeActionForKey:aFIRE_ANIM];
NSMutableArray *walkAnimFrames = [NSMutableArray array];
int k =0;
if (self.weaponAnimDuration == 0)
{
k = (self.weaponShootInterval / 0.1f)/[r count];
} else
{
k = (self.weaponAnimDuration / 0.1f)/[r count];
}
for (int i = 0; i<k; i++)
{
for (NSString *sname in r)
{
[walkAnimFrames addObject:[SKTexture textureWithImageNamed:sname]];
}
}
NSLog(#"%#",walkAnimFrames);
SKAction *weaponAnim = [SKAction animateWithTextures:walkAnimFrames timePerFrame:0.1f];
[firstSprite runAction:weaponAnim withKey:aFIRE_ANIM];
#import "SKTextureAtlas+MySKTextureAtlas.h"
#implementation SKTextureAtlas (MySKTextureAtlas)
+(SKTextureAtlas*)atlasWithRetinaCorrection:(NSString*)name
{
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00)
{
name = [NSString stringWithFormat:#"%##2x",name];
}
NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:#"atlasc"];
if (path == Nil) return Nil;
return [SKTextureAtlas atlasNamed:name];
}
#implementation NSArray (Tools)
-(NSArray*)animationTextureFrames
{
NSMutableArray *rr = [NSMutableArray new];
for (NSString *name in self)
{
SKTexture *tex = [SKTexture textureWithImageNamed:name];
[rr addObject:tex];
}
return rr;
}
I found the bug!
I had to preload the textures.
[SKTexture preloadTextures:explosionTextures withCompletionHandler:^(void){}];
This is how I do mine, and havent had any issues yet.
NSMutableArray *textures = [NSMutableArray arrayWithCapacity:5];
for (int i = 1; i < 5; i++) {
NSString *textureName = [NSString stringWithFormat:#"rocket%d", i];
SKTexture *texture = [SKTexture textureWithImageNamed:textureName];
[textures addObject:texture];
}
self.rocketAnimation = [SKAction animateWithTextures:textures timePerFrame:0.1];
// add animation to my sprite
[self.projectile runAction:[SKAction repeatActionForever:self.rocketAnimation]];
// add spite to screen etc...
[self addChild:self.projectile];
See this post, there is a bug when images have a lot of transparent space using texture atlas.
SKTexture returns wrong size?
NSLog is very slow compared to most other operations. Just inserting that call adds a significant pause to the main thread of your app. I'm guessing that your texture loading is sending tasks off to the GPU. Without the NSLog call the GPU may not have enough time to complete the tasks. Maybe you can preload the textures.
Go to you'r Project and follow these steps:- 1> Go to Build Settings, 2> Search for Enable Texture Atlas Generation and select YES

Resources