Prevent SKSpriteNode from bouncing off other SKSpriteNode - sprite-kit

I have a SKSpriteNode that collides and bounces off another SKSpriteNode. What I want is to be able to detect the collision, but not have it bounce off. I want it to bounce off other nodes, but not this one. Is that possible?
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
self.zone = [SKSpriteNode spriteNodeWithImageNamed:#"Oval.png"];
self.zone.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame)); self.zone.xScale = 0.3;
self.zone.yScale = 0.3;
self.zone.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.zone.frame.size.width/2];
self.zone.physicsBody.restitution = 0.0f;
self.zone.physicsBody.density = 0;
self.zone.physicsBody.friction = 0.4f;
self.zone.physicsBody.categoryBitMask = zoneCategory;
self.zone.physicsBody.dynamic = NO;
self.ball = [SKSpriteNode spriteNodeWithImageNamed:#"Ball.png"];
self.ball.position = CGPointMake(80,0);
self.ball.name = #"BallNode";//how the node is identified later
self.ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.ball.frame.size.width/2];
self.ball.physicsBody.restitution = 0.1f;
self.ball.physicsBody.friction = 0.4f;
self.ball.physicsBody.categoryBitMask = ballCategory;
self.ball.physicsBody.dynamic = NO;
I don't want ball and zone to bounce. Any ideas?

set collisionBitMask and contactTestBitMask of those two bodies
like:
self.zone.collisionBitMask = 0xFFFFFFFF & (~ballCategory);
self.ball.collisionBitMask = 0xFFFFFFFF & (~zoneCategory);
self.zone.contactTestBitMask = ballCategory;
then when contact occurs expect call of didBeginContact: in your SKPhysicsContactDelegate.
There will be no collsion.

Related

SKSpriteNode vibrating when physics body is attached and impulse is applied

I've noticed something very odd with my subclassed SKSpriteNode with physicsBody attached and responding to impulses.
It has a SKPhysicsBody attached, but when applying impulses to the sprite it vibrates during movement. It's highly annoying and looks awful.
What could be causing this?
Here's the setup code:
self.texture = [[SKTextureAtlas atlasNamed:#"karl"]textureNamed:#"karlidle-1"];
self.size = CGSizeMake(69.0, 93.0);
self.userInteractionEnabled = NO;
self.name = #"karl";
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(69.0, 93.0)];
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.affectedByGravity = YES;
self.physicsBody.usesPreciseCollisionDetection = YES;
self.physicsBody.mass = 1.0;
self.physicsBody.linearDamping = 0.0;
self.physicsBody.angularDamping = 0.0;
self.physicsBody.restitution = 0.3;
self.physicsBody.categoryBitMask = karlCategory;
self.physicsBody.collisionBitMask = obstaclesCategory|floorCategory|wallCategory;
self.physicsBody.contactTestBitMask = obstaclesCategory|floorCategory|wallCategory;
and applying the impulse:
if (self.physicsBody.velocity.dy >= kKarlMaxVelocity) {
self.physicsBody.velocity = CGVectorMake(0, kKarlMaxVelocity);
}
else if (self.physicsBody.velocity.dy <= kKarlLowVelocityBoostThreshold){
self.physicsBody.velocity = CGVectorMake(0, kKarlVelocityImpulseIncrement*kKarlVelocityBoost);
}
else{
[self.physicsBody applyImpulse:CGVectorMake(0, kKarlVelocityImpulseIncrement)];
//[self.physicsBody applyForce:CGVectorMake(0, 3000) atPoint:self.frame.origin];
//self.physicsBody.velocity = CGVectorMake([self returnNormalisedXVelocity], self.physicsBody.velocity.dy);
}
One thing to note is I clamp the velocity so it doesn't go nuts, but turning this off doesn't seem to fix the issue.

Stop node rotation in Sprite Kit

I can't figure out how to stop node from rotating.
Why allowsRotation isn't disabling it?
Here's how I describe my node:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.velocity = CGVectorMake(0, 0);
badguy.physicsBody.categoryBitMask = CollisionTypeEnemy;
badguy.physicsBody.contactTestBitMask = CollisionTypePlayer | CollisionTypeWall | CollisionTypeEnemy;
badguy.physicsBody.collisionBitMask = CollisionTypeWall | CollisionTypePlayer | CollisionTypeEnemy;
badguy.physicsBody.mass = 10000;
badguy.physicsBody.restitution = 0;
badguy.physicsBody.dynamic = YES;
badguy.zPosition = 10;
On Update I call this method:
-(void)enemiesFollow
{
[self.world enumerateChildNodesWithName:#"badGuy" usingBlock:^(SKNode * _Nonnull badGuyNode, BOOL * _Nonnull stop) {
if((SDistanceBetweenPoints(self.player.position, badGuyNode.position) < 100)&&
(SDistanceBetweenPoints(self.player.position, badGuyNode.position) > 32))
{
SKAction * actionMove = [SKAction moveTo:self.player.position duration:2.0];
[badGuyNode runAction:actionMove];
}else{
[badGuyNode removeAllActions];
}
}];
}
Thanks to Skyler Lauren's suggestion, I am pretty much sure that the problem is in these lines:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture:[self.spriteAtlas textureNamed:#"test"]];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = NO;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
The point is that you can't set properties of a physics body before you create an actual body. So, just move those lines after you create a physics body and you will be good, like this:
SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(32,32)];
badguy.texture.filteringMode = SKTextureFilteringNearest;
badguy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(32, 32)];
badguy.physicsBody.angularVelocity = 0;
badguy.physicsBody.allowsRotation = YES;

precise collision error with sprite kit

I have created a hero node and enemy node, when they collide,game over.But I have problem with precise collision. Sometimes there is overlap.Sometimes collision happens when one node doesn't reach the other's frame. can anybody give me some advise? appreciate your help~
my hero is affected by gravity, when tap, it will change the direction of gravity.
following is some of my code:
-(void)addRectHero {
rectHero = [SKSpriteNode spriteNodeWithImageNamed:#“hero.png”];
rectHero.scale = 0.2;
rectHero.position = CGPointMake(self.size.width/2, self.size.height*0.3);
rectHero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rectHero.size];
rectHero.physicsBody.restitution = 0.0;
rectHero.physicsBody.allowsRotation = NO;
rectHero.physicsBody.dynamic = YES;
rectHero.physicsBody.affectedByGravity=NO;
rectHero.physicsBody.categoryBitMask = heroCategory;
rectHero.physicsBody.contactTestBitMask = enemyCategory;
rectHero.zPosition = 100;
rectHero.physicsBody.collisionBitMask = enemyCategory;
rectHero.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:rectHero];
}
-(void)createEnemy{
randomStartPoint =(float)((random()%(int)(self.size.height/3))+self.size.height/3);
startPoint = CGPointMake(self.size.width + 50, randomStartPoint);
enemyNode = [SKSpriteNode spriteNodeWithImageNamed:#"enemy_4.png"];
enemyNode.scale =0.5;
enemyNode.position = startPoint;
enemyNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemyNode.size];
enemyNode.physicsBody.dynamic = NO;
enemyNode.physicsBody.categoryBitMask = enemyCategory;
enemyNode.physicsBody.contactTestBitMask = heroCategory;
enemyNode.physicsBody.collisionBitMask = heroCategory;
enemyNode.physicsBody.usesPreciseCollisionDetection = YES;
enemyNode.physicsBody.allowsRotation = NO;
enemyNode.physicsBody.restitution = 0.0;
enemyNode.name = #"enemy";
[self addChild:enemyNode];
}
-(void)didBeginContact:(SKPhysicsContact *)contact{
if (!_gameIsOn) {
return;
}
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask<contact.bodyB.categoryBitMask) {
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody=contact.bodyB;
secondBody=contact.bodyA;
}
if (firstBody.categoryBitMask == heroCategory && secondBody.categoryBitMask == enemyCategory) {
[self runAction:sound_play completion:^{
[self gameOver];
}];
[self stopTimer];
}
}
I create a lot of enemies in update method: (I also tried self repeatActionForever method to create enemy but the problem still exists)
-(void)update:(CFTimeInterval)currentTime {
if (_lastTime)
{
_dt = currentTime - _lastTime;
}
else
{
_dt = 0;
}
_lastTime = currentTime;
if( currentTime - _lastEnemyAdded > 1 && _gameIsOn)
{
_lastEnemyAdded = currentTime + 1;
[self createEnemy];
}
}
In your ViewController make sure you have skView.showsPhysics = YES; Run your game again and look if your physics bodies are what you expect them to be. It sounds like you are creating a larger physics body than what you want.
If the issue ends up being a larger than desired physics body, try creating a physics body like this:
// to create a circular physics body
self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10 center:CGPointMake(0, 0)];
// to create a rect physics body
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(20, 20) center:CGPointMake(0, 0)];
Use the center coordinates to properly center the body.
To create a physics body made up of more than one shape, you can do something like this:
SKPhysicsBody *firstBody = [SKPhysicsBody bodyWithCircleOfRadius:20 center:CGPointMake(0, 0)];
SKPhysicsBody *secondBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(20, 20) center:CGPointMake(0, 20)];
self.physicsBody = [SKPhysicsBody bodyWithBodies:#[firstBody, secondBody]];

Spritekit - Spawn waves of monsters

I'm making a simple racing game in which the monsters are spawned (randomly) from 3 out of the 5 lanes in the portrait mode.
-(void)addEnemy
{
SKSpriteNode *Enemy;
Enemy = [SKSpriteNode spriteNodeWithImageNamed:#"Enemy1"];
[Enemy setScale:.65];
Enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy.size];
Enemy.physicsBody.categoryBitMask = obstacleCategory;
Enemy.physicsBody.dynamic = YES;
Enemy.zPosition = 2;
Enemy.physicsBody.contactTestBitMask = TurtleCategory;
Enemy.physicsBody.collisionBitMask = 0;
Enemy.physicsBody.usesPreciseCollisionDetection = YES;
Enemy.name = #"Enemy";
//selecting random y position for Enemy
int r = (arc4random() % 5) ;
Enemy.position = CGPointMake(48+r*56,self.frame.size.height);
[self addChild:Enemy];
SKAction *actionMove =
[SKAction moveTo:CGPointMake(Enemy.position.x,-80)
duration:1.43];
[Enemy runAction:actionMove];
SKSpriteNode *Enemy2;
Enemy2 = [SKSpriteNode spriteNodeWithImageNamed:#"Enemy1"];
[Enemy2 setScale:.65];
//Adding SpriteKit physicsBody for collision detection
Enemy2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy.size];
Enemy2.physicsBody.categoryBitMask = obstacleCategory;
Enemy2.physicsBody.dynamic = YES;
Enemy2.zPosition = 2;
Enemy2.physicsBody.contactTestBitMask = TurtleCategory;
Enemy2.physicsBody.collisionBitMask = 0;
Enemy2.physicsBody.usesPreciseCollisionDetection = YES;
Enemy2.name = #"Enemy2";
//selecting random y position for Enemy
int r2 = (arc4random() % 5) ;
Enemy2.position = CGPointMake(48+r2*56,self.frame.size.height);
[self addChild:Enemy2];
SKAction *actionMove2 =
[SKAction moveTo:CGPointMake(Enemy2.position.x,-80)
duration:1.43];
[Enemy2 runAction:actionMove2];
SKSpriteNode *Enemy1;
Enemy1 = [SKSpriteNode spriteNodeWithImageNamed:#"boss1"];
[Enemy1 setScale:.65];
//Adding SpriteKit physicsBody for collision detection
Enemy1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Enemy1.size];
Enemy1.physicsBody.categoryBitMask = obstacleCategory;
Enemy1.physicsBody.dynamic = YES;
Enemy1.zPosition =2;
Enemy1.physicsBody.contactTestBitMask = TurtleCategory;
Enemy1.physicsBody.collisionBitMask = 0;
Enemy1.physicsBody.usesPreciseCollisionDetection = YES;
Enemy1.name = #"Enemy1";
int r1 = (arc4random() % 5) ;
Enemy1.position = CGPointMake(48+r1*56,self.frame.size.height);
[self addChild:Enemy1];
SKAction *actionMove1 =
[SKAction moveTo:CGPointMake(Enemy1.position.x,-80)
duration:1.43];
[Enemy1 runAction:actionMove1];
However, one of problem of this code is that monsters are sometimes spawned on top of each other. Is there a better way to do this?
Thanks
- (CGFloat)randomValueBetween:(CGFloat)low andValue:(CGFloat)high {
return (((CGFloat) arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}
I found this piece of code from a raywenderlich tutorial I think.
What u can do is call,
CGFloat r1 = [self randomValueBetween:0 andValue:3];
CGFloat r2 = [self randomValueBetween:3 andValue:6]; etc
that might give you different values that u can use as offset.

Not able to apply impulse to SKSpriteNode physics body

I am new to xcode's sprite kit and I'm an trying to apply an impulse to a SKSpriteNode's physics body.
Here is how I create the scene:
self.backgroundColor = [SKColor colorWithRed:0 green:0 blue:0 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody.friction = 0.0f;
self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);
ballCategory = 1;
wallCategory = 2;
self.physicsBody.categoryBitMask = wallCategory;
Here is how I create the player AND give it its impulse:
player = [SKSpriteNode spriteNodeWithImageNamed:filePath];
player.size = CGSizeMake(100, 100);
player.position = CGPointMake(150, 250);
player.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:player.frame];
player.physicsBody.categoryBitMask = ballCategory;
player.physicsBody.collisionBitMask = wallCategory;
player.physicsBody.friction = 0.0f;
player.physicsBody.restitution = 1.0f;
player.physicsBody.linearDamping = 0.0f;
player.physicsBody.allowsRotation = NO;
[self addChild:player];
CGVector impulse = CGVectorMake(100,100);
[player.physicsBody applyImpulse:impulse];
Is there anything obvious that I am missing because I've been following the iOS Developer Library Sprite Kit Programming Guide perfectly? Thanks in advance for the help!
You are creating the player's physicsBody as an edge body - these are always static (immovable by forces/impulses). You should change that line to:
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size];
This example makes it a dynamic volume based on a rectangle which will be affected by physics forces. You can read up on the types of physics bodies here.