【问题标题】:Struggling with collision detection. How do I detect the collision correctly?与碰撞检测作斗争。如何正确检测碰撞?
【发布时间】:2019-08-21 14:17:51
【问题描述】:
class ShapePlanet
{
public:
    sf::CircleShape shape;
    sf::Vector2f planetposition;
    int radius = 45;
    ShapePlanet()
    {
        float x = rand() % 1020; //invece che 1280
        float y = rand() % 650; //invece che 720
        this->shape.setFillColor(sf::Color::Green);
        this->planetposition.x = x;
        this->planetposition.y = y;
        this->shape.setPosition(x, y);
    }
};

struct Node_Planet
{
    ShapePlanet Planet;
    Node_Planet* next;
};
typedef Node_Planet* ptr_list;

class Planet
{
private:
    ptr_list head;
public:
    ptr_list create(int n)
    {
        ptr_list tmp = NULL;
        for (int i = 0; i < n; i = i + 1)
        {
            {
                tmp = new Node_Planet;
                tmp->Planet = ShapePlanet();
                tmp->next = head;
                head = tmp;
            }
            return this->head;
        }


        void draw(sf::RenderWindow& window)
        {
            ptr_list p = this->head;
            while (p != NULL)
            {
                window.draw(p->Planet.shape);
                p = p->next;
            }
        }

        void IsItOverLapped()
        {
            ptr_list p1 = this->head;
            ptr_list p2 = this->head;
            // bool collision = false;
            sf::FloatRect shape1;
            sf::FloatRect shape2;
            float distance;
            float dx;
            float dy;
            //float distance = std::sqrt((dx * dx) + (dy * dy));

            while ((p1 != NULL))
            {
                //float distance = std::sqrt((dx * dx) + (dy * dy));
                while (p2 != NULL)
                {
                    shape1 = p1->Planet.shape.getGlobalBounds();
                    shape2 = p2->Planet.shape.getLocalBounds();
                    dx = (p1->Planet.shape.getPosition().x + (shape1.width / 2)) - (p2->Planet.shape.getPosition().x + (shape2.width / 2));
                    dy = (p1->Planet.shape.getPosition().y + (shape1.height / 2)) - (p2->Planet.shape.getPosition().y + (shape2.height / 2));
                    distance = std::sqrt((dx * dx) + (dy * dy));
                    if (distance <= (shape1.width / 2) + (shape2.width / 2))
                    //if (p2->Planet.shape.getGlobalBounds().intersects(p1->Planet.shape.getLocalBounds()))
                    {
                        std::cout << "Collision Detected" << std::endl;
                        //p2 = p2->next;
                        //collision = true;
                    }
                    else
                    {
                        std::cout << "No Collision Detected" << std::endl;
                        //collision = false;
                    }
                    /*if (p2->Planet.shape.getLocalBounds().intersects(p1->Planet.shape.getLocalBounds()))
                        std::cout << "collision";
                        std::cout <<'\n'; */
                    p2 = p2->next;
                }
                p1 = p1->next;
            }
            //return collision;
        }
    }
};

所以,我希望能够在屏幕上绘制形状。问题是我很难检测形状的碰撞。如果我能够检测到碰撞,那么我可以改变重叠形状的位置。但我正在为此苦苦挣扎。 我有一个对象列表。它们有一些特征,如形状、位置等。 我也尝试过使用 if(object1.getLocalBounds.intersects(object2.getLocalbounds()) {then do something} 但似乎代码没有进入 if 方面。我已经尝试了很多次,但我真的没有不知道怎么处理这件事了。

【问题讨论】:

  • 请不要typedef指针!这只是来自 MS 的一个坏习惯,只是为了隐藏信息......
  • 如果你考虑 round 行星,那么我不会与矩形相交,相反,你可以计算它们中心的距离,如果这个距离小于两个半径之和...
  • 我们的教授总是这样做。
  • 我尝试计算距离和做半径的事情,但在那种情况下我也失败了。我在网上查了一下,试图找到一些东西,我找到了那个代码,但仍然没有得到任何地方:/
  • 嗯,教授养成坏习惯的情况并不少见。他们是专业的or,而不是专业的ional(在开发人员的意义上;我承认他们是专业的老师)...

标签: c++ sfml collision shapes


【解决方案1】:

首先,您不应该构建自己的数据结构(例如ptr_list),除非您有充分的理由(或者,如果您明确编写代码以了解指针和数据结构,但随后可能不要将其与碰撞混合)。相反,请使用STL - 已经少了一件您不必担心的事情。还有avoid new and delete

接下来,请确保您了解所使用的 SFML 函数。 getLocalRect()getGlobalRect() 在两个不同的坐标系中返回矩形,您不能只添加/减去它们并期望得到有意义的结果。请参阅 SFML 文档以获得更清晰的信息。另外,您应该直接使用sf::Rect::intersects(),而不是自己构建。

您需要考虑的是,SFML 将对轴对齐的边界框进行相交检查,而检查实际矩形是否相交。这比正确的矩形检查更简单、更快捷,但不太准确。我会从轴对齐的矩形开始,然后从那里开始。

还可以将检查重叠的代码(碰撞检测)和对其做出反应的代码(碰撞响应)分开。第一个是不修改任何状态的简单布尔函数,然后第二个执行必要的操作。

【讨论】:

  • 感谢您的回复。是的,我有充分的理由这样做,因为这就是我在学校学会做事的方式,而且我不知道其他方式来处理它。而且我更喜欢使用自己的数据结构,而不是处理一些库而不知道我要去哪里。关于 getLocalrect,我不得不承认我已经从 youtube 上的一个人那里复制了这些代码,他在那里展示了如何检测碰撞。我正在尝试另一种方式,但那不起作用:/
  • “我更喜欢使用自己的数据结构,而不是处理一些库而不知道我要去哪里”——嗯,重点是你学习如何使用这些库;)您很快就会注意到它们为您提供了大量支持。 STL 已经过全面测试,适用于广泛的问题,它还负责内存管理,并提供查找、排序、过滤等算法。如果您可以花时间开发游戏,为什么还要为基本的 C++ 功能重新发明轮子?
【解决方案2】:
p1 = head;
p2 = head;

while (p1)
{
    while (p2)
    {
        // ...
        p2 = p2->next;
    }
    (*)
    p1 = p1->next;
}

当代码第一次到达(*)时,p2在内循环中被设置为nullptr;但由于您不在内部循环中重置它,它会在所有其他循环运行时保留在那里,因此不再将列表中的第二个行星与其他行星进行比较。

此外,当您最初将两个指针都设置为 head 时,您会将第一个行星与其自身进行比较,自然会导致碰撞。

解决这两个问题:

p1 = head;
while (p1)
{
    p2 = p1->next;
    //       ^ avoid self-comparison
    while (p2)
    {
        // ...
        p2 = p2->next;
    }
    p1 = p1->next;
}

【讨论】:

  • 非常感谢!不敢相信这件事:p2 = p1->next;我在做代码。非常感谢你!真的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2011-09-05
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多