Cannot get class data in box2d collision callback - c++

I'm building a simple 2D game in C++ and am using Box2D for collision detection.
I have an Entity class from which an Enemy and Bullet class is derived, and an EnemySquare class is derived from the Enemy class.
I'm trying to detect collisions between the EnemySquare class and the Bullet class (will have more collision combinations to process later in development). To do this I have created a CollisionManager class deriving from the Box2D class b2ContactListener which handles the collision callbacks.
Each Entity instance has a private variable m_collisionObjectType which is an enum class of object types (shown below).
In the BeginContact() callback, I'm trying to cast the box2d fixture's user data to the correct class type so I can apply damage, mark bullets for removal etc.
(non-relevant code removed for simplicity)
Object Type Enum:
enum class COLLISION_OBJECT_TYPE {BULLET, ENEMY, PLAYER};
Entity class
.h
class Entity
{
public:
Entity();
~Entity();
COLLISION_OBJECT_TYPE getCollisionObjectType() { return m_collisionObjectType; }
protected:
b2Body* m_body = nullptr;
b2Fixture* m_fixtures[3];
COLLISION_OBJECT_TYPE m_collisionObjectType;
};
Enemy Class
.h
class Enemy : public Entity
{
public:
Enemy();
~Enemy();
virtual void init(glm::vec2 position, float health, float speed, Player* player, b2World* physicsWorld) = 0;
virtual void update(float deltaTime) = 0;
protected:
float m_health;
float m_speed;
Player* m_playerTarget;
};
Enemy Square Class
.h
class EnemySquare : public Enemy
{
public:
EnemySquare();
~EnemySquare();
void init(glm::vec2 position, float health, float speed, Player* player, b2World* physicsWorld) override;
void update(float deltaTime) override;
};
.cpp
void EnemySquare::init(glm::vec2 position, float health, float speed, Player * player, b2World* physicsWorld) {
// init physics body
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(m_position.x, m_position.y);
bodyDef.fixedRotation = false;
bodyDef.angle = 0;
bodyDef.userData = this;
m_body = physicsWorld->CreateBody(&bodyDef);
// init physics fixtures
b2PolygonShape squareShape;
squareShape.SetAsBox(m_width * 0.5f, m_height * 0.5f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &squareShape;
m_fixtures[0] = m_body->CreateFixture(&fixtureDef);
}
Bullet Class
.h
class Bullet : public Entity
{
public:
Bullet(
b2World* world,
glm::vec2 startPosition,
glm::vec2 direction,
Tempest::glTexture texture,
float width,
float height,
float damage,
float speed,
float range
);
~Bullet();
// methods are unrelated
private:
// private variables are unrelated
};
.cpp
Bullet::Bullet(
b2World* world,
glm::vec2 startPosition,
glm::vec2 direction,
Tempest::glTexture texture,
float width,
float height,
float damage,
float speed,
float range
) {
// Make the body
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(m_position.x, m_position.y);
bodyDef.fixedRotation = true;
bodyDef.angle = 0;
bodyDef.userData = this;
m_body = world->CreateBody(&bodyDef);
// Create the box
b2PolygonShape boxShape;
boxShape.SetAsBox(m_height * 0.4f, m_width * 0.5f);
b2FixtureDef boxDef;
boxDef.shape = &boxShape;
m_fixtures[0] = m_body->CreateFixture(&boxDef);
m_collided = false;
m_collisionObjectType = COLLISION_OBJECT_TYPE::BULLET;
}
In my the CollisionManager class I'm trying to retrieve the colliding fixture's userData (which is a void*) then cast it to an Entity* to call the getCollisionObjectType() method. When I know what type of entity I'm dealing with I then want to cast it to the correct object type and do things like apply damage, mark bullets for removal etc. Code below:
void CollisionManager::BeginContact(b2Contact * contact) {
void* fixtureABodyData = contact->GetFixtureA()->GetBody()->GetUserData();
void* fixtureBBodyData = contact->GetFixtureB()->GetBody()->GetUserData();
if (fixtureABodyData && fixtureBBodyData) {
Entity* fixtureAData = static_cast<Entity*>(fixtureABodyData);
Entity* fixtureBData = static_cast<Entity*>(fixtureBBodyData);
if (fixtureAData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::BULLET) {
std::cout << "A BULLET" << std::endl;
}
if (fixtureBData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::BULLET) {
std::cout << "B BULLET" << std::endl;
}
if (fixtureAData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::ENEMY) {
std::cout << "A ENEMY" << std::endl;
}
if (fixtureBData->getCollisionObjectType() == COLLISION_OBJECT_TYPE::ENEMY) {
std::cout << "B ENEMY" << std::endl;
}
std::cout << "----------------------" << std::endl;
}
}
For some reason, the casting works for the Bullet class but not for the Enemy class. I think it returns a nullptr. So I know one of the colliding bodies is a bullet, but I can't tell what the second body is.
I have a feeling I'm doing something wrong with the static_cast calls or it might be because the EnemySquare class is twice removed from the Entity class? or I could be doing something wrong in the Box2D code. Any advice would be appreciated!

Set the m_collisionObjectType member variable for the Enemy derived class. Preferably to COLLISION_OBJECT_TYPE::ENEMY.
As the code appears now, it's only setting m_collisionObjectType in the code for the Bullet derived class. So the Enemy derived class instances are getting constructed with their m_collisionObjectType member variables uninitialized. I.e. the value out of the getCollisionObjectType() method could be whatever was in the memory location of m_collisionObjectType before it got used by the constructor.
Hope this helps!

Related

How to handle collisions in a 2d console game

I'm making a simple console game using windows.h library. Class Game has a map, which is an array of type CHAR_INFO (structure of unicode symbol and its color). This class also has an array of Enemy and Projectile objects. Every iteration game updates the position of each object in the game using Entity's method called move(), which calculates the next position of an entity and checks if there is a symbol which represents an enemy or a projectile. If there is, method move() calls one of these functions:
virtual bool onProjectileCollision() = 0; //collision methods return 0 if the entity is dead
virtual bool onEnemyCollision() = 0;
these functions are overriden by Enemy and Projectile classes like this:
bool onProjectileCollision() override {
return 1;
};
bool onEnemyCollision() override {
return 1;
};
The problem is that I don't know which object the entity collides with (I know only its class), therefore i can't call any method of this object:
class Enemy : public Entity {
int hp;
public:
void die() {
hp = 0;
}
bool onProjectileCollision() override {
die(); //I can do this
return 1;
};
}
class Projectile : public Entity {
public:
bool onEnemyCollision() override {
enemy.die(); // but I can't do this
return 0;
};
}
How should i build a connection between these objects ?

(SFML) Issues with inheritance (C++)

So, I'm using SFML and I'm trying to setup an entity class and a player sub-class that inherits from it, but this is my first time working with inheritance and I'm having issues:
First, I have an AssetManager class that I cobbled together from different sources, since I don't quite understand how they work yet:
AssetManager.h:
class AssetManager {
public:
AssetManager();
static sf::Texture& LoadTexture(std::string const& path);
static sf::SoundBuffer& LoadSoundBuffer(std::string const& path);
static sf::Font& LoadFont(std::string const& path);
private:
std::map<std::string, sf::Texture> m_Textures;
std::map<std::string, sf::SoundBuffer> m_SoundBuffers;
std::map<std::string, sf::Font> m_Fonts;
static AssetManager* sInstance;
};
But you can only need to see the part relating to textures, here is that part from AssetManager.cpp:
AssetManager* AssetManager::sInstance = nullptr;
AssetManager::AssetManager() {
assert(sInstance == nullptr);
sInstance = this;
}
sf::Texture& AssetManager::LoadTexture(std::string const& path) {
auto& texMap = sInstance->m_Textures;
auto pairFound = texMap.find(path);
if (pairFound != texMap.end()) {
return pairFound->second;
}
else {
auto& texture = texMap[path];
texture.loadFromFile(path);
return texture;
}
}
Then an object of that class is included inside a Sprite class, that facilitates declaring sprites for me.
Sprite.h:
class Sprite {
public:
AssetManager manager;
sf::Texture m_Texture;
sf::Sprite m_Sprite;
sf::Vector2f sprite_scale;
sf::Vector2u original_size;
sf::Vector2f texture_size;
Sprite(std::string path,sf::IntRect rect,sf::Vector2f size);
};
Sprite.cpp:
Sprite::Sprite(std::string path, sf::IntRect rect, sf::Vector2f size) {
m_Texture = sf::Texture(AssetManager::LoadTexture(path));
m_Sprite.setTextureRect(rect);
m_Sprite.setTexture(m_Texture);
original_size = m_Texture.getSize();
texture_size.x = static_cast<float>(original_size.x);
texture_size.y = static_cast<float>(original_size.y);
sprite_scale.x = size.x / texture_size.x;
sprite_scale.y = size.y / texture_size.y;
m_Sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
m_Sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
}
Then, an object of the Sprite class is itself included within an Entity class.
Entity.h:
class Entity {
public:
Sprite entity_sprite;
int health;
float speed;
bool collision = false;
bool entity_collision(sf::Sprite entity2_sprite);// Entity.cpp only contains the declaration of this function so far so no need to post it.
};
Now, for a reason I don't understand, I'm not able to directly assign any arguments to the entity_sprite object when declaring it, and I'm only able to declare it with no arguments, despite the class having not a default constructor.
However I am able to get around it using assignment:
Entity entity_sprite = Entity("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
But this isn't the main issue, and using the Entity class directly is not what I'm trying to do, I'm trying to write the Player sub-class and use that instead:
Player.h:
class Player:public Entity {
Player() {
entity_sprite = Sprite("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
}
};
Now I'm once again not able to directly assign arguments to the object directly, because the call of an object of a class type without appropriate operator() or conversion function to pointer-to-function type (Interestingly enough if I go back to the Entity object and assign the arguments there and pretend the errors don't exist, the error produced by the Player class changes to Too many arguments' and 'Too many initializers
This is getting too confusing.
Nonetheless, I am once again able to get around it using assignment, exactly the same as before, except this time I get an error saying the default constructor "Entity" cannot be referenced -- its a deleted function., so I go back to the Entity class and add an empty constructor like this: Entity() { } but then this constructor gives me another error saying no default constructor exists for class "Sprite", even though the Entity class doesn't exactly inherit from the Sprite class, so I go back even further to the Sprite class and give that an empty constructor: Sprite(){}, and the errors seemingly disappear, that is until I declare a Player object in the main.cpp file and try to compile and get a debug error pointing to the following line in AssetManager.cpp: assert(sInstance == nullptr);
So many problems for such a seemingly simple task, how do I pull myself out of this?
Ok, after consulting the SFML Forums, I have refactored the code to the following:
Sprite.h:
#include "AssetManager.h"
class Sprite{
public:
sf::Sprite m_sprite;
sf::Vector2f sprite_scale;
sf::Vector2u original_size;
sf::Vector2f texture_size;
Sprite(){}
sf::Sprite set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size);
};
Sprite.cpp:
#include "Sprite.h"
sf::Sprite Sprite::set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size) {
sf::Sprite spr(tx);
spr.setTextureRect(rect);
original_size =tx.getSize();
texture_size.x = static_cast<float>(original_size.x);
texture_size.y = static_cast<float>(original_size.y);
sprite_scale.x = size.x / texture_size.x;
sprite_scale.y = size.y / texture_size.y;
spr.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
spr.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));
return spr;
}
Entity.h:
#pragma once
#include "Sprite.h"
#include "collision.h"
#include "Timer.h"
class Entity {
public:
Sprite spr;
sf::Sprite entity_sprite;
int health;
float max_speed;
sf::Vector2f speed;
sf::Vector2f direction;
float acceleration;
bool collision = false;
timer t;
float acc_time;
};
Player.h:
#pragma once
#include "Entity.h"
class Player:public Entity {
public:
Player();
float acc_time = t.accumulate_time();
void keyboard_controls();
void mouse_controls(sf::Vector2f cursor);
};
Player.cpp:
#include "Player.h"
#include <math.h>
Player::Player() {
speed = { 0,0 };
acceleration = 2;
max_speed = 500 + acceleration;
entity_sprite = spr.set_sprite(AssetManager::LoadTexture("res/wildcard.png"), { 0,0,60,63 }, { 60,63 });
}
In short, the Sprite class' constructor is replaced with a method that has the same exact role, that way I can simply declare a Sprite object with no parameters inside the Entity class, and I won't have any issues with the derived Player class since I won't be asked to create default constructors for both the Sprite and Entity classes.

Calling a constructor of a class, inherited by multiple classes

Straight to the point:
I've got 2 classes. One stores one set of information, another - different information.
.h file
class Direction
{
private:
std::vector<float> dir;
public:
Direction(std::vector<float> objDir); ......};
.cpp file
#ifndef frw_dir_ed
#define frw_dir_ed
#include "frw_direction.h"
#endif
FRW::Direction::Direction(std::vector<float> objDir = { .0f, .0f })
{
for (int i = 0; i < 2; i++)
dir[i] = objDir[i];
}
Direction(float x, float y);
Another .h file:
class Position
{
private:
float posX;
float posY;
public:
Position(float x, float y);
Another .cpp file:
#ifndef frw_pos_ed
#define frw_pos_ed
#include "frw_position.h"
#endif // !frw_pos_ed
FRW::Position::Position(float x = 0, float y = 0)
{
setPos(x, y);
}
I also have a third class. This one inherits 2 previous.
class gameObj : public Position, public Direction
{
public:
gameObj(float x, float y, std::vector<float> direction, bool renderable);
gameObj(float posX, float posY, float dirX, float dirY, bool renderable);
//some funcs, destructor
private:
FRW::Position objPos;
FRW::Direction objDir;
bool isRendered;
};
That was a header file, now .cpp:
FRW::gameObj::gameObj(float x = 0.5f, float y = 0.5f, std::vector<float> direction = { .0f, .0f }, bool renderable = true)
: FRW::Direction::Direction(direction), FRW::Position::Position(x,y)
{
isRendered = renderable;
}
FRW::gameObj::gameObj(float posX = 0.5f, float posY = 0.5f, float dirX = .0f, float dirY = 0.f, bool renderable = true)
: FRW::Direction::Direction(dirX, dirY), FRW::Position::Position(posX, posY)
{
isRendered = renderable;
}
C2456 compiler error: member function or nested class in costructor initializer list
Error 3 error C2535: 'void FRW::gameObj::__dflt_ctor_closure(void)' : member function already defined or declared.
Please, can anyone tell me, which concept of OOP I missed? Why I am getting this error?
You either need to inherit from a class or have an element of that type as a member, not both! i.e. this:
class gameObj
{
public:
// ...
private:
FRW::Position objPos;
FRW::Direction objDir;
bool isRendered;
};
or this:
class gameObj : public Position, public Direction
{
public:
// ...
private:
bool isRendered;
};
but not this:
class gameObj : public Position, public Direction
{
public:
// ...
private:
FRW::Position objPos;
FRW::Direction objDir;
bool isRendered;
};
(Actually it's possible you'd want the last one, but very rare in practice.) With the last one, you end up with two directions in gameObj: the gameObj::objDir member, and the direction that the gameObj inherits from. In this case you probably want the member variable (a person has a direction, but it's not true that a person is a direction).This is called using composition rather than inheritance, and it's usually best if you can get away with it. As guide, you normally shouldn't use inheritance unless you need virtual functions. The reason for the compilation error is that you're only initialising one of those two directions (and one of the two positions).
By the way, the error would have been hidden by the fact that you have default values for the constructors. But they need to be in the header than the .cpp (otherwise only code in the .cpp after the definitions will "know" about the defaults).
Edit: Additionally, the code FRW::Direction::Direction(dirX, dirY) should be FRW::Direction(dirX, dirY). This is the real cause of the compilation error (but once you fix it I think you'll get the error I mention above).

C++ (Arduino wrapper): variable or field declared void arduino

C++ (Arduino wrapper) question: This is related to this thread on double pointer member access regarding a shoot em up game.
I have a base class (Sprite), and from this other classes are derived - Alien and Player. For collision detection I want to pass pointers to Alien and Player, then access coordinates as in:
void Collision( Alien *pAlien, Player *pPlayer )
{
// obtain alien and player's (x,y) and do collision check here
pAlien->getX();
pPlayer->getX();
}
But after declaring the above function after the class I get this:
error: variable or field 'Collision' declared void
My question is: How can I resolve this? streamlined code and a screen shot are shown below.
/*****************************************************************************************/
// Bass class - has a form/shape, x and y position also has a method of moving
class Sprite
{
public:
Sprite(unsigned char * const spacePtrIn, unsigned int xInit, unsigned int yInit);
protected:
};
/*****************************************************************************************/
// Derived class "Alien" - has a specific form/shape, and specific (x,y) position
class Alien : public Sprite
{
public:
Alien();
virtual void Move();
};
/*****************************************************************************************/
// Derived class "Player" - has a specific form/shape, and specific (x,y) position
class Player : public Sprite
{
public:
Player(): Sprite(&spaceShip[0], xPlayer(), yPlayer()) {}
virtual void Move();
};
/*****************************************************************************************/
/*****************************************************************************************/
void Collision( Alien *pAlien, Player *pPlayer )
{
// obtain alien and player's (x,y) and do collision check here
pAlien->getX();
pPlayer->getX();
}
/*****************************************************************************************/
/*****************************************************************************************/

Inheriting from Transformable and Drawable in SFML

I'm trying to inherit from Transformable and Drawable in SFML in order to make my objects... well, transformable and drawable. I'm making a simple breakout game, but perhaps I'm going about this the wrong way. Here's my code:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
class Player : public sf::Transformable, public sf::Drawable {
public:
Player(int x, int y);
~Player() {};
sf::RectangleShape p_rect;
void doMovement(const sf::RenderWindow& window);
sf::FloatRect getGlobalBounds() const;
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
target.draw(p_rect, states);
}
};
class Ball : public sf::Transformable, public sf::Drawable {
public:
Ball(int r, int x, int y);
~Ball() {};
sf::CircleShape b_circle;
void doXMovement();
void doYMovement();
bool doXCollisions(const Player& player);
bool doYCollisions(const Player& player);
sf::FloatRect getGlobalBounds() const;
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
states.transform *= getTransform();
target.draw(b_circle, states);
}
bool right;
bool up;
};
Player::Player(int x, int y) {
p_rect = sf::RectangleShape(sf::Vector2f(x, y));
}
void Player::doMovement(const sf::RenderWindow& window) {
setPosition(sf::Mouse::getPosition(window).x, 500);
if (getPosition().x < 0)
setPosition(0, 500);
else if (getPosition().x > 720)
setPosition(720, 500);
}
sf::FloatRect Player::getGlobalBounds() const {
return getTransform().transformRect(p_rect.getGlobalBounds());
}
Ball::Ball(int r, int x, int y) {
b_circle = sf::CircleShape(r);
b_circle.setPosition(x, y);
right = true;
up = false;
}
void Ball::doXMovement() {
if (right)
move(1, 0);
else
move(-1, 0);
}
void Ball::doYMovement() {
if (up)
move(0, -1);
else
move(0, 1);
}
bool Ball::doXCollisions(const Player& player) {
bool coll;
if (getGlobalBounds().intersects(player.getGlobalBounds())) {
right = !right;
coll = true;
} else
coll = false;
if (getPosition().x >= 800 - b_circle.getRadius())
right = false;
else if (getPosition().x <= 0)
right = true;
return coll;
}
bool Ball::doYCollisions(const Player& player) {
bool coll;
if (getGlobalBounds().intersects(player.getGlobalBounds())) {
up = !up;
coll = true;
} else
coll = false;
if (getPosition().x <= 0)
up = false;
return coll;
}
sf::FloatRect Ball::getGlobalBounds() const {
return getTransform().transformRect(b_circle.getGlobalBounds());
}
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Breakout");
window.setMouseCursorVisible(false);
Player player(80, 10);
Ball ball(3, 100, 100);
sf::Clock clock;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
player.doMovement(window);
if (clock.getElapsedTime().asMilliseconds() >= 3) {
clock.restart();
if (!ball.doYCollisions(player))
ball.doXCollisions(player);
ball.doYMovement();
ball.doXMovement();
}
window.clear(sf::Color::Black);
window.draw(player);
window.draw(ball);
window.display();
}
return 0;
}
Now moving and drawing work (nearly) as expected, however collisions are a bit wonky. First my collisions problems:
Do I need to implement the getGlobalBounds function the way I did? Or is there a better way to do it with things included in Transformable and Drawable?
Should I be performing transformations on the shapes directly, or should I pass the transformations to the draw function like I currently am?
Something strange is also happening with the drawing which is probably a quick fix. Right now the getPosition method returns incorrect values for my ball object. The area it returns seems to be shifted down and to the right a bit. Any reason that might be?
Thanks for any help you are able to give!
EDIT: Also any general C++ tips are welcome, I'm still a beginner.
If I were you I would define a new class, called TransformableAndDrawable like this:
class TransformableAndDrawable : public sf::Transformable, public sf::Drawable {
// Your code here
}
In this class you should define all the members which are generally needed by your transformable and drawable classes. Also, in this class you should define all the methods which can be generally implemented in your transformable and drawable classes. Then, your classes should be inherited from TransformableAndDrawable, like this:
class Player : TransformableAndDrawable {
// Your code here
}
Now, the answer to the first question is: I would implement in the TransformableAndDrawable class the given method if it is a general method, so all the classes inherited from TransformableAndDrawable will have this method.
Instead of giving different names, like p_rect and p_circle, name these members with the same name, like p_shape, so you will have no naming issues. Also, I believe that you can declare your p_shape to be of an ancestor class or interface (I do not know what classes are defined in the library you are working with) and only when needed specify the nature of the shape (whether it is a circle or a rectangle or something else).
As for the second questions: I like the way you have implemented things, but you have made two mistakes:
it is not scalable: we want a general solution, a class which can be used for any shape you are working with now and in the future, don't we?
it is not general enough: When I want to know the global bounds of a shape, then I am not interested of the nature of the shape, I would prefer your code to handle the nature of the shape without me knowing it
In short, you should do the following:
Create a wrapper class which will be inherited from Transformable and Drawable
In your wrapper class, be agnostic to the nature of the shape, be as general as possible, hopefully there is some class or interface which is ancestor to both RectangleShape and CircleShape.
Inherit all your drawable and transformable classes from your wrapper class, so you will have a shared functionality among your classes
If something in your wrapper class is not good for a class which was inherited from it, overwrite the method in that class.
EDIT:
I have looked into the library you are using in more detail and found out that there is a class called Shape, which is the ancestor to both CircleShape and RectangleShape. So, instead of these classes use Shape and your code will be more general and reusable.