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;
Related
I am setting background color in this code:
- (void)randomBackground {
int random = arc4random() % 3;
NSLog(#"%d", random);
switch (random) {
case 0:
self.background = [SKSpriteNode spriteNodeWithImageNamed:#"image1"];
break;
case 1:
self.background = [SKSpriteNode spriteNodeWithImageNamed:#"image2"];
break;
case 2:
self.background = [SKSpriteNode spriteNodeWithImageNamed:#"image3"];
break;
}
self.background.position = CGPointMake(self.size.width / 2.0, self.size.height / 2.0);
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
NSLog(#"Size: %#", NSStringFromCGSize(size));
}
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
return self;
}
-(void)didMoveToView:(nonnull SKView *)view {
self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
[self randomBackground];
self.player = [SKSpriteNode spriteNodeWithImageNamed:#"ninja"];
self.player.position = CGPointMake(self.player.size.width / 2.0, self.player.size.height / 2.0);
[self removeAllChildren];
[self addChild:self.background];
[self addChild:self.player];
}
After my player looses, I present another scene, and than present this scene again:
SKAction *loseAction = [SKAction runBlock:^{
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
GameOverScene *gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO];
[self.view presentScene:gameOverScene transition:reveal];
}];
[hero runAction:[SKAction sequence:#[move, loseAction, moveDone]]];
Here is how I present main scene again:
[self runAction:
[SKAction sequence:#[[SKAction waitForDuration:0.5],
[SKAction runBlock:^{
[self.parentScene removeAllChildren];
SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
GameScene *myScene = [GameScene sceneWithSize:self.size];
[self.view presentScene:myScene transition:reveal];
}]
]]];
The problem is that sometimes, when a specific background is loaded, the whole content seems to be covered by it, however, when I nslog the children of scene, the background is on the first place of an array.
As the result, I can see only background. Strangely enough, this happens only on certain backgrounds, while on other backgrounds it is OK and the content is displayed properly.
Any ideas how to fix it?
The order of initialization is actually very interesting, but its a completely different topic. To fix your issue, you need to specify each node's position on the z-axis, through the property zPosition. For example, if you write:
background.zPosition = -1;
myNode.zPosition = 1;
myNode will always present itself on top of background.
didBeginContact doesnt get called for some reason. How can I fix this? Thanks! I set the category bitmasks and the skphysicsContactDelegate, yet it is still not registering contacts. I've been stuck at this for some time now.
#import "MyScene.h"
#import "FuelNode.h"
#import "SKSpriteNode+DebugDraw.h"
typedef NS_OPTIONS(uint32_t, CollisionCategory) {
CollisionCategoryPlayer = 1 << 0,
CollisionCategoryFuel = 1 << 1,
};
#interface MyScene() <SKPhysicsContactDelegate>
#end
#implementation MyScene
{
SKNode *_playerNode;
SKNode *_backgroundNode;
SKNode *_foreGround;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size]) {
self.physicsWorld.contactDelegate = self;
_backgroundNode = [self createBackground];
[self addChild:_backgroundNode];
_foreGround = [SKNode node];
[self addChild:_foreGround];
//add a fuelNode
FuelNode *fuel = [self createFuelAtPosition:CGPointMake(160, 440)];
[_foreGround addChild:fuel];
_playerNode = [self createPlayer];
[_foreGround addChild:_playerNode];
SKAction *actionMove = [SKAction moveToY:-100 duration:3.0];
[fuel runAction:actionMove];
NSLog(#"yea");
}
return self;
}
-(SKNode *)createPlayer
{
CGSize playerPhysicsBody;
//Create player
SKNode *playerNode = [SKNode node];
SKSpriteNode *player = [SKSpriteNode spriteNodeWithImageNamed:#"wship-3.png"];
player.position = CGPointMake(self.size.width/2, 120);
[playerNode addChild:player];
//Add physics
playerPhysicsBody = CGSizeMake(player.size.width/2, player.size.height/2);
playerNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:playerPhysicsBody];
playerNode.physicsBody.dynamic = NO;
//Setup collision settings
playerNode.physicsBody.usesPreciseCollisionDetection = YES;
playerNode.physicsBody.categoryBitMask = CollisionCategoryPlayer;
playerNode.physicsBody.collisionBitMask = 0;
playerNode.physicsBody.contactTestBitMask = CollisionCategoryFuel;
[player attachDebugRectWithSize:playerPhysicsBody];
return playerNode;
}
-(SKNode *)createBackground
{
//Create background
SKNode *bgNode = [SKNode node];
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:#"purple"];
bg.anchorPoint = CGPointZero;
[bgNode addChild:bg];
return bgNode;
}
- (FuelNode *)createFuelAtPosition:(CGPoint)position
{
// 1
FuelNode *node = [FuelNode node];
[node setPosition:position];
[node setName:#"NODE_FUEL"];
// 2
SKSpriteNode *sprite;
sprite = [SKSpriteNode spriteNodeWithImageNamed:#"fuelBlue"];
[node addChild:sprite];
// 3
CGSize contactSize = CGSizeMake(sprite.size.width/2, sprite.size.height/2);
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:contactSize];
// 4
node.physicsBody.dynamic = NO;
//Setup collision settings
node.physicsBody.categoryBitMask = CollisionCategoryFuel;
node.physicsBody.collisionBitMask = 0;
//node.physicsBody.contactTestBitMask = CollisionCategoryPlayer;
[sprite attachDebugRectWithSize:contactSize];
//SKAction *actionMove = [SKAction moveToY:-100 duration:3.0];
//[node runAction:actionMove];
return node;
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
BOOL fuelCollision = NO;
SKNode *other = (contact.bodyA.node != _playerNode) ? contact.bodyA.node : contact.bodyB.node;
NSLog(#"collision");
fuelCollision = [(GameObjectNode *)other collisionWithPlayer:_playerNode];
}
#end
In order to enable contact detection, you need to set
node.physicsBody.dynamic = YES;
Have a look at the documentation as well.
Fixed! In the create player method I have mistakenly set the position of the player sprite instead of setting the position of the player node!
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
Ok, i've read the iOS Games book and i've searched for my question in a number of sites and although I do find that a number of people had this problem, I haven't found a solution as such.
I am building a game where I transition a few times from a SKScene to another SKScene. What happens is that even when I transition from a simple SKScene, as the example bellow, to an empty SKScene the memory does not get deallocated. I've heard that I need to remove any strong references to my SKScene, but I do not believe that my code bellow has any:
#import "LaunchScene.h"
#import "EmptyScene.h"
#implementation LaunchScene
{
float _scaleForDevice;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
_scaleForDevice = 0.5;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
_scaleForDevice = 0.208335;
}
SKSpriteNode *bg;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && IS_WIDESCREEN) {
bg = [SKSpriteNode spriteNodeWithImageNamed:#"launchBackground-568h"];
} else {
bg = [SKSpriteNode spriteNodeWithImageNamed:#"launchBackground"];
}
bg.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
bg.zPosition = 10;
bg.name = #"launchBackground";
[self addChild:bg];
for (int i = 0; i < 5; i++) {
SKSpriteNode *launch = [SKSpriteNode spriteNodeWithImageNamed:[NSString stringWithFormat:#"launch%d",i]];
launch.position = CGPointMake(self.size.width, 0);
launch.anchorPoint = CGPointMake(0.5, 0.5);
launch.zPosition = 1000+i;
launch.name = [NSString stringWithFormat:#"launch%d",i];
[launch setScale:_scaleForDevice];
[self addChild:launch];
if (i == 0 || i == 2) {
SKAction* rotate = [SKAction rotateByAngle:-RadiansToDegrees(360) duration:10000*(i+1)];
[launch runAction:rotate];
} else if (i == 1) {
SKAction* rotate = [SKAction rotateByAngle:RadiansToDegrees(360) duration:10000*(i+1)];
[launch runAction:rotate];
}
}
SKSpriteNode *mainMenuBackground;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && IS_WIDESCREEN) {
mainMenuBackground = [SKSpriteNode spriteNodeWithImageNamed:#"mainMenuBackground-568h"];
} else {
mainMenuBackground = [SKSpriteNode spriteNodeWithImageNamed:#"mainMenuBackground"];
}
mainMenuBackground.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
mainMenuBackground.zPosition = 5;
mainMenuBackground.name = #"mainMenuBackground";
[self addChild:mainMenuBackground];
[SKActionEffects fadeOutAndRemove:bg duration:2];
SKSpriteNode *mainMenuGround;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone && IS_WIDESCREEN) {
mainMenuGround = [SKSpriteNode spriteNodeWithImageNamed:#"mainMenuGround-568h"];
} else {
mainMenuGround = [SKSpriteNode spriteNodeWithImageNamed:#"mainMenuGround"];
}
mainMenuGround.position = CGPointMake(self.size.width, 0);
mainMenuGround.zPosition = 500;
mainMenuGround.anchorPoint = CGPointMake(1, 1);
mainMenuGround.name = #"mainMenuGround";
[self addChild:mainMenuGround];
SKAction *waitMainMenuGround = [SKAction waitForDuration:1];
SKAction *moveMainMenuGround = [SKAction moveToY:(self.size.height)/3 duration:0.3];
moveMainMenuGround.timingMode = SKActionTimingEaseInEaseOut;
SKAction *shakeMainMenuGround = [SKAction runBlock:^{
[SKActionEffects shakeSprite:mainMenuGround toDirection:1];
}];
SKAction *shrinkLaunch = [SKAction runBlock:^{
for (int i = 0; i < 5; i++) {
SKSpriteNode *launch = (SKSpriteNode*)[self childNodeWithName:[NSString stringWithFormat:#"launch%d",i]];
[SKActionEffects disappearAndRemove:launch];
}
}];
SKAction *presentMainMenu = [SKAction runBlock:^{
//Create and configure the scene.
EmptyScene * scene = [[EmptyScene alloc] initWithSize:self.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[self.view presentScene:scene];
}];
SKAction *group = [SKAction sequence:#[waitMainMenuGround, moveMainMenuGround, shakeMainMenuGround, shrinkLaunch, waitMainMenuGround, presentMainMenu]];
[mainMenuGround runAction:group];
}
return self;
}
#end
I have created an EmptyScene that is just that. It doesn't have anything in its init.
#import "EmptyScene.h"
#implementation EmptyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
}
return self;
}
#end
When I run just the EmptyScene from the start my memory is around 25mb. When I run the LaunchScene first, the memory goes to 95mb, and when it transitions to the EmptyScene, where one would expect the memory to go down to 25mb, it remains at 95mb. Any idea why and what I can do to solve this?
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;