I am using box2d based game and it detect my player body collied with enemy body but when i write destroybody method for enemy at collied point that time my enemy can not destroy and gives error and my apps crashed.
I show you my code
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = contactListener->_contacts.begin();
pos != contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
if (spriteA.tag == 1 && spriteB.tag == 2)
{
// SpriteA = PlayerSprite
// SpriteB = EnemySprite
NSString *t=[NSString stringWithFormat:#"Game Over"];
label.string=t;
[self removeChild:spriteB cleanup:YES];
world->DestroyBody(bodyB);
}
else if (spriteA.tag == 2 && spriteB.tag == 1)
{
//toDestroy.push_back(bodyB);
NSLog(#"Enemy Touch");
}
}
}
Here my spriteB can not destroy.
One more thing is enemy sprite is into the Enemy.mm file.
Please help me i am stuck with this problem.
Thanks in advance
Your making a fundamental error of handling enemy contact with player different from player contact with enemy(its just the order of thing), you should treat both case the same because you cant know what order they arrive.
Also you arent using toDestroy properly.
std::vector<b2Body *>toDestroy;
std::vector<MyContact>::iterator pos;
for(pos = contactListener->_contacts.begin();
pos != contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
b2Body *bodyA = contact.fixtureA->GetBody();
b2Body *bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
if ((spriteA.tag == 1 && spriteB.tag == 2) ||(spriteA.tag == 2 && spriteB.tag == 1))
{
// SpriteA = PlayerSprite
// SpriteB = EnemySprite
NSString *t=[NSString stringWithFormat:#"Game Over"];
label.string=t;
[self removeChild:spriteB cleanup:YES];
toDestroy.push_back(bodyB);
}
}
}
//iterate and delete everything from toDestroy
Related
After collision using listener one, sprite1 should be destroyed and other sprite2 will jump. I destroy sprite1 but sprite2 is not jumping after collision with sprite1. Here is my code:
Update(float dt) {
if(collisionOccurs == 1)
{
CCJumpTo * myJump = CCJumpTo::create(1, ccp(winSize.width/6,winSize.height/8),winSize.height/2 ,1);
Sprite2->runAction(myJump);
collisionOccurs = 0;
if(Sprite1 != NULL && BodyofSprite1 != NULL)
{
BodyofSprite1->SetActive(false);
Sprite1->removeFromParentAndCleanup(true);
}
}
}
I'm trying to simulate a flick in cocos2d and I need to create a ball every time the users touch is ended, but I can't get the ball to move during the tick method, and I can't destroy the ball (which is a b2body) afterwards without unscheduling the method every time.
- (void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touch = [touches anyObject];
location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
endPoint = location;
force = b2Vec2(endPoint.x - startPoint.x ,endPoint.y - startPoint.y);
if ((force.x != 0) || (force.y != 0)) {
if (ballCount == 0) {
ball.position = startPoint;
[self createBall]; - Here i create the ball every time
[self schedule: #selector(tick:)]; -I schedule the tick method right after the ball is created
[self scheduleOnce:#selector(kick) delay:0]; - This is the only place the ball will launch. For some reason I can't get the kick method to work any where else
}
}
- (void)kick
{
int speed = 30;
float32 setSpeed = speed/sqrt(powf(force.x,2) + powf(force.y, 2));
b2Vec2 ballSpeed = b2Vec2(force.x * setSpeed, force.y * setSpeed);
_ballBody->SetLinearVelocity(ballSpeed);
}
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
ballData = (__bridge CCSprite *)_ballBody->GetUserData();
ballData.position = ccp(_ballBody->GetPosition().x * PTM_RATIO,
_ballBody->GetPosition().y * PTM_RATIO);
ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(_ballBody->GetAngle());
std::set<b2Body *>toDestroy;
//takes collisions from contact listener
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
bodyA = contact.fixtureA->GetBody();
bodyB = contact.fixtureB->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
spriteA = (__bridge CCSprite *) bodyA->GetUserData();
spriteB = (__bridge CCSprite *) bodyB->GetUserData();
contactPositionX = spriteA.position.x;
contactPositionY = spriteB.position.y;
if (spriteA.tag == kCurrentItem && spriteB.tag == 8)
{
NSLog(#"contact");
[self removeChild:spriteA cleanup:YES];
[self removeChild:spriteB cleanup:YES];
toDestroy.insert(bodyA);
toDestroy.insert(bodyB);
[self unschedule:#selector(tick:)]; (i unschedule the tick method every time which in turn messes up my other sprites.)
}
}
}
for(std::set<b2Body *>::iterator pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2)
{
b2Body *body = *pos2;
_world->DestroyBody(body);
}
toDestroy.clear();
}
I try to implement Contact Listener in box2d *cocos2d*. And I want integrate NSNotificationCenter in PostSolve function, but when I try to point the object: parametr I've got the error:
No viable conversion from 'MyContact' to 'id'
How can I send MyContact object through the NSNotificationCenter?
MyContactListener class
//
// MyContactListener.m
// Box2DPong
//
// Created by Ray Wenderlich on 2/18/10.
// Copyright 2010 Ray Wenderlich. All rights reserved.
//
#import "MyContactListener.h"
#import "ConfigMacro.h"
MyContactListener::MyContactListener() : _contacts(),_contactsObjects(){}
MyContactListener::~MyContactListener() {}
void MyContactListener::BeginContact(b2Contact* contact) {
b2Body *bodyA = contact->GetFixtureA()->GetBody();
b2Body *bodyB = contact->GetFixtureB()->GetBody();
if(bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.push_back(myContact);
}
}
void MyContactListener::EndContact(b2Contact* contact) {
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
std::vector<MyContact>::iterator pos;
pos = std::find(_contacts.begin(), _contacts.end(), myContact);
if (pos != _contacts.end()) {
_contacts.erase(pos);
}
}
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {}
void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {
b2Body *bodyA = contact->GetFixtureA()->GetBody();
b2Body *bodyB = contact->GetFixtureB()->GetBody();
if(bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
int32 count = contact->GetManifold()->pointCount;
float32 maxImpulse = 0.0f;
b2Vec2 collision;
for (int32 i = 0; i < count; ++i) {
maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
if (i == 0) {
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
collision = worldManifold.points[0];
}
}
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB(), maxImpulse, collision };
[[NSNotificationCenter defaultCenter] postNotificationName:kReceivedImpulse object:myContact userInfo:nil];
}
}
The object: argument should be a pointer to an Objective-C object - you're trying to pass what looks like a struct.
I have multiple sprites placed onto a background sprite like this:
//my background
CCSprite *bg = [CCSprite spriteWithFile:#"imageName.png"];
[self addchild:bg];
And then I add my items onto bg
//this is how i add my items
CCSprite *items = [CCSprite spriteWithFile:#"itemName.png"];
[bg addchild:items];
Oh and not forgetting my car sprite
//my car
CCSprite *car = [CCSprite spriteWithFile:#"car.png"];
[self addchild:car];
I use a loop to add multiple sprites onto the bg.
Now the question is how do I detect whether the car collided with the multiple sprites that I have placed onto the bg?
I've tried using CGRectIntersectsRect and it doesn't work.
I've tried using the pythagoras theorem method and once again it doesn't work.
There was a method which involved adding the items sprites into a NSMutableArray and it doesn't work either.
Can anyone suggest a method whereby I can try?
Additional code:
-(void) initializeCarAndItems
{
car = [CCSprite spriteWithFile:#"android.png"];
car.position = ccp(screenSize.width/2, screenSize.height * 0.30);
[self addChild:car z:1];
carRect = [car boundingBox];
}
-(void) initializeMap
{
bg1 = [CCSprite spriteWithFile:#"racingBG.png"];
bg1.anchorPoint = ccp(0, 0);
bg1.position = ccp(0, 0);
[self addChild:bg1 z:-1];
bg2 = [CCSprite spriteWithFile:#"racingBG2.png"];
bg2.anchorPoint = ccp(0,0);
bg2.position = ccp(0, bg1.boundingBox.size.height - 1);
[self addChild:bg2 z:-1];
convertedWidth = (int)bg1.boundingBox.size.width;
convertedHeight = (int)bg1.boundingBox.size.height;
for (y = 0; y < 15; y++)
{
positionX = arc4random()%convertedWidth;
positionY = arc4random()%convertedHeight;
items = [CCSprite spriteWithFile:#"item.png"];
items.position = ccp(positionX, positionY + 300);
[bg1 addChild:items z:100];
[itemsArray addObject:items];
}
for (y = 0; y < 15; y++)
{
positionX = arc4random()%convertedWidth;
positionY = arc4random()%convertedHeight;
items = [CCSprite spriteWithFile:#"item.png"];
items.position = ccp(positionX, positionY);
[bg2 addChild:items z:100];
[itemsArray addObject:items];
}
}
-(void) accelerate
{
bg1.position = ccp(0, bg1.position.y - accelerateNumber);
bg2.position = ccp(0, bg2.position.y - accelerateNumber);
if (bg1.position.y < -bg1.boundingBox.size.height)
{
questionCount++;
bg1.position = ccp(0, bg2.position.y + bg2.boundingBox.size.height - 1);
[self question];
[bg1 removeAllChildrenWithCleanup:YES];
for (y = 0; y < 15; y++)
{
positionY = arc4random()%convertedHeight;
positionX = arc4random()%convertedWidth;
items.position = ccp(positionX, positionY);
items = [CCSprite spriteWithFile:#"item.png"];
[bg1 addChild:items z:100];
[itemsArray addObject:items];
}
}
else if (bg2.position.y < -bg2.boundingBox.size.height)
{
questionCount++;
bg2.position = ccp(0, bg1.position.y + bg1.boundingBox.size.height - 1);
[self question];
[bg2 removeAllChildrenWithCleanup:YES];
for (y = 0; y < 15; y++)
{
positionY = arc4random()%convertedHeight;
positionX = arc4random()%convertedWidth;
items.position = ccp(positionX, positionY);
items = [CCSprite spriteWithFile:#"item.png"];
[bg2 addChild:items z:100];
[itemsArray addObject:items];
}
}
}
-(void) update:(ccTime)deltaTime
{
[self ifEdgeOfScreen];
[self accelerate];
for (CCSprite *itemFromArray in itemsArray)
{
CGRect itemRect = [itemFromArray boundingBox];
if (CGRectIntersectsRect(carRect, itemRect))
{
NSLog(#"Collision!");
}
}
if (leftButton.active == TRUE)
{
[self moveLeftRight:1];
}
else if (rightButton.active == TRUE)
{
[self moveLeftRight:2];
}
}
UPDATE:
It's fixed :)
-(void) update:(ccTime)deltaTime
{
car = [car boundingbox];
[self ifEdgeOfScreen];
[self accelerate];
for (CCSprite *itemFromArray in itemsArray)
{
if (CGRectIntersectsRect(carRect, [itemFromArray boundingbox]))
{
NSLog(#"Collision!");
}
}
if (leftButton.active == TRUE)
{
[self moveLeftRight:1];
}
else if (rightButton.active == TRUE)
{
[self moveLeftRight:2];
}
}
I found so many problems with the code....
When you call removeAllChildren.. Make sure you also remove objects from array.. Removing sprite from parents does not remove it from array.
update the car rect in update Method. So in your update method
-(void) update:(ccTime)deltaTime
{
[self ifEdgeOfScreen];
[self accelerate];
carRect = [car boundingBox];
...........
}
Hope this helps.. :)
im new to programming, i have tried the ray wenderlich tutorial but im still confused.
i have a sprite called rock, and a sprite called player, im trying to detect collision between them. but im extremely confused. in need of some help.
-(void)addRock {
CCSprite *rock = [CCSprite spriteWithFile:#"rock.png"
rect:CGRectMake(0, 0, 27, 40)];
// Determine where to spawn the target along the X axis
CGSize winSize = [[CCDirector sharedDirector] winSize];
int minX = rock.contentSize.width/2;
int maxX = winSize.width - rock.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
// Create the target slightly off-screen along the right edge,
// and along a random position along the X axis as calculated above
rock.position = ccp(actualX, 500);
[self addChild:rock];
// Determine speed of the sprite
int actualDuration = 5;//speed of sprite
}
- (id)init {
if ((self=[super init])) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCSprite *player = [CCSprite spriteWithFile:#"Player.png"
rect:CGRectMake(0, 0, 27, 40)];
player.position = ccp(winSize.width/2, winSize.height/4+15);
[self addChild:player];
[self schedule:#selector(gameLogicRock:) interval:0.2];
they are the two sprites, they spawn and position correctly, i only need to detect collision
You have to implement a new class for the collision or say contact listener based on some criteria as tag no. i have an example for you.
// ContactListener.h
#import "Box2D.h"
class ContactListener : public b2ContactListener
{
private:
void BeginContact(b2Contact* contact);
void EndContact(b2Contact* contact);
};
// ContactListener.mm
#import "ContactListener.h"
#import "cocos2d.h"
#import "BodyNode.h"
#import "GameScene.h"
void ContactListener::BeginContact(b2Contact* contact)
{
b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();
if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL)
{
BodyNode* bNodeA = (BodyNode*)bodyA->GetUserData();
BodyNode* bNodeB = (BodyNode*)bodyB->GetUserData();
if ((bNodeA.tag == GameSceneNodeTagBall && bNodeB.tag == GameSceneNodeTagHole) ||
(bNodeA.tag == GameSceneNodeTagHole && bNodeB.tag == GameSceneNodeTagBall))
{
switch (bNodeA.tag) {
case GameSceneNodeTagBall:
if ([bNodeA isKindOfClass:[Ball class]]) {
Ball* ball = (Ball*)bNodeA;
ball.sprite.visible = NO;
[[GameScene sharedGameScene] gameOver];
}
break;
case GameSceneNodeTagHole:
if ([bNodeB isKindOfClass:[Ball class]]) {
Ball* ball = (Ball*)bNodeB;
ball.sprite.visible = NO;
[[GameScene sharedGameScene] gameOver];
}
break;
default:
break;
}
}
}
}
This is an example of ball and hole collision. You can use this as per your requirement.
Hope this will help you.
Thanks!