【问题标题】:Collision Detection & Classes碰撞检测和分类
【发布时间】:2012-12-23 00:35:39
【问题描述】:

我正在尝试为我的大学工作制作基于 2D 平台的游戏(SFML)。我不是要求任何人为我写一些代码,但如果有人能提供一些指点,我将非常感激:)

目前我有大约 13 个课程,包括:

BaseEntity(大多数游戏对象由此派生)

玩家(从 BE 继承)

甲虫(继承自 BE - 游戏称为“Beetle Dodger”,因此会有移动的甲虫对玩家构成威胁)

宝石

MagicGem(玩家需要这些才能通过关卡)

平台

SolidBlock(从平台继承)

DownBlock(从 Platform 继承 - 玩家可以跌倒但不能跳过此块)

UpBlock(如上,反之亦然)

游戏音效

游戏(游戏管理员)

可以说,我已经构建了大部分游戏“积木”——每个类都有自己的更新函数,该函数在 Game::Update 中调用。这同样适用于每个对象的 Draw() 函数。每个类都有一个指向游戏窗口的指针,因此它可以实现这些事情,并且它们还从 Game 传递了许多变量,例如当前按下的键以及经过的时间(用于移动计算)。

到这里为止一切看起来都很好而且很漂亮——然后我遇到了碰撞。虽然我了解它们的工作原理,但我尝试了两种或三种不同的方法来实现它们。起初我只是让 Player 类拥有一堆函数,例如 CollidesWith( Beetle& b ) 和 CollidesWith( Platform& plat )。显然,在对我的关卡中的每个对象(当然包括宝石)进行测试时,这是非常费力的,我开始考虑如何实现广泛的相位碰撞检测。然后我尝试使用由 2 个 2DVectors 定义的 AABB 类(SFML 的内置类)。这就是我有点卡住并决定来这里寻求帮助的地方。我回到纯粹使用精灵的大小来测试碰撞(因为它们是由一个盒子定义的 - 与 AABB 的一样,对吗?)但我不确定这是/是否是明智的选择。

在我严重搞砸游戏的良好基础之前,任何人都可以提供一些友好的建议来实现宽相位和窄相位碰撞检测的好方法吗?我在某个阶段的狭窄工作非常好,然后我意识到玩家仍然可以通过平台的一侧移动,呵呵。

我应该为碰撞创建一个专用类吗?或者我应该继续使用每个对象的精灵的大小(每个对象都有自己的精灵和图像 - 实际上我将展示一个示例):

class BaseEntity
{
public:
// Constructors
BaseEntity();
BaseEntity(sf::RenderWindow* gameWin, string imgPath, sf::Vector2f position = sf::Vector2f(0,0), sf::Vector2f velocity = sf::Vector2f(0,0));
virtual ~BaseEntity();
// Setters
void SetCurrentPos(sf::Vector2f newPos); // Set the current position 
void SetPreviousPos(sf::Vector2f newPrevPos); // Shouldn't be needed but there may be rare circumstances
void SetCurrentVel(sf::Vector2f newVel); // Set the velocity

// Getters
sf::Vector2f GetCurrentPos(); // Returns the current position values
sf::Vector2f GetPreviousPos(); // Returns the previous position values
sf::Vector2f GetCurrentVel(); // Returns the current velocity values 

void virtual SetSprite(string imgPath); // Set up the images for the sprite

void virtual Update(float elapsedTime); // The function that handles the updating of movement
void virtual Draw(); // The function that handles the 'Draw' aspect of this object

protected:


sf::RenderWindow* p_GameWin; // A pointer to the game window (used for drawing)
sf::Vector2f currentPos;
sf::Vector2f previousPos;
sf::Vector2f currentVel;
sf::Sprite mySprite; // This objects sprite
sf::Image myImage; // This objects image
};

player 类继承自 this 并具有一些额外的函数,例如 CheckBoundaries、CollidesWith、Jump,并且还包含一些变量 - bool isColliding 可能在这种情况下感兴趣。

大家好,对这篇文章感到抱歉!

【问题讨论】:

    标签: c++ collision-detection collision sfml


    【解决方案1】:

    正如您发现的那样,解决碰撞不能仅在单个游戏对象的级别上考虑。您需要一个可以跟踪所有参与碰撞的对象的对象,并且可以从它们中读取所有影响碰撞的属性。如果这样做了,那么它可以在每次游戏更新滴答时为所有对象全局解决碰撞。

    我建议创建一个界面,您可以通过该界面获取处理碰撞检测所需的所有信息。所有参与碰撞的对象都需要从这里继承。该界面将允许您从每个对象案例和全局案例顺利过渡。

    这只是一个帮助您理解的示例。您需要根据自己的代码对其进行调整。

    class ICollidable
    {
    public:
        // we use these function to retrieve collision relevant information
        // (can be optimised)
        virtual sf::Vector2f GetPosition() = 0; // objects have position
        virtual sf::Vector2f GetSize() = 0; // objects have a size
    
        // using this function, we notify the object that it collided with something else
        virtual void ProcessCollision(ICollidable* other) = 0;
    
        // if you use virtual methods, you need a virtual destructor
        virtual ~ICollidable{};
    };
    

    现在您可以创建一个碰撞系统。碰撞系统将保存一个可以相互交互的ICollidable 对象列表。您甚至可以选择一些对象根本不参与碰撞。这将负责在全球层面解决冲突。

    class CollisionSystem
    {
    private:
        // hold all objects that participate in collision
        std::vector<ICollidable*> objectList; 
    public:
        void AddToCollisionList(ICollidable* obj);
        void RemoveFromCollisionList(ICollidable* obj);
        void ProcessCollisionList();
    }
    

    CollisionSystem::ProcessCollisionList(); 包含碰撞检查算法的实现。它将获取每个对象的位置和大小。根据该信息,它将决定两个对象发生碰撞并为每个发生碰撞的对象调用ICollidable::ProcessCollision(ICollidable&amp; other);。此方法将被子类覆盖以提供特定于类的功能。

    CollisionSystem 中,您可以使用四叉树或二叉树等数据结构来加快解决所有冲突所需的时间。作为第一步,我建议只在 X 轴上进行排序。通过保持列表排序,您只需检查距离不超过对象大小的邻居。

    如果您的游戏需求发生变化,您可以更新更好的碰撞检查算法,您可以添加更多属性到ICollidable。一般来说,你还需要处理物理,你也可以通过ICollidable提供相应的功能。

    作为提示,如果两个物体发生碰撞,我建议立即将它们移开,以免它们在下一个游戏时间点发生碰撞。

    【讨论】:

      【解决方案2】:

      根据您要处理的实体数量,仅检查游戏中每个对象的碰撞可能会在内存和/或性能方面产生巨大的成本。

      您可能希望对对象进行预处理以按轴对它们进行分类,例如增加 x 坐标,以简化碰撞检查。甚至在游戏开始之前准备好所有对象并对其进行分类可能会更好,例如作为一个级别的启动。我认为这是我第一次尝试的方式。

      【讨论】:

        猜你喜欢
        • 2011-09-05
        • 1970-01-01
        • 1970-01-01
        • 2015-10-06
        • 2019-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多