Im having a problem. When i present a new scene in spritekit (with objective c) It only shows a gray color with node and fps count on the screen.
I have animated the scene in the .sks file so it should not look like this.
The transition when im presenting the new scene also works, but it just wont show the images and background that i animated in the .sks file.
Here is the code on how i do it.
//In gameviewcontroller.m
// Creating and configuring the scene.
GameScene *Level1 = [GameScene nodeWithFileNamed:#"GameSceneLevel1"];
Level1.scaleMode = SKSceneScaleModeAspectFill;
// GameScene.m inside touchesbegan
SKTransition *reveal = [SKTransition doorwayWithDuration:4];
GameScene *Level1 = [GameScene sceneWithSize:self.view.bounds.size];
Level1.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:Level1 transition:reveal];
You have originally loaded scene from .sks file and as you said you have some animations there. Later on, (inside touchesBegan) you are creating a scene by providing a size (using sceneWithSize static method). So the scene is not loaded from from the archive.
To fix the problem, load your scene like you did initially, in the GameViewController.
EDIT:
To transition between two scenes you have to create two .sks files. You can name them like this : MenuScene and GameScene (you already have this one by default). Note that when you create these files you don't have to write an extension (.sks) but rather just file name. Then you have to create corresponding .m and .h files. So create MenuScene.m and MenuScene.h. GameScene .m and .h files are there by default.
MenuScene should be a subclass (not necessarily direct subclass) of an SKScene.
Then inside of your view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
SKView * skView = (SKView *)self.view;
GameScene *scene = [GameScene nodeWithFileNamed:#"GameScene"];
scene.scaleMode = SKSceneScaleModeAspectFill;
scene.size = skView.bounds.size;
[skView presentScene:scene];
}
Later on in your GameScene's touchesBegan method if you want to transition to the MenuScene, you should do something like this :
MenuScene *nextScene = [MenuScene nodeWithFileNamed:#"MenuScene"];
SKTransition *transition = [SKTransition fadeWithDuration:3];
[self.view presentScene:nextScene transition:transition];
Similarly, to transition back to the GameScene, in your MenuScene's touchesBegan, do this:
GameScene *nextScene = [GameScene nodeWithFileNamed:#"GameScene"];
SKTransition *transition = [SKTransition fadeWithDuration:3];
[self.view presentScene:nextScene transition:transition];
Of course right before each transition you can set scene's scale mode to match the scale mode of the old scene.
From your code, it looks like you are trying to make a transition to the same scene: GameScene -> GameScene. That is certainly possible, but are you sure you wanted that ?
If so, just use the code I've provided for MenuScene's touchesBegan method.
I created an sks file with the settings I want it to have, and when I call the method of adding the node onto the scene, the emitter particles don't look anything similar to what I set up. Any reason why?
-(SKEmitterNode *)emitParticles
{
SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"explosionParticles" ofType:#"sks"]];
emitter.position = CGPointMake(self.size.width/2, self.size.height/2);
emitter.targetNode = self.scene;
[self addChild:emitter];
return emitter;
}
What I want.
What I get.
I have tried the following code when trying to transition between scenes in my Sprite Kit project:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
XYZGameScene *gameScene = [[XYZGameScene alloc] initWithSize:CGSizeMake(self.size.width, self.size.height)];
crossFade = [SKTransition fadeWithColor:[UIColor blackColor] duration:2];
[playButtonSprite runAction:changePlayButtonTextureOFF];
if(toGameAction){
[self.scene.view presentScene:gameScene transition:crossFade];
}else{}
}
The problem is, when I press the button that triggers the TRUE with toGameAction and the transition begins, the SKActions I have which are moving some objects in the background stop. Which isn't what I want. I am trying to make the transition between the two scenes seamless. As the backgrounds are the same just that one scene is the menu and the other is the actual game.
If you are having trouble with understanding what I am trying to implement, it's essentially when you press the button in Flappy Bird and the background doesn't stop moving through the transition between the menu and the game.
SKTransition has a property for this named pausesOutgoingScene that has a default value of YES. All you have to do is set this property to NO.
crossFade.pausesOutgoingScene = NO;
I'm testing out a few different technologies to integrate into my Sprite Kit-powered game, and I'm stumbling on what I'm sure is a simple task.
The test project I'm using came as part of a framework that integrates Spine with Sprite Kit. Everything is contained (and defined) in a single ViewController (which creates one of four views depending on which option of a UISegmentedControl is currently selected). At the bottom of the screen I have a UISwitch which is hooked up to an action:
-(IBAction)changeCostume:(UISwitch *)sender {
if(sender.on) {
NSLog(#"New costume");
} else {
NSLog(#"Old costume");
}
}
The scene I'm working on is defined like this:
+ (SKScene *) buildAvatarWithSize:(CGSize) size
{
SpineSkeleton *avatar = [DZSpineSceneBuilder loadSkeletonName:#"test-avatar" scale:1]; //json
spSkeleton_setSkinByName(avatar.spineContext->skeleton, "test-avatar");
spSkeleton_setSlotsToSetupPose(avatar.spineContext->skeleton);
DZSpineSceneDescription *sceneDesc = [DZSpineSceneDescription description];
... define animations etc. here...
NSArray *nodes = [sceneDesc buildScene];
SKNode *placeHolder = [SKNode node];
placeHolder.position = CGPointMake(100, size.height);
placeHolder.name = #"root";
... more setup code...
SKScene *scene = [[SKScene alloc] initWithSize:size];
scene.scaleMode = SKSceneScaleModeAspectFill;
scene.backgroundColor = [UIColor whiteColor];
[scene addChild:placeHolder];
return scene;
}
The property I want to access is sceneDesc - I need to modify its contents on the fly, when the UISwitch is pressed. I know that it's possible from within the scene setup code, but I'm having trouble figuring out how to do so once the scene's on screen.
Changing values of this property will alter the SKTexture used in various nodes.
It probably doesn't help that I'm still new to Objective-C, and the setup of the project is rather different to how I've been working so far (splitting up scenes into their own classes, with properties that can be easily accessed programatically).
You can use NSNotificationCenter to send a message to the scene when the switch is pressed.
I actually gave up on trying to access sceneDesc programatically, and just changed the textures of the relevant SKSpriteNodes:
SKSpriteNode *root = (SKSpriteNode *)[placeHolder.children[0] childNodeWithName:#"root"];
SKSpriteNode *arm = (SKSpriteNode *)[root childNodeWithName:#"upper arm"];
SKSpriteNode *upperArm = (SKSpriteNode *)[arm childNodeWithName:#"upper arm"];
SKSpriteNode *lowerArm = (SKSpriteNode *)[[arm childNodeWithName:#"bone3"] childNodeWithName:#"lower arm"];
upperArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_upper"];
lowerArm.texture = [SKTexture textureWithImageNamed:#"blue_sleeve_lower"];
I have created a SKSpriteNode for a camera with a physic body size of 0.0 , to avoid unwanted collisions and a world node:
-(void)createSceneContents {
SKNode *world = [SKNode node];
world.name = #"world";
self.anchorPoint = CGPointMake(0.1, 0);
SKSpriteNode *camera = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(300, 300)];
camera.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(0, 0)];
camera.physicsBody.affectedByGravity = NO;
camera.physicsBody.usesPreciseCollisionDetection = NO;
camera.physicsBody.categoryBitMask = noColisions;
camera.alpha = 0.5;
camera.zPosition = 1;
camera.name = #"cam";
[self addChild:world];
[world addChild:camera];
I've tried a little tutorial to add a camera in a spriteKit platform game, but i can't even move the view, i don't know hoy to access to the property that move the view. Anybody knows what am i doing wrong?
Here's my code:
-(void)didSimulatePhysics
{
//I've tried with #"cam" and #"hero"
[self centerOnNode: [self childNodeWithName:#"world"]];
}
-(void)centerOnNode:(SKNode *) camera {
CGPoint cameraPositionInScene = [camera.scene convertPoint:camera.position fromNode:camera.parent];
[self.parent setPosition:CGPointMake(
camera.parent.position.x - cameraPositionInScene.x,
camera.parent.position.y - cameraPositionInScene.y
)];
}
In the example from Apple's Documentation, which you are following the camera node isn't an SKSprite, it's an SKNode. I think that will fix your problem.
To answer the question from the title, what you're essentially doing is attaching a world node to the scene. Inside this node, all the sprites are placed. As a child to the world node you add another node for the camera.
This gives you three distinct coordinate systems. Imagine, three sheets of paper, the bottom most one is your world, ie the layer with all the sprites. On top of that is a small piece of paper that represents the camera. Above all of this you have a transparent box that represents your viewing area.
The way it's set up it's impossible to move the top most transparent viewing layer. Instead, what you're doing is moving the point that's sits on top of the world layer and then sliding the world layer to that point.
Now imagine, in the paper scenario, this is a 2D scrolling world where you can only go left and right. Now take the camera point and put it all the way to the right most side of the viewing area. Now, take the world layer and drag it to the left until the camera is in the center of the non-moveable viewing area. That is more or less, what's happening.
In Apple's Adventure sample game they don't move the camera but the "World" SKNode which is the top one.
Excerpt from Apple docs on how they do it:
In Adventure all world-related nodes, including background tiles,
characters, and foliage, are children of a world node, which in turn
is a child of the scene. We change the position of this top-of-tree
world node within the scene to give the effect of moving a camera
across the level. By contrast, the nodes that make up the HUD are
children of a separate node that is a direct child of the scene rather
than of the world node, so that the elements in the HUD don’t move
when we “move the camera.”
Read about it more here
to add the previous answers , you should center on your camera , not the world..
so instead of
[self centerOnNode: [self childNodeWithName:#"world"]];
you should use
[self centerOnNode: [self childNodeWithName:#"cam"]];
and dont forget to change your camera to SKNode instead of SKSprite.
.. and for testing, add a moveTo action on your camera node , move it around back and forth to check if your camera centering works. I recommend putting the call in the touchesbegan
example (put this on your scene where your camera is) :
Put these before the #implementation
#interface yourClassNameHere() // edit this to your own class name
#property SKNode *theWorld;
#property SKNode *theCamera;
#property BOOL cameraRunning;
#end
As you see above, i put the nodes (world and camera) on property of this class, so i dont refer them with node name like you did on your post..
Put this on the Implementation section
// Process Camera centering
-(void) didSimulatePhysics {
[self centerOnNode:self.theCamera];
}
-(void) centerOnNode: (SKNode *) node {
CGPoint pos = [node.scene convertPoint:node.position fromNode:node.parent];
CGPoint p = node.parent.position;
node.parent.position = CGPointMake(p.x - pos.x, p.y-pos.y);
}
// .. Move the camera around when you touch , to see if it works..
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.cameraRunning) {
self.cameraRunning = YES;
SKAction *moveUp = [SKAction moveByX:0 y:500 duration:3];
SKAction *moveDown = [SKAction moveByX:0 y:-500 duration:3];
SKAction *moveLeft = [SKAction moveByX:-500 y:0 duration:3];
SKAction *moveRight = [SKAction moveByX:500 y:0 duration:3];
SKAction *sequence = [SKAction sequence:#[moveUp, moveRight,moveDown,moveLeft]];
[self.theCamera runAction:sequence];
} else {
self.cameraRunning = NO;
[self.theCamera removeAllActions];
self.theCamera.position = CGPointZero;
}
}
regards
PS: do you want anchor point 0,0 or 1,1 ? check your anchor point setting there
If you want to move the view, just move the camera:
// Center the view at 100, 0
camera.position = CGPointMake(100, 0);
Here's a slightly longer example here on how to set up a 2D camera system in SpriteKit (in Swift, not ObjC, but easily translated).