I have two objects : GameObject* A & GameObject* B, each objet have two animation:idle and colli, with each animation, object have state: m_stateidle and m_statecolli .
i want one condition : “When object A in m_statecolli and object B in m_stateidle OR object A in m_statedile and object B in m_statecolli”, two object collide each other
i use ContactListerner.h vs ContactListerner.cpp
class ContactListener : public b2ContactListener {
public:
ContactListener();
~ContactListener();
virtual void BeginContact(b2Contact *contact);
virtual void EndContact(b2Contact *contact);
virtual void PreSolve(b2Contact *contact, const b2Manifold *oldManifold);
virtual void PostSolve(b2Contact *contact, const b2ContactImpulse *impulse);
};
ContactListener::ContactListener() {
}
ContactListener::~ContactListener() {
}
void ContactListener::BeginContact(b2Contact *contact) {
}
}
void ContactListener::EndContact(b2Contact *contact) {
}
}
void ContactListener::PreSolve(b2Contact *contact, const b2Manifold *oldManifold) {
}
void ContactListener::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) {
}
so how to two object collide with condition. thanks
mage
March 13, 2013, 8:24am
#2
You can do something like this in your contact listener
void ContactListener::BeginContact(b2Contact* contact) {
if (contact->IsTouching()) {
b2Fixture *a = contact->GetFixtureA();
b2Fixture *b = contact->GetFixtureB();
b2Body *aBody = a->GetBody();
b2Body *bBody = b->GetBody();
if (aBody !=NULL && bBody != NULL) {
GameObject *obj = static_cast(aBody->GetUserData());
GameObject *obj2 = static_cast(bBody->GetUserData());
if(obj != NULL && obj2 != NULL) {
obj->collisionCallback(obj2);
obj2->collisionCallback(obj);
}
}
}
}
And in your GameObject Class create a function like this
void collisionCallback(GameObject *obj);
So whenever your collision happens both objects get a callback to collisionCallback with the other object…
can’t detect detect collsion in box2d, RootObject inherit from CCNode:
void MyContactListener::BeginContact(b2Contact* contact) {
// We need to copy out the data because the b2Contact passed in
// is reused.
/*
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.push_back(myContact);
*/
void* bodyAUserData = contact->GetFixtureA()->GetBody()->GetUserData();
void* bodyBUserData = contact->GetFixtureB()->GetBody()->GetUserData();
if(bodyAUserData!=NULL && bodyBUserData!=NULL)
{
RootObject* obj = static_cast(bodyAUserData);
RootObject* obj1 = static_cast(bodyBUserData);
obj->collisioncallBack(obj1);
obj1->collisioncallBack(obj);
}
}
class RootObject()
{
void RootObject :: collisioncallBack(RootObject *obj)
{
m_actionState = kActionIdle ;
if(obj->m_actionState == kActionIdle)// this condition can't check although it's true:(
{
obj->m_actionState = kActionBigger; //i add breakpoint here and can't run this
}
else if(this->m_actionState == kActionIdle)
{
this->m_actionState = kActionBigger;
}
}
}
In RootObject class, m_actionState init : kActionIdle. So why can’t run this line added breakpoint:(, i think it’s out of gameloop? so can’t check . I have 5 ball (RootObject in scene)
mage
March 16, 2013, 11:52am
#4
use CCLog to check if it is going in the callback function.
Also have you added an object of ContactListener class in your box2d world.
world->SetContactListener(&ContactListenerInstance);
yeah, i added u added an object of ContactListener class in your box2d world,
as i said,
if(obj->m_actionState == kActionIdle) can’t check although it’s true:(
mage
March 16, 2013, 12:26pm
#6
try adding a CCLog in your contact listener.
void RootObject :: collisioncallBack(RootObject *obj)
{
CCLog("object action state %d", obj->m_actionState);
m_actionState = kActionIdle ;
if(obj->m_actionState == kActionIdle)// this condition can't check although it's true:(
{
obj->m_actionState = kActionBigger; //i add breakpoint here and can't run this
}
else if(this->m_actionState == kActionIdle)
{
this->m_actionState = kActionBigger;
}
}
So object action state : 2 >_< ,
my code :
enum ActionState
{
kActionIdle =1,
kActionBigger,
kActionCollision,
};
mage
March 16, 2013, 3:58pm
#8
try this instead
CCLog("object action state %d", (int)obj->m_actionState);
if it still gives garbage value, that means the enum object isn’t getting set.
when two ball collsion , ball actionState gives garbage value_
, but i add cclog in init method, it give true result(1), so why_
mage
March 17, 2013, 7:08am
#10
Can you paste your entire class here… it would be easier to debug.
//
// RootObject.cpp
// GameBlastar
//
// Created by Lion User on 04/03/2013.
//
//
#include "RootObject.h"
#include "Global.h"
RootObject::RootObject(b2World *m_world,CCLayer*layer,CCPoint position,b2Vec2 force )
{
cache = CCSpriteFrameCache::sharedSpriteFrameCache();
cache->addSpriteFramesWithFile("Blue_1.plist");
m_Layer = layer;
world = m_world ;
m_score = 0;
m_force = force;
m_Collision = false;
m_Bigger = false;
m_actionState = kActionIdle ; // init ball is action idle
CCLOG("init state : %d",(int)m_actionState);
spritebatch = CCSpriteBatchNode::create("Blue_1.pvr");
m_pSprite1 = CCSprite::createWithSpriteFrameName("Blue_1.png");
m_pSprite1->setPosition(CCPoint(position));
spritebatch->addChild(m_pSprite1);
m_Layer->addChild(spritebatch);
arrayAction = CCArray ::createWithCapacity(3);
arrayAction->retain();
CCArray *idleAnimFrames = CCArray::createWithCapacity(10);
idleAnimFrames->retain();
for(int i = 1 ;i < 9 ;i++)
{
CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Blue_%d.png",i)->getCString());
idleAnimFrames->addObject(frame);
}
CCAnimation *idleAnimation = CCAnimation ::createWithSpriteFrames(idleAnimFrames,float(1.0/60.0)) ;
//ball collision and die
CCArray* collidieAnimaFrames = CCArray::createWithCapacity(15);
collidieAnimaFrames->retain();
for (int i = 1;i < 15; i++)
{
CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("BlueColli_%d.png",i)->getCString());
collidieAnimaFrames->addObject(frame);
}
CCAnimation* collidieAnimation = CCAnimation::createWithSpriteFrames(collidieAnimaFrames, float(1.0/5.0));
this->m_actionIdle = CCRepeatForever::create(CCAnimate::create(idleAnimation));
this->m_actionIdle->retain();
this->m_actionColli = CCRepeat::create(CCAnimate::create(collidieAnimation), 1); //action for ball bigger and collision
this->m_actionColli->retain();
// arrayAction->addObject(m_actionColli);
m_pSprite1->runAction(m_actionIdle);
Init();
}
void RootObject::Init()
{
createBox2d();
}
void RootObject :: setBallBiger() //set ball bigger and collision
{
if(m_actionState == kActionIdle) //when touch on ball, if ball idle, ball will bigger and collision with other ball
{
m_Bigger = true;
m_pSprite1->stopAction(m_actionIdle);
m_actionState = kActionBigger;
m_pSprite1->runAction(m_actionColli);
}
}
bool RootObject::getRect(CCPoint point) //use for touch on ball bigger
{
m_Rect = CCRectMake(
m_pSprite1->getPositionX() - (m_pSprite1->getTextureRect().size.width/2) * m_pSprite1->getScaleX(),
m_pSprite1->getPositionY() - (m_pSprite1->getTextureRect().size.height/2) * m_pSprite1->getScaleY(),
m_pSprite1->getTextureRect().size.width * m_pSprite1->getScaleX(),
m_pSprite1->getTextureRect().size.height * m_pSprite1->getScaleY()
);
if(m_Rect.containsPoint(point))
{return true;}
else return false ;
}
void RootObject ::createBox2d()
{
m_ballBodyDef.type = b2_dynamicBody;
m_ballBodyDef.position.Set(m_pSprite1->getPositionX()/PTM_RATIO,m_pSprite1->getPositionY()/PTM_RATIO);
m_ballBodyDef.userData = m_pSprite1;
m_ballBody = world->CreateBody(&m_ballBodyDef);
//create ball definition
b2CircleShape m_circle ;
m_circle.m_radius = m_pSprite1->getContentSize().width/2/PTM_RATIO ;
m_ballFixtureDef.filter.categoryBits = 0x0002; //this's not important
m_ballFixtureDef.filter.maskBits = 1 | 0x0008;
m_ballFixtureDef.shape = &m_circle;
m_ballFixtureDef.density = 1.0f;
m_ballFixtureDef.friction = 0.0f;
m_ballFixtureDef.restitution = 1.0f;
m_ballFixture = m_ballBody->CreateFixture(&m_ballFixtureDef);
m_ballBody->ApplyLinearImpulse(m_force, m_ballBody->GetWorldCenter());
}
void RootObject::update(float dt)
{
}
void RootObject::collisionCallBack(RootObject* obj) //collision Call Back
{
if(m_Bigger == false) //first i use if(m_actionState == kActionIdle) but this condition can't not rune, cclog give garbage number., then i replace by bool m_bigger. check : if ball bigger = false will bigger after collsion
{
m_Bigger = true;
CCLog("%d",m_Bigger);
m_pSprite1->stopAction(m_actionIdle);//error at here although in method setballbiger not error
m_actionState = kActionBigger;
m_pSprite1->runAction(m_actionColli);
}
}
RootObject:: ~RootObject(void)
{
this->m_ballBody->GetWorld()->DestroyBody(m_ballBody);
}
In tick method of helloworld scene:
std::vector::iterator i = m_ListBall->begin(); //m_listball is vector object manage all ball
std::vector::iterator end = m_ListBall->end();
// for (std::vector::iterator i = m_ListBall->begin();i!= m_ListBall->end(); i++) {
for (; i!=end; ++i) {
if((*i)->m_actionColli->isDone()==true) //when m_actionColli finish, it will remove sprite vs body .
{
this->removeChild((*i)->spritebatch);
RootObject* ball = *i;
delete ball;
if ( i != m_ListBall->end() )
ManagerObject::Instance()->getListBall()->erase(i);
}
void HelloWorld ::ccTouchesEnded(CCSet* touches, CCEvent* event) //when touch on ball, ball will call function setBallBiger
{
CCTouch* touch = (CCTouch*)( touches->anyObject() );
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
for (std::vector::iterator i = m_ListBall->begin();i!= m_ListBall->end(); i++) {
if((*i)->getRect(location))
{
(*i)->m_ballBody->DestroyFixture((*i)->m_ballFixture);
createBox2d((*i));
(*i)->m_ballBody->SetLinearVelocity(b2Vec2(0,0));
(*i)->setBallBiger();
}
}
// Set up initial location of projectile
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
}
felix
March 20, 2013, 3:54am
#13
what is the size of the balls relative to PTM_RATIO? Make sure m_circle.m_radius at least 1. i.e.
in
m_circle.m_radius = m_pSprite1->getContentSize().width/2/PTM_RATIO
the value of m_circle.m_radius is >= 1;