Fixed floor in Sprite Kit Xcode - ios

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

Related

SpriteNodes are disappearing randomly upon collision

I'm creating an iOS iPhone game similar to tetris where blocks fall from the sky and stack up on each other. However, my SpriteNodes blocks randomly disappear sometimes when a block comes on top of another one.
This is my block placement, I call this for 10 iterations to place random blocks that fall:
-(void)setupBlocksForT:(float)time {
Block *block = (Block *)[SKSpriteNode spriteNodeWithImageNamed:#"block1"];
block.physicsBody = [SKPhysicsBody bodyWithTexture:block.texture size:block.size];
block.physicsBody.dynamic = YES;
block.physicsBody.allowsRotation = NO;
block.physicsBody.usesPreciseCollisionDetection = YES;
block.physicsBody.restitution = 0;
block.physicsBody.friction = 1.0;
block.physicsBody.categoryBitMask = BlockMask;
block.physicsBody.collisionBitMask = CharacterMask | GroundMask | BlockMask;
block.physicsBody.contactTestBitMask = BlockMask | CharacterMask;
double randomSize = rand_range_double(0.10, 0.5);
block.xScale = randomSize;
block.yScale = randomSize;
block.position = CGPointMake(rand_range_int(0, self.frame.size.width, self.frame.size.height);
SKAction *wait = [SKAction waitForDuration:1.5 * time];
SKAction *spawn = [SKAction runBlock:^{
[self.myWorld addChild: block];
}];
SKAction *spawnSequence = [SKAction sequence:#[wait, spawn]];
[self runAction:spawnSequence];
}
Nowhere in my code do I call a remove(node).
I'm developing using SpriteKit and my setup is having an SKNode that contains all of my blocks so that the camera stays focused on my character's position in the DidSimulatePhysics() method.
Has anyone run into an issue where their sprites are randomly disappearing?

Spritekit node jitters while moving.... why?

Im trying to make a node move using SKAction but whenever I add the node and move it, it begins to jitter up and down along the y axis like crazy!
Any ideas?
I've tried using MoveToY, MoveTo, etc.. and no luck not sure what is causing the jitter..
Thanks..
-(void)addEnemy{
enemy = [SKSpriteNode spriteNodeWithImageNamed:#"enemy"];
enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(40, 40)];
enemy.physicsBody.dynamic = YES;
enemy.physicsBody.usesPreciseCollisionDetection = YES;
enemy.physicsBody.categoryBitMask = enemyHitCatagory;
enemy.physicsBody.contactTestBitMask = bulletHitCatagory;
enemy.physicsBody.collisionBitMask = bulletHitCatagory;
enemy.position = CGPointMake(random() % 300, CGRectGetMaxY(self.frame));
enemy.size = CGSizeMake(40, 40);
enemy.zPosition = 5;
SKAction *attack = [SKAction moveTo:(CGPointMake(20, 300)) duration:(3)];
[enemy runAction:[SKAction repeatAction:attack count:1]];
[self addChild:enemy];
}
This is happening because the physics bodies are colliding. By default, an SKPhysicsBody has a restitution of 0.2, making it a little bouncy. Setting enemy.physicsBody.restitution = 0 and doing the same for the physics body your enemy is colliding with should resolve the jitter you're seeing.

method not spawning sprite properly

Right now I have five bricks at the top of the screen all on the same y position and equally spaced apart. I would like to have five more breaks spawn outside of the top of the scene and slide down every 5 seconds. While the new bricks are sliding down I want the previous bricks to slide down to make room for the new. I want this sequence to continue on forever. I would like the new bricks to pick up the same properties of the old ones , such as when a ball hits them the react.
With the code I put in to accomplish this, I get a single brick spawning and then sliding down. Also the new brick does not act the same way as the old, it does not act like its a part of the physics world. How do I get 5 bricks spawning then sliding down and applying the same properties as the other bricks.
This code is the code I added to spawn more bricks:
-(void) spawnMoreBricks:(CGSize)size {
for (int i = 0; i < 5; i++) {
SKSpriteNode *brick = [SKSpriteNode spriteNodeWithImageNamed:#"brick"];
//resize bricks
brick.size = CGSizeMake(60, 30);
//position it
brick.position = CGPointMake(self.size.width/2, self.size.height);
SKAction *wait = [SKAction waitForDuration:5];
SKAction *spawn = [SKAction runBlock:^{[self addChild: brick];
SKAction *move = [SKAction moveByX:0 y:-80 duration:3];
[brick runAction: move];
}];
SKAction *spawnSequence = [SKAction sequence:#[wait, spawn]];
SKAction *repeatSequence = [SKAction repeatActionForever:spawnSequence];
[self runAction:repeatSequence];
}
}
This code adds the bricks into the scene right when it initializes, they react to the ball colliding with them and everything:
- (void) addBricks:(CGSize)size {
for (int i = 0; i < 5; i++) {
//create brick sprite from image
SKSpriteNode *brick = [SKSpriteNode spriteNodeWithImageNamed:#"brick"];
//resize bricks
brick.size = CGSizeMake(60, 30);
//psoition bricks
int xPos = size.width/5 * (i+.5);
int yPos = size.height - 25;
brick.position = CGPointMake(xPos, yPos);
brick.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:brick.frame.size];
brick.physicsBody.dynamic = NO;
brick.physicsBody.categoryBitMask = brickCategory;
//add bricks to scene
[self addChild:brick];
}
}

Possible way to move Nodes in a set duration without varying speeds?

I am trying move nodes to a set X distance using an SKAction with the same duration. The Nodes are in different X positions so the speed of how the node moves is different, is there a way to make the speed the same without affecting the positioning of the nodes?
Example.
-(void)beginningGamePlatforms {
SKSpriteNode *beginningPlatform = [SKSpriteNode spriteNodeWithImageNamed:#"PlatformBeginning"];
beginningPlatform.zPosition = 2;
beginningPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:beginningPlatform.size];
beginningPlatform.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
beginningPlatform.position = CGPointMake(beginningPlatform.position.x - 20, beginningPlatform.position.y - 129);
beginningPlatform.physicsBody.dynamic = NO;
SKSpriteNode *platformSpawn1 = [SKSpriteNode spriteNodeWithImageNamed:#"platformSpawn1"];
platformSpawn1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:platformSpawn1.size];
platformSpawn1.position = CGPointMake(beginningPlatform.position.x, CGRectGetMidY(self.frame));
platformSpawn1.position = CGPointMake(platformSpawn1.position.x + 196, platformSpawn1.position.y - 129);
platformSpawn1.physicsBody.dynamic = NO;
SKSpriteNode *platformSpawn2 = [SKSpriteNode spriteNodeWithImageNamed:#"platformSpawn1"];
platformSpawn2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:platformSpawn2.size];
platformSpawn2.position = CGPointMake(platformSpawn1.position.x,CGRectGetMidY(self.frame));
platformSpawn2.position = CGPointMake(platformSpawn2.position.x + 196, platformSpawn2.position.y - 129);
platformSpawn2.physicsBody.dynamic = NO;
SKAction *moveLeft = [SKAction moveTo:CGPointMake(-100 , beginningPlatform.position.y) duration:9];
SKAction *removeFromParent = [SKAction removeFromParent];
SKAction *AllTwo = [SKAction sequence:#[moveLeft,removeFromParent]];
[self addChild:beginningPlatform];
[self addChild:platformSpawn1];
[self addChild:platformSpawn2];
[beginningPlatform runAction:AllTwo];
[platformSpawn1 runAction:AllTwo];
[platformSpawn2 runAction:AllTwo];
}
In my code I created 3 platforms with a set distance within each other that when the sprite images combined, it creates the illusion of a single wide platform. However when running the actions, the illusion breaks. Any information will be appreciated.
You can try replacing the moveTo: in:
SKAction *moveLeft = [SKAction moveTo:CGPointMake(-100 , beginningPlatform.position.y) duration:9];
with a moveBy: varient. Currently, the different platforms start at different positions to make the illusion of a continuous platform, but by moving all of them to the same place, they won't maintain their original position intervals.

How can I keep my sprites velocity constant?

I'm making a simple space shooter in Sprite Kit. I have asteroid rock sprites that are randomly added to my scene. I give them a random velocity within a certain range. However, once added to the scene their velocity decreases every second and eventually they stop. as they get closer to the bottom of the screen their velocity decreases at a slower rate. I have gravity of my physics world set to (0,0).
below is the method that adds the rocks to the scene
- (void)addRock {
SPRockNode *rock = [SPRockNode rock];
float dy = [SPUtil randomWithMin:SPRockMinSpeed max:SPRockMaxSpeed];
rock.physicsBody.velocity = CGVectorMake(0, -dy);
float y = self.frame.size.height + rock.size.height;
float x = [SPUtil randomWithMin:10 + rock.size.width max:self.frame.size.width - 10 - rock.size.width];
rock.position = CGPointMake(x, y);
[self addChild:rock];
}
I set up the physics world in my scenes initWIthSize method
self.physicsWorld.contactDelegate = self;
self.physicsWorld.gravity = CGVectorMake(0, 0);
below is the code for my rock node class
+ (instancetype)rock {
SPRockNode *rock = [self spriteNodeWithImageNamed:#"rock"];
rock.name = #"Rock";
float scale = [SPUtil randomWithMin:50 max:100] / 100.0f;
rock.xScale = scale;
rock.yScale = scale;
NSInteger randomInt = [SPUtil randomWithMin:1 max:3];
if (randomInt == 1) {
SKAction *oneRevolution = [SKAction rotateByAngle:-M_PI*2 duration: 1.0];
SKAction *repeat = [SKAction repeatActionForever:oneRevolution];
[rock runAction:repeat];
} else {
SKAction *oneRevolution = [SKAction rotateByAngle:M_PI*2 duration: 1.0];
SKAction *repeat = [SKAction repeatActionForever:oneRevolution];
[rock runAction:repeat];
}
[rock setupPhysicsBody];
return rock;
}
- (void)setupPhysicsBody {
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.frame.size];
self.physicsBody.affectedByGravity = NO;
self.physicsBody.categoryBitMask = SPCollisionCategoryRock;
self.physicsBody.collisionBitMask = 0;
self.physicsBody.contactTestBitMask = SPCollisionCategoryProjectile | SPCollisionCategoryShip;
}
any ideas on what causing them to slow down? I dont modify their velocity anywhere else but the addRock method. is there air resistance or something like that on by default? I just dont understand why their velocity is decreasing.
It sounds like you are having an issue with linear damping.
From SKPhysicsBody reference :
This property is used to simulate fluid or air friction forces on the body. The property must be a value between 0.0 and 1.0. The default value is 0.1. If the value is 0.0, no linear damping is applied to the object.
Try adding this :
rock.physicsBody.linearDamping = 0.0f;
It's worthwhile to give the SKPhysicsBody class reference a reading at least once. It only takes a short while, but can save you a ton of time if you have become acquainted with it's properties and methods.

Resources