- (void)didBeginContact:(SKPhysicsContact *) refuses to fire - ios

1) I set the delegate protocol on the SKScene header:
#interface WorldScene : SKScene <SKPhysicsContactDelegate>
2) I set delegate to the physics world:
- (id) init
{
self = [super init];
if (self)
{
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
}
return self;
}
3) I set my bitmasks:
static const uint32_t playerCategory = 0x1 << 0;
static const uint32_t wallsCategory = 0x1 << 1;
static const uint32_t endCategory = 0x1 << 2;
4) I make my player:
SKSpriteNode *player = [[SKSpriteNode alloc] initWithColor:[SKColor blueColor] size:CGSizeMake(PLAYERSIZE, PLAYERSIZE)];
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.size];
player.name = #"player";
player.physicsBody.dynamic = YES;
player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.collisionBitMask = wallsCategory;
player.physicsBody.contactTestBitMask = endCategory;
5) I make my end tile:
SKSpriteNode *tile = [[SKSpriteNode alloc] initWithColor: [SKColor whiteColor] size:CGSizeMake(TILESIZE,TILESIZE)];
if ([cell isEnd]){
tile.color = [SKColor greenColor];
tile.name = #"endTile";
tile.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: tile.size];
NSLog(#"END TILE OF SIZE %f x %f", tile.size.width, tile.size.height);
tile.physicsBody.dynamic = YES;
tile.physicsBody.affectedByGravity = NO;
tile.physicsBody.categoryBitMask = endCategory;
tile.physicsBody.collisionBitMask = 0;
tile.physicsBody.contactTestBitMask = playerCategory;
}
6) But this never gets called! :(
- (void)didBeginContact:(SKPhysicsContact *)contact
{
NSLog(#"Touched!");
[self removeAllChildren];
}
I'm making a maze game. The player currently collides with all the walls fine, but I want the game to end when it reaches the last tile. Currently, the contact event isn't being called. I don't really know what's wrong, I have my debugger output set to displaying all output (and in any case all the children should be getting removed if it reaches the event anyway).
Whyyyyyy

SOLVED -- turns out init was never being called, so the delegate was not actually being set. Moved all the init code to - (void) didMoveToView:(SKView *)view and it began working just fine.

Related

SpriteKit didBeginContact function not called

I am trying to get collision working in my SpriteKit game using the didBeginContact function.
My problem is that the function is just not getting called at all when the ball bounces off of the bricks. This is how I have set them both up:
static const uint32_t blockCollisionCheck = 0x1 << 0;
static const uint32_t ballCollisionCheck = 0x1 << 1;
Ball:
SKShapeNode *ball = [[SKShapeNode alloc] init];
CGMutablePathRef drawPath = CGPathCreateMutable();
CGPathAddArc(drawPath, NULL, 0, 0, _ballRadius, 0, M_PI * 2, YES);
ball.path = drawPath;
CGPathRelease(drawPath);
ball.fillColor = [SKColor greenColor];
ball.position = CGPointMake(CGRectGetMidX(self.frame), 150);
ball.name = #"ball";
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_ballRadius];
ball.physicsBody.friction = 0.0;
ball.physicsBody.restitution = 1.0;
ball.physicsBody.linearDamping = 0.0f;
ball.physicsBody.allowsRotation = NO;
ball.physicsBody.dynamic = YES;
ball.physicsBody.categoryBitMask = ballCollisionCheck;
ball.physicsBody.contactTestBitMask = blockCollisionCheck;
[self addChild:ball];
Bricks:
SKSpriteNode *block = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(_blockWidth, _blockHeight)];
block.name = #"block";
block.position = CGPointMake(x, y);
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size];
block.physicsBody.allowsRotation = NO;
block.physicsBody.friction = 0.0;
block.physicsBody.dynamic = YES;
block.physicsBody.categoryBitMask = blockCollisionCheck;
block.physicsBody.contactTestBitMask = ballCollisionCheck;
[self addChild:block];
I can't for the life of me see what is wrong with this, as I have the category bit masks correct I think? Also both of the sprites are Dynamic, which is another problem I read it could have been.
It's not that the contents of my didBeginContact function is not working, it's just never getting there as evidenced from a lack of NSLog message and breakpoints not being reached.
Any help would be greatly appreciated.
Thank you.
If, as you say, the didBeginContact method is not being called at all, I suspect you did not add the self.physicsWorld.contactDelegate = self; into your GameScene init method.

How to make balls ignore collisions with each other

With sprite kit, I'm trying to make series of balls drop from the air through physics simulation, and I want them to drop without colliding with each other and bounce off. I just want them to go straight down and pass through each other. How should I make this happen with collisionBitMask and categoryBitMask ?
// Common.h
#ifndef Rainy_Poops_common_h
#define Rainy_Poops_common_h
static int poopSize_x = 20;
static int poopSize_y = 20;
static const uint32_t poopCategory = 0x1 << 1;
#endif
// MyScene.h
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
_timer++;
if (_timer % 3 == 0) {
SKSpriteNode * p = [[Poop alloc] init];
NSInteger random_x = arc4random_uniform([[UIScreen mainScreen]applicationFrame].size.width);
p.position = CGPointMake(random_x, [[UIScreen mainScreen]applicationFrame].size.height - 5);
[self addChild: p];
[self enumerateChildNodesWithName:#"poop" usingBlock:
^(SKNode *node, BOOL *stop) {
Poop *poop = (Poop *) node;
if (!poop.isDropping) {
poop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(poopSize_x, poopSize_y)];
poop.isDropping = YES;
}
if (poop.position.y < 0) {
[poop removeFromParent];
}
}];
}
}
#import "Poop.h"
#implementation Poop
- (id)init {
self = [super initWithImageNamed:#"poop2.png"];
self.isDropping = NO;
self.name = #"poop";
self.size = CGSizeMake(poopSize_x, poopSize_y);
SKPhysicsBody *physicsPoop = self.physicsBody;
physicsPoop.collisionBitMask = 0;
physicsPoop.categoryBitMask = poopCategory;
physicsPoop.affectedByGravity = YES;
physicsPoop.mass = 100;
physicsPoop.allowsRotation = NO;
physicsPoop.dynamic = YES;
return self;
}
#end
I think your problem is related to this line -
poop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(poopSize_x,poopSize_y)];
You initialise your categoryBitMask to 2 and collisionBitMask to 0 in the init of your node, but this line will reset the physicsBody for your poop and assign the default collisionBitMask and categoryBitMask values of 0xFFFFFFFF
set collisionButMask equal to 0 for no collision or equal to the categoryBitMask of the sprite you would like the balls to collide with.

Spritekit drastic frame rate drop

I have tried my best to boil this question down as simple as possible. I have a coin object in my game:
#implementation
-(CollectableCoin*)initWithLocation:(CGPoint) Location andValue: (int) val
{
self = [super initWithImageNamed:#"coin"];
[self setScale:.35];
_value = val;
_collected = false;
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.size];
self.physicsBody.categoryBitMask = APAColliderTypeCoin;
self.physicsBody.collisionBitMask = APAColliderTypeBall;
self.physicsBody.mass = 0.00009;
self.physicsBody.restitution = .35;
self.position = Location;
self.name = #"collectableCoin";
return self;
}
#end
I also have a shelf object:
#implementation Shelf
-(Shelf*)initWithLocation:(CGPoint) location andWidth:(NSInteger) width
{
self = [super initWithImageNamed:#"shelf"];
if(self)
{
self.size = CGSizeMake(width, HEIGHT);
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.size];
self.physicsBody.dynamic = false;
self.physicsBody.restitution = 0;
self.position = location;
self.name = #"shelf";
SKSpriteNode* topOfShelf;
if(width > 5)
topOfShelf = [[SKSpriteNode alloc] initWithColor:[UIColor yellowColor] size:CGSizeMake(width-2, 1)];
else
topOfShelf = [[SKSpriteNode alloc] initWithColor:[UIColor yellowColor] size:CGSizeMake(width, 1)];
topOfShelf.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:topOfShelf.size];
topOfShelf.physicsBody.restitution = 1;
topOfShelf.physicsBody.dynamic = false;
topOfShelf.position = CGPointMake(0, location.y + self.size.height/2);
NSLog([NSString stringWithFormat:#"%f", location.y + self.size.height/2]);
NSLog([NSString stringWithFormat:#"%f", location.y]);
topOfShelf.name = #"shelf";
[self addChild:topOfShelf];
}
return self;
}
#end
I create a scene like so:
-(id)initWithSizeTest:(CGSize)size
{
self.physicsWorld.gravity = CGVectorMake(0, 0);
_gameState = READYTOSTART;
self.physicsWorld.contactDelegate = self;
if (self = [super initWithSize:size])
{
self.physicsWorld.gravity = CGVectorMake(0, 0);
for(int i = 0; i < 25; i++)
{
CollectableCoin* orb = [[CollectableCoin alloc] initWithLocation:CGPointMake(i*10, self.size.height*.75) andValue:1];
[self addChild:orb];
}
Shelf* shelf = [[Shelf alloc] initWithLocation:CGPointMake(self.size.width/2, self.size.height/2) andWidth:self.size.width];
[self addChild:shelf];
}
return self;
}
Here is the touchesBegan method:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
if(_gameState == READYTOSTART)
{
self.physicsWorld.gravity = CGVectorMake(0, -2.0);
_gameState = PLAYING;
[[self childNodeWithName:#"taptostart"] removeFromParent];
}
When the scene starts, I have a row of coins hovering above a shelf, gravity is disabled, and I have a solid 60fps. When I tap the screen, the touchesbegan function enables gravity and the coins fall on the shelf, and the frame rate drops to 5fps. The didBeginContact function is not being called because the shelf object is not dynamic nor does it have contact or collision bitmasks, so I am fairly sure that it is not being overloaded by extraneous calls to didBeginContact. This happens on an iPad mini and an iPhone 4s, but not in any of the simulators. This is a very simple example of the actual problem that I am having. Anyone have any insights?

Prevent player from falling through the ground - Sprite Kit

I've been trying to work on a simple Sprite Kit game that involves dodging red balls. I'm using the built-in gravity mechanism, but I'm having trouble preventing the player from falling through the ground. I've looked up a solution (set ground.physicsBody.dynamic = NO), but the player still falls through. What exactly do I need to do?
Edit: The green and brown texture is the ground. Right now the player is set to not being dynamic, so it is 'flying'
Here is my code in the MyScene.m file:
//
// MyScene.m
// DodgeMan
//
// Created by Cormac Chester on 3/8/14.
// Copyright (c) 2014 Testman Industries. All rights reserved.
//
#import "MyScene.h"
#import "EndGameScene.h"
static const uint32_t redBallCategory = 0x1 << 0;
static const uint32_t playerCategory = 0x1 << 1;
#implementation MyScene
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
/* Setup your scene here */
//Sets player location
playerLocX = 50;
playerLocY = 100;
//Sets player score
score = 0;
//Set Background
self.backgroundColor = [SKColor colorWithRed:0.53 green:0.81 blue:0.92 alpha:1.0];
//Set Ground
SKSpriteNode *ground = [SKSpriteNode spriteNodeWithImageNamed:#"ground"];
ground.position = CGPointMake(CGRectGetMidX(self.frame), 34);
ground.xScale = 0.5;
ground.yScale = 0.5;
ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
ground.physicsBody.dynamic = NO;
//Player
self.playerSprite = [SKSpriteNode spriteNodeWithImageNamed:#"character"];
self.playerSprite.position = CGPointMake(playerLocX, playerLocY);
//Set Player Physics
self.playerSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.playerSprite.size];
self.playerSprite.physicsBody.dynamic = YES;
self.playerSprite.physicsBody.categoryBitMask = playerCategory;
self.playerSprite.physicsBody.contactTestBitMask = redBallCategory;
self.playerSprite.physicsBody.collisionBitMask = 0;
self.playerSprite.physicsBody.usesPreciseCollisionDetection = YES;
//Score Label
self.scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Arial-BoldMT"];
self.scoreLabel.text = #"0";
self.scoreLabel.fontSize = 40;
self.scoreLabel.fontColor = [SKColor blackColor];
self.scoreLabel.position = CGPointMake(50, 260);
//Pause Button
self.pauseButton = [SKSpriteNode spriteNodeWithImageNamed:#"pauseButton"];
self.pauseButton.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height - 40);
self.pauseButton.name = #"pauseButton";
//Add nodes
[self addChild:ground];
[self addChild:self.playerSprite];
[self addChild:self.scoreLabel];
//[self addChild:self.pauseButton];
//Sets gravity
self.physicsWorld.gravity = CGVectorMake(0,-2);
self.physicsWorld.contactDelegate = self;
}
return self;
}
-(void)addBall
{
SKSpriteNode *redBall = [SKSpriteNode spriteNodeWithImageNamed:#"locationIndicator"];
int minY = redBall.size.height / 2;
int maxY = self.frame.size.height - redBall.size.height / 2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
NSLog(#"Actual Y: %i", actualY);
//Initiates red ball offscreen
if (actualY >= 75)
{
//Prevents balls from spawning in the ground
redBall.position = CGPointMake(self.frame.size.width + redBall.size.width/2, actualY);
[self addChild:redBall];
}
redBall.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:redBall.size.width/2];
redBall.physicsBody.dynamic = YES;
redBall.physicsBody.categoryBitMask = redBallCategory;
redBall.physicsBody.contactTestBitMask = playerCategory;
redBall.physicsBody.collisionBitMask = 0;
redBall.physicsBody.affectedByGravity = NO;
redBall.physicsBody.usesPreciseCollisionDetection = YES;
//Determine speed of red ball
int minDuration = 3.0;
int maxDuration = 5.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
// Create the actions
SKAction *actionMove = [SKAction moveTo:CGPointMake(-redBall.size.width/2, actualY) duration:actualDuration];
SKAction *actionMoveDone = [SKAction removeFromParent];
SKAction *ballCross = [SKAction runBlock:^{
score++;
self.scoreString = [NSString stringWithFormat:#"%i", score];
self.scoreLabel.text = self.scoreString;
NSLog(#"Score was incremented. Score is now %d", score);
}];
[redBall runAction:[SKAction sequence:#[actionMove, ballCross, actionMoveDone]]];
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast
{
self.lastSpawnTimeInterval += timeSinceLast;
if (self.lastSpawnTimeInterval > 0.5) {
self.lastSpawnTimeInterval = 0;
[self addBall];
}
}
-(void)update:(CFTimeInterval)currentTime
{
/* Called before each frame is rendered */
// Handle time delta.
//Prevents bad stuff happening
CFTimeInterval timeSinceLast = currentTime - self.lastUpdateTimeInterval;
self.lastUpdateTimeInterval = currentTime;
if (timeSinceLast > 1) { // more than a second since last update
timeSinceLast = 1.0 / 120.0;
self.lastUpdateTimeInterval = currentTime;
}
[self updateWithTimeSinceLastUpdate:timeSinceLast];
}
NSDate *startTime;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
/* Called when a touch begins */
[super touchesBegan:touches withEvent:event];
//Starts Timer
startTime = [NSDate date];
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//Pauses Scene
if ([node.name isEqualToString:#"pauseButton"])
{
NSLog(#"Pause button pressed");
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
/* Called when a touch ends */
[super touchesEnded:touches withEvent:event];
NSTimeInterval elapsedTime = [startTime timeIntervalSinceNow];
NSString *elapsedTimeString = [NSString stringWithFormat:#"Elapsed time: %f", elapsedTime];
NSLog(#"%#", elapsedTimeString);
for (UITouch *touch in touches)
{
//Gets location of touch
CGPoint location = [touch locationInNode:self];
NSLog(#"Touch Location X: %f \n Touch Location Y: %f", location.x, location.y);
//Prevents destination from being in the ground
if (location.y < 88)
{
location.y = 87.5;
}
//Moves and animates player
//int velocity = elapsedTime * -3000;
int velocity = 800.0/1.0;
NSLog(#"Velocity: %i", velocity);
float realMoveDuration = self.size.width / velocity;
SKAction *actionMove = [SKAction moveTo:location duration:realMoveDuration];
[self.playerSprite runAction:[SKAction sequence:#[actionMove]]];
}
NSLog(#"Touch ended");
}
//Collision between ball and player
- (void)redBall:(SKSpriteNode *)redBall didCollideWithPlayer:(SKSpriteNode *)playerSprite
{
NSLog(#"Player died");
[redBall removeFromParent];
[playerSprite removeFromParent];
SKTransition *reveal = [SKTransition crossFadeWithDuration:0.5];
SKScene *endGameScene = [[EndGameScene alloc] initWithSize:self.size gameEnded:YES];
[self.view presentScene:endGameScene transition: reveal];
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody, *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
//Red ball collides with the player
if ((firstBody.categoryBitMask & redBallCategory) != 0 && (secondBody.categoryBitMask & playerCategory) != 0)
{
[self redBall:(SKSpriteNode *) firstBody.node didCollideWithPlayer:(SKSpriteNode *) secondBody.node];
}
}
#end
you definitely can't set its dynamic to no brother. you need gravity effect that player. (he is not effected by physic world so he is flying right now. we need him to fall down to ground aren't we? :)
So here is the simple solution. idea is that you create a "invisible rectangle block" on the ground surface that has physic body. and you need to set its dynamic to no in order to prevent it falling down
so this block is a node obviously, and its size : as high as the ground , and as wide as the screen. and you need to adjust the position a little bit to put its upper bound right on the ground surface.
good luck
i actually drew a picture but i can't post it here because of my reputation :(
Your problem is with physicsBody's categoryBitMask and collisionTestBitMask.
Your bitwise declarations :
static const uint32_t redBallCategory = 0x1 << 0;
static const uint32_t playerCategory = 0x1 << 1;
This has actually set the following bit patterns (i've shortened to 8 bits for the example) :
redBallCategory - 00000001 and
playerCategory - 00000010
However in the following code, you tell the player to only collide with collision bit mask - 00000000;
self.playerSprite.physicsBody.collisionBitMask = 0;
So your first problem is here. The player will not collide with any category that you have defined.
Your second problem is you have not given the ground a categoryBitMask, or collisionBitMask. By default this means all bits are set, IE the ground's collisionBitMask is equal to 11111111;
There will be no collision between these two physics bodies.
Try this - i have simply added a third physics category, and edited your code slightly to set the ground categoryBitMask / collisionBitMask, and your player collisionBitMask.
static const uint32_t redBallCategory = 0x1 << 0;
static const uint32_t playerCategory = 0x1 << 1;
static const uint32_t groundCategory = 0x1 << 2;
#implementation MyScene
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
/* Setup your scene here */
//Sets player location
playerLocX = 50;
playerLocY = 100;
//Sets player score
score = 0;
//Set Background
self.backgroundColor = [SKColor colorWithRed:0.53 green:0.81 blue:0.92 alpha:1.0];
//Set Ground
SKSpriteNode *ground = [SKSpriteNode spriteNodeWithImageNamed:#"ground"];
ground.position = CGPointMake(CGRectGetMidX(self.frame), 34);
ground.xScale = 0.5;
ground.yScale = 0.5;
ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
ground.physicsBody.categoryBitMask=groundCategory;
ground.physicsBody.collisionBitMask=playerCategory|redBallCategory;
ground.physicsBody.dynamic = NO;
//Player
self.playerSprite = [SKSpriteNode spriteNodeWithImageNamed:#"character"];
self.playerSprite.position = CGPointMake(playerLocX, playerLocY);
//Set Player Physics
self.playerSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.playerSprite.size];
self.playerSprite.physicsBody.dynamic = YES;
self.playerSprite.physicsBody.categoryBitMask = playerCategory;
self.playerSprite.physicsBody.contactTestBitMask = redBallCategory;
self.playerSprite.physicsBody.collisionBitMask = groundCategory|redBallCategory;
self.playerSprite.physicsBody.usesPreciseCollisionDetection = YES;
//Score Label
self.scoreLabel = [SKLabelNode labelNodeWithFontNamed:#"Arial-BoldMT"];
self.scoreLabel.text = #"0";
self.scoreLabel.fontSize = 40;
self.scoreLabel.fontColor = [SKColor blackColor];
self.scoreLabel.position = CGPointMake(50, 260);
//Pause Button
self.pauseButton = [SKSpriteNode spriteNodeWithImageNamed:#"pauseButton"];
self.pauseButton.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height - 40);
self.pauseButton.name = #"pauseButton";
//Add nodes
[self addChild:ground];
[self addChild:self.playerSprite];
[self addChild:self.scoreLabel];
//[self addChild:self.pauseButton];
//Sets gravity
self.physicsWorld.gravity = CGVectorMake(0,-2);
self.physicsWorld.contactDelegate = self;
}
return self;
}
Just:
self.playerSprite.physicsBody.dynamic = NO;
should work.
Your problem occurs due to scaling. For some reason in sprite kit scaling an image doesn't change it's size when used in following code. Judging by your pictures, your physics body rectangle for your ground is actually twice as big as you think and already engulfing the player, which is why there would by no collision detection. This is from recent experience with a very similar style game.
Do you have an edge loop physcis body around the scene? Collision flags and category flags set correctly so the player collides with the ground?
i had same problem and i soved it simply...
On the update method i've putted an if statement:
if(player.position.y<your_closest_value_near_ground){
player.position.y == your_Closest_value_near_ground
}
The comparition differs by the anchor point you have.. hope it helps someone

didBeginContact doesn't fire

Any idea why my didBeginContact method is never firing? The sphere and rectangles are actually touching each other...
Here i declare the two categories
static const uint32_t rectangleCategory = 0x1 << 0;
static const uint32_t ballCategory = 0x1 << 1;
This method creates a sphere
- (SKSpriteNode *)createSphereNode
{
SKSpriteNode *sphereNode =
[[SKSpriteNode alloc] initWithImageNamed:#"sphere.png"];
sphereNode.name = #"sphereNode";
sphereNode.physicsBody.categoryBitMask = ballCategory;
sphereNode.physicsBody.contactTestBitMask = rectangleCategory;
return sphereNode;
}
This method creates a rectangle
- (void) createRectangle
{
SKSpriteNode *rectangle = [[SKSpriteNode alloc] initWithImageNamed:#"balk.png"];
rectangle.position = CGPointMake(randomBetween(0, self.size.width),
self.size.height);
rectangle.name = #"rectangleNode";
rectangle.physicsBody =
[SKPhysicsBody bodyWithCircleOfRadius:(rectangle.size.width/2)-7];
rectangle.physicsBody.usesPreciseCollisionDetection = YES;
rectangle.physicsBody.categoryBitMask = rectangleCategory;
rectangle.physicsBody.contactTestBitMask = ballCategory;
[self addChild:rectangle];
}
This is the didBeginContact method that doesn't fire
- (void) didBeginContact:(SKPhysicsContact *)contact
{
NSLog(#"Contact begin");
SKSpriteNode *firstNode, *secondNode;
firstNode = (SKSpriteNode *)contact.bodyA.node;
secondNode = (SKSpriteNode *) contact.bodyB.node;
if ((contact.bodyA.categoryBitMask == rectangleCategory)
&& (contact.bodyB.categoryBitMask == ballCategory))
{
CGPoint contactPoint = contact.contactPoint;
float contact_x = contactPoint.x;
float target_x = secondNode.position.x;
float margin = secondNode.frame.size.height/2 - 25;
if ((contact_x > (target_x - margin)) &&
(contact_x < (target_x + margin)))
{
NSLog(#"Hit");
self.score++;
}
}
}
Any ideas? All help is much appreciated!
Thanks in advance
Stijn
I originally suspected it could be the lack of a proper SKPhysicsContactDelegate as it was not mentioned in the original post. Upon inspection of the code however, this was not the case and the problem was simply that the SKPhysicsBody used for rectangle was created with the ill-fitting bodyWithCircleOfRadius: rather than the bodyWithRectangleOfSize:.
rectangle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: rectangle.size];
Original answer, not correct for this particular case, but leaving it here for anyone with a similar problem down the line:
There is no mention of the SKPhysicsContactDelegate anywhere to be seen in the code you supply. The didBeginContact: method is a delegate method for the physicsWorld property of your SKScene.
So if you for instance want to have the SKScene being its own delegate it must support the SKPhysicsContactDelegate protocol. e. g.:
#interface YourSceneSubclass : NSObject <SKPhysicsContactDelegate>
Then you need to set the delegate somewhere in your scene before the game starts proper...
self.physicsWorld.contactDelegate = self;

Resources