C++ Box2D Iterate through vector of bodies and deleting - c++

I have created a game which uses a color coded image to create different bodies/fixtures. So for example if the pixel is red it will get stored into an array as 7 and then the program will create a body called jewel. If there are 10 red pixels, 10 jewels will be created:
else if (array[w][h]==7)
{
b2BodyDef Jewel_BodyDef;
Jewel_BodyDef.position.Set(x, y);
m_collectableJewel = m_world->CreateBody(&Jewel_BodyDef);
b2PolygonShape box;
box.SetAsBox(0.5f, 0.5f);
m_collectableJewelFixture=m_collectableJewel->CreateFixture(&box, 0.0f);
collide.m_jewelFix.push_back(m_collectableJewelFixture);
jewels a;
a.jewel_dim.set(1.0f,1.0f);
a.jewel_pos.set(x,y);
m_jewels.push_back(a);
x+=5.0f;
}
My problem is when calculating the collision between the player and the jewels. The program knows when the player has collided with a jewel. However, I can't get it to delete the fixture. Or rather, it will only delete the last fixture placed, i.e. the last one to be created in the vector. Is there a way to name the fixtures individually? So that then the program can delete the one it has actually collided with, rather than the last one?
edit:
int Collision_with_Player::PickJewel(b2Fixture *player, b2Fixture *foot)
{
int CollisionJewel=0;
std::vector<MyContact>::iterator posi;
for(posi = m_contactListener->m_contacts.begin(); posi != m_contactListener->m_contacts.end(); ++posi)
{
MyContact contact = *posi;
for(std::vector<b2Body*>::iterator iterb = m_jewelBodyVec.begin(); iterb != m_jewelBodyVec.end(); ++iterb)
{
for(std::vector<b2Fixture*>::iterator iter = m_jewelFix.begin(); iter != m_jewelFix.end(); ++iter)
{
if ((contact.fixtureA == player && contact.fixtureB == *iter) ||
(contact.fixtureA ==*iter && contact.fixtureB == player))
{
m_deleteJewels.clear();
std::cout<<"size"<<m_deleteJewels.size()<<std::endl;
CollisionJewel=1;
std::cout<<"Jewel"<<*iter<<std::endl;
deletejewel = *iter;
deletejewelbody= *iterb;
}
else
{
CollisionJewel=0;
}
}
}
}
return CollisionJewel;
}
and in another file
if (collide.PickJewel(m_playerFixture, m_footSensorFixture)==1)
{
collide.deletejewelbody->DestroyFixture(collide.deletejewel);
}

Related

Why setPosition work in some condition but doesn't work in other condition?

i make a game let's say ThrowBall, the Player can pick up the ball spawned and throw it into target get the score added then the ball return it's position and repeat. The problem is when Ball dragged by Player (i make the Ball as child of Player) into target, the Ball return it's position correctly into desired position, but the odd happens when it collided after i send the Ball into target by applying impulse it won't return the ball into desired position, why is this happening?
i'm running this game for android, i'm running this code in VS'17 using cocos2d-x-3.17. I tried changing impulse into force, moveby. I tried making the ball stop (setVelocity to zero before setPosition). I tried changing Point into Vect, vec2. I tried to break point debug, the code do read setPosition but do nothing.
GameScene.cpp
bool GameScene::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto pickupListener = EventListenerPhysicsContact::create();
pickupListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(pickupListener, this);
return true;
}
bool GameScene::onContactBegin(cocos2d::PhysicsContact &contact)
{
PhysicsBody *a = contact.getShapeA()->getBody();
PhysicsBody *b = contact.getShapeB()->getBody();
if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && PLAYER_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
// make the ball follow Player
isfollow = true;
}
else if (
(BALL_COLLISION_BITMASK == a->getCollisionBitmask() && TARGET_COLLISION_BITMASK == b->getCollisionBitmask()) ||
(BALL_COLLISION_BITMASK == b->getCollisionBitmask() && TARGET_COLLISION_BITMASK == a->getCollisionBitmask())
)
{
isfollow = false;
// add score
score++;
__String *tempScore = __String::createWithFormat("%i", score);
scoreLabel->setString(tempScore->getCString());
// return spawn ball
ball->returnPos();
return false;
}
void GameScene::throwBall() {
if (isfollow == true) {
isfollow = false;
ball->getSprite()->getPhysicsBody()->applyImpulse(Vec2(100000, 100000));
}
}
Ball.h
class Ball
{
public:
Ball(cocos2d::Layer *layer);
cocos2d::Sprite *getSprite() { return randomSpawn; };
void returnPos();
private:
cocos2d::Size visibleSize;
cocos2d::Vec2 origin;
cocos2d::Sprite *randomSpawn;
};
Ball.cpp
Ball::Ball(cocos2d::Layer *layer)
{
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
randomSpawn = Sprite::create("res/ball.png");
randomSpawn->setPosition(Vec2(400, 80));
auto randomBallBody = PhysicsBody::createCircle(randomSpawn->getContentSize().width / 2);
randomBallBody->setCollisionBitmask(BALL_COLLISION_BITMASK);
randomBallBody->setContactTestBitmask(true);
randomBallBody->setGravityEnable(false);
randomSpawn->setPhysicsBody(randomBallBody);
layer->addChild(randomSpawn);
}
void Ball::returnPos()
{
randomSpawn->setPosition(Vec2(400, 80));
}
i want to make the object (Ball) return position when collided into Target and repeat. i'm sorry if the format is a mess, i'm new here, also it's not my full code, it's actually works fine i can run it, but only the setPosition won't work

advanced Collision detection?

Hi i'm currently making an RPG similar to Legend of Zelda. I have a feature in my game where when Player attacks enemy with his sword, the enemy is knocked back n units. i have a collision detection that sometimes works as intended, and other times the enemy goes through the wall and gets stuck on the other side, and then other times the enemy can simply walk right through the wall. If possible, making the enemy move toward player upon collision with wall would be one possible solution to this problem I believe, but I do not know how to implement this. Here is my current collision code:
// Enemy Collides with Wall
counter1 = 0;
for (iter4 = enemyArray.begin(); iter4 != enemyArray.end(); iter4++)
{
counter2 = 0;
for (iter15 = wallArray.begin(); iter15 != wallArray.end(); iter15++)
{
if (enemyArray[counter1].rect.getGlobalBounds().intersects(wallArray[counter2].rect.getGlobalBounds()))
{
enemyArray[counter1].isCollided = true;
//Hit Wall
if ((enemyArray[counter1].direction == 1 || enemyArray[counter1].rect.getPosition().y >= wallArray[counter2].rect.getPosition().y)) //up
{
enemyArray[counter1].canMoveUp = false;
enemyArray[counter1].canMoveLeft = false;
enemyArray[counter1].canMoveRight = false;
enemyArray[counter1].rect.move(0, 7);
}
else if ((enemyArray[counter1].direction == 2 || enemyArray[counter1].rect.getPosition().y <= wallArray[counter2].rect.getPosition().y)) //Down
{
enemyArray[counter1].canMoveDown = false;
enemyArray[counter1].canMoveRight = false;
enemyArray[counter1].canMoveLeft = false;
enemyArray[counter1].rect.move(0, -7);
}
else if ((enemyArray[counter1].direction == 3 || enemyArray[counter1].rect.getPosition().x >= wallArray[counter2].rect.getPosition().x)) //Left
{
enemyArray[counter1].canMoveLeft = false;
enemyArray[counter1].canMoveUp = false;
enemyArray[counter1].canMoveDown = false;
enemyArray[counter1].rect.move(7, 0);
}
else if ((enemyArray[counter1].direction == 4 || enemyArray[counter1].rect.getPosition().x <= wallArray[counter2].rect.getPosition().x)) //Right
{
enemyArray[counter1].canMoveRight = false;
enemyArray[counter1].canMoveUp = false;
enemyArray[counter1].canMoveDown = false;
enemyArray[counter1].rect.move(-7, 0);
}
}
counter2++;
}
counter1++;
}
//Knock Back enemy away from sword && sword2
counterKnockBack++;
counter2 = 0;
for (iter4 = enemyArray.begin(); iter4 != enemyArray.end(); iter4++)
{
if (enemyArray[counter2].knockback == true)
{
if (enemyArray[counter2].isCollided == false)
{
if ((Player1.rect.getPosition().y > enemyArray[counter2].rect.getPosition().y))
{
enemyArray[counter2].rect.move(0, -3); //up
}
else if ((Player1.rect.getPosition().y < enemyArray[counter2].rect.getPosition().y))
{
enemyArray[counter2].rect.move(0, 3); //down
}
if ((Player1.rect.getPosition().x > enemyArray[counter2].rect.getPosition().x))
{
enemyArray[counter2].rect.move(-3, 0); //left
}
else if ((Player1.rect.getPosition().x < enemyArray[counter2].rect.getPosition().x))
{
enemyArray[counter2].rect.move(3, 0); //right
}
if (counterKnockBack >= 20)
{
enemyArray[counter2].knockback = false;
}
}
}
counter2++;
}
//turn off collided counter
counterCollided++;
counter2 = 0;
for (iter4 = enemyArray.begin(); iter4 != enemyArray.end(); iter4++)
{
if (enemyArray[counter2].isCollided == true)
{
if (counterCollided >= 30)
enemyArray[counter2].isCollided = false;
}
counter2++;
}
I have no idea why the enemy is able to sometimes simply walk right through the wall without being knocked back. So how can I fix this, any ideas?
Without reading the code completely I can already tell you that your collision detection code is wrong. Mostly because you are moving your objects directly, probably without checking for collisions within your rect::move function.
It is possible that the rect::move function will move objects through the walls without triggering any collision reaction code. Consider the following scenario:
First frame:
enemyArray[counterX].rect.move(3, 0);
Second frame:
The enemy object is moved behind the wall and will not trigger the collision detection code.
My advise is (despite the obvious one: read some books): for each enemy store its previous location and check for collision not between the enemy and the wall's rectangle but between wall and a rectangle between two enemy positions. Something like that:
This is of course only one of the possible scenarios when your collision detection code would be error-prone.

c++ card game, hand being dealt more than once when a new round deck is created / new round is started

I'm writing a video poker game and I'm having a problem with a hand being drawn and then replaced when a new round is started.
The idea is you start with five cards, you select which cards to keep and then the others are switched out when you click "deal", you will then be shown your new cards and told what you've won, after that you will be asked to start a new round, when you click "new round" the deck that was used previously should be discarded, a new hand taken from that deck and then drawn onto the screen.
The first two things work, the problem is that when I click "new round" it very quickly draws the hand to the screen and then replaces it with another hand, this doesn't effect the players bet, the money they have, absolutely nothing, it took me a while to notice that it was actually happening.
I can't post a working example, that would require the entire game to be uploaded (my code isn't very elegant) but I will try to show the relevant text.
Main:
int main(int argc, char *argv[])
{
srand(time(NULL));
//load static cards
SDL_Surface* deal_card = load_surface("resources/images/cards/misc/deal.png");
SDL_Surface* round_card = load_surface("resources/images/cards/misc/new_round.png");
SDL_Surface* held = load_surface("resources/images/cards/effect/held.png");
//initiate standard sdl modules
if(!init())
{
printf("fail init");
}
//initiate SDL_ttf
else if(TTF_Init() == -1)
{
printf("TTF INit fail");
}
else
{
//should exit
bool quit = false;
//events
SDL_Event e;
//font and font colour to be used for rendering text1
TTF_Font* font = TTF_OpenFont("resources/fonts/OpenSans-Regular.ttf", 18);
SDL_Color text_colour = {236, 251, 100};
//create a new deck, draw out a hand, sort it numerically, setup images and positions for cards
vector<card>my_deck = new_shuffled_deck();
vector<card>my_hand = hand(my_deck);
sort_hand(my_hand);
setup_hand(my_hand);
//should switch cards that are not held and remove those used
//must be TRUE on start otherwise the first deal will duplicate cards
bool switch_hand = true;
int round_number = 1;
//get or set bet information
read_bet(player_pot, cash_borrowed);
while(!quit)
{
//starting mouse position
int mouse_x_pos = 0;
int mouse_y_pos = 0;
//push current mouse position to starting mouse positions
SDL_GetMouseState(&mouse_x_pos, &mouse_y_pos);
//set up to blit hold icon
update_hold_position(my_hand);
//check for winning hand
winning_hand hand_details = my_scores.card_check(my_hand, bet_amount);
//setup render and blit text
render_and_blit_text(font, hand_details, player_pot, cash_borrowed, text_colour);
scoring_text(font, hand_details, text_colour);
//switch out cards that are not held
if(switch_hand == true)
{
swap_cards(my_hand, my_deck);
}
switch_hand = false;
while(SDL_PollEvent(&e) != 0)
{
if(e.type == SDL_QUIT)
{
quit = true;
}
if(e.type == SDL_MOUSEBUTTONDOWN)
{
//set mouse position to carry over without resetting
int n_mouse_pos_x = mouse_x_pos;
int n_mouse_pos_y = mouse_y_pos;
//check if card is clicked, if is selected de-select, if not selected then select
for(size_t cpc = 0; cpc < my_hand.size(); cpc++)
{
// if mouse position is in range of left side of card and right side of card
if(n_mouse_pos_x > my_hand[cpc].position.x and n_mouse_pos_x < my_hand[cpc].position.x + my_hand[cpc].image->w &&
n_mouse_pos_y > my_hand[cpc].position.y and n_mouse_pos_y < my_hand[cpc].position.y + my_hand[cpc].image->h)
{
//if clicked un-click, if un-clickde click
if(my_hand[cpc].selected == 0)
{
my_hand[cpc].selected = 1;
}
else if(my_hand[cpc].selected == 1)
{
my_hand[cpc].selected = 0;
}
}
}
//if deal is clicked
if(n_mouse_pos_x > deal_rect.x and n_mouse_pos_x < deal_rect.x + deal_card->w &&
n_mouse_pos_y > deal_rect.y and n_mouse_pos_y < deal_rect.y + deal_card->h)
{
//switch held cards, if last round switch entire hand, update cash
deal_clicked(switch_hand, round_number, my_hand, my_deck, cash_borrowed, player_pot, amount_won,
bet_amount, hand_details);
}
}
}
//blit section
//blit cards to screen
blit_cards(my_hand, round_number, held, screen_surface, deal_rect, round_card, deal_card);
SDL_Surface* fill_screen;
fill_screen = SDL_CreateRGBSurface(0, screen_width, screen_height, 32, 0, 0, 0, 0);
SDL_UpdateWindowSurface(window);
SDL_FillRect(screen_surface, 0, SDL_MapRGB(fill_screen->format, 18, 17, 233));
SDL_FreeSurface(fill_screen);
SDL_Delay(30);
}
}
close();
return 0;
}
Swap cards:
void swap_cards(vector<card>&my_hand, vector<card>&my_deck)
{
for(size_t b = 0; b < my_hand.size(); b++)
{
if(my_hand[b].selected == false)
{
SDL_FreeSurface(my_hand[b].image);
//replace card with card of the same index from the deck
my_hand[b] = my_deck[b];
// remove card from deck so it cannot be chosen again
my_deck.erase(my_deck.begin() + b);
}
else
{
// this prevents memory leak on held cards, no idea why.
SDL_FreeSurface(my_hand[b].image);
}
}
//set up images and position for cards again
setup_hand(my_hand);
}
Deal clicked:
void deal_clicked(bool &switch_hand, int &round_number, vector<card>&my_hand, vector<card>&my_deck,
int &cash_borrowed, int &player_pot, int &amount_won, int& bet_amount, winning_hand &hand_details)
{
switch_hand = true;
round_number++;
// aka if(round_number % 2 == 0 and round_number != 0)
if(round_number == 3)
{
//free card surface images
for(size_t d = 0; d < my_hand.size(); d++)
{
SDL_FreeSurface(my_hand[d].image);
}
vector<card>().swap(my_deck);
//replace deck with new deck
my_deck = new_shuffled_deck();
//draw new hand
vector<card>().swap(my_hand);
my_hand = hand(my_deck);
//sort hand by card number
sort_hand(my_hand);
//load images and position cards
setup_hand(my_hand);
//set round number back to beginning
round_number = 1;
//distribute winnings and take next bet amount
amount_won = hand_details.hand_score;
if(cash_borrowed > 0)
{
cash_borrowed -= amount_won;
}
else if(cash_borrowed < 0)
{
player_pot += abs(cash_borrowed);
cash_borrowed = 0;
}
else
{
player_pot += amount_won;
}
if(player_pot <= 0)
{
cash_borrowed +=5;
}
else
{
player_pot -= bet_amount;
}
write_bet(player_pot, cash_borrowed);
}
}
Hopefully that should be enough for someone to have an idea about where my problem is coming from.
If anyone wants more code I can post it, it jut gets even more messy, these are the only areas I think could be causing the problem, then again I can't figure out what it is.
EDIT:
Solved, duplicate call to the setup_hand function.
Duplicate call to setup_hand function.

How to move an entity with a mouse click?

Ok i now manage to figure out the problem but now another issue appear, my robot seem to move on its own to another point which i have no idea where its from. Here my code
His code make this robot move to the location i click on the terrain.
bool DemoApp::nextLocation(void){
mDestination = mtoward;
mRobotDir = mDestination - mRobotNode[0]->getPosition();
mDistance = mRobotDir.normalise();
return true;
}
bool DemoApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if (mRobotDir == Ogre::Vector3::ZERO) {
if (nextLocation()) {
// Set walking animation
mAnimationState = mRobot[0]->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}//if
}else{
Ogre::Real move = mWalkSpeed * evt.timeSinceLastFrame;
mDistance -= move;
if (mDistance <= 0.0f){
mRobotNode[0]->setPosition(mDestination);
mRobotDir = Ogre::Vector3::ZERO;
// Set animation based on if the robot has another point to walk to.
if (!nextLocation()){
// Set Idle animation
mAnimationState = mRobot[0]->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}else{
// Rotation Code will go here later
Ogre::Vector3 src = mRobotNode[0]->getOrientation() * Ogre::Vector3::UNIT_X;
if ((1.0f + src.dotProduct(mRobotDir)) < 0.0001f) {
mRobotNode[0]->yaw(Ogre::Degree(180));
}else{
Ogre::Quaternion quat = src.getRotationTo(mRobotDir);
mRobotNode[0]->rotate(quat);
} // else
}//else
}else{
mRobotNode[0]->translate(mRobotDir * move);
} // else
} // if
mAnimationState->addTime(evt.timeSinceLastFrame);
}
Here is the raycast code for my mouse click
Ogre::Terrain* pTerrain = mTerrainGroup->getTerrain(0, 0);
Ogre::Viewport* vp = this->mWindow->getViewport(0);
Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(static_cast<float>(mMouse->getMouseState().X.abs)/mMouse->getMouseState().width, static_cast<float>(mMouse->getMouseState().Y.abs)/mMouse->getMouseState().height);
std::pair <bool, Ogre::Vector3> result;
result = pTerrain->rayIntersects(mouseRay, true, 0);
if (result.first = true)
{
mtoward = result.second - mRobotNode[0]->_getDerivedPosition();
mRobotNode[0]->translate(mtoward, Ogre::Node::TS_LOCAL);
}

Box2d Cocos2d ContactListener detecting collision

My problem is very simple, but I can't fix it.
I have a radar that is rotating and I have a player that is moving with a Joystick
Well, I just want to detect the collision between the radar and the player. It works perfectly when both are moving but it doesn't when radar is moving and my player is not.
Here you have the code to detect it and how it works:
//moves radar
[self schedule:#selector(loopRadar) interval: 12];
//moves player with joystick
body->SetLinearVelocity(b2Vec2(scaledVelocity.x*dt, scaledVelocity.y*dt));
actor.position = ccp(body->GetPosition().x * PTM_RATIO,
body->GetPosition().y * PTM_RATIO);
// DETECTS COLLISION BETWEEN RADAR AND PLAYER
std::vector<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
pos != _contactListener->_contacts.end(); ++pos) {
MyContact contact = *pos;
if ((contact.fixtureA == radarBody->GetFixtureList() && contact.fixtureB == body->GetFixtureList()) ||
(contact.fixtureA == body->GetFixtureList() && contact.fixtureB == radarBody->GetFixtureList())) {
//DO SOMETHING LIKE GAME OVER
}
}
//ENDS COLLISION
MycontactListener class:
#import "MyContactListener.h"
MyContactListener::MyContactListener() : _contacts() {
}
MyContactListener::~MyContactListener() {
}
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 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) {
}
So, the problem is that when radar goes through the player and player isn't moving, it doesn't detect collision, but when both are moving it works perfectly.
Any tips?
Thank you very much!
Worked adding these lines as "LearnCocos2D" said, setting both bodies awake
body->SetAwake(TRUE);
radarBody->SetAwake(TRUE);
Thank you very much!