如何在游戏中实现碰撞效果?

7
我正在使用QT构建一个游戏。我的GraphicsScene中的所有对象都继承自GraphicsPixmapItem(玩家,障碍物,炸弹...)。我想实现碰撞效果。例如,当玩家悬停在奖励上时,他可以拾取它。使用QT框架,我可以获取碰撞项,但我不知道它们是哪种类型,因为没有"instanceof"函数。有什么提示吗?
编辑:我已经获得了碰撞"事件",我想要做的是处理不同的碰撞。我用更好的措辞另外发了一个问题
4个回答

9

设计考虑:

我不建议从图形表示中继承游戏对象。为什么?您可能希望有一个游戏对象的多个图形表示(比如在游戏视图中显示一个,在小地图中显示另一个,或者其他)。关系是“玩家拥有一个图形表示”而不是“玩家是一个图形表示”。更好的解决方案是使用组合而不是继承。其他不错的效果包括可能封装其他碰撞检测(如果您对Qt提供的检测不满意)、解耦等。但对于简单游戏来说,这也可能已经足够了。

对于足够简单的游戏逻辑,可以使用继承,其中其他对象会对主动对象做出反应。但这对于任何更复杂的游戏机制来说可能过于简单了。

class Asteroid {
public:
  virtual void CollideWithPlayer(Player&) { p.loseHealth(100); }
};

class ExplodingAsteroid: Asteroid {
public:
  virtual void CollideWithPlayer(Player&) { explode(); p.loseHealth(1000); }
};

如果交互变得复杂(许多活动对象表现出自己的行为),您可能需要识别您的对象:
- 有RTTI,但很难推荐,请参见:RTTI费用高吗?简而言之:昂贵,难以维护。 - 您可以使用双重分派。使用两个虚拟调用来识别对象。 问题:相当多的语法,有时难以维护(特别是当您添加新对象时),所有权问题(请参阅更多)。 维基百科上的游戏示例:
class SpaceShip {};
class GiantSpaceShip : public SpaceShip {};

class Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    cout << "Asteroid hit a SpaceShip" << endl;
  }
  virtual void CollideWith(GiantSpaceShip&) {
    cout << "Asteroid hit a GiantSpaceShip" << endl;
  }
};

class ExplodingAsteroid : public Asteroid {
public:
  virtual void CollideWith(SpaceShip&) {
    cout << "ExplodingAsteroid hit a SpaceShip" << endl;
  }
  virtual void CollideWith(GiantSpaceShip&) {
    cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl;
  }
};

  • “枚举”

虚函数标识符

class GameObject() {
  virtual getId() { return GAME_OBJECT; }
};

class Asteroid() {
  virtual getId() { return ASTEROID; }
};

作为会员或者成员
class GameObject() {
  ID getId() { return id; }
protected:
  GameObject(ID id):id(id) {}
private:
  ID id;
};

或者使用自动初始化id的模板(语法有点令人费解,我们先不考虑它 :o)

  • 以及其他内容

现在来看这样的游戏循环:

for each object
  update by (fixed) time step
  detect collisions and resolve them

您将遇到以下问题:

所有权问题:

当玩家被小行星击中并摧毁时,玩家会失去生命值。

Asteorid::collideWithPlayer(Player& p) { p.loseHealth(100); this->explode(); }

现在考虑以下内容。
Player::collideWithAsteroid(Asteroid& a) { this->loseHealth(100); a.explode(); }

结果:代码重复或游戏机制不清晰

穷人的解决方案:找别人帮忙 :o)

Asteorid::collideWithPlayer(Player& p) { resolveCollision(p, *this); }
Player::collideWithAsteroid(Asteroid& a) { resolveCollision(*this, a); }
resolveCollision(Player, Asteroid) { p.loseHealth(100); a.explode(); }

优秀的论文加一分。附上图片会更好哦;-) - Thomas Matthews
非常感谢您的解释。C++不是游戏开发的最佳选择,这是真的吗? - amirouche
2
C++ 在我看来是游戏开发中最好的选择之一。当需要时,您可以更好地控制内存并访问低级调用。但是,由于我从未尝试过使用除 C++ 和 Java 以外的任何语言制作游戏,因此我的观点可能有偏见。 - Adam W

4

一个想法:
继承:每个玩家可以碰撞的对象都有一个CollideWithPlayer方法,执行对象需要的操作。

例如,C++伪代码如下:

class Item : GameObject { 
public:
    CollideWithPlayer( Player p );
}

class PointBag : Item {
public:
    CollideWithPlayer( Player p ) { p.points += 5000; }
}

1

你可以使用外部库,如Nvidia PhysX或Bullet,这些库可以让你设置回调函数来处理碰撞事件。通过使用这样的库,你不需要使用Qt的碰撞系统,而是在每一帧中模拟物理效果,然后更新GraphicsPixmapItem的属性以反映它们在物理模拟中的状态。


0
你可以看一下以下的Qt示例:碰撞小鼠示例。 这很容易,它将为您提供有关使用Qt处理基本碰撞的非常好的介绍。
简单地总结一下,每个对象都将有一个边界框,它将给出它使用的空间... 然后您将使用这些边界框来判断物品是否相互接触...
希望这可以帮助到你!

http://web.archive.org/web/20100409105849/http://doc.trolltech.com/4.6/graphicsview-collidingmice.html - Fuhrmanator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接