I have an Entity baseclass which the classes Player and Enemy Inherit.
class Entity
{
public:
virtual void Update(sf::RenderWindow &window) {};
virtual void Draw(sf::RenderWindow &window) {};
};
Both player and enemy contain a sprite object that looks like this:
class Player : Entity
{
public:
sf::Sprite sprite
void Update(sf::RenderWindow &window);
void Draw(sf::RenderWindow &window)
}
Player and Enemy are created inside a vector which is set up like this:
class EntityManager
{
public:
void CollisionCheck();
private:
std::vector<Entity*> entityVector;
}
I'm looking to use a collision detection function of this form:
bool Collision::CircleTest(const sf::Sprite& Object1, const sf::Sprite& Object2)
So I'm trying to do something like this:
void EntityManager::ColCheck()
{
if (Collision::CircleTest(entityVector[0]->sprite, entityVector[1]->sprite))
{
cout << "COLLISION\n";
}
}
This results in the following compile error:
‘class Entity’ has no member named ‘sprite’
I'm unsure how to create a dummy sprite in Entity so that I can access the player and enemy sprites using the above method. Is this possible?
I'm stumped and would greatly appreciate any help anyone can offer!
If everything in your code that derives from Entity has a sprite object, then you should declare that object in the base class.
Not declaring the object in the base class means that there could be a class inheriting from Entity that does not have a sprite object, which means that ColCheck has no valid basis for assuming that elements of entityVector point to something that has a variable called sprite. Make sense?
You probably shouldn't create a dummy unless having a sprite is something ALL entities have.
What you might want is to use a visitor pattern or possibly one of the many multiple-dispatch implementations. Which and what will end up having to be up to you.
If both Player and Enemy classes contain sprite, why not declare it inside Entity? This should solve your problem.
You could make a member function sprite() that is declared as a pure virtual function inside Entity:
class Entity {
public:
virtual void Update(sf::RenderWindow &window) {};
virtual void Draw(sf::RenderWindow &window) {};
virtual sf::Sprite& sprite() = 0;
};
Then, the Player and Enemy implementations would return the sf::Sprite instance variables each has. However, the other posters bring up a valid point; it might make sense to have the sprite be in the base class if all derived classes are going to have one.
Related
(sorry for my bad english)
I have a base class with vector of pointers on Drawable objects in it and method draw() that uses data from this vector.
class GameObject
{
protected:
std::vector<Drawable*> drawable;
...
void GameObject::draw() { for (const auto& object : drawable) window.draw(*object); }
In the derived classes I want to have an ability to add some Drawable objects
class Player : public GameObject
{
protected:
RectangleShape shape;
...
Player::Player(float x, float y, float z)
{
shape.setPosition [...]
drawable.push_back(&shape);
...
and draw them using method of base class pointer
std::vector<GameObject*> gameObjects;
...
for (auto& gameObject : gameObjects) gameObject->draw();
The program crashes (I think because the base class don't know anything about vector data in derived class).
I understand that I could make this method pure virtual and define it in the derived classes, but it's not that convenient. Maybe there is another way more similar to this?
upd:
Level::Level()
{
player = Player(500.f, 500.f); //Player player; in header file
gameObjects.push_back(&player);
}
void Level::display()
{
for (auto gameObject : gameObjects) gameObject->draw();
}
The problem is in the code added by your edit -- it looks like my crystal ball is working today.
You're creating a temporary Player and moving it into the player member variable. That ends up with a vector holding the address of the shape inside the temporary Player, which is immediately destroyed, leaving a dangling pointer.
Use a ctor-initializer-list to avoid the move:
Level::Level()
: player(500.f, 500.f /* where did Z go? */)
{
gameObjects.push_back(&player);
}
And disable the assignment operators to prevent doing this by accident in other places:
class Player
{
// ...
Player& operator=(const Player&) = delete;
Player& operator=(Player&&) = delete;
};
So basically I have a class:
class Rigidbody
{
Collider _collider;
//blah
}
The Collider class looks like
class Collider
{
public:
Collider(Transform trans);
virtual ~Collider();
void SetType(const ColliderType newType){_type = newType;}
const ColliderType GetType(){return _type;}
void SetTransform(const Transform& trans) { _transform = trans; }
const Transform& GetTransform() { return _transform; }
private:
ColliderType _type;
Transform _transform;
};
There are a couple of derived classes; for instance:
class CircleCollider : public Collider
{
public:
CircleCollider(Transform trans);
~CircleCollider();
const float GetRadius(){return _radius;}
void SetRadius(const float newRad) { _radius = newRad; }
private:
float _radius;
};
In my physics class, basically I have to call the correct collision method, based on which derived classes are colliding (the code for Box vs Circle is different to Circle vs Circle). So I use stuff like
if(CircleCollider* circ1 = dynamic_cast<CircleCollider*>(&bodyA.GetCollider()))
{
CircleVsCircle(circ1, circ2)
}
etc.
To test this, I create a Rigidbody, then do
CircleCollider coll(player->GetTransform());
coll.SetRadius(10.0f);
player->SetCollider(coll);
So the player's collider should be an instance of CircleCollider. But when I try to dynamic cast it to CircleCollider, the cast fails.
Any ideas why?
class Rigidbody
{
Collider _collider;
}; // < This had fallen off
In your RigidBody class, you store an instance of Collider. Not something derived from a Collider, but a Collider.
Polymorphism implies indirection : if you wish to store someting derived from Collider, you need to use a pointer or a reference. In your example, that would be a Collider* (you can reset it, and the RigidBody doesn't own it).
I'm just guessing here (since you don't show the GetCollider function), but the GetCollider function returns Rigidbody::_collider then you don't actually have a CircleCollider object, all you have is a Collider object.
For the polymorphism to work the Rigidbody::_collider needs to be a pointer, and actually initialized to a pointer to a CircleCollider object.
Related reading: object slicing (it's what happens if you assign a CircleCollider object to the _collider object).
I've been coding a simple board game to learn concepts of C++ in practice. I have implemented the board: it consists of tiles, each of which is a child class inheriting from a parent class. The board is a class that has a vector of the tiles.
There are several kinds of tiles. Some of them can be bought by players. There are several different kinds of buyable tiles as well with different properties, so I deemed it cute to make a base class TileOnSale for tiles that can be bought and make child classes of the actual types, two of which I have provided in the below code.
Now my problem is that how can I access the child members' functions not defined within the parent class (TileOnSale)? Board gets initialized with all kinds of different tiles, so I can extract a Tile from there using getTile(int location) function. However, this gets interpreted as just a Tile, not a TileOnSale or a StreetTile. I know of no way to grasp StreetTile's buildHouses function this way.
So, is there a robust, or even better, a neat way of doing this? Can I make a template or something to hold Tile objects that might be StreetTiles or StationTiles or something else that is a Tile?
Or should I just redesign the class structure?
Here's a bare bones code. I have tried to provide only what is needed for understanding the question. Also, originally Tile and Board were in their own header files. I decided it not necessary to show the Player class that has a vector of owned TileOnSale objects but which retains the exact same access problem as Board.
// Board.h
#include "Tile.h"
typedef vector<Tile> Tiles;
class Board
{
public:
Board();
~Board();
Tile getTile(int location);
private:
Tiles tiles;
};
// Tile.h
class Tile
{
public:
Tile();
~Tile();
protected:
tileType tile_type; // this is enum containing unique type
string description;
};
class TileOnSale : public Tile
{
public:
TileOnSale();
~TileOnSale();
virtual int getRent() const { return 0; };
};
class StreetTile : public TileOnSale
{
public:
StreetTile();
~StreetTile();
int getRent() override;
void buildHouses(int number);
private:
int houses;
};
class StationTile : public TileOnSale
{
public:
StationTile();
~StationTile();
int getRent() override;
};
EDIT: added a potentially clarifying comment to code.
You might want to take a look at the visitor pattern.
In essence, the visitor allows one to add new virtual functions to a family of classes without modifying the classes themselves; instead, one creates a visitor class that implements all of the appropriate specializations of the virtual function. The visitor takes the instance reference as input, and implements the goal through double dispatch.
The double dispatch means you are actually calling a virtual function twice: first on the subject which in turn polymorphically calls the visitor.
In your case there is just one method, namely building houses, but you might want to add others later (like drawing them on a screen for example). Given your current example you should add this method to Tile and StreetTile:
virtual void accept(Visitor& v) { v.visit(*this); }
This is the Visitor base class implementation:
class Visitor {
public:
virtual void accept(Tile& t) = 0;
virtual void accept(StreetTile& t) = 0;
};
After that you can implement a Builder class:
class Builder: public Visitor {
private:
int numberOfHouses;
public:
Builder(int n): numberOfHouses(n) {}
virtual void accept(Tile& t) {}
virtual void accept(StreetTile& t) {
t.buildHouses(numberOfHouses);
}
};
After that all you have to do is construct such a builder, and call it on every tile in your vector of tiles:
Builder b(10);
for (Tile tile : tiles) {
tile.accept(b);
}
A Simple way is to add a unique id (enum or string) to each type. The player class can ask for the type (defined in the base class) and cast to the derived class accordingly.
Since it needs to call a function on the derived (e.g. specialized) class it has the knowledge to perform the cast.
Having a type ID is also nice for debugging purposes.
I'm new to C++ and i'm having a hard time figuring out what's wrong with my virtual functions. So, here's what i have:
GEntity.h
class GEntity
{
public:
//...
virtual void tick(void);
virtual void render(void);
//...
};
GEntity.cpp
//...
void GEntity::tick(void){}
void GEntity::render(void){}
//...
GLiving.h
class GLiving : public GEntity
{
public:
//...
virtual void tick(void);
virtual void render(void);
//...
};
GLiving.cpp
//...
void GEntity::tick(void){}
void GEntity::render(void){}
//...
Then i have other classes that derive from GLiving (Player, Enemy) which implement their own versions of this two methods:
Player.h
class Player : public GLiving
{
public:
//...
void tick(void);
void render(void);
//...
};
Player.cpp
//...
void GEntity::tick(void)
{
//Here there's some actual code that updates the player
}
void GEntity::render(void)
{
//Here there's some actual code that renders the player
}
//...
Now, if i declare an object of class Player, and call the render/tick method, everything goes well, but i am in a situation in which i add my player to an arraylist (a struct i created) of GEntity, and then, when i get it back, i get it as a GEntity, and i need to call the render/tick methods without knowing it's derived class...
I've tried with the code above, but i get an access violation in the line where i call either the render or tick method, on the extracted GEntity...
...is what i want even possible to achieve?
(sorry if my english is not so good, but i'm italian)
If you have an array of GEntity then, each time you "add" a derived type, the equivalent of this happens:
GEntity g;
Player p;
g = p; // object slicing, you assigned a Player to a GEntity object.
g.render(); // GEntity::render() gets called
On the other hand, you can use a pointer to a base class to access a derived method:
GEntity* g;
Player p;
g = &p;
g->render(); // calls Player::render()
So a way to deal with polymorphism in containers is to have arrays/containers of (preferably smart) pointers to the base class. This example uses raw pointers for simplicity, but you should use smart pointers in real code:
std::vector<CEntity*> entities;
entities.push_back(new Player);
entities.push_back(new GLiving);
// some c++11
for ( auto e : entities) {
e->render();
}
In a Game class function I am allocating a Boundary class to the stack
void Game::loadContent()
{
Boundary b(this, body);
}
The boundary class has a pointer to the main Game class and a pointer to a rigid body. I'm not certain whether I should use a reference for each though? Some clarity here would be helpful for reasons explained later.
class Boundary : public DynamicEntity
{
public:
Boundary(Game *game, btRigidBody *body);
~Boundary(void);
// Override functions
virtual void draw(float dt);
virtual glm::vec3 getPosition();
virtual void update(float dt);
};
The DynamicEntity class assigns the body and handles the pointer deletion in its destructor.
class DynamicEntity : public Entity
{
public:
virtual ~DynamicEntity(void);
virtual void draw(float dt) = 0;
btRigidBody* getBody();
glm::vec3 getPosition() = 0;
virtual void update(float dt) = 0;
protected:
explicit DynamicEntity(Game *game, btRigidBody *body);
btRigidBody *m_body;
};
DynamicEntity.cpp Destructor
DynamicEntity::~DynamicEntity(void)
{
m_game->m_dynamicsWorld->removeRigidBody(m_body);
delete m_body;
}
The DynamicEntity derives from the base class of all game objects called Entity
Entity.h
class Entity
{
public:
// Make destructor virtual as this is a base class
virtual ~Entity(void);
virtual void draw(float dt) = 0;
int getID();
virtual glm::vec3 getPosition() = 0;
virtual void update(float dt) = 0;
protected:
explicit Entity(Game *game); // Abstract base constructor
Game *m_game;
int m_id; // Unique ID
};
I can't call delete on the Game class pointer in this class' destructor though which is why I am not sure whether passing as a pointer is the correct method (instead of a reference)?
Entity::~Entity(void)
{
// Derived class destructors are called first
delete m_game; // ERROR
}
The Entity class adds a pointer to itself which can be accessed via a list in the Game class (useful for iterating and calling Entity functions in the main Game class).
Entity::Entity(Game *game)
: m_game(game), // Initialise members
m_id(m_game->g_idGenerator->generateNewID()) // Generate unique ID
{
m_game->m_entities.push_back(std::shared_ptr<Entity>(this));
}
The main problem I am having is that once the Game::loadContent() method has finished the destructor is called for the Entity class. This ruins the *shared_ptr* stored in the list and errors occur when trying to call any of the virtual methods.
I would like the Boundary pointer to persist until I say delete. Is there any way of doing this without allocating the Boundary to the heap?
EDIT
In response to the suggestion for using const& Game
It would appear that I have to change my Entity header to the following
Entity.h
#pragma once
#include <glm\glm\glm.hpp>
#include "Game.h"
// Forward declarations
class Game;
class Entity
{
public:
// Make destructor virtual as this is a base class
virtual ~Entity(void);
// '= 0' means pure virtual function (like 'abstract' in C#)
// This means they do not have to be declared in the source file '.cpp'
virtual void draw(float dt) = 0;
int getID();
virtual glm::vec3 getPosition() = 0;
virtual void update(float dt) = 0;
protected:
explicit Entity(const Game &game); // Abstract base constructor
Game m_game;
int m_id; // Unique ID
};
Doesn't the Game m_game allocate an instance of the Game class to the stack? How should it be declared in the header if it to represent a reference?
EDIT 2
If I store a protected reference to the Game class in the base Entity class const Game &m_game I cannot seem to access a global member of the Game class g_wireShapeDrawer in derived classes.
class Game
{
public:
GL_WireShapeDrawer g_wireShapeDrawer;
Game(void);
~Game(void);
void init();
void draw(float dt);
void handleInput(float dt);
void loadContent();
void update(float dt);
};
For example I get the following error when trying to access a global member in the draw method of the derived Boundary class source
void Boundary::draw(float dt)
{
m_game.g_wireShapeDrawer.drawPlane(glm::vec3(0, 1, 0), 0.0f, glm::vec4(1, 1, 1, 1));
}
error C2662: 'GL_WireShapeDrawer::drawPlane' : cannot convert 'this' pointer from 'const GL_WireShapeDrawer' to 'GL_WireShapeDrawer &
Why is this?
The Game object should never be deleted from any Entity or derived class. It should be one of the last things to be deallocated before the application shuts down.
You should pass it to your Entity classes as a Game&. Why? Because you only have one instance of the Game, so there is no need to reset what it points to, and it always should be valid (since the game will exist before the Entity objects do).
Another option is to implement the Singleton Pattern in your Game class, and access it like this Game::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);
As per your edit, you can create an Entity using the initializer list. This way you can store const members, like so:
class Entity
{
protected:
explicit Entity(Game &game) : m_game(game) {}
private:
Game& m_game;
}
Your design is flawed. You need to clearly state (through your design) who owns the pointer. If Entity owns the pointer then it should deallocate it in its destructor as you are doing (better yet; just wrap it in a std::unique_ptr). If it does not own the pointer then simply don't deallocate it.
You cannot have it both ways. You're using a shared_ptr, so that implies multiple "owners" and, once the last owner is done with it, the memory will be deallocated. Again, you needs to clearly design around who owns this memory.
Judging from your code, it seems like Entity does not really own the Game*. It needs it for implementation reasons, but should not be responsible for its deallocation.
on a side note, you are violating The Rule of Three.