Cocos2d v3 & chipmunk collision detection issues - cocos2d-iphone

First try at Chipmunk.
Not getting collision detection registering is the problem.
My code:
#implementation MainPlayScene
{
CCPhysicsNode *_physics;
CCNode *MyPhysicsBody;
CCNode *bottomBody;
}
+ (instancetype)scene
{
return [[self alloc] init];
}
- (instancetype)init
{
// Apple recommend assigning self with supers return value, and handling self not created
self = [super init];
if (!self) return(nil);
_physics = [CCPhysicsNode node];
_physics.debugDraw = YES;
[self addChild:_physics z:1];
/// BOTTOM
CGRect bottomRect = CGRectMake(0, 0, [CCDirector sharedDirector].viewSize.width, 10);
bottomBody = [CCNode node];
bottomBody.physicsBody = [CCPhysicsBody bodyWithPolylineFromRect:bottomRect cornerRadius:0];
bottomBody.physicsBody.collisionCategories = #[#"Bottom"];
bottomBody.physicsBody.type = CCPhysicsBodyTypeStatic;
[_physics addChild:bottomBody];
/// MyBody to bounce around
MyPhysicsBody = [CCSprite spriteWithImageNamed:#"MyBody-64x64-24.png"];
MyPhysicsBody.position = ccp((self.contentSize.width/2),(self.contentSize.height/2));
MyPhysicsBody = [CCNode node];
MyPhysicsBody.physicsBody = [CCPhysicsBody bodyWithRect:(CGRect){CGPointZero, MyPhysicsBody.contentSize.height,MyPhysicsBody.contentSize.width} cornerRadius:0];
MyPhysicsBody.physicsBody.collisionCategories = #[#"MyBody"];
[_physics addChild:MyPhysicsBody z:150];
self.userInteractionEnabled = YES;
return self;
}
Detecting touch events and applying force to physics body to have it bounce up and down onto bottom body
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CCLOG(#"Touch Detected");
[MyPhysicsBody.physicsBody applyImpulse:ccp(0, 300.f)];
}
Now I try to detect a collision on “Bottom” but nothing is being registered even though I see debug lines of 2 objects touch.
/// try onCollisionEnter first ... nothing
-(void)onCollisionEnter:(CCNode *)entity collisionPair:(CCPhysicsCollisionPair *)pair
{
if ([entity.physicsBody.collisionCategories isEqual: #"Bottom"]) {
CCLOG(#"Hit bottomBody");
}
}
/// try ccPhysicsCollisionBegin pair ... nothing
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair MyBody:(CCNode *) MyBody Botton:(CCNode *)Bottom
{
CCLOG(#"Hit bottomBody");
return TRUE;
}
Obviously I’m missing something critical here …
Any help is VERY appreciated!
Thanks

I am finding it difficult to see the relevant code with all the things you posted.
I will give you an example of 2 CCSprite objects collision detection. One is called _arrowand the other one is _obstacle.
First step is to define the collision types like so :
_arrow.physicsBody.collisionType = #"arrow";
_obstacle.physicsBody.collisionType = #"obstacle";
Second step is to define the callback
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair arrow:(CCNode *)arrow obstacle:(CCNode *)obstacle
{
// Do some cool stuff
return TRUE;
}
Notice the naming, arrow and obstacle according to the collision type of theses sprites.
And third, the one that you forgot to do is set the delegate so you actually get these methods called on your physicsNode object
_physics.collisionDelegate = self;
And self (which is typically just your scene) should implement the CCPhysicsCollisionDelegate protocol.

Tibor has the correct answer, but there's an important clue that I was missing which was driving me crazy. From the comments in CCPhysicsNode.h section on the CCPhysicsCollisionDelegate:
The final two parameter names (typeA/typeB) should be replaced
with names used with CCPhysicsBody.collisionType or
CCPhysicsShape.collisionType.
If both final parameter names are "default" then the collision
method is called when a more specific method isn't found.
So I was incorrectly trying to implement something like this:
-(BOOL) ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair typeA:(CCNode *)nodeA typeB:(CCNode *)nodeB
{
// Compare if we're ignored collisions
if (([nodeA.physicsBody.collisionType isEqualToString: #"foo"])
|| ([nodeB.physicsBody.collisionType isEqualToString: #"foo"]) )
{
return NO;
}
return YES;
}
But that's WRONG!!! The correct thing I wanted to implement was this:
-(BOOL) ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair foo:(CCNode *)nodeA foo:(CCNode *)nodeB
{
return NO;
}
Note how the ignored collision type is part of the method signature.
Whew!
EDIT:
For completeness, don't forget to do:
_physics.collisionDelegate = self;

You are setting collision categories which along with collisions mask allow you to discard certain collisions. The collision type property is what works with the delegate methods.

Related

cocos2d v3 chipmunk collision method not firing

ok so i've been messing around with chipmunk a bit, and i can get two sprites to bounce off of each other, but when i try to use the following method, it never fires,
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair tower:(CCNode *)nodeA BG:
(CCNode *)nodeB
{
NSLog(#"HELLO");
return YES;
}
Heres where I create the physics node:
_physics = [CCPhysicsNode node];
_physics.debugDraw = YES;
[self addChild:_physics z:1];
_physics.collisionDelegate = self;
I use this code to create the first sprite:
background = [CCSprite spriteWithImageNamed:gameLevelImage];
[background setPosition:ccp(winSize.width/2,winSize.height/2)];
background.physicsBody.collisionType = #"BG";
background.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:self.position];
and this for the other :
tower = [[TowerType alloc] initWithTheGame:self location:ccp(winSize.width/2, winSize.height/2)];
[towers addObject:tower];
[self MenuItemsVisible];
tower.physicsBody = [CCPhysicsBody bodyWithCircleOfRadius:50 andCenter:tower.position];
tower.physicsBody.collisionType = #"tower";
I also have the protocol in the h file.
if anyone knows whats happening help would be greatly appreciated. (:
First of all, are both bodies under the same CCPhysicsNode?
Second, ccPhysicsCollisionBegin is just called when the collision BEGIN, so as both of your bodies are one over the other and they aparenttly will move together due to gravity the collision will never begin, because they started colliding. The cycle for collision evaluation is:
ccPhysicsCollisionBegin: called once both bodies start colliding
ccPhysicsCollisionPreSolve: called every frame update, before physics calculations
ccPhysicsCollisionPostSolve : called every frame, after physics calculations
ccPhysicsCollisionSeparates: called once they separate
Make sure your sprites are allocated properly before you try to set the collisionType. That was the issue for me in my similar case.

cocos2d v3 collision detection

I'm trying to inspect collision collision of two bodies, but collision detection callbacks are not being fired.
Here is my code:
1) My CCScene implements CCPhysicsCollisionDelegate protocol
2) I set collision delegate for physics
_physics = [CCPhysicsNode node];
_physics.gravity = PHYSICS_GRAVITY;
_physics.debugDraw = YES;
_physics.collisionDelegate = self;
[self addChild:_physics];
3) For each of two body I set a collision type
body1.collisionType = #"body1";
body2.collisionType = #"body2";
4) That's it, when these two bodies collide none of CCPhysicsCollisionDelegate callback methods is being called.
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair typeA:(CCNode *)nodeA typeB:(CCNode *)nodeB
{
NSLog(#"HELLO");
return YES;
}
Could you please help me with this? Have you been able to receive collision callbacks in cocos2d v3?
Thanks in advance
In cocos2d v3 physics, collisionType eliminates the need to set integer bit masks to define the type of collision. The parameter name CCPhysicsCollisionDelegate methods must be the collisionTypes that you want to deal with yourself. So in your case , the collision callback method should be
- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair body1:(CCNode *)nodeA body2:(CCNode *)nodeB
{
NSLog(#"HELLO");
return YES;
}
By default everything collides in cocos2d, but if you set the collisionGroup of two bodies to be the same then they wouldn't collide.

No visible #interface for 'class' declares the selector 'selector'

I'm following "Learn Cocos2D" and in chapter 4 I'm met with the following directive:
And in the GameLayer init method, add the call to the initSpiders method discussed next, right after scheduleUpdate:
-(id) init {
if ((self=[super init])) {
...
[self scheduleUpdate];
[self initSpiders];
}
return self;
}
I get and ARC error message: no visible #interface for 'GameLayer' declares the selector 'initSpiders'
I get the same message at the line: self resetSpiders
what am i missing? everything builds and runs great up to that point.
This issue derives from the fact that the initSpiders and resetSpiders are not declared in your class interface and are defined in the .m file after the point where they are used.
If they are not missing altogether, you can fix this in either of 2 ways:
move the definition of the initSpiders and resetSpiders methods above your init method and the errors will disappear;
add a declaration for both methods in the #interface of the class.
(If you do both, it will also work)
Check your code to see if the implementation for those methods is available.
Your error appears to be that you haven't followed the next bit of the book too. Completing the next section should allow you to compile your code without warnings like this.
A more complete extract of that section of the book is:
And in the GameScene init method add the call to the initSpiders method discussed next, right after scheduleUpdate:
-(id) init {
if ((self = [super init]))
{
… 96 CHAPTER 4: Your First Game
[self scheduleUpdate];
[self initSpiders];
}
return self;
}
After that a fair bit of code is added to the GameScene class, beginning with the initSpiders method in Listing 4–8, which is creating the spider sprites.
Listing 4–8. For Easier Access, Spider Sprites Are Initialized and Added to a CCArray
-(void) initSpiders
{
CGSize screenSize = [[CCDirector sharedDirector] winSize];
// using a temporary spider sprite is the easiest way to get the image's size
CCSprite* tempSpider = [CCSprite spriteWithFile:#"spider.png"];
float imageWidth = [tempSpider texture].contentSize.width;
// Use as many spiders as can fit next to each other over the whole screen width.
int numSpiders = screenSize.width / imageWidth;
// Initialize the spiders array using alloc.
spiders = [[CCArray alloc] initWithCapacity:numSpiders];
for (int i = 0; i < numSpiders; i++)
{
CCSprite* spider = [CCSprite spriteWithFile:#"spider.png"];
[self addChild:spider z:0 tag:2];
// Also add the spider to the spiders array.
[spiders addObject:spider];
}
// call the method to reposition all spiders
[self resetSpiders];
}

how to properly handle touch events for multiple layers?

I currently have a "Console" CClayer, which is handling touch detection for sprites that have been added to it. However, I also have some sprites that I want to do touch detection on that are not part of the Console layer... They are currently children of a class that inherits from CCNode.
My understanding is, the more cocos objects have the "isTouchEnabled" property set to true, the more performance will be affected, so I am curious how I should approach this?
Should I:
A) Have the console's touchesBegan method perform detection of the sprites belonging to the CCNode?
B) Just implement isTouchEnabled on the CCNode object
C) Some other approach?
well, for starters, you should only concern yourself about performance if you are concerned i.e. you are seeing or measuring (on DEVICES not a simulator) some inappropriate response times.
I would avoid detecting touches that concern another node - it could get messy, software wise. I tend to return YES (from a ccTouchBegan) strictly when the touch is at a location of an object of concern to the detecting node. When you return NO, the dispatcher will pass on the touch to other handlers ('under' the console), until one such CCNode takes the bite. Kind of as follows:
- (void) onEnter{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
[super onEnter];
}
- (void) onExit{
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
if (!_visible || !_enabled) {
return NO;
}
CGPoint loc = [touch locationInView:touch.view];
loc = [[CCDirector sharedDirector] convertToGL:loc];
if ([self containsPoint:loc]) {
// do your thing here !
return YES;
}
return NO;
}
-(BOOL) containsPoint:(CGPoint) location {
// determine here whether this node should be handling
// this touch.
}

iPhone dev> Getting a CCSprite position from an other object in cocos2d?

Hey people,
I'm creating a game in cocos2d, (I'm very new to it, and was trying to solve this thing)
in the game I'm making I created a "Bomb" class, and a "Player" class,
I want the bomb to check for collision with the player, if a collision detected, explode.
My problem is that I have no idea how to get the player's position from the bomb class,
I'd be happy if you guys could help me out here,
Thanks!
You did add the CCSprites to a CCLayer, didn't you? Then that CCLayer should have the access to both of them. So, you can use the CCLayer's tick function to track the positions of the CCSprites and trigger actions if their bounding boxes overlap.
Some sample code to illustrate:
#interface MyLayer : CCLayer {
BombSprite *bomb;
PlayerSprite *player;
}
...
#end
#implementation MyLayer
- (id)init {
if ((self = [super init])) {
bomb = ...
player = ...
[self schedule:#selector(tick:)];
}
return self;
}
- (id)tick:(ccTime)dt {
if (CGRectContainsRect([bomb boundingBox], [player boundingBox])) {
NSLog(#"Collision!");
// call [player didCollideWith:bomb] or something
...
}
}
#end