Objective c SpriteKit node - ios

i want to make simple game in SpriteKit, basically what i want do do is make node what shows up on touch and disappear after like 5 sec. here are sample of code that is for board:
SKSpriteNode* board = [[SkSpriteNode alloc] initWithImageNamed:#"board"];
board.name = boardCategoryName;
board.position = CGPointMake (CGRectGetMaxX(self.frame),board.frame.seize.height *4.6f);
[self.addChild:board];
board.physicsBody = [SKphysicsBody bodyWithRectangleOFSize:board.frame.size];
board.physicsBody.restitution =0.1f;
board.physicsBody.friction = 0.4f;
board.physicsBody.dynamic = No;

Mr T does present 1 option, but personally I would use the SKActions sequence, waitForDuration, and removeFromParent() when dealing with nodes, like this:
let waitDuration = SKAction.waitForDuration(5)
let killAction = SKAction.removeFromParent()
let seqAction = SKAction.sequence([waitDuration,killAction])
....
board.runAction(seqAction)

There are many ways you can do it. One way is to call [board removeFromParent] after 5 seconds. This could be a call by NSTimer or you can use the update method which runs continuously,and check for the flag if node is added on the screen or not, and then remove the node after 5 seconds. You might need to set the flag in the touchesBegan method.
Edit:
You can also make use of SKAction waitForDuration
Sample code:
SKAction *delay = [SKAction waitForDuration:5];
SKAction *remove = [SKAction removeFromParent];
SKAction *actionSequence = [SKAction sequence:#[delay,remove]];
[board runAction:actionSequence];
So that after the wait is done, the node will be removed.

Related

Sprite Kit - Objective c, move multiple SKNode at the same time

i have this method that makes the Lines
lineaGuida_Img = [SKTexture textureWithImageNamed:#"LineaGuida copia.jpeg"];
_Linea = [SKNode node];
_Linea.position = CGPointMake((self.frame.size.width / 7 ) * 2, self.frame.size.height / 2 );
_Linea.zPosition = -10;
SKSpriteNode * linea = [SKSpriteNode spriteNodeWithTexture:lineaGuida_Img];
linea.position = CGPointMake(0,0);
linea.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:linea.size];
linea.physicsBody.dynamic = FALSE;
linea.physicsBody.collisionBitMask = 0;
linea.physicsBody.categoryBitMask = CollisionEnemy;
[_Linea addChild:linea];
[self addChild:_Linea];
In the touchesBegan method when i touch the screen, the player is always on the center of screen, and those lines behind him have to move by -x.
[_Linea runAction:[SKAction moveByX: -(self.size.width/8) y:0 duration:0.1]];
[self spawn_Lines];
But this action is only executed by the last SKNode. I need to apply this to all Lines simultaneously. After that, when the line's position is less then the player's position, the line must be deleted.
SpriteKit uses a tree based model, so whatever the parent node does, the children fall suit. Create an SKNode to house all of your lines, add all of your lines to this SKNode, then apply the actions to the SKNode, not the lines.
Add them to NSMutableArray to keep the reference and use for each loop to make each one run the action. I would recommend you to use NSTimer to provide [SKAction moveByX: -1 y:0 duration:0]] with constant speed which will result in the same motion as you already used. Each time this NSTimer execute you will check all positions of object from your NSMutableArray and than delete it if it fits your conditions. Be careful when you want to lose the reference completely use [object removeFromParent]; and remove it also from your NSMutableArray to avoid lose of performance later on. For this I use rather forLoop with continue method

Can't disable physics in Sprite Kit

I have two nodes one near another. And I want one node to be on top of another when I tap. I do so like this:
SKAction *moveUp= [SKAction moveByX:0 y:25 duration:0.1];
SKAction *moveDown= [SKAction moveByX:0 y:-25 duration:0.1];
SKAction *playerSequence = [SKAction sequence:#[moveUp,moveDown]];
[self.player runAction:[SKAction repeatAction:playerSequence count:1] withKey:#"attack"];
And instead I get that one node pushes the other (bots nodes created via editor and both body type is set to none).
I tried adding these to didMoveToView on both nodes:
node.physicsBody.dynamic = NO;
node.physicsBody.collisionBitMask = 0;
node.physicsBody.contactTestBitMask = 0;
node.physicsBody.affectedByGravity = NO;
I even tried setting velocity to 0 on Update. And still no effect.
Set your bit masks in
-(void)didBeginContact:(SKPhysicsContact *)contact
as shown in this post.
I think you have a timing issue if you set the bit masks in
didMoveToView
because only one of those will be run at a time and both physics bodies will need to mutually agree not contact each other.
You have to set the physics body to nil:
node.physicsBody = nil;

Endless Action with SKActions Objective C

I am building a game with sprite kit and have a sprite moving from left to right with an endless action.
SKAction *moveRight = [SKAction moveByX:3.0 y:0 duration:3.5];
SKAction *moveLeft = [SKAction moveByX:-3.0 y:0 duration:3.5];
SKAction *reversedMoveRight = [moveRight reversedAction];
SKAction *reversedMoveLeft = [moveLeft reversedAction];
SKAction *completion = [SKAction runBlock:^{
SKAction *sequence = [SKAction sequence:#[moveRight, moveLeft, reversedMoveRight,reversedMoveLeft]];
SKAction *endlessAction = [SKAction repeatActionForever:sequence];
[snake runAction:endlessAction];
}];
[snake runAction:completion withKey:#"KeySnake"];
This works, but after a short period of time my game slows down. The CPU and memory usage continues to grow in the debug navigator in Xcode. I think the endless action is causing the problem, but I don't know any other way to move it constantly like I want to.
From your comment I understand you are calling
[snake runAction:completion withKey:#"KeySnake"];
inside the update method. This is the problem, infact you are creating and running a new action every frame.
Move the whole block of code (you showed in your question) inside a method that is called only once.
Example: here I also refactored the construction of your action and changed the x value (in the action) from 3.0 to 100.0
#import "GameScene.h"
#implementation GameScene
{
SKSpriteNode * _snake;
}
- (void)didMoveToView:(SKView *)view {
[self addSnake];
[self startSnakeMoving];
}
- (void)addSnake{
_snake = [SKSpriteNode spriteNodeWithImageNamed:#"Snake"];
_snake.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:_snake];
}
- (void)startSnakeMoving {
SKAction * moveRight = [SKAction moveByX:100.0 y:0 duration:3.5];
SKAction * sequence = [SKAction sequence:#[moveRight, moveRight.reversedAction, moveRight.reversedAction, moveRight]];
SKAction * endlessAction = [SKAction repeatActionForever:sequence];
[_snake runAction:endlessAction withKey:#"KeySnake"];
}
#end
Rather than making snake (whatever is snake) calling your endless action (that is in fact 'sequence' repeated forever), you should call 'sequence' via a CADisplayLink (which is a screen refresh), that is make to drive the rendering of anything (so game) at screen refresh frequency.

Sprite Kit, force stop on physics

I'm creating an ongoing learning project (basically I code while learning to use the framework in hope it will be useful for me and for someone else) for Sprite Kit (you can find it here if you are interested) but I'm facing some performance problems with my code.
The project puts cubes on the screen and make them falling. Here's the class that creates the piece
// The phisics for our falling piece:
// It will be a square, subject to gravity of 5: check common.h (9.8 is way too much for us)
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.size.width, self.size.height)];
self.physicsBody.dynamic = YES;
self.physicsBody.mass = 100;
self.physicsBody.collisionBitMask = piecesCollisionBitmask;
self.physicsBody.allowsRotation = NO;
and here is the scene file with the loop.
//schedule pieces
SKAction *wait = [SKAction waitForDuration:1];
SKAction *pieceIsFalling = [SKAction runBlock:^{
FLPPiece *piece = [[FLPPiece alloc] init];
[self addChild:piece];
}];
SKAction *fallingPieces = [SKAction sequence:#[wait,pieceIsFalling]];
[self runAction:[SKAction repeatActionForever:fallingPieces]];
I suspect that physics is behind my frame rate drop. I would like to stop physics execution on node while keeping it on the screen as soon as it collides with something else.
Is that possible? How can I do that?

(iOs SpriteKit)passing a sprite in a method

i want to make a parallax effect on my background title screen with mountains moving. The "trick" i want to make is when a mountain goes to the end of the screen, instead of destroying the node and create it again at the begining position, i just want to change it's position to the begining position and loop the rest of actions. For this i create my moutain sprite at the begining of the createSceneContents() function and i pass the sprite to a method animate() wich do allways the same combo of actions forever: animate to the right, then when it's at x position, change mountain.position.x to the begining...
-(void)createSceneContents{
//crear
SKSpriteNode *mountain = [SKSpriteNode spriteNodeWithImageNamed:#"mountain.png"];
mountain.name = #"mountain";
//initial position
mountain.position = CGPointMake(-161.5,15);
//animate
SKAction *animRight = [SKAction moveToX:801.5 duration:4];
SKAction *comboActions = [SKAction repeatActionForever:[SKAction performSelector:#selector(animate:mountain) onTarget:#"mountain"]];
And here i have my method declaration:
- (void) animate:(SKSpriteNode*)mountain
{
// code....
}
My problem is i'm allways having errors passing the SKSpriteNode *mountain in my method and
I'm going crazy trying everithing.
You can avoid performSelector action, using a custom action like this.
SKAction* parallaxMoveAction = [SKAction sequence:#[[SKAction moveToX:801.5 duration:4.0f],[SKAction customActionWithDuration:0 actionBlock:^(SKNode* node, CGFloat elapsedTime){
[node setPosition:CGPointMake(-161.5,15)];
}]]];
If you set custom action duration to 0 it will be performed only once.
On the other hand your perform selector action should look like this:
[SKAction performSelector:#selector(animate:) onTarget:self]
As far as i know you can't pass arguments to it.

Resources