c++ - 圆和线段之间的错误碰撞检测

标签 c++ rotation collision-detection sfml

我正在用 C++ 制作 SFML 游戏。

这是一款赛车游戏,从顶部观察汽车。 该电路由 2 种不同类型的路障(方形)组成:直路和拐角。

问题是汽车(有一个圆形碰撞框)和道路周围的墙壁(是路段)之间的碰撞没有被正确检测到。

路段是用(近似地)从路障中获取的值初始化的常量。

然后,我们围绕 block 的中心旋转线段以允许 block 旋转。

game 是游戏的主循环。 RoadBox 定义了 RoadBlock 的命中框。

碰撞.hpp:

/*
* Definitions of all that are related to collisions:
* -hitBox
* -repulsions
*/
#ifndef DEF_COLLISION_HPP
#define DEF_COLLISION_HPP

#include <SFML/Graphics/Rect.hpp>

class RoadBox;

namespace collision
{
    class RectHitBox
    {
        public:
            RectHitBox();
            RectHitBox(const sf::FloatRect &rect1, float orient1);

            sf::FloatRect rect;
            float orientation;

    };

    class LineHitBox
    {
        public:
            LineHitBox();
            LineHitBox(const sf::Vector2f &point1, const sf::Vector2f &point2);

            void move(const sf::Vector2f &point2);

            sf::Vector2f p1;
            sf::Vector2f p2;
    };

    class CircleHitBox
    {
        public:
            CircleHitBox();
            CircleHitBox(const sf::Vector2f &point, float rayon1);

            sf::Vector2f p;
            float rayon;

    };

    bool collision(const RectHitBox &rectBox1, const RectHitBox &rectBox2);
    bool collision(const RectHitBox &rectBox, const LineHitBox &lineBox);
    bool collisionAsInfiniteLine(const CircleHitBox &cercleBox, const LineHitBox &lineBox);

    //circle and segment
    bool collision(const CircleHitBox &cercleBox, const LineHitBox &lineBox);
    bool collision(const sf::Vector2f &point, const CircleHitBox &cercleBox);
    bool collision(const CircleHitBox &cercleBox1, const CircleHitBox &cercleBox2);

    bool collision(const CircleHitBox &circleBox, const RoadBox &roadBox);

}

#endif

碰撞.cpp:

#include "collision.hpp"
#include "RoadBox.hpp"
#include <cmath> //sqrt needed

#include <iostream>

namespace collision
{

    RectHitBox::RectHitBox()
    {
        orientation = 0;
    }

    RectHitBox::RectHitBox(const sf::FloatRect &rect1, float orient1)
    {
        rect = rect1;
        orientation = orient1;
    }

    LineHitBox::LineHitBox()
    {
        p1 = sf::Vector2f(0, 0);
        p2 = p1;
    }

    LineHitBox::LineHitBox(const sf::Vector2f &point1, const sf::Vector2f &point2)
    {
        p1 = point1;
        p2 = point2;
    }

    void LineHitBox::move(const sf::Vector2f &point2)
    {
        p1 += point2;
        p2 += point2;
    }


    CircleHitBox::CircleHitBox()
    {
        p = sf::Vector2f(0,0);
        rayon = 1;
    }

    CircleHitBox::CircleHitBox(const sf::Vector2f &point, float rayon1)
    {
        p = point;
        rayon = rayon1;
    }

    bool collision(const RectHitBox &rectBox1, const RectHitBox &rectBox2)
    {
        sf::FloatRect rect1 = rectBox1.rect, rect2 = rectBox2.rect;

        /*int centre1_x = rect1.left + rect1.width/ 2;
        int centre1_y = rect1.top + rect1.height/ 2;
        int centre2_x = rect2.left + rect2.width/ 2;
        int centre2_y = rect2.top + rect2.height/ 2;*/

        int dis2centre = (rect1.left-rect2.left)*(rect1.left-rect2.left) + (rect1.top-rect2.top)*(rect1.top-rect2.top); //Distance entre deux centre

        int rayon1 = ((rect1.height * rect1.height) + (rect1.width * rect1.width))/2;
        int rayon2 = ((rect2.height * rect2.height) + (rect2.width * rect2.width))/2;
        return (dis2centre < (rayon1 + rayon2)*(rayon1 + rayon2));
    }

    bool collision(const sf::Vector2f &point, const CircleHitBox &cercleBox)
    {
        sf::Vector2f C(cercleBox.p);
        float x = point.x, y = point.y;
        float rayon = cercleBox.rayon;

        float d2 = (x-C.x)*(x-C.x) + (y-C.y)*(y-C.y);
        if (d2>rayon*rayon)
            return false;
        else
            return true;
    }

    bool collisionAsInfiniteLine(const CircleHitBox &cercleBox, const LineHitBox &lineBox)
    {
        sf::Vector2f A(lineBox.p1), B(lineBox.p2), C(cercleBox.p);
        sf::Vector2f u;
        u.x = B.x - A.x;
        u.y = B.y - A.y;

        sf::Vector2f AC;
        AC.x = C.x - A.x;
        AC.y = C.y - A.y;

        float numerateur = u.x*AC.y - u.y*AC.x;
        if(numerateur < 0)
        {
            numerateur = -numerateur;
        }

        float denominateur = std::sqrt(u.x*u.x + u.y*u.y);
        float CI = numerateur / denominateur;
        if(CI < cercleBox.rayon)
        {
            return true;
        }
        return false;
    }

    bool collision(const CircleHitBox &cercleBox, const LineHitBox &lineBox)
    {
        sf::Vector2f A(lineBox.p1), B(lineBox.p2), C(cercleBox.p);

        if(!collisionAsInfiniteLine(cercleBox, lineBox))
        {
            return false;
        }

        sf::Vector2f AB,AC,BC;
        AB.x = B.x - A.x;
        AB.y = B.y - A.y;
        AC.x = C.x - A.x;
        AC.y = C.y - A.y;
        BC.x = C.x - B.x;
        BC.y = C.y - B.y;
        float pscal1 = AB.x*AC.x + AB.y*AC.y;  // produit scalaire
        float pscal2 = (-AB.x)*BC.x + (-AB.y)*BC.y;  // produit scalaire
        if (pscal1>=0 && pscal2>=0)
            return true;   // I entre A et B, ok.
        // dernière possibilité, A ou B dans le cercle
        if (collision(A,cercleBox))
            return true;
        if (collision(B,cercleBox))
            return true;
        return false;
    }

    bool collision(const CircleHitBox &cercleBox1, const CircleHitBox &cercleBox2)
    {
        sf::Vector2f C1(cercleBox1.p), C2(cercleBox2.p);
        float d2 = (C1.x-C2.x)*(C1.x-C2.x) + (C1.y-C2.y)*(C1.y-C2.y);
        if (d2 > (cercleBox1.rayon + cercleBox2.rayon)*(cercleBox1.rayon + cercleBox2.rayon))
            return false;
        else
            return true;
    }

    bool collision(const CircleHitBox &circleBox, const RoadBox &roadBox)
    {
        bool collided = false;
        const std::vector<collision::LineHitBox> &hitBox = roadBox.getLineArray();

        for(unsigned int i = 0; i < hitBox.size() && !collided; i++)
        {
            collided = collision(circleBox, hitBox[i]);
            /*if(collided)
            {
                //std::cout<< "collision\n";
            }*/
        }

        return collided;
    }

} //namespace collision

汽车.hpp:

// A Car shall be drawable and transformable. It can collide with other objects.

#ifndef DEF_CAR_HPP
#define DEF_CAR_HPP

#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/Sprite.hpp>

#include "Timer.hpp"
#include "collision.hpp"

namespace sf
{
    class Texture;
}

class Car : public sf::Drawable, public sf::Transformable
{
    public:
        Car(sf::Texture &tex, float maxSpeed = 100);


        void accelerate(float accel);

        void rotate(float rot);

        void apply_physics();

        collision::CircleHitBox getHitBox() const;

    protected:
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;

    private:
        float norm(const sf::Vector2f &v) const;

        float m_acceleration;
        float m_rotation;

        sf::Sprite m_sprite;

        Timer m_physicTimer; //timer that permit the physics to apply at every frame

        sf::Vector2f m_speedVector;
        float m_maxSpeed;


        float m_hitBoxRadius;
};

#endif

汽车.cpp:

#include "Car.hpp"

#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/RenderTarget.hpp>

#include <cmath>
#include <iostream>

Car::Car(sf::Texture &tex, float maxSpeed)
{
    m_acceleration = 0;
    m_rotation = 0;

    m_sprite.setTexture(tex);

    sf::Vector2u texSize(tex.getSize());
    m_sprite.setOrigin(float(texSize.x)/2.f, float(texSize.y)/2.f);
    m_speedVector = sf::Vector2f(0, 0);

    //to take the included circle, take the min btw width and height
    m_hitBoxRadius = 93/2;

    m_maxSpeed = maxSpeed;

    m_physicTimer.setDuration(sf::seconds(1./60.)); //60 fps
    m_physicTimer.restart();

}

void Car::accelerate(float accel)
{
    m_acceleration = accel;
}

void Car::rotate(float rot)
{
    m_rotation = rot;
}

void Car::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    states.transform *= getTransform();
    //states.transform.rotate(-90); //the car is not well orientated in the loaded image
    target.draw(m_sprite, states);
}

void Car::apply_physics()
{
    if(m_physicTimer.ticked())
    {
        float currentSpeed = norm(m_speedVector);

        sf::Transformable::rotate(m_rotation/**(currentSpeed / m_maxSpeed)*/);
        float rotation = getRotation();

        float accelFactor = m_physicTimer.getFullWaitedDuration().asSeconds();

        //std::cout<< accelFactor * 60<< "\n";

        //calculate the new speed with the acceleration
        m_speedVector.x += std::cos(rotation*M_PI/180)*m_acceleration*accelFactor;
        m_speedVector.y += std::sin(rotation*M_PI/180)*m_acceleration*accelFactor;

        //calculate the new position with the speed
        move(m_speedVector);


        m_acceleration = 6;
        m_physicTimer.restart();

        //std::cout<< getPosition().x<< " ; "<< getPosition().y<< '\n';
        //std::cout<< 60*accelFactor<< '\n';
    }
}

float Car::norm(const sf::Vector2f &v) const
{
    return std::sqrt((v.y*v.y) + (v.x*v.x));
}

collision::CircleHitBox Car::getHitBox() const
{
    return collision::CircleHitBox(getPosition(), m_hitBoxRadius);
}

路障.hpp :

#ifndef DEF_ROADBLOCK_HPP   
#define DEF_ROADBLOCK_HPP

#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/RenderStates.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Sprite.hpp>

#include <string>
#include <vector>

#include "collision.hpp"
#include "RoadBox.hpp"

namespace sf
{
    class RenderTarget;
}

static const std::string STRAIGHT_TEXTURE_NAME("gameData/images/straight.png");
static const std::string CORNER_TEXTURE_NAME("gameData/images/corner1.png");
static const std::string GRASS_TEXTURE_NAME("gameData/images/grass2.png");

class RoadBlock : public sf::Drawable, public sf::Transformable
{
    public:
        enum roadType
        {
            straight = 0, 
            corner = 1
        };

        enum rotation //clockwise
        {
            standard = 0, 
            right= 1, 
            left = 2, 
            down = 3
        };

        RoadBlock();
        RoadBlock(const sf::Texture &texture, roadType t, rotation r, const sf::Vector2f &pos);
        RoadBlock(roadType t, rotation r, const sf::Vector2f &pos = sf::Vector2f(0.0, 0.0));

        rotation getRotation() const;
        roadType getRType() const;

        void setRotation(rotation r);
        void setType(roadType t);

        RoadBox getHitBox() const;

        //standard shared textures
        static const sf::Texture straightTexture;
        static const sf::Texture cornerTexture;
        static const sf::Texture grassTexture;

        //standard shared textures size
        static const sf::Vector2i texSize;

    protected:  
        virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const;

    private:
        sf::Sprite m_sprite;
        roadType m_type;
};

//turn 90° clockwise
RoadBlock::rotation operator++(RoadBlock::rotation &r, int);

//turn -90° clockwise
RoadBlock::rotation operator--(RoadBlock::rotation &r, int);

//change of roadType to the next one
RoadBlock::roadType operator++(RoadBlock::roadType &r, int);

#endif

路障.cpp:

#include "RoadBlock.hpp"

#include <SFML/Graphics/RenderTarget.hpp>
#include "FileLoader.hpp"
#include "collision.hpp"

#include <iostream>

const sf::Texture RoadBlock::straightTexture = createFromFile<sf::Texture>(STRAIGHT_TEXTURE_NAME);
const sf::Texture RoadBlock::cornerTexture = createFromFile<sf::Texture>(CORNER_TEXTURE_NAME);
const sf::Texture RoadBlock::grassTexture = createFromFile<sf::Texture>(GRASS_TEXTURE_NAME);

const sf::Vector2i RoadBlock::texSize = sf::Vector2i(256, 256);

RoadBlock::RoadBlock()
{
    m_sprite.setOrigin(float(texSize.x)/2.f, float(texSize.y)/2.f);
}

RoadBlock::RoadBlock(const sf::Texture &texture, roadType t, rotation r, const sf::Vector2f &pos)
{
    setPosition(pos);

    m_sprite.setTexture(texture);
    setType(t);

    m_sprite.setOrigin(float(texSize.x)/2.f, float(texSize.y)/2.f);

    setRotation(r);

    m_sprite.setOrigin(0, 0);
}

RoadBlock::RoadBlock(roadType t, rotation r, const sf::Vector2f &pos)
{
    m_sprite.setOrigin(float(texSize.x)/2.f, float(texSize.y)/2.f);

    setPosition(pos);

    //std::cout<< pos.x<< " ; "<< pos.y<< '\n';

    setRotation(r);
    setType(t);
}

void RoadBlock::setRotation(rotation r)
{
    switch(r)
    {
        case right:
            m_sprite.setRotation(90);
            break;
        case left:
            m_sprite.setRotation(-90);
            break;
        case down:
            m_sprite.setRotation(180);
            break;
        case standard:
            m_sprite.setRotation(0);
            break;
        default:
            break;
    }
    //m_sprite.rotate(10);
}

void RoadBlock::setType(roadType t)
{
    m_type = t;

    switch(t)
    {
        case straight:
            m_sprite.setTexture(RoadBlock::straightTexture);
            break;
        case corner:
            m_sprite.setTexture(RoadBlock::cornerTexture);
            break;
        default:
            break;
    }
}

RoadBlock::rotation RoadBlock::getRotation() const
{
    float r = m_sprite.getRotation();
    std::cout<< r<< '\n';
    switch(int(r))
    {
        case 90:
            return right;
            break;
        case 270:
            return left;
            break;
        case 180:
            return down;
            break;
        default:
            break;
    }
    return standard; //shall never be executed
}

RoadBlock::roadType RoadBlock::getRType() const
{
    return m_type;
}

RoadBox RoadBlock::getHitBox() const
{
    return RoadBox(*(this));
}

void RoadBlock::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    states.transform *= getTransform();
    states.transform.translate(float(texSize.x)/2.f, float(texSize.y)/2.f);

    target.draw(m_sprite, states);
}

RoadBlock::rotation operator++(RoadBlock::rotation &r, int nn)
{
    RoadBlock::rotation ans(r); //answer
    switch(r)
    {
        case RoadBlock::standard:
            r = RoadBlock::right;
            break;
        case RoadBlock::right:
            r = RoadBlock::down;
            break;
        case RoadBlock::down:
            r = RoadBlock::left;
            break;
        case RoadBlock::left:
            r = RoadBlock::standard;
            break;
        default:
            break;
    }
    return ans;
}

RoadBlock::rotation operator--(RoadBlock::rotation &r, int nn)
{
    RoadBlock::rotation ans(r); //answer
    switch(r)
    {
        case RoadBlock::standard:
            r = RoadBlock::left;
            break;
        case RoadBlock::right:
            r = RoadBlock::standard;
            break;
        case RoadBlock::down:
            r = RoadBlock::right;
            break;
        case RoadBlock::left:
            r = RoadBlock::down;
            break;
        default:
            break;
    }
    return ans;
}

RoadBlock::roadType operator++(RoadBlock::roadType &r, int)
{
    RoadBlock::roadType ans(r);
    switch(r)
    {
        case RoadBlock::straight:
            r = RoadBlock::corner;
            break;
        case RoadBlock::corner:
            r = RoadBlock::straight;
            break;
        default:
            break;
    }
    return ans;
}

RoadBox.hpp:

// A RoadBox is the RoadBlock's hit box.
// It's meant to easy collisions with the cars.

#ifndef DEF_ROADBOX_HPP
#define DEF_ROADBOX_HPP

#include <SFML/Graphics/Transformable.hpp>
#include "collision.hpp"
//#include "RoadBlock.hpp"

#include <vector>

class RoadBlock;

class RoadBox: public sf::Transformable //be careful with SFML transformations, none shall be used from a outside
{
    public:
        RoadBox(const RoadBlock &roadBlock);

        const std::vector<collision::LineHitBox> & getLineArray() const;

        /*
        These variables are initialized on program start.
        They represent the different standard hitBoxes of RoadBlocks.
        */
        static const std::vector<collision::LineHitBox> bigArcHitBox;
        static const std::vector<collision::LineHitBox> smallArcHitBox;
        static const std::vector<collision::LineHitBox> straightHitBox;

    private:
        std::vector<collision::LineHitBox> m_hitBox;

};

#endif //DEF_ROADBOX_HPP

RoadBox.cpp:

#include "RoadBox.hpp"
#include "RoadBlock.hpp"


/*
All functions defined as static in this file are initializers for RoadBox's static variables (hit boxes).
Therefore there is no mean to give access to these in other files.
*/

namespace pv //private
{
    static std::vector<collision::LineHitBox> getBigArcHitBox();
    static std::vector<collision::LineHitBox> getSmallArcHitBox();
    static std::vector<collision::LineHitBox> getStraightHitBox(); 
}
namespace pv //private
{
    static std::vector<collision::LineHitBox> getBigArcHitBox()
    {
        using namespace collision;

        sf::Vector2f posOffsetToCenter( - RoadBlock::texSize/2);

        std::vector<LineHitBox> hitBox(3);
        hitBox[0] = LineHitBox(sf::Vector2f(31, 256), sf::Vector2f(31, 134));
        hitBox[1] = LineHitBox(sf::Vector2f(31, 134), sf::Vector2f(121, 32));
        hitBox[2] = LineHitBox(sf::Vector2f(121, 32), sf::Vector2f(256, 31));

        //center the hitBox on (0, 0)
        for(unsigned int i = 0; i < hitBox.size(); i++)
        {
            hitBox[i].move(posOffsetToCenter);
        }

        return hitBox;
    }

    static std::vector<collision::LineHitBox> getSmallArcHitBox()
    {
        using namespace collision;

        sf::Vector2f posOffsetToCenter( - RoadBlock::texSize/2);

        std::vector<LineHitBox> hitBox(2);
        hitBox[0] = LineHitBox(sf::Vector2f(225, 255), sf::Vector2f(226, 224));
        hitBox[1] = LineHitBox(sf::Vector2f(226, 224), sf::Vector2f(256, 225));

        //center the hitBox on (0, 0)
        for(unsigned int i = 0; i < hitBox.size(); i++)
        {
            hitBox[i].move(posOffsetToCenter);
        }

        return hitBox;
    }

    static std::vector<collision::LineHitBox> getStraightHitBox()
    {
        using namespace collision;

        sf::Vector2f posOffsetToCenter( - RoadBlock::texSize/2);

        std::vector<LineHitBox> hitBox(2);
        hitBox[0] = LineHitBox(sf::Vector2f(31, 256), sf::Vector2f(31, 0)/*sf::Vector2f(0, 0), sf::Vector2f(0, 256)*/);
        hitBox[1] = LineHitBox(sf::Vector2f(225, 256), sf::Vector2f(225, 0)/*sf::Vector2f(256, 0), sf::Vector2f(256, 256)*/);

        //center the hitBox on (0, 0)
        for(unsigned int i = 0; i < hitBox.size(); i++)
        {
            hitBox[i].move(posOffsetToCenter);
        }

        return hitBox;
    }

}

const std::vector<collision::LineHitBox> RoadBox::bigArcHitBox = pv::getBigArcHitBox();
const std::vector<collision::LineHitBox> RoadBox::smallArcHitBox = pv::getSmallArcHitBox();
const std::vector<collision::LineHitBox> RoadBox::straightHitBox = pv::getStraightHitBox();

RoadBox::RoadBox(const RoadBlock &roadBlock)
{
    using namespace collision;

    //to get the right hit box, we need to transform the default hit box, because no rotation is in it
    sf::Transform transf;
    transf.rotate(roadBlock.sf::Transformable::getRotation());

    RoadBlock::roadType t = roadBlock.getRType();
    switch(t)
    {
        case RoadBlock::straight:
            m_hitBox.resize(straightHitBox.size());
            for(unsigned int i = 0; i < m_hitBox.size(); i++)
            {
                m_hitBox[i] = LineHitBox
                (
                    transf.transformPoint(straightHitBox[i].p1)
                    ,transf.transformPoint(straightHitBox[i].p2)
                );
            }
            break;
        case RoadBlock::corner:
            m_hitBox.resize(bigArcHitBox.size() + smallArcHitBox.size());
            for(unsigned int i = 0; i < bigArcHitBox.size(); i++)
            {
                m_hitBox[i] = LineHitBox
                (
                    transf.transformPoint(bigArcHitBox[i].p1)
                    ,transf.transformPoint(bigArcHitBox[i].p2)
                );
            }
            for(unsigned int i = 0; i < smallArcHitBox.size(); i++)
            {
                m_hitBox[i] = LineHitBox
                (
                    transf.transformPoint(smallArcHitBox[i].p1)
                    ,transf.transformPoint(smallArcHitBox[i].p2)
                );
            }
            break;
        default: //shall never be used
            break;

    }

    //place the calculated hit boxes at the right position
    sf::Vector2f pos(roadBlock.getPosition());
    for(unsigned int i = 0; i < m_hitBox.size(); i++)
    {
        m_hitBox[i].p1 += pos;
        m_hitBox[i].p2 += pos;
    }
}

const std::vector<collision::LineHitBox> & RoadBox::getLineArray() const
{
    return m_hitBox;
}

游戏.cpp:

#include "game.hpp"

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Keyboard.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Graphics/View.hpp>

#include <iostream>

#include "Map.hpp"
#include "Timer.hpp"
#include "OpenFileError.hpp"

namespace game
{
    Action::Action(float orien, int accel): 
        orientation(orien), acceleration(accel)
    {
    }

    void getEvents(sf::RenderWindow &window, Action &action)
    {
        action.acceleration = 0;
        action.orientation = 0;
        sf::Event event;
        while(window.pollEvent(event))
        {
            switch(event.type)
            {
                case sf::Event::Closed:
                    exit(EXIT_SUCCESS);
                    break;
                case sf::Event::KeyPressed:
                    switch(event.key.code)
                    {
                        case sf::Keyboard::Escape:
                            exit(EXIT_SUCCESS);
                            break;
                        default:
                            break;
                    }
                    break;
                case sf::Event::KeyReleased:
                    break;
                default:
                    break;
            }
        }

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
            action.acceleration = -5;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
        {
            action.acceleration = 5;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
            action.orientation = 5;
        }
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
            action.orientation = -5;
        }

    }

    void game(sf::RenderWindow &window)
    {
        //view that will follow the car
        sf::View carView(sf::FloatRect(0, 0, 800, 600));
        //carView.setSize(640, 480);
        window.setView(carView);

        //image loading
        sf::Texture texPlayerCar;
        if(!texPlayerCar.loadFromFile(CAR_FILE))
        {
            throw OpenFileError();
        }

        Map map(std::string("saveMap.pwet"));

        std::cout<< map.begin()->getPosition().x<< " ; "<< map.begin()->getPosition().y<< '\n';

        Car playerCar(texPlayerCar, 50); //50 = max speed
        playerCar.setPosition(sf::Vector2f(RoadBlock::texSize/2));

        //other variables
        Action action;

        Timer loopTimer(sf::seconds(1./60.)); //60 fps
        //std::cout<< loopTimer.getDuration().asSeconds()<< '\n';
        loopTimer.restart();

        int j = 0; //count the number of collisions (max 1 each frame)

        //main loop
        while(true)
        {
            getEvents(window, action);

            //game physic/////////////////////////////
            playerCar.accelerate(action.acceleration);  
            playerCar.rotate(action.orientation);

            playerCar.apply_physics();

            //collisions tests
            bool collided = false;
            int i = 0;
            for(Map::iterator it = map.begin(); it != map.end() && !collided; it++)
            {   
                collided = collision::collision(playerCar.getHitBox(), it->getHitBox());
            }
            if(collided)
            {
                std::cout<< ++j<<"\n";
            }

            // \game physics /////////////////////////

            //game display////////////////////////////
            carView.setCenter(playerCar.getPosition());
            window.setView(carView);

            window.clear(sf::Color::Black);

            window.draw(map);
            window.draw(playerCar);

            window.display();

            // \game display//////////////////////////

            //time handling///////////////////////////

            loopTimer.autoSleep();

            // \time handling/////////////////////////  
        }

    }

    void loadCars(std::vector<Car> &carsTab, std::vector<sf::Texture> &texTab)
    {
        try
        {
            sf::Texture texCar;
            if(!texCar.loadFromFile(CAR_FILE))
            {
                OpenFileError error;
                throw error;
            }

            texTab.push_back(texCar);
            carsTab.push_back(Car(texTab[0], CAR_SPEED));
        }
        catch(std::exception &except)
        {
            std::cerr<< except.what()<< "\n";
        }
    }
}

我正在给你一个问题的例子,正如 Anon Mail 所建议的那样。

我取消了 collision.cpp 中的以下行的注释:

bool collision(const CircleHitBox &circleBox, const RoadBox &roadBox)
    {
        bool collided = false;
        const std::vector<collision::LineHitBox> &hitBox = roadBox.getLineArray();

        for(unsigned int i = 0; i < hitBox.size() && !collided; i++)
        {
            collided = collision(circleBox, hitBox[i]);
            if(collided) //These ones, from here ...
            {
                std::cout<< "collision\n";
            } //... to here
        }

        return collided;
    }

从第 161 行开始

然后我让调试器完成他的工作。我只是开始游戏,然后按下向下按钮,直到找到测试 circle 和 roadBoxes 之间碰撞的函数中的断点。

(gdb) break collision.cpp:171
Breakpoint 1 at 0x404577: file collision.cpp, line 171.
(gdb) run
Starting program: /home/victor/projetCarRacing/carRacing 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffeeebe700 (LWP 2878)]
0 ; 0

Breakpoint 1, collision::collision (circleBox=..., roadBox=...) at collision.cpp:171
171                 std::cout<< "collision\n";
(gdb) print circleBox 
$1 = (const collision::CircleHitBox &) @0x7fffffffd740: {p = {x = 75,2980652, y = 128}, rayon = 46}
(gdb) print hitBox[i]
$2 = {p1 = {x = 31, y = 256}, p2 = {x = 31, y = 0}}

我想您需要一张图片才能完全理解正在发生的事情。 记住一件事:汽车碰撞框的半径是汽车的宽度:46 像素。 汽车后面的道路上的线不是墙。它不应有命中框。

game screenshot

我需要补充一点,game.hpp/cpp 的大部分内容与这里无关。 只有测试碰撞的部分才可能有用:

            //collisions tests
            bool collided = false;
            int i = 0;
            for(Map::iterator it = map.begin(); it != map.end() && !collided; it++)
            {   
                collided = collision::collision(playerCar.getHitBox(), it->getHitBox());
            }
            if(collided)
            {
                //some stuff...
            }

最佳答案

首先感谢那些花时间参与我们工作的人。 我设法自己解决了这个问题。

实际上我们的代码中有很多错误,在 RoadBox::RoadBox 中:

  1. 我忘记了中断指令(愚蠢的错误,是的)
  2. 我没有修改m_hitBox中好的值
  3. 当使用变换来旋转 hitBox 时,我使用了错误的函数 sf::Transform::rotate。本来应该是有一个中心作为参数的那个,但是我拿了另一个。它起作用的唯一原因是标准碰撞盒以 (0, 0) 为中心。

最后我会解释我遇到的最后一个错误,因为它很有趣: 当测试与角 block 和汽车的碰撞时,gdb 的调用告诉我这里有 bigArcHitBox 值,但不是 smallArcHitBox 值,而是 straightHitBox 值! 事实上,我只是在 smallArcHitBox 中走得太远了。但是如果你查看 RoadBox.hpp/cpp 文件,straightHitBox 就存储在 smallArcHitBox 之后。所以我以没有段错误结束,但错误的值来自错误的位置。

祝你有美好的一天!

关于c++ - 圆和线段之间的错误碰撞检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33741174/

相关文章:

c++ - 指向类成员函数的指针类型转换错误

physics - 球与球碰撞

c++ - 为什么调用复制构造函数而不是转换构造函数?

CSS 在头像图像上以相反方向旋转 2 个图像

java - 如何逆时针旋转数组并将其垂直反转?

CSS Transitions 仅适用于 FF Nightly (18.0a1)?

collision-detection - 重力物理学,避免无限反弹?

java - 画好的形状停止后一直在振动

c++ - 对 FILE 的操作改为对 QByteArray 的操作?

c++ - 在 OpenGL 中使用自定义顶点数的几何着色器输入?