Why isn't my SpriteNode being added to the Scene? - ios

I am making a SpriteNode and trying to add it to the scene. It is not showing up even if I use the [self addChild: child]. I just can't see where I went wrong. Here is my View Controller.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Pause the view (and thus the game) when the app is interrupted or backgrounded
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleApplicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleApplicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [TitleScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
And here is my Scene.m
- (void)viewWillAppear:(BOOL)animated
{
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
SKTexture *YellowLabelTexture = [SKTexture textureWithImageNamed:#"YellowLabel.png"];
SKTexture *BlueLabelTexture = [SKTexture textureWithImageNamed:#"BlueLabel.png"];
SKTexture *GreenLabelTexture = [SKTexture textureWithImageNamed:#"GreenLabel.png"];
SKTexture *RedLabelTexture = [SKTexture textureWithImageNamed:#"RedLabel.png"];
SKTexture *WhiteLabelTexture = [SKTexture textureWithImageNamed:#"WhiteLabel.png"];
NSArray *anim = [NSArray arrayWithObjects:YellowLabelTexture, BlueLabelTexture, GreenLabelTexture, RedLabelTexture, WhiteLabelTexture, nil];
SKSpriteNode *labelNode = [SKSpriteNode spriteNodeWithImageNamed:#"WhiteLabel.png"];
labelNode.position = CGPointMake(160, 400);
SKAction *actionAnimate = [SKAction animateWithTextures:anim timePerFrame:.5 resize:YES restore:NO];
SKAction *actionRepeat = [SKAction repeatActionForever:actionAnimate];
[self runAction:actionRepeat];
[self addChild:labelNode];
}
Can someone figure out what is causing the sprite to NOT be added to the scene. Also, How can I add it to the scene? Thanks!

As #akashg said you can't use viewWillAppear method, and also you should use runAction for labelNode:
[self runAction:actionRepeat]; to [labelNode runAction:actionRepeat];
here is how your code should look like:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
SKTexture *YellowLabelTexture = [SKTexture textureWithImageNamed:#"YellowLabel.png"];
SKTexture *BlueLabelTexture = [SKTexture textureWithImageNamed:#"BlueLabel.png"];
SKTexture *GreenLabelTexture = [SKTexture textureWithImageNamed:#"GreenLabel.png"];
SKTexture *RedLabelTexture = [SKTexture textureWithImageNamed:#"RedLabel.png"];
SKTexture *WhiteLabelTexture = [SKTexture textureWithImageNamed:#"WhiteLabel.png"];
NSArray *anim = [NSArray arrayWithObjects:YellowLabelTexture, BlueLabelTexture, GreenLabelTexture, RedLabelTexture, WhiteLabelTexture, nil];
SKSpriteNode *labelNode = [SKSpriteNode spriteNodeWithImageNamed:#"WhiteLabel.png"];
labelNode.position = CGPointMake(160, 400);
SKAction *actionAnimate = [SKAction animateWithTextures:anim timePerFrame:.5 resize:YES restore:NO];
SKAction *actionRepeat = [SKAction repeatActionForever:actionAnimate];
[labelNode runAction:actionRepeat];
[self addChild:labelNode];
}
return self;
}
#end

Related

How can I change Sprite Image every half a second?

I have been trying to achieve this from this morning but haven't figured it out. I have a SKSpriteNode which is an Image that displays the name of my game on the main screen. What I am trying to achieve is to change those images every half a second. I have made multiple images of the name with different colors so I can change images every half a second.That will give the effect of the title changing colors like a typical arcade game. This is what I have done so far...
- (void)viewDidLoad
{
[super viewDidLoad];
_images = [NSArray arrayWithObjects:#"YellowLabel.png", #"BlueLabel.png", #"GreenLabel.png", #"RedLabel.png", #"WhiteLabel.png", nil];
NSTimer *myTimer = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(doAnimation) userInfo:nil repeats:YES];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [TitleScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
SKSpriteNode *labelNode = [SKSpriteNode spriteNodeWithImageNamed:#"WhiteLabel.png"];
labelNode.position = CGPointMake(160, 400);
// Present the scene.
[skView presentScene:scene];
[self doAnimation];
[scene addChild:labelNode];
}
And I also have this additional method:
-(void)doAnimation {
SKSpriteNode *labelNode = [SKSpriteNode spriteNodeWithImageNamed:#"WhiteLabel.png"];
static int counter = 0;
if ([_images count] == counter+1) {
counter = 0;
}
labelNode = [SKSpriteNode spriteNodeWithImageNamed:[_images objectAtIndex:counter]];
}
Thanks for any help!
Here's one way you could do this with SKAction :
SKAction *actionWait = [SKAction waitForDuration:.5];
SKAction *actionBlock = [SKAction runBlock:^(void)
{
// do whatever you want to do every half second here
}];
SKAction *actionSequence = [SKAction sequence:#[actionWait, actionBlock]];
SKAction *actionRepeat = [SKAction repeatActionForever:actionSequence]
[self runAction:actionRepeat];
Another way, could be like this, since I think you are just animating textures :
// create an NSArray called anim that includes all your SKATextures
SKAction *actionAnimate = [SKAction animateWithTextures:anim timePerFrame:.5 resize:YES restore:NO];
SKAction *actionRepeat = [SKAction repeatActionForever:actionAnimate];
[self runAction:actionRepeat];

Why does my simulator still show node count and FPS? [SpriteKit]

I have prepared my game to be published to the app store. Before I do that, I wanted to turn off the node count and FPS and did not want those two things to be displayed. I have a GameScene.m and a TitleScene.m. I tried view.showsFPS = NO; and view.showsNodeCount = NO; in my GameScene.m and it works fine. In my TitleScene.m I tried self.view.showsNodeCount = NO; and self.view.showsFPS = NO;, but it still shows the NodeCount and FPS. Here is my code for TitleScene.m:
#import "TitleScene.h"
#import "GameScene.h"
#implementation TitleScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.view.showsNodeCount = NO;
self.view.showsFPS = NO;
SKTexture *YellowLabelTexture = [SKTexture textureWithImageNamed:#"YellowLabel.png"];
SKTexture *BlueLabelTexture = [SKTexture textureWithImageNamed:#"BlueLabel.png"];
SKTexture *GreenLabelTexture = [SKTexture textureWithImageNamed:#"GreenLabel.png"];
SKTexture *RedLabelTexture = [SKTexture textureWithImageNamed:#"RedLabel.png"];
SKTexture *WhiteLabelTexture = [SKTexture textureWithImageNamed:#"WhiteLabel.png"];
SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:#"awsome.png"];
background.size = CGSizeMake(640, 1136);
background.position = CGPointMake(0,0);
NSArray *anim = [NSArray arrayWithObjects:YellowLabelTexture, BlueLabelTexture, GreenLabelTexture, RedLabelTexture, WhiteLabelTexture, nil];
SKSpriteNode *labelNode = [SKSpriteNode spriteNodeWithImageNamed:#"WhiteLabel.png"];
labelNode.position = CGPointMake(self.size.width / 2, self.size.height / 2 * 1.5);
SKSpriteNode *startButtonNode = [SKSpriteNode spriteNodeWithImageNamed:#"playButton.png"];
startButtonNode.position = CGPointMake(self.size.width / 2, self.size.height / 3);
SKAction *actionAnimate = [SKAction animateWithTextures:anim timePerFrame:.3 resize:YES restore:NO];
SKAction *actionRepeat = [SKAction repeatActionForever:actionAnimate];
[labelNode runAction:actionRepeat];
[self addChild:background];
[self addChild:labelNode];
[self addChild:startButtonNode];
}
return self;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
GameScene* gameScene = [[GameScene alloc] initWithSize:self.size];
gameScene.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:gameScene transition:[SKTransition doorsOpenHorizontalWithDuration:1.5]];
}
Is there something that I am doing wrong? Thanks!
The default SpriteKit template sets node count and fps after the initialization of the scene in ViewController.m, you have to remove these lines.
Comment showsFPS and ShowsNodeCount in your ViewController.m file;
//skView.showsFPS = YES;
//skView.showsNodeCount = YES;

SpriteKit change Image after swipe gesture

I am trying to code a game. I got an object, that can jump and slide.
I want to hold the animation of 'run' while jumping, but while sliding, I want to change the image. My problem: the image won't show off , if I just change the image to 'slide7'.
Nothing happens.
The slide animation should appear only for about 4 seconds, than go again into the run animation. Any suggestions?
My Code :
-(void)Mensch{
SKTexture * MenschTexture1 = [SKTexture textureWithImageNamed:#"Mensch1"];
MenschTexture1.filteringMode = SKTextureFilteringNearest;
SKTexture * MenschTexture2 = [SKTexture textureWithImageNamed:#"Mensch2"];
MenschTexture2.filteringMode = SKTextureFilteringNearest;
SKAction * Run = [SKAction repeatActionForever:[SKAction animateWithTextures:#[MenschTexture1, MenschTexture2] timePerFrame:0.4]];
Mensch = [SKSpriteNode spriteNodeWithTexture:MenschTexture1];
Mensch.size = CGSizeMake(45, 45);
Mensch.position = CGPointMake(self.frame.size.width / 5, Boden.position.y + 73);
Mensch.zPosition = 2;
Mensch.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Mensch.size];
Mensch.physicsBody.dynamic = YES;
Mensch.physicsBody.allowsRotation = NO;
Mensch.physicsBody.usesPreciseCollisionDetection = YES;
Mensch.physicsBody.restitution = 0;
Mensch.physicsBody.velocity = CGVectorMake(0, 0);
[Mensch runAction:Run];
[self addChild:Mensch];
}
- (void)didMoveToView:(SKView *)view
{
UISwipeGestureRecognizer *recognizerDown = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(handleSwipeDown:)];
recognizerDown.direction = UISwipeGestureRecognizerDirectionDown;
[[self view] addGestureRecognizer:recognizerDown];
}
-(void)handleSwipeDown:(UISwipeGestureRecognizer *)sender
{
[Mensch removeAllActions];
Mensch = [SKSpriteNode spriteNodeWithImageNamed:#"slide7.png"];
NSLog(#"Slide");
}
You are replacing the Mensch object. More specifically, you are replacing the pointer you have to the object, but that doesn't stop it from being displayed in the scene.
You can either:
Replace the SKTexture inside the sprite, which should be displayed immediately. This means Mensch.texture = [SKTexture textureWithImageNamed:#"slide7.png"];
Replace the Sprite. This entails removing the current sprite ([sprite removeFromParent]) and adding the new one ([self addChild:newSprite]).
I think you want the first one, since you don't have to recreate the Mensch object.
Might I add that you are performing a lot of Mensch-specific logic in this object? It would be better (from an Object Oriented standpoint) to move this creation code to an SKSpriteNode subclass Mensch.
#interface Mensch : SKSpriteNode
- (void) displayRunAnimation;
- (void) displaySlideAnimation;
#end
#implementation : Mensch
- (instancetype) init {
self = [super init];
if (self) {
// your initialization code here, including physics body setup
[self displayRunAnimation];
}
return self;
}
- (void) displayRunAnimation {
SKTexture * MenschTexture1 = [SKTexture textureWithImageNamed:#"Mensch1"];
MenschTexture1.filteringMode = SKTextureFilteringNearest;
SKTexture * MenschTexture2 = [SKTexture textureWithImageNamed:#"Mensch2"];
MenschTexture2.filteringMode = SKTextureFilteringNearest;
SKAction * Run = [SKAction repeatActionForever:[SKAction animateWithTextures:#[MenschTexture1, MenschTexture2] timePerFrame:0.4]];
// if you plan to call this often, you want to cache this SKAction, since creating it over and over is a waste of resources
[self runAction:Run];
}
- (void) displaySlideAnimation {
[self removeAllActions];
self.texture = [SKTexture textureWithImageNamed:#"slide7.png"];
NSLog(#"Slide");
// re-start the runAnimation after a time interval
[self performSelector:#selector(displayRunAnimation) withObject:nil afterDelay:4.0];
}

SpriteKit Add Child not working

I had a general SKScene where I created a SKSpriteNode, added it via
[self addChild:_charecter];
And all was well..
I tried making a new class for the SKSpriteNode so that I could add some custom methods to it. Here is it's init method:
- (instancetype)init
{
if (self = [super init]) {
SKTexture *run1 = [SKTexture textureWithImageNamed:#"run1"];
SKTexture *run2 = [SKTexture textureWithImageNamed:#"run2"];
SKTexture *run3 = [SKTexture textureWithImageNamed:#"run3"];
_charecterSprites = [NSArray arrayWithObjects:run1, run2, run3, nil];
self.texture = run1;
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1.0]; //CHANGE THIS LATER
}
return self;
}
The problem is that now when I add the _charecter to the view, it doesn't appear. I'm adding him in the SKScene as follows:
_charecter = [[RUNPlayer alloc] init];
_charecter.position = CGPointMake(CGRectGetMidX(self.frame), CHARECTER_Y_AXIS);
self.physicsWorld.gravity = CGVectorMake(0, -10.0/150.0);
[self addChild:_charecter];
Any idea why my SKSpriteNode isn't visible?
Thanks
Trying using one of the SKSpriteNode initializers instead of init
- (instancetype)initWithImageNamed:(NSString *)name
{
if (self = [super initWithImageNamed:name]) {
SKTexture *run1 = [SKTexture textureWithImageNamed:#"run1"];
SKTexture *run2 = [SKTexture textureWithImageNamed:#"run2"];
SKTexture *run3 = [SKTexture textureWithImageNamed:#"run3"];
_charecterSprites = [NSArray arrayWithObjects:run1, run2, run3, nil];
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:1.0]; //CHANGE THIS LATER
}
return self;
}
From what I understand, when you use initWithImageNamed:, the sprite node's size is set to the texture's size. Your sprite could of been on screen but had a size of (0,0). Let us know if this works!
On a side note, check out Ray's tutorial on texture atlases to replace _characterSprites http://www.raywenderlich.com/45152/sprite-kit-tutorial-animations-and-texture-atlases

Why didn't the SpriteKit PhysicContactDelegate work?

I am implementing a simple game for iOS.
I am trying to use Sprite Kit for development.
However, I don't know why the detection of contact did not happen.
Can anyone help me fix this problem?
Here is the code that I cannot get the expected results with:
#import "TesttingScene.h"
#interface TesttingScene()<SKPhysicsContactDelegate>
#property (nonatomic) SKTexture *ballText;
#end
#implementation TesttingScene
-(id)initWithSize:(CGSize)size{
self = [super initWithSize:size];
if (self) {
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
SKSpriteNode *hitBoxx = [[SKSpriteNode alloc] initWithColor:[UIColor clearColor] size:CGSizeMake(self.frame.size.width/3, self.frame.size.height/3)];
hitBoxx.anchorPoint = CGPointMake(0, 0);
hitBoxx.position = CGPointMake(self.size.width/2, self.size.height/2);
hitBoxx.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hitBoxx.frame.size];
hitBoxx.physicsBody.dynamic = YES;
hitBoxx.physicsBody.categoryBitMask = abPlayerHitBoxCategory;
hitBoxx.physicsBody.contactTestBitMask = adsViewCategory;
hitBoxx.physicsBody.collisionBitMask = 0;
hitBoxx.physicsBody.usesPreciseCollisionDetection = YES;
self.ballText = [SKTexture textureWithImageNamed:#"FinalBossSkill1SS"];
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
SKTexture *t1 = [SKTexture textureWithRect:CGRectMake(0, 0, 0.5, 1) inTexture:self.ballText];
SKTexture *t2 = [SKTexture textureWithRect:CGRectMake(0.5, 0, 0.5, 1) inTexture:self.ballText];
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithTexture:t1];
ball.position = CGPointMake(self.size.width, self.size.height/2);
ball.name = #"FinalBossSkill1Ball";
ball.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ball.size];
ball.physicsBody.dynamic = YES;
ball.physicsBody.categoryBitMask = adsViewCategory;
ball.physicsBody.contactTestBitMask = abPlayerAttackBoxCategory | abPlayerHitBoxCategory;
ball.physicsBody.collisionBitMask = 0;
ball.physicsBody.usesPreciseCollisionDetection = YES;
SKAction *moveTo = [SKAction moveToX:-ball.size.width duration:1.0];
SKAction *flash = [SKAction animateWithTextures:#[t1,t2] timePerFrame:0.1];
SKAction *moveBall = [SKAction repeatAction:flash count:moveTo.duration/flash.duration];
SKAction *group = [SKAction group:#[moveTo, moveBall]];
[self addChild:ball];
[ball runAction:[SKAction sequence:#[group, [SKAction removeFromParent]]]];
}
-(void)didBeginContact:(SKPhysicsContact *)contact{
NSLog(#"Contact"); // <~~~~this msg doesn't appear in console when the ball pass the hitboxx.
}
You will need to define bit mask category, right below your imports.
static const uint32_t abPlayerHitBoxCategory = 0x1 << 0;
static const uint32_t adsViewCategory = 0x1 << 1;

Resources