Наследование от Transformable и Drawable в SFML

Я пытаюсь наследовать от Transformable и Drawable в SFML, чтобы сделать мои объекты... ну, трансформируемый и привлекательный. Я делаю простую игру прорыва, но, возможно, я иду по этому неправильному пути. Вот мой код:

#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;
}

теперь перемещение и рисование работают (почти), как ожидалось, однако столкновения немного шаткие. Сначала мои проблемы с столкновениями:

  1. мне нужно реализовать функцию getGlobalBounds так, как я это сделал? Или есть лучший способ делать это с вещами, включенными в Transformable и Drawable?
  2. должен ли я выполнять преобразования непосредственно на фигурах или должен передать преобразования функции draw, как я в настоящее время?

что-то странное также происходит с рисунком, который, вероятно, является быстрым решением. Прямо сейчас метод getPosition возвращает неправильные значения для объекта my ball. Область, которую он возвращает, кажется, немного сдвинута вниз и вправо. Любая причина, которая может быть?

Спасибо за любую помощь вы можете дать!

EDIT: также любые общие советы C++ приветствуются, я все еще новичок.

1 ответов


на вашем месте я бы определил новый класс, называемый TransformableAndDrawable такой:

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

в этот класс, вы должны определить все члены которой, как правило, нужен свой трансформер и выигрышного классов. Также, в этот класс, вы должны определить все методы, которые могут быть реализованы в вашем трансформер и выигрышного классов. Тогда ваши классы должны быть унаследованы от TransformableAndDrawable, например:

class Player : TransformableAndDrawable {
    // Your code here
}

Итак, ответ на первый вопрос: я будет реализован в TransformableAndDrawable class данный метод, если это общий метод, поэтому все классы унаследованы от TransformableAndDrawable будет иметь этот метод.

вместо того, чтобы давать разные имена, как p_rect и p_circle, назовите этих членов с тем же именем, как p_shape, поэтому у вас не будет проблем с именами. Кроме того, я считаю, что вы можете объявить свой p_shape классом предка или интерфейсом (я не знаю, какие классы определены в библиотеке, с которой вы работаете) и только при необходимости укажите характер фигуры (будь то круг или прямоугольник или что-то еще).

что касается второго вопроса: мне нравится, как вы реализовали вещи, но вы сделали две ошибки:

  • это не масштабируемо: мы хотим общее решение, класс, который может быть использован для любой формы, с которой вы работаете сейчас и в будущем, не так ли?
  • это не достаточно: Когда я хочу знать глобальные границы фигуры, то я меня не интересует природа формы, я бы предпочел, чтобы ваш код обрабатывал природу формы без моего ведома

короче говоря, вы должны сделать следующее:

  1. создать класс-оболочку, который будет унаследован от Transformable и Drawable

  2. в вашем классе обертки, быть агностиком к природе формы, быть как можно более общим, надеюсь, есть какой-то класс или интерфейс, который является предком оба!--11--> и CircleShape.

  3. наследуйте все ваши drawable и transformable классы от вашего класса-оболочки, поэтому у вас будет общая функциональность среди ваших классов

  4. если что-то в вашем классе-оболочке не подходит для класса, который был унаследован от него, перезапишите метод в этом классе.

EDIT:

я посмотрел в библиотеку, которую вы используете более подробно и узнал что есть класс под названием Shape, который является предком обоих CircleShape и RectangleShape. Итак, вместо этих классов используйте Shape и ваш код будет более общим и многоразовым.