SpriteKit collision Detection does not work - ios7

I thought I understand the concepts of bitmasks, CategoryBitMasks and CollisionBitMasks, but it turns out I am not ;-(
but I dont understand why.
I set the bit Masks for collision detection, I add the category Bit mask to the frame, and I add the categoryBitMask to my object (in this case a taxi). But the taxi just drops down the screen :-/
Any ideas why this is like that?
#import "MyScene.h"
#import "SKSpriteNode+DebugDraw.h"
// Define Bit Masks for Collision Detection
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory) {
CNPhysicsCategoryEdge = 1 <<0,
CNPhysicsCategoryTaxi = 1 <<1,
};
#interface MyScene() <SKPhysicsContactDelegate>
#end
#implementation MyScene{
SKNode *_gameNode;
SKSpriteNode *_taxiNode;
}
-(instancetype)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
[self initializeScene];
}
return self;
}
-(void)initializeScene{
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
self.physicsBody.categoryBitMask = CNPhysicsCategoryEdge;
SKSpriteNode* bg = [SKSpriteNode spriteNodeWithImageNamed:#"background.png"];
bg.position = CGPointMake(self.size.width/2, self.size.height/2);
[self addChild: bg];
[self addTaxi];
_gameNode = [SKNode node];
[self addChild:_gameNode];
}
-(void)addTaxi{
_taxiNode = [SKSpriteNode spriteNodeWithImageNamed:#"taxi.png"];
_taxiNode.position = CGPointMake(self.size.width/2, self.size.height/2);
[self addChild:_taxiNode];
CGSize contactSize = CGSizeMake(_taxiNode.size.width, _taxiNode.size.height);
_taxiNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: contactSize];
[_taxiNode attachDebugRectWithSize:contactSize];
_taxiNode.physicsBody.categoryBitMask = CNPhysicsCategoryTaxi;
}

I finally managed it - the problem was not the collision detection, but it was the layout of the phone, since I did not replace the viewDidLoad method in the ViewController with viewWillLayoutSubviews method.
Now everything works fine.
The significant post was the following: bodyWithEdgeLoopFromRect not working in landscape
Thanks for your support!

Related

Cocos2D v3 CCParallaxNode scrolling can't keep player in focus

I am very fresher to game development and I need to develop a game like NinjaJump.
I have created a CCParallaxNode to setup scrolling background and added CCPhysicsNode to setup Physics world. I have created player object as shown below.
// Add a sprite
_sprite = [CCSprite spriteWithImageNamed:#"Icon.png"];
_sprite.position = ccp(self.contentSize.width/2,100);
_sprite.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, _sprite.contentSize} cornerRadius:0.0];
_sprite.physicsBody.friction = 0.0f;
_sprite.physicsBody.collisionGroup = #"player";
_sprite.physicsBody.collisionType = #"Player";
//_sprite.physicsBody.collisionMask = 0;
//[self addChild:_sprite];
[foreground addChild:_sprite];
foreground is just a node added into CCScene to easily manage player in-focus.
// code for physics world
_physicsWorld = [CCPhysicsNode node];
_physicsWorld.gravity = ccp(0,-100);
_physicsWorld.debugDraw = YES;
//_physicsWorld.collisionDelegate = self;
[self addChild:_physicsWorld];
_foreground = [CCNode node];
//[self addChild: _foreground];
[_physicsWorld addChild: _foreground];
To make player always visible we have implemented update method as
- (void) update:(CFTimeInterval)currentTime {
// Calculate player y offset
if (_player.position.y > 200.0f) {
//_midgroundNode.position = CGPointMake(0.0f, -((_player.position.y - 200.0f)/4));
_foreground.position = CGPointMake(0.0f, -(_player.position.y - 200.0f));
}
}
I can't understand but the player scrolls off screen anyhow. The code is written in Cocos2d v3.
I have also setup a demo project to show what I implemented: https://www.dropbox.com/s/5s55d00kk80wun4/HumptyJump-Example.zip?dl=0
Any kind of help is appreciated. Thanks in advance.
I could not run your sample code but one thing, I can tell you for sure that there is no need of Physics Engine here.
You just keep your player at a particular height and just move your object right to left.
Apply moving parallax background image and objects to give a feel that your character is moving upwards or downwards.
For reference you can see the games like Swing Drop, made on the same approach as above.
I have implemented 2 fixed views changing their positions while physics body goes down ;).
See the same in action
#interface TestScene () {
CCNode *_background;
CCNode *_foreground;
NSArray *grounds; // Keeps track of each of the 2 views
CCPhysicsNode *_physicsWorld;
}
#implementation TestScene
- (id)init {
self = [super init];
if (!self) return(nil);
// Enable touch handling on scene node
self.userInteractionEnabled = YES;
// Physics world setup
_physicsWorld = [CCPhysicsNode node];
_physicsWorld.gravity = ccp(0,-100);
_physicsWorld.debugDraw = YES;
_physicsWorld.collisionDelegate = self;
[self addChild:_physicsWorld];
// Foreground node in which platforms are there and moves downwards as player goes up
_foreground = [CCNode node];
// Adding background images
CCSprite *default1 = [CCSprite spriteWithImageNamed: #"Default.png"];
[default1 setAnchorPoint: ccp(0, 0)];
CCSprite *default2 = [CCSprite spriteWithImageNamed: #"Default.png"];
[default2 setAnchorPoint: ccp(0, 0)];
[default2 setPosition: ccp(0, default1.contentSize.height)];
[_foreground addChild: default1];
[_foreground addChild: default2];
// Adding into array
grounds = #[default1, default2];
// Adding into physics world
[_physicsWorld addChild: _foreground];
// creating player
_player = [CCSprite spriteWithImageNamed: #"Assets.atlas/Player.png"];
[_player setPosition: ccp(160.0f, 160.0f)];
_player.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, _player.contentSize} cornerRadius:0]; // 1
_player.physicsBody.collisionGroup = #"playerGroup"; // 2
_player.physicsBody.collisionType = #"player";
//[_physicsWorld addChild:_player];
[_foreground addChild: _player];
// Multiple platforms can be added into body, they are static entities only
PlatformNode *platform = (PlatformNode *)[PlatformNode node];
[platform createPlatformAtPosition:CGPointMake(110, 50) ofType: PLATFORM_NORMAL];
[_foreground addChild: platform];
return self;
}
- (void) update:(CFTimeInterval)currentTime {
// Take background and physics world down, 163 was Y position of the player
_physicsWorld.position = ccp(_physicsWorld.position.x, 163 - _player.position.y);
// loop the ground
for (CCNode *ground in grounds) {
// Get the world position
CGPoint groundWorldPosition = [_physicsWorld convertToWorldSpace: ground.position];
// Get screen position
CGPoint groundScreenPosition = [self convertToNodeSpace: groundWorldPosition];
NSLog(#"Positioning ground ---> world: (%f, %f) & screen: (%f, %f)", groundWorldPosition.x, groundWorldPosition.y, groundScreenPosition.x, groundScreenPosition.y, nil);
if (groundScreenPosition.y <= -ground.contentSize.height) {
ground.position = ccp(ground.position.x, ground.position.y + 2 * ground.contentSize.height);
break;
}
}
}
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
// Take the player upside
[_player.physicsBody applyImpulse: ccp(0, 215)];
}
#end
This is how I coded the background :).

How to apply constant force to sprite?

I have a sprite that I want to apply a constant force to, as opposed to reapplying that force every update, which is giving me strange results.
I have a sprite that has a mass of 60 kg and is affected by gravity. I want to apply a force that is equal to the force of gravity constantly. The way I'm doing it still causes the sprite to fall of the screen really fast because the force of gravity is somehow greater. I'm wondering how and when the force of gravity is applied, and if it is possible fore me to set a constant force on the object, similar to the force of gravity.
Currently, my scene looks like this:
#import "MyScene.h"
#interface MyScene ()
#property (nonatomic, strong)SKSpriteNode *parachutist;
#end
#implementation MyScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
CGSize spriteSize = CGSizeMake(80.0f, 80.0f);
self.parachutist = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:#"parachutist.png"] size:spriteSize];
[self addChild:self.parachutist];
self.parachutist.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.parachutist.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteSize];
self.parachutist.physicsBody.dynamic = YES;
self.parachutist.physicsBody.mass = 60.0; // kg
self.parachutist.physicsBody.affectedByGravity = YES;
}
return self;
}
- (void)update:(NSTimeInterval)currentTime
{
// this ought to match the force of gravity
[self.parachutist.physicsBody applyForce:CGVectorMake(0.0f, 60.0f * 9.8f)];
}
#end
Fixed:
#import "MyScene.h"
#define WEIRD_FACTOR 150.0f
#define GRAVITY -9.8f
#interface MyScene ()
#property (nonatomic, strong)SKSpriteNode *parachutist;
#end
#implementation MyScene
- (id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
CGSize spriteSize = CGSizeMake(80.0f, 80.0f);
self.physicsBody.affectedByGravity = YES;
self.physicsWorld.gravity = CGVectorMake(0.0f, GRAVITY / WEIRD_FACTOR);
self.parachutist = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:#"Parachutist.png"] size:spriteSize];
[self addChild:self.parachutist];
self.parachutist.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
self.parachutist.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteSize];
self.parachutist.physicsBody.dynamic = YES;
self.parachutist.physicsBody.mass = 60.0; // kg
self.parachutist.physicsBody.affectedByGravity = YES;
}
return self;
}
- (void)update:(NSTimeInterval)currentTime
{
[self.parachutist.physicsBody applyForce:CGVectorMake(0.0f,
self.parachutist.physicsBody.mass * -GRAVITY)];
}
#end
See this question for an explanation: applyForce(0, 400) - SpriteKit inconsistency
Doctordoder:
I am new to sprite kit myself but am currently working on a game as well. I believe that you need to make the vector's Y component be negative.
[self.parachutist.physicsBody applyForce:CGVectorMake(0.0f, -9.8)];
that should apply force straight down at -9.8 units. However unlike gravity I do not believe this to be cumulative. gravity is -9,8 meters per sec squared.
By multiplying the gravity by 60 your essentially making gravity 60 times what it is normally.
Alternatively you could adjust the property for physicsWorld Gravity and that would apply the gravity to any object with a physics body not set to physicsBody.dynamic = YES
self.physicsWorld.gravity = CGVectorMake(0, -9.8 );
edit: grammer and punctuation.

Detecting collision between objects in array in sprite kit

i'm trying to make a game where obstacles fall from the top of the screen and the player has to try to avoid them, but the didBeginContact method is not getting called and its driving me crazy. here are the parts of my code relevant to the node collisions...
//myScene.h
#interface MyScene : SKScene <SKPhysicsContactDelegate>
//myScene.m
#implementation MyScene
static const uint32_t playerCategory = 0x1 << 0;
static const uint32_t obstacleCategory = 0x1 << 1;
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
//setup scene
self.backgroundColor = [SKColor whiteColor];
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
obstacles = [NSMutableArray array];
//add player node
player = [SKNode node];
SKSpriteNode *spritePlayer = [SKSpriteNode spriteNodeWithImageNamed:#"black.png"];
spritePlayer.size = CGSizeMake(50, 50);
spritePlayer.position = CGPointMake(self.frame.size.width/2, 100);
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size];
player.physicsBody.dynamic = NO;
player.physicsBody.mass = 0.02;
[player addChild:spritePlayer];
player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.contactTestBitMask = obstacleCategory;
player.physicsBody.collisionBitMask = 0;
player.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild:player];
[self spawnNewObstacles];
}
return self;
}
- (void)spawnNewObstacles
{
//spawn obstacles
obstacle = [SKSpriteNode spriteNodeWithImageNamed:#"black.png"];
obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle.frame.size];
obstacle.physicsBody.dynamic = YES;
obstacle.physicsBody.categoryBitMask = obstacleCategory;
obstacle.physicsBody.contactTestBitMask = playerCategory;
obstacle.physicsBody.collisionBitMask = 0;
obstacle.physicsBody.usesPreciseCollisionDetection = YES;
}
-(void)didBeginContact:(SKPhysicsContact *)contact
{
NSLog(#"didBeginContact Called!");
}
the didBeginContact method is not getting called and i can't find what wrong with my code
all help is appreciated...
sknode size isn't set correctly because there is no image reference, and if you log its size if should be inf, and when I tested your code I returned an exception.
to fix this error change the following line
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size]; change that to
to the following and it should work
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spritePlayer.size];
as I said below just ditch the player sknode, it is simply redundant unless there is a strong reason to use it.
///////previous answer
I couldn't help but to notice that you didn't add the obstacle node to any parent node, namely the scene, like what you did with the player node using this line
[self addChild:player];
you need to do the same thing with the obstacle node
[self addChild:obstacle];
, I am surprised that you didn't mention not seeing those nodes on the screen, unless you added them in a different section of your code that you did not include, then at this point I suggest you log the positions of both nodes to give an idea of how things are located on the screen.
as for the array you won't need it all you have to do is give a name for every obstacle node like #"obstacle", then you can use the following method to access all the nodes that has that name
obstacle.name = #"obstacle";
/////later when you want to check for node removal
[self enumerateChildNodesWithName:#"obstacle" usingBlock:^(SKNode *node, BOOL *stop) {
SKSpriteNode *child = (SKSpriteNode*)node;
if (child.position.y <0){ //or any arbitrary condition
[child removeFromParent];
}
}];
Lastly, I can't see the point from using the player as a sknode and then adding an skspritenode to it, unless I am missing something !!! :) . You can simply ditch the player sknode all together and simply use the spritePlayer node instead.
Hope this helps.

Set the Camera Position CCScene

I've come across an issue with my CCScene. I'm trying to set the position of my scene on the player block. Here is my init for my scene:
- (id)init
{
// Apple recommend assigning self with supers return value
self = [super init];
if (!self) return(nil);
self.userInteractionEnabled = YES;
// Create a colored background (Dark Grey)
CCNodeColor *background = [CCNodeColor nodeWithColor:[CCColor colorWithRed:0 green:0 blue:0 alpha:1.0f]];
[self addChild:background];
// Add a sprite
_player = [[PlayerBlock alloc]initWithX:[bp getPlayerX] withY:[bp getPlayerY] maxX:1000 maxY:1000 levelBlocks:blocks endBlock:fb];
[self addChild:_player];
self.positionType=CCPositionTypePoints;
self.position=_player.position;
// done
return self;
}
Here's my init for player block:
-(id)initWithX:(double)x withY:(double)y maxX:(double)maxX maxY:(double)maxY levelBlocks:(NSMutableArray*)sprites endBlock:(FinishBlock*)finishBlock{
self=[self initWithImageNamed:#"player.png"];
self.position = ccp(x,y);
_finish=finishBlock;
_sprites=sprites;
_startX=x;
_startY=y;
_maxX=maxX;
_moving=0;
_maxY=maxY;
self.width=25;
self.height=25;
self.positionType=CCPositionTypePoints;
return self;
}
What currently happens is that it doesn't focus on the player block.
Can anyone clear this up for me?
Needed to add this line to my scene:
self.contentSize=CGSizeMake(1000, 1000);
As my sprite lay outside of the scene bounds.

Background position alternating position every time I build in Xcode 5

I am just beginning programming games in Xcode 5 using cocos2D and found this pretty strange. I'm starting out fresh on a menu scene and was importing a background and a button. The following code positions my background just fine sometimes, but then other times it's adjusted upwards about 50 pixels (my simulator is on it's side, or it's length is lying horizontal, so technically it's shifting about -50 pixels in the "width" direction, although to the simulator it shifts upwards).
Note I found that every time I run my program, it alternates between being properly aligned and shifted. Why would this be happening ugh! Below is the code I'm using.
Note 2 I'm using Kobold2D and the framework I'm using has a config.lua that's a little beyond my scope for me to understand everything. The config.lua code is located here http://snipt.org/BEt6
-(id) init
{
if ((self = [super init]))
{
CCSprite *sprite = [CCSprite spriteWithFile:#"background.png"];
sprite.anchorPoint = CGPointZero;
[self addChild:sprite z:-1];
sprite = [CCSprite spriteWithFile:#"button.png"];
sprite.anchorPoint = CGPointZero;
sprite.position = CGPointMake(200,200);
[self addChild:sprite z:0];
}
return self;
}
The only problem with your code is that you are initializing sprite twice, which is NOT very good.
I would think it is causing your problem.
Try this code:
-(id) init
{
if ((self = [super init]))
{
CCSprite *sprite = [CCSprite spriteWithFile:#"background.png"];
sprite.anchorPoint = CGPointZero;
[self addChild:sprite z:-1];
CCSprite *sprite2 = [CCSprite spriteWithFile:#"button.png"];
sprite2.anchorPoint = CGPointZero;
sprite2.position = CGPointMake(200,200);
[self addChild:sprite2 z:0];
}
return self;
}