【问题标题】:Inheriting from Transformable and Drawable in SFML从 SFML 中的 Transformable 和 Drawable 继承
【发布时间】:2013-07-28 10:22:03
【问题描述】:

我正在尝试从 SFML 中的 Transformable 和 Drawable 继承,以使我的对象......好吧,可变形和可绘制。我正在制作一个简单的突围游戏,但也许我做错了。这是我的代码:

#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. 我应该直接对形状执行变换,还是应该像现在一样将变换传递给绘图函数?

绘图也发生了一些奇怪的事情,这可能是一个快速修复。现在 getPosition 方法为我的球对象返回不正确的值。它返回的区域似乎向下和向右移动了一点。有什么原因吗?

感谢您提供的任何帮助!

编辑:也欢迎任何一般的 C++ 技巧,我还是个初学者。

【问题讨论】:

    标签: c++ collision-detection game-physics sfml


    【解决方案1】:

    如果我是你,我会定义一个新类,称为 TransformableAndDrawable,如下所示:

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

    在这个类中,您应该定义可变形和可绘制类通常需要的所有成员。此外,在此类中,您应该定义通常可以在可转换和可绘制类中实现的所有方法。然后,你的类应该继承自TransformableAndDrawable,像这样:

    class Player : TransformableAndDrawable {
        // Your code here
    }
    

    现在,第一个问题的答案是:如果是通用方法,我会在TransformableAndDrawable类中实现给定方法,所以从TransformableAndDrawable继承的所有类都会有这个方法。

    不要使用不同的名称,例如 p_rectp_circle,而是使用相同的名称命名这些成员,例如 p_shape,这样您就不会有命名问题。另外,我相信您可以将您的 p_shape 声明为祖先类或接口(我不知道您正在使用的库中定义了哪些类),并且仅在需要时指定形状的性质(无论是圆形或矩形或其他东西)。

    关于第二个问题:我喜欢你实现事物的方式,但你犯了两个错误:

    • 它不可扩展:我们想要一个通用的解决方案,一个可用于您现在和将来使用的任何形状的类,不是吗?
    • 不够通用:当我想知道形状的全局边界时,我对形状的性质不感兴趣,我希望你的代码在我不知道的情况下处理形状的性质

    简而言之,你应该做到以下几点:

    1. 创建一个将从TransformableDrawable继承的包装类

    2. 在你的包装类中,不知道形状的性质,尽可能通用,希望有一些类或接口是 RectangleShapeCircleShape 的祖先。

    3. 从包装类继承所有可绘制和可转换的类,以便在类之间共享功能

    4. 如果包装类中的某些内容不适合从它继承的类,请覆盖该类中的方法。

    编辑:

    我更详细地查看了您正在使用的库,发现有一个名为 Shape 的类,它是 CircleShapeRectangleShape 的祖先。因此,使用Shape 代替这些类,您的代码将更加通用和可重用。

    【讨论】:

    • 好吧,我正在考虑为这些类创建一个超类,因为我真的很讨厌两次编写相同的代码。希望这样做时,我能够解决绘图的奇怪问题。
    • 在使用 getRadius 函数时投射 Shape 指针是个好主意吗?它会起作用,但我觉得这可能是不好的做法。我个人不这么认为,因为它属于一个必须具有圆形形状的类。编辑:像这样:if (getPosition().x &gt;= 800 - dynamic_cast&lt;sf::CircleShape*&gt;(shape)-&gt;getRadius())
    • 你可以转换它,但我相信你也应该在超类中实现一个功能,在那里你可以使用模板支持任何类。
    • 我该怎么做呢?应该有某种功能吗?
    猜你喜欢
    • 2016-06-11
    • 1970-01-01
    • 2021-01-04
    • 2016-08-26
    • 2017-07-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    相关资源
    最近更新 更多