Inheriting from Transformable and Drawable in SFML - c++

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.

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 ?

Error: "this declaration has no storage class or type specifier" in c++

I am trying to write some code that will make it easier for me to make SDL programs because I am learning and frequently start new projects. It basically needs to do all the standard SDL stuff. This is the code
namespace engine {
class Engine
{
private:
SDL_Renderer* renderer;
SDL_Window* window;
SDL_Event event;
bool initialised = true;
bool quit = false;
public:
Engine(const char* name, int x, int y, int w = SDL_WINDOWPOS_CENTERED, int h = SDL_WINDOWPOS_CENTERED, bool fullscreen = false)
{
window = SDL_CreateWindow(name, x, y, w, h, fullscreen);
if (window == nullptr)
initialised = false;
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer == nullptr)
initialised = false;
}
~Engine()
{
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
}
void handleEvents()
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
quit = true;
}
}
}
virtual void update()
{
}
virtual void render()
{
}
void start()
{
if (initialised && !quit)
{
handleEvents();
update();
render();
}
}
};
}
And then inherit from this to make a game class
class Game : public engine::Engine
{
private:
engine::Engine game{"engine", 1200, 600};
public:
game.update() override
{
}
game.render() override
{
}
};
And something like this in main
int main(int argc, char* argv[])
{
Game game();
game.start();
return 0;
}
But I am getting the error specified in the title in line engine::Engine game{"engine", 1200, 600}; in Game class. I don't know if what I am doing is possible or how to do it. Thanks for any help
My Goal: I want some code, almost like a library that I can reuse with different SDL projects. This engine will be a separate library. So I want some kind of engine class that inherits from engine in my project. Say the class that inherits form engine is game. I want game to override update and render, so that I can call different drawing methods defined in engine from render function. That way I wont have to make window, renderer and handle for events every time I start a project. I don't know if this is a good way to do it but any better solutions are welcome.
I'm gutting Engine to make the example smaller. We don't need any of the SDL stuff in the class to show how to fix this up. Other than that, Engine looks pretty good. Don't need to change anything.
namespace engine {
class Engine
{
private:
bool initialised = true;
bool quit = false;
public:
Engine(const char* , int , int ) // simplified to remove the SDL stuff
{
}
~Engine() // may want this to be virtual. See link about virtual destructors
{
}
void handleEvents()
{
}
virtual void update()
{
}
virtual void render()
{
}
void start()
{
if (initialised && !quit)
{
handleEvents();
update();
render();
}
}
};
}
Where things start going wrong is in trying to implement Engine. I'm going to comment inline as I make changes.
class Game : public engine::Engine // correct
{
// engine::Engine game{"engine", 1200, 600};
// don't need an engine::Engine as a member. Game IS an Engine.
public:
Game ():
engine::Engine {"engine", 1200, 600} // initialize base class here
{
}
// game.update() override
void update() override // use a normal function definition
// Compiler will figure out the rest
{
}
// game.render() override
void render() override // same as above
{
}
};
There's one small bug in main. The language has a little quirk where TYPE name() looks like a function, not a variable. This was cleaned up in C++11 with the addition of {} for more general initialization1.
int main()
{
// Game game(); declares a function, game, that returns a Game.
Game game; // defines a variable named game that is a Game. Could also be Game game{};
// note the different braces.
game.start();
return 0;
}
1 Watch out when using this with container classes. vector<int> test{5}; is a vector with one element containing five, NOT five elements containing the default zero you get from vector<int> test(5);.
Some additional reading:
When to use virtual destructors?
C++, What does the colon after a constructor mean?

(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.

C++ Game AI only works in main

I have a problem getting the AI to work if I do it in a subclass.
Here is my main loop in which I access the player and enemy classes for their move, logic, and show functions.
//Logic
myPlayer.player_move();
myEnemy.enemy_logic();
//Rendering
myPlayer.player_show();
myEnemy.enemy_show();
So I access the Player class's function that moves the player then I access the logic(AI) function of the Enemy Class.
void Enemy::enemy_move(){
eX -= 2;
}
void Enemy::enemy_logic(){
Player myPlayer;
if(myPlayer.x > SCREEN_WIDTH / 2){
enemy_move();
}
}
So if the Players x value is greater than half the screen, I want the enemy to start moving left
I can compile the program but when I move the player past the halfway point of the screen, the enemy does nothing. If I were to put this if statement in the main.cpp then it works fine. Any advice?
It's because you're re-initializing your instance of the class Player. Instead, pass it as a parameter:
void Enemy::enemy_logic(Player myPlayer){
if(myPlayer.x > SCREEN_WIDTH / 2){
enemy_move();
}
}
That way the function uses your instance, and not a new instance in a different scope.
Because you are initializing an instance of Player as myPlayer that is not connected to anything.
You should define a private variable for myPlayer inside your Enemy Class or pass a pointer to the Player class instance as an argument, in this way you will be able to maintain the state.
If your enemies depend on a single player you can "bind" each enmy to a player like this:
class Player
{
Position m_x, m_y, m_z;
public:
Position const & x (void) { return m_x; }
};
class Enemy
{
public:
Enemy (Player &p) : m_player(p) { }
Player & m_player;
void logic (void)
{
if (m_player.x() > SCREEN_WIDTH/2)
{
move_x();
}
}
void move_x (void) { /*...*/ }
};
int main (void)
{
Player the_player;
Enemy the_enemy(the_player);
// move the player
the_enemy.logic(); // the_enemy knows the_player and acts accordingly
}

Refactoring code for drawing game components

How can I refractor the following, to move my drawing functions from the h-file into a GraphicsManager class?
//drawingFunctions.h
void drawTexturedQuad( Texture texture, Vector2 pos, Vector2 dim) {
// bind texture...
glBegin(...); // draw
//...
glEnd(...);
}
//class file
#include "drawingFunctions.h"
class Player {
void drawPlayer(){ drawTexturedQuad( texture, pos, dim) }
};
class Enemy {
void drawEnemy(){ drawTexturedQuad( texture, pos, dim) }
};
class Item {
void drawItem(){ drawTexturedQuad( texture, pos, dim) }
};
// and so on for the other components
//gameloop file
// instantiate components objects
while (true) {
// input, logic
Player.drawPlayer();
Enemy.drawEnemy();
Item.drawItem();
// and so on
}
(The code is obviously simplified, I am just asking about the drawing here)
Should I...
pass a pointer to the GraphicsManager to every call of drawPlayer, drawEnemy etc from within the gameloop
have Player, Enemy etc have a pointer to GraphicsManger as a data member
have Player, Enemy etc extend a drawableGameComponent class that has a pointer to GraphicsManager as a data member
something else?
That sounds like a perfect use case for inheritance:
class Drawable
{
public:
void draw()
{
// gl stuff
}
protected:
Texture _texture;
Vector2 _pos;
Vector2 _dim;
};
class Player : Drawable
{
public:
// should modify _texture _pos and _dim somewhere.
};
// same thing for the other objects.
I would pass a renderer to the model, and ask it to draw itself.
class Player
{
public:
void draw(Renderer& renderer);
};
class Enemy
{
public:
void draw(Renderer& renderer);
};
Note you don't have to name the function drawPlayer or drawEnemy, because you already know that it's a Player or an Enemy by the class type. This uniform calling convention is perfect for extracting into a common interface:
class Model
{
public:
virtual void draw(Renderer& renderer) = 0;
virtual ~Model() {}
};
Then you can have each of your models inherit from Model, and each implement draw.
As I mentioned in a comment on #J.N.'s answer you can also have Renderer be an abstract class. For example I worked on a project which used OpenGL, GDI+, and also needed to create printouts of schematics.
class Renderer
{
public:
virtual render(const Triangle& triangle, const Texture& texture) = 0;
virtual ~Renderer() {}
};
I would go for the first possibility: passing the pointer to the GraphicsManager in the call. Eventhough it seems a bit overkill, the knowledge of which GraphicsManager is used is maintained on higher level and can be modified easier later on.
Having said this, I would still inherit from a Drawable interface and put the items that need to be drawn in a container, so you can just iterate through it to display the items via a virtual drawItem() function.
Like so (C++03, not tested):
std::vector<Drawable*> Items;
Items.push_back(&player);
Items.push_back(&enemy);
...
for (std::vector<Drawable*>::iterator it = Items.begin(); it != Items.end(): ++it)
{
(*it)->drawItem(&graphMgr);
}