Sprite Kit didBeginContact not called between body and edgeRect - ios

I have a game where I'm flicking bodies off the screen. I want to detect when these bodies are coming into contact with the edges (still letting the bodies pass through to off the screen) of the screen and I've implemented everything but still it is not working..here's my code:
GameScene.h
typedef NS_OPTIONS(uint32_t, FAPhysicsCategory) {
FAWallCategory = 1 << 0,
FABottomWallCategory = 1 << 1,
FAAnimalCategory = 1 << 2,
};
GameScene : SKScene <SKPhsyicsContactDelegate>
GameScene.m
-(void)setupWorldPhysics
{
// Set world gravity
self.physicsWorld.gravity = CGVectorMake(0.0, -5.0);
float bottomOffset = 400.0;
CGRect newFrame = CGRectMake(0, -bottomOffset, self.frame.size.width, self.frame.size.height + bottomOffset);
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:newFrame];
self.physicsBody.categoryBitMask = FAWallCategory;
self.physicsBody.contactTestBitMask = FAAnimalCategory;
self.physicsBody.collisionBitMask = 0;
}
-(void)launchBody {
SKSpriteNode* animalSprite = [SKSpriteNode spriteNodeWithImageNamed:[animalImagesArray objectAtIndex:animalChoice]];
animalSprite.position = CGPointMake(self.size.width/2, -animalSprite.size.height);
animalSprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:25];
animalSprite.physicsBody.dynamic = YES;
animalSprite.physicsBody.allowsRotation = YES;
animalSprite.name = #"animalSprite";
animalSprite.physicsBody.categoryBitMask = FAAnimalCategory;
animalSprite.physicsBody.contactTestBitMask = FAWallCategory;
animalSprite.physicsBody.collisionBitMask = 0;
animalSprite.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:animalSprite];
}

Alright so it's late and I'm exhausted and I feel like an idiot..i was missing:
self.physicsWorld.contactDelegate = self;
tool

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.

Physics Body edges IOS8, Sprite Kit

SO following an IOS game tutorial, its IO7 as not many for 8 are out yet.
The following code is supposed to be a ball bouncing around but only bounces on the top and bottom of the screen, if it hits the side edges the ball goes of screen
#import "GameScene.h"
#implementation GameScene
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
self.backgroundColor =[SKColor whiteColor];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0, 0);
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
ball.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
//ball.physicsBody.friction = 0;
ball.physicsBody.linearDamping = 0;
ball.physicsBody.restitution = 1;
[self addChild:ball];
CGVector myVector = CGVectorMake(0, 5);
[ball.physicsBody applyImpulse:myVector];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
#end
There has to be something simple here but i can't seem to find an answer on stack overflow
Use NSLog to check the size of your view: NSLog(#"%f,%f",self.size.width,self.size.height);
There is a problem with SpriteKit that causes the view dimensions to be off of what you expect. If this is what is happening in your case, then make sure to change the size of your view to the correct one:
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
self.size = self.view.frame.size;
self.backgroundColor =[SKColor whiteColor];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity = CGVectorMake(0, 0);
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
ball.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
//ball.physicsBody.friction = 0;
ball.physicsBody.linearDamping = 0;
ball.physicsBody.restitution = 1;
[self addChild:ball];
CGVector myVector = CGVectorMake(50, 20);
[ball.physicsBody applyImpulse:myVector];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}

Sprite Kit Overlap lag with xcode

So I am trying to just get a feel of how Sprite Kit works, and one thing that I cannot figure out is why my demo lags when multiple versions of the same sprite over lap each other.
Basically what I do is I made a class that inherits SKSpriteNode, and on init I set the following properties
marioCategory = 1 << 1;
wallCategory = 1 << 2;
platformCategory = 1 << 3;
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.size];
self.physicsBody.density = 1.0;
self.physicsBody.angularDamping = 0.0;
self.physicsBody.linearDamping = 0.0;
self.physicsBody.friction = 0.0;
self.physicsBody.categoryBitMask = marioCategory;
self.physicsBody.collisionBitMask = platformCategory ;
self.physicsBody.contactTestBitMask = wallCategory ;
self.physicsBody.dynamic = YES;
self.physicsBody.allowsRotation = NO;
self.physicsBody.restitution = 0;
self.name = #"Mario";
Then I add all these "Mario"'s into an SKNode as its children, then I add this Node to the scene. (Adding the children directly to the scene does not add perfomance);
What I think it is doing is an extensive check to see if the overlapping marios are colliding or contacting, even though the contactTest bit mask says to only check for walls.
Any help to determine what step I am missing would really be appreciated, thanks.
This has been tested on an iPhone 5 btw.
Here are how I have about 40 platforms setup on screen, all are 16x16,even Mario
node.position = CGPointMake(x, y);
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node.size];
node.physicsBody.angularDamping = 0.0;
node.physicsBody.linearDamping = 0.0;
node.physicsBody.friction = 0.0;
node.physicsBody.affectedByGravity = NO;
node.physicsBody.categoryBitMask = platformCategory;
node.physicsBody.collisionBitMask = 0 ;
node.physicsBody.contactTestBitMask = 0 ;
node.physicsBody.dynamic = NO;

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?

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

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.

Resources