碰撞检测&类

时间:2013-01-09 01:58:20

标签: c++ collision-detection collision sfml

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

目前我有大约13个班级,包括:

BaseEntity(大多数游戏对象都来自此)

播放器(从BE继承)

Beetle(从BE继承 - 游戏被称为'Beetle Dodger',因此将会有移动的甲虫作为对玩家的威胁)

宝石

MagicGem(玩家需要通过这些级别进步)

平台

SolidBlock(继承自Platform)

DownBlock(继承自平台 - 玩家可以通过但不会跳过此区块)

UpBlock(如上所述,反之亦然)

GameSound

游戏(游戏经理)

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

一切看起来都很好,并且在这里花花公子 - 然后我遇到了碰撞。虽然我理解它们如何工作的基础,但我已经尝试了两种或三种不同的方法来实现它们。起初我开始只是让Player类拥有一系列功能,如CollidesWith(Beetle& b)和CollidesWith(Platform& plat)。显然,当测试我的关卡中的每个对象(当然包括宝石)时,这是非常费劲的,我开始考虑如何实现广泛的相位碰撞检测。然后我尝试使用由2个2DVectors(SFML内置的类)定义的AABB类。这是我稍微陷入困境的地方,决定来这里寻求帮助。我回去测试使用纯粹的精灵大小的碰撞(因为它们是由一个盒子定义的 - 和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
};

播放器类继承自此并具有一些额外的功能,如CheckBoundaries,CollidesWith,Jump,并且还包含一些变量 - 在这种情况下,bool isColliding可能会很有用。

干杯们,对着这篇文章感到抱歉!

2 个答案:

答案 0 :(得分:0)

根据您正在处理的实体数量,只需检查游戏中每个对象的碰撞,就内存和/或性能而言,可能会产生巨大的成本。

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

答案 1 :(得分:0)

正如你已经发现解决碰撞不能仅仅考虑单个游戏对象的水平。您需要一个可以跟踪参与碰撞的所有对象的对象,并且可以从中读取影响碰撞的所有属性。如果这样做,则每次游戏更新时都可以解决所有对象的全局冲突。

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

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

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& other);。子类将覆盖此方法以提供特定于类的功能。

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

如果您的游戏要求发生变化,您可以使用更好的碰撞检查算法进行更新,您可以向ICollidable添加更多属性。一般而言,您还需要处理物理,您还可以通过ICollidable提供相应的功能。

作为提示,如果两个物体发生碰撞,我建议立即将它们彼此远离,这样它们就不会在下一个游戏时碰撞。