How to make something like this? - ios

I'm not sure if I'm correct in wording it "modal sprite-kit scene" but what I'm trying to do is have a smaller sized scene appear over a scene when the game is complete. Attached is a screenshot to show what I mean:
The screenshot is from Flappy Bird where when the player dies, the small game-over scene pops up almost like a modal effect, and displays the user's final results. I was wondering how to go about creating this.
I tried calling this when the game was done:
[self.player runAction:death completion:^{
[self removeAllActions];
GameOverNode *gameOverNode = [[GameOverNode alloc] initWithScore:self.size];
gameOverNode.gameScene = self;
gameOverNode.position = CGPointMake(self.scene.size.width/2, -150);
[self addChild:gameOverNode];
[gameOverNode runAction:[SKAction moveToY:self.scene.size.height/2 duration:0.6]];
And this was the code for the gameOverNode in the gameOverScene.m's file:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.userInteractionEnabled = YES;
self.zPosition = 20;
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(280*DoubleIfIpad, 300*DoubleIfIpad)];
bg.alpha = 0.55;
But the node only shows up in the bottom left hand corner of the screen, as opposed to in the middle like I want it too.
What am I doing wrong? How can I make the small gameover node pop up and sit in the middle of the scene.

You simply can't. According to Apple Docs and multiple StackOverflow posts you cannot be running two SKScene's at the same time. To recreate the effect you want, you can create an SKShapeNode with border and line color similar to those you want, and place objects like score inside, or you can create an image for the screen that pops up and just add SKLabelNodes to the scene that show the high score and current score. I'm attaching a picture of how I created an end "view" for my app, Average Guy.
I made the popup screen using an SKShapeNode like this:
SKShapeNode *optionsMenu = [SKShapeNode node];
CGRect tempRect = CGRectMake(SELF_WIDTH/2, SELF_HEIGHT/2, SELF_WIDTH-20, (finalScoreLabel.position.y+(finalScoreLabel.frame.size.height/2)) - (mainMenuButton.position.y-(mainMenuButton.frame.size.height/2)) + 20);
CGPathRef tempPath = CGPathCreateWithRoundedRect(CGRectMake(tempRect.origin.x - tempRect.size.width/2, tempRect.origin.y - tempRect.size.height/2, tempRect.size.width, tempRect.size.height), 5, 5, Nil);
optionsMenu.path = tempPath;
optionsMenu.fillColor = [SKColor grayColor];
optionsMenu.strokeColor = [SKColor blueColor];
optionsMenu.zPosition = 30;
optionsMenu.glowWidth = 2.0f;
CGPathRelease(tempPath);
Of course, don't mind the hectic CGRect implementation, I wanted to make everything relative to fit all of the screen sizes so I didn't hardcode any of the positions. As for adding the score and the buttons, I did this:
SKLabelNode *restartButton = [SKLabelNode labelNodeWithFontNamed:#"00 Starmap Truetype"];
restartButton.text = #"Play Again";
restartButton.zPosition = 31;
restartButton.fontColor = [SKColor blueColor];
restartButton.fontSize = 30;
restartButton.position = CGPointMake(HALF_WIDTH, HALF_HEIGHT-50);
restartButton.name = #"restart_button";
SKLabelNode *restartButtonShadow = restartButton.copy;
restartButtonShadow.position = CGPointMake(restartButton.position.x+1, restartButton.position.y-1);
restartButtonShadow.color = [SKColor colorWithRed:0 green:0 blue:.5 alpha:.1];
SKLabelNode *mainMenuButton = [SKLabelNode labelNodeWithFontNamed:#"00 Starmap Truetype"];
mainMenuButton.text = #"Main Menu";
mainMenuButton.zPosition = 31;
mainMenuButton.fontColor = [SKColor blueColor];
mainMenuButton.fontSize = 30;
mainMenuButton.position = CGPointMake(HALF_WIDTH, HALF_HEIGHT - 85);
mainMenuButton.name = #"main_menu_button";

Related

How to make a sprite which has physicsBody unmovable/static upon collision?

I have a game with balloons. I am adding the balloons from the bottom and they fly up while able to fly offscreen. I gave the balloons physicsBodys so they collide which each other but I want to make the balloons bouce of the left and right edge of the screen. I found a solution where the sprite object bounce of all screens on Rays site. But I need a different solution.
This is my balloon code:
MBDBallon *randomBallon = [[MBDBallon alloc] initWithImageName:balloonImageName
andBallonSize:ballonSize
withBallonImageName:[self.balloonColorImageNamesArray objectAtIndex:balloonWithColorIndex]
withStartingPosition:CGPointMake(self.viewSize.width/2, - self.viewSize.height )];
//randomBallon.name = [self returnRandomImageNameFromArray:self.ballonSpriteImageNamesArray];
randomBallon.physicsBody.usesPreciseCollisionDetection = YES;
randomBallon.physicsBody.categoryBitMask = balloonCategory;
randomBallon.physicsBody.collisionBitMask = balloonCategory;
randomBallon.physicsBody.contactTestBitMask = balloonCategory;
and this is my left wall code:
SKSpriteNode *leftWall = [[SKSpriteNode alloc] initWithColor:[UIColor redColor] size:CGSizeMake( self.viewSize.width / 15, self.viewSize.height * 3 )];
[leftWall setAnchorPoint:CGPointMake(0.0f, 0.0f)];
leftWall.position = CGPointMake( self.viewSize.width / 15 , 0.0f );
leftWall.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake( self.viewSize.width / 15, self.viewSize.height * 3 )];
leftWall.physicsBody.categoryBitMask = balloonCategory;
leftWall.physicsBody.collisionBitMask = balloonCategory;
leftWall.physicsBody.contactTestBitMask = balloonCategory;
leftWall.physicsBody.usesPreciseCollisionDetection = YES;
leftWall.physicsBody.allowsRotation = NO;
leftWall.physicsBody.dynamic = NO;
leftWall.physicsBody.friction = 0.0f;
[self addChild:leftWall];
However the walls is moving after some few balloon collisions. I really don't know wheres the catch or property to stop such behavior. The :
leftWall.physicsBody.dynamic = NO;
Should stop all movement but it doesn't. Please help, thanks :).
You have not properly set up your categoryBitMasks.
randomBallon.physicsBody.categoryBitMask = balloonCategory;
randomBallon.physicsBody.collisionBitMask = wallCategory|balloonCategory;
leftWall.physicsBody.collisionBitMask = wallCategory;
leftWall.physicsBody.contactTestBitMask = balloonCategory;
CategoryBitMask is the category you want to assign to your sprite. CollisionBitMask is the category you want your sprite to collide with. Balloons in this case should be set to collide with walls and other balloons. Walls should be set to only collide with balloons.

Fixed floor in Sprite Kit Xcode

I can't seem to get a unmovable fixed floor / wall in Sprite Kit.
I have a scene which has an SKNode as a "floor" and when the user presses the screen, a block drops from the touched position onto the "floor". That works well, but when the user adds another lets say 20 blocks or so, suddenly the floor rotates.
This is the code for my Floor:
SKSpriteNode *floorNode = [[SKSpriteNode alloc] initWithColor:[SKColor clearColor] size:CGSizeMake(self.size.width*2, 10)];
floorNode.position = CGPointMake(CGRectGetMidX(self.frame), -5);
floorNode.name = #"floor";
floorNode.zPosition = 1;
floorNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:floorNode.size];
floorNode.physicsBody.affectedByGravity = NO;
floorNode.physicsBody.dynamic = NO;
floorNode.physicsBody.usesPreciseCollisionDetection = YES;
return floorNode;
Sorry i'm quite new to Sprite Kit. Does anyone know what's wrong with my code?
EDIT: I've added some images to make the problem a bit more clear. Since it happens in this screen also. Those black spheres you see are flying from left to right like a canonball. I increased the amount of spheres to show the problem occurring. This is the code:
- (SKNode *)newEditButton {
SKLabelNode *editButtonNode = [SKLabelNode labelNodeWithFontNamed:#"chalkduster"];
editButtonNode.text = #"EDIT CASTLE";
editButtonNode.fontSize = 19;
editButtonNode.fontColor = [SKColor darkGrayColor];
editButtonNode.position = CGPointMake(CGRectGetMidX(self.frame) + 110, CGRectGetMidY(self.frame) + 30);
editButtonNode.name = #"edit_button";
editButtonNode.zPosition = 2;
editButtonNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(140, 40)];
editButtonNode.physicsBody.usesPreciseCollisionDetection = YES;
editButtonNode.physicsBody.dynamic = NO;
editButtonNode.physicsBody.affectedByGravity = NO;
SKAction *hover = [SKAction sequence:#[[SKAction moveByX:0 y:6.0 duration:0.9],
[SKAction moveByX:0 y:-6.0 duration:0.9]]];
SKAction *hoverForever = [SKAction repeatActionForever:hover];
[editButtonNode runAction:hoverForever];
return editButtonNode;
}
- (SKNode *)newPlayButton {
SKLabelNode *playButtonNode = [SKLabelNode labelNodeWithFontNamed:#"chalkduster"];
playButtonNode.text = #"SLAUGHTER";
playButtonNode.fontSize = 19;
playButtonNode.fontColor = [SKColor darkGrayColor];
playButtonNode.position = CGPointMake(CGRectGetMidX(self.frame) - 110, CGRectGetMidY(self.frame) + 30);
playButtonNode.name = #"play_button";
playButtonNode.zPosition = 2;
playButtonNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(140, 40)];
playButtonNode.physicsBody.usesPreciseCollisionDetection = YES;
playButtonNode.physicsBody.dynamic = NO;
playButtonNode.physicsBody.affectedByGravity = NO;
SKAction *hover = [SKAction sequence:#[[SKAction moveByX:0 y:6.0 duration:0.9],
[SKAction moveByX:0 y:-6.0 duration:0.9]]];
SKAction *hoverForever = [SKAction repeatActionForever:hover];
[playButtonNode runAction:hoverForever];
return playButtonNode;
}
After a while 5-10 seconds, the "buttons" called "slaughter" and "edit castle" start to rotate everytime a sphere collides with it. But it doesn't seem like it has to do something with physics, because, if it rotates to the left, it's rotation direction will always be left. And if it starts rotating right, it's rotation direction will always be right.
It looks funny though! But not what i want ;-)
You don't know it, but you're telling SpriteKit to apply collisions from the cannonballs to the labels, and from the blocks to the floor!
That's because you're leaving SKPhysicsBody.collisionBitMask to its default value, which is to observe collisions for everything.
From the documentation:
Discussion
When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a nonzero value, this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.
The default value is 0xFFFFFFFF (all bits set).
So, do:
floorNode.physicsBody.collisionBitMask = 0

Draw smooth circle in iOS sprite kit

I try to draw a single circle in my iOS SpriteKit project but the edges of the circle are not smooth. I would like to have a nicely drawn circle as I would draw it with Photoshop (anti-aliasing). I found several similar questions but the my problem remains.
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.backgroundColor = [SKColor whiteColor];
self.scaleMode = SKSceneScaleModeAspectFill;
self.size = CGSizeMake(640, 1136);
CGRect circle = CGRectMake(100.0, 100.0, 80.0, 80.0);
SKShapeNode *shapeNode = [[SKShapeNode alloc] init];
shapeNode.path = [UIBezierPath bezierPathWithOvalInRect:circle].CGPath;
shapeNode.fillColor = [SKColor redColor];
shapeNode.lineWidth = 0;
[self addChild:shapeNode];
}
return self;
}
What is the trick here?
The antialiasing is activated by default, but It only applies to the lines, not the fill.
Set the lineWidth to a number greater than 0 and try again.
Set the antialised property to YES.
shapeNode.antialiased = YES;
The rough edges are not visible when you use fill color.
//shapeNode.fillColor = [SKColor redColor];
shapeNode.strokeColor =[SKColor redColor];
shapeNode.antialiased = YES;
shapeNode.lineWidth = 1;
Now switch between YES and NO for antialisaed property.
You will notice the difference.

Cannot stop label from accepting my touches

I am working on a game where, when the user uses a skill, there is a time limit before he can use it again. Say 5 seconds, so I have a button, and in the middle of that button is a label which count downs the seconds till I am able to use said skill again.
During testing i noticed that my skill didnt, work since sometimes i would click the label node. Therefore i wrote
- (void)setupHUD
{
int barHeight = 50;
CGSize backgroundSize =
CGSizeMake(self.size.width, barHeight);
// myView.backgroundColor = [UIColor colorWithWhite:myWhiteFloat alpha:myAlphaFloat];
SKColor *backgroundColor =
[SKColor colorWithRed:0 green:1 blue:0.0 alpha:0.4];
SKSpriteNode *hudBarBackground =
[SKSpriteNode spriteNodeWithColor:backgroundColor
size:backgroundSize];
[hudBarBackground setUserInteractionEnabled:NO];
hudBarBackground.position =
CGPointMake(0, self.size.height - barHeight);
hudBarBackground.anchorPoint = CGPointZero;
[_hudLayer addChild:hudBarBackground];
timeButtTimmer = [SKLabelNode labelNodeWithFontNamed:#"Copperplate"];
tbutttimmer.userInteractionEnabled=NO;
// [tbutttimmer setUserInteractionEnabled: FALSE];
timeButtTimmer.name=#"label";
timeButtTimmer.fontSize=15;;
timeButtTimmer.position =
CGPointMake(self.size.width-75,
self.size.height - 30);
[_hudLayer addChild:timeButtTimmer];
}
Much to my surprise the label is still clickable and my nslog confirms that i can click it, since i have an nslog of the name of the node i touched.
I have modified my code to read
if ([node.name isEqualToString:#"button"] | [node.name isEqualToString:#"Readypras"])
I know this is dirty, but anyone has come across this before or am i doing something wrong. am i using the wrong property? thou in the documentation userInteraction is what sets if a node receives touch events.
-(id)initWithSize:(CGSize)size level:(int)level {
if (self = [super initWithSize:size]) {
_hudLayer = [SKNode node];
[_hudLayer setUserInteractionEnabled:NO];
[self addChild:_hudLayer];
[self setupHUD];
}
return self;
}
- (void)createUserInterface
{
SKLabelNode* startMsg =
[SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
startMsg.name = #"msgLabel";
startMsg.userInteractionEnabled=NO;
startMsg.text = #"Tap Screen to run!";
startMsg.fontSize = 32;
startMsg.position = CGPointMake(250, 150);
[self addChild: startMsg];
}

How to pin one SKPhysicBody to another without both falling

I am trying to join two SKPhysicsBodies together so that the one on top stays in place and the one below falls with gravity but is attached with a joint. Imagine two rectangles, one on top and one below. The one on top stays in place "floating" and the one below is attached with a joint and can move (swing perhaps or bounce etc)
When I attempt to create this, both nodes fall with gravity even if I set the affectedByGravity to NO.
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
self.physicsWorld.gravity = CGVectorMake(0, -9.8);
SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:#"myFont"];
myLabel.text = #"Hello, World!";
myLabel.fontSize = 30;
myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
myLabel.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:myLabel.frame.size];
myLabel.physicsBody.affectedByGravity = NO;
[self addChild:myLabel];
SKLabelNode *myLabel2 = [SKLabelNode labelNodeWithFontNamed:#"myFont"];
myLabel2.text = #"Hello, World!";
myLabel2.fontSize = 30;
myLabel2.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
myLabel2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:myLabel2.frame.size];
[self addChild:myLabel2];
CGPoint anchor = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
SKPhysicsJointFixed* fixedJoint = [SKPhysicsJointFixed jointWithBodyA:myLabel.physicsBody
bodyB:myLabel2.physicsBody
anchor:anchor];
[self.scene.physicsWorld addJoint:fixedJoint];
You can set the dynamic property of the static body to NO, and that will cause the body to ignore all forces and impulses, including gravity.

Resources