I have several bird sprites in my scene. I want to call function Bird::Die() which plays a animation and increment score when weapon hit them. But the only thing I get from them is contact object is getBody(A/B)->getNode(). What is the correct way of achieving this?
What do you mean object type? Like if it is a bird or not?
have you set your bit-masks for collisions, contact, etc?
I have setup collision bit mask correctly and I works fine when I simply call
if (bodyA->getCollisionBitmask() == (int) PhysicsCategory::Bird ){
bodyA->getNode()->removeFromParent();
bodyB->getNode()->removeFromParent();
}
In this case I know that the first object bodyA is a Bird. Then how do I call Bird::Die() on it.
I think you need to show more code. I’d need to see Bird::Die() and maybe more in that class and also more code before the collision code you posted. Specifically types.
I am new to cocos so please tell me mistakes so that I can improve. Physics is handled here.
My main scene.
#include "BadBirdz.hpp"
#include "Bird.hpp"
#include "CustomHelperFunctions.hpp"
#include <iostream>
USING_NS_CC;
Scene* BadBirdz::createScene(){
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0,0));
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
auto label = BadBirdz::create();
scene->addChild(label);
return scene;
}
bool BadBirdz::init(){
if (!Layer::init()){
return false;
}
printf("Here => %d \n", (1 << 4 ));
srand(time(nullptr));
auto origin = Director::getInstance()->getVisibleOrigin();
auto winSize = Director::getInstance()->getWinSize();
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("Badbirds.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("player.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("assetpack3.plist");
auto background = DrawNode::create();
background->drawSolidRect(origin, winSize, Color4F(0.51764,0.70588, 0.9098 ,1.0));
this->addChild(background);
printf("OK the WinX is %f , WinY is %f ", winSize.width,winSize.height);
car = Sprite::createWithSpriteFrameName("Generics/0.png");
car->setPosition(winSize.width/2,car->getContentSize().height * 2);
this->addChild(car);
player = Player::create();
// player->setPosition(-500,-200);
// car->addChild(player);
player->setPosition(player->getBodySize().x/2, player->getBodySize().y/2 );
this->addChild(player);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(BadBirdz::onContactBegin,this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
this->schedule(schedule_selector(BadBirdz::createBird), 1.5f);
return true;
}
bool BadBirdz::onContactBegin(cocos2d::PhysicsContact &contact){
auto bodyA = contact.getShapeA()->getBody();
auto bodyB = contact.getShapeB()->getBody();
// bodyA->getNode()->runAction(CallFunc::create(Bird::Die()));
if (bodyA->getCollisionBitmask() == (int) PhysicsCategory::Bird ){
bodyA->getNode()->removeFromParent();
bodyB->getNode()->removeFromParent();
}
return true;
}
void BadBirdz::createBird(float dt){
auto birded = Bird::create();
//birded->setPosition(winSize.width/2,winSize.height/2);
this->addChild(birded);
}
And here is my Bird class.
#include "Bird.hpp"
#include "CustomHelperFunctions.hpp"
USING_NS_CC;
bool Bird::init(){
if (!Sprite::initWithSpriteFrameName("Birds/Gidh/Fly/0.png")){
printf("Error Loading Bird Sprite");
return false;
}
auto director = Director::getInstance();
// this->setPosition(0,director->getVisibleSize().height/2);
this->setScale(0.65, 0.65);
int valX ;
if (rand()%2 > 0)
{
valX = 0 - this->getContentSize().width;
this->destinationX = director->getVisibleSize().width + this->getContentSize().width;
}else {
valX = director->getVisibleSize().width + this->getContentSize().width;
//this->destinationX =director->getVisibleSize().width + this->getContentSize().width;
this->destinationX = 0 - this->getContentSize().width;;
this->setScaleX(-0.65);
}
int minY = director->getVisibleSize().height/2;
int maxY = director->getVisibleSize().height - this->getContentSize().height/2;
int rangeY = maxY - minY;
int randomY = (rand() % rangeY) + minY;
this->destinationY = randomY;
randomY = (rand() % rangeY) + minY;
this->setPosition(valX,randomY);
AnimateFly();
AddPhysics();
//Debug Controls
/*
auto listner = EventListenerTouchOneByOne::create();
listner->onTouchBegan = [&] (Touch* touch, Event *unused) -> bool {
if (this->getBoundingBox().containsPoint(touch->getLocation()))
if ((rand() % 2) > 0) this->Poop(); else this->Die();
return true;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listner, this);
// director->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listner, this );
*/
return true;
}
void Bird::AddPhysics(){
auto size = this->getContentSize();
auto physicsBody = PhysicsBody::createBox(size,PhysicsMaterial(0.1f,1.0f,0.0f));
physicsBody->setDynamic(true);
physicsBody->setCategoryBitmask((int) PhysicsCategory::Bird);
physicsBody->setCollisionBitmask((int) PhysicsCategory::None);
physicsBody->setContactTestBitmask((int) PhysicsCategory::Bullet);
this->setPhysicsBody(physicsBody);
}
void Bird::Die(){
this->stopAllActions();
auto frames = CustomHelperFunctions::getAnimation("Birds/Gidh/Die/%d.png", 5);
auto flyAnimation = Animation::createWithSpriteFrames(frames,1.0f/15);
this->runAction(Sequence::create( Animate::create(flyAnimation), RemoveSelf::create() ,nullptr));
}
void Bird::Poop(){
auto poop = Sprite::createWithSpriteFrameName("Birds/Gidh/Poop/0.png");
poop->setPosition(this->getPosition());
this->getParent()->addChild(poop);
auto frames = CustomHelperFunctions::getAnimation("Birds/Gidh/Poop/%d.png", 3);
auto flyAnimation = Animation::createWithSpriteFrames(frames,1.0f/10);
poop->runAction(RepeatForever::create(Animate::create(flyAnimation)));
poop->runAction(MoveBy::create(2, Vec2(0,-1000)));
}
void Bird::AnimateFly(){
Vector<FiniteTimeAction*> actions;
auto frames = CustomHelperFunctions::getAnimation("Birds/Gidh/Fly/%d.png", 4);
auto flyAnimation = Animation::createWithSpriteFrames(frames,1.0f/10);
this->runAction(RepeatForever::create(Animate::create(flyAnimation)));
//actions.pushBack(RotateTo::create(0,-45));
actions.pushBack(MoveTo::create(5, Vec2(this->destinationX, this->destinationY)));
actions.pushBack(RemoveSelf::create());
//Debug Actions
//actions.pushBack(RotateTo::create(0,-45));
//actions.pushBack(MoveBy::create(1, Vec2(200,350)));
// actions.pushBack(MoveTo::create(0, Vec2(100,500)));
auto sequence = Sequence::create(actions);
this->runAction(sequence);
}
Can you post a screenshot too?
I’ll look at this soon when I finish my first priority tasks today 
is BadBirdz a subclass of Bird?
Also, consider the following from one of my games:
void CornSprite::addEvents()
{
// physics event
auto contactListener = cocos2d::EventListenerPhysicsContact::create();
contactListener->onContactBegin = std::bind(&CornSprite::onContactBegin, this,
std::placeholders::_1);
cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
// touch events.
auto listener = cocos2d::EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [&](cocos2d::Touch* touch, cocos2d::Event* event)
{
if (!_gameObject->Instance()->getGameIsPaused())
{
cocos2d::Vec2 p = touch->getLocation();
cocos2d::Rect rect = this->getBoundingBox();
if(rect.containsPoint(p))
{
CornSprite::touchEvent(touch);
return true;
}
}
return false;
};
listener->onTouchEnded = [=](cocos2d::Touch* touch, cocos2d::Event* event)
{
};
cocos2d::Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
}
void CornSprite::touchEvent(cocos2d::Touch* touch)
{
//std::cout << "touched " << this->getTag() << std::endl;
cocos2d::Vec2 p = touch->getLocation();
cocos2d::Rect rect = this->getBoundingBox();
if(rect.containsPoint(p))
{
//std::cout << "touched corn sprite" << std::endl;
CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("reward.mp3");
GAMEOBJECTINSTANCE->incrementCurrentScore();
//GAMEOBJECTINSTANCE-> setScoreLabel(GAMEOBJECTINSTANCE->getCurrentScore());
GAMEOBJECTINSTANCE->decrementCornCount();
addMoreSprites(1);
for (int i=0; i < GAMEOBJECTINSTANCE->getCornVector().size(); i++)
{
CornSprite* c = GAMEOBJECTINSTANCE->getCornVector().at(i);
if (this->getTag() == c->getTag())
{
GAMEOBJECTINSTANCE->getCornVector().erase(GAMEOBJECTINSTANCE->getCornVector().begin()+i);
break;
}
}
removeFromParentAndCleanup(true);
//std::cout << "current score: " << GAMEOBJECTINSTANCE->getCurrentScore() << std::endl;
//std::cout << "high score: " << GAMEOBJECTINSTANCE->getCurrentScore() << std::endl;
}
}
bool CornSprite::onContactBegin(cocos2d::PhysicsContact& contact)
{
return true;
}
No BadBirdz is derived from cocos2d::Label while Bird is derived from cocos2d::Sprite. Looks like my pattern has some issues. As it is my first project therefore I have not a good idea what I am doing. You are using Touch listener in your code can you give me a example of a physics contact handling?
What I provided is most of my code, but again, I subclass.
Take a look at this too: http://www.cocos2d-x.org/docs/cocos2d-x/en/physics/collisions.html
Ok. Now I am understanding that I have to add contact listener on each bird instance. Right now I only had it in my main scene class. Just a quick question. Your this code does nothing yet?
bool CornSprite::onContactBegin(cocos2d::PhysicsContact& contact)
{
return true;
}
it does something, it lets the physics world know a contact has occurred.
Thanks for the help I will start working on it as you suggested tomorrow. 
let me know if you have more questions.
Well my old problem is resolved but now the issue is when My bullet hit one bird then the Die() function of all other birds is also called. In simple words when my bullet hits one bird all of them die. How can I fix this?
How are you storing your Birds? In a vector?
No I am not storing them in vector. Just creating them like this
void BadBirdz::createBird(float dt){
auto bird = Bird::create();
//birded->setPosition(winSize.width/2,winSize.height/2);
this->addChild(bird);
}
and scheduling this function from init() method of scene. Like this
this->schedule(schedule_selector(BadBirdz::createBird), 1.5f);
I could store them in a vector and assign each one a name or a tag. Then you can cycle through your vector and act upon any Sprite.
Thanks for help by using tags the physics works great. Anyway is it because of my bad design that the physics is called for every bird instance?
