Inheriting from Transformable and Drawable to SFML

I am trying to inherit from Transformable and Drawable in SFML to make my objects ... well, transformable and accessible. I make a simple game, but maybe I'm wrong. Here is 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 is (almost) as expected, however the collision is a bit uncomfortable. My conflict problems first:

  • Do I need to implement the getGlobalBounds function the way I do? Or is there a better way to do this with things included in Transformable and Drawable?
  • Do I have to do the transformations on the shapes directly or do I need to pass the transforms to the draw function, as I am now?

Something strange is also happening with the drawing, which is probably a quick fix. The getPosition method is currently returning invalid values ​​for my ball object. The returned area seems to be shifting down and to the right. Any reason that could be?

Thanks for any help you can give!

EDIT: Any general advice in C ++ is also welcome, I'm still a beginner.

+7
c ++ collision-detection game-physics sfml
source share
1 answer

If I were you, I would define a new class called TransformableAndDrawable as follows:

 class TransformableAndDrawable : public sf::Transformable, public sf::Drawable { // Your code here } 

In this class, you must define all the members that your transformable and accessible classes typically need. In addition, in this class you must define all the methods that can be generally implemented in your transformable and accessible classes. Then your classes should be inherited from TransformableAndDrawable , for example:

 class Player : TransformableAndDrawable { // Your code here } 

Now the answer to the first question: I would implement this method in the TransformableAndDrawable class if it is a common method, so all classes inherited from TransformableAndDrawable will have this method.

Instead of specifying different names, for example p_rect and p_circle , name these members with the same name, for example p_shape , so you will not have problems with naming. In addition, I believe that you can declare your p_shape a class or ancestor interface (I don’t know which classes are defined in the library you are working with), and only if necessary specify the nature of the form (whether it be a circle or a rectangle or something still).

Regarding the second questions: I like the way you implemented things, but you made two mistakes:

  • it does not scale: we need a general solution, a class that can be used for any form that you work with now and in the future, right?
  • This is not general enough: when I want to know the global boundaries of the form, I am not interested in the nature of the figure, I would prefer your code to process the nature of the form without knowing it

In short, you should do the following:

  • Create a wrapper class that will inherit from Transformable and Drawable

  • In your wrapper class, agnostic in the nature of the form, as general as possible, we hope that there is some kind of class or interface that is the ancestor of both RectangleShape and CircleShape .

  • Inherit all your cool and transformable classes from your wrapper class, so you will have common functionality among your classes.

  • If something in your wrapper class is not suitable for the class that was inherited from it, rewrite the method in that class.

EDIT:

I looked at the library that you are using in more detail, and found that there was a Shape class that is the ancestor of both CircleShape and RectangleShape . So, instead of these classes, use Shape , and your code will be more general and reusable.

+1
source share

All Articles