【问题标题】:How to move multiple rectangles as collision response?如何移动多个矩形作为碰撞响应?
【发布时间】:2010-07-28 15:00:21
【问题描述】:

我正在尝试制作一款游戏(使用带有 c++ 的 irrlicht 引擎),您可以在其中使用盒子来诱捕敌人。但是我只是不知道如何检测当检测到用户与一个或多个盒子之间的碰撞时应该移动什么。另一件事是,还会有一些称为砖块的物体可以阻挡移动。

由于我不太擅长解释事情,所以我附上了一张图片,希望它能澄清我的意思:
(来源:jrahmati.info)

我用我的代码尝试了几件事,但没有成功。所以我真的希望有人会努力回答这个问题。提前致谢。 顺便说一句,我不需要c++的答案,java或.Net语言也可以。

对于任何对代码感兴趣的人:

bool Game::tryMove(user, dir) 的内容,它试图将所有东西从玩家身上移开

bool thereIsCollision = false;
bool undoMovements = false;
bool userCollision = false;
do{
    thereIsCollision = false;
    for (int i = 0; i < totalObjects; i++) {
        //First check if object hits the user
        if(gameObjects[i].hits(user)){
            if (gameObjects[i]->isMovable()) {
                MovableObject* mObject = (MovableObject*) gameObjects[i];
                mObject->move(dir);
                mObject->setPushVector(dir);
                userCollision = true;
                //thereIsCollision = true;
            }
            else{
                undoMovements = true;
                thereIsCollision = false; //To break do-while loop
                userCollision = true;
                break;
            }
        }
    }
    if(undoMovements)
        break;
    for (int i = 0; i < totalObjects; i++) {
        //Then check if objects hit each other
        for (int i2 = 0; i2 < totalObjects; i2++) {
            if(i == i2)
                continue;
            if (gameObjects[i2].hits(gameObjects[i])){
               //thereIsCollision = true;
               if(gameObjects[i]->isMovable() && gameObjects[i2]->isMovable()){
                   MovableObject* mObject = (MovableObject*) gameObjects[i];
                   MovableObject* mObject2 = (MovableObject*) gameObjects[i2];
                   if(mObject->getPushVector().X > 0 
                           || mObject->getPushVector().Y > 0 
                           || mObject->getPushVector().Z > 0){
                       mObject2->move(mObject->getPushVector());
                       mObject2->setPushVector(mObject->getPushVector());
                       mObject->setPushVector(irr::core::vector3df(0, 0, 0));
                   }
                   else if(mObject2->getPushVector().X > 0 
                           || mObject2->getPushVector().Y > 0 
                           || mObject2->getPushVector().Z > 0){
                       mObject->move(mObject2->getPushVector());
                       mObject->setPushVector(mObject2->getPushVector());
                       mObject2->setPushVector(irr::core::vector3df(0, 0, 0));
                   }
               }
               else{
                   undoMovements = true;
                   thereIsCollision = false; //To break do-while loop
                   break;
               }
           }
        }
    }
}while(thereIsCollision);

for (int i = 0; i < totalObjects; i++) {
    if (gameObjects[i]->isMovable()) {
        MovableObject* mObject = (MovableObject*) gameObjects[i];
        if(undoMovements){
            // Resets position of gameObject to its previous one
            mObject->undoMovement();
        }
        else{
            // confirms movement(i.e. prevPosition=curPosition)
            mObject->confirmMovement();
        }
    }
}
return !(userCollision);

【问题讨论】:

  • 我认为你提供的代码太多已经把所有人都吓跑了。
  • 我想代码甚至都不需要,因为我只想知道如何去做。

标签: c++ response collision irrlicht


【解决方案1】:

这是一种推箱子游戏,玩家可以向 8 个方向移动,并且可以同时移动多个盒子吗?是从鸟瞰视图中看到的游戏场,就像在推箱子中一样,还是我们在示例中看到的掉落的盒子(侧视图,就像在俄罗斯方块中一样)?盒子和玩家之间的摩擦力是无限的吗(换句话说,当玩家触摸的盒子斜向移动时,是否禁止玩家触摸的盒子从玩家移动的方向滑开)?两个盒子之间的摩擦力是无穷大吗?

我无法专注于您的代码,但这是我的 2cents 算法。该算法暗示任何两个物体之间的摩擦力是无限的。

当玩家移动时,您需要确定哪些可移动物体可能会受到影响。将玩家在移动方向上触摸的对象放入某个搜索堆栈,然后为搜索堆栈中的每个项目重复搜索过程,将更多对象放入其中。最后你会用完可移动的物体。如果在任何时候你偶然发现了一个不可移动的物体,那么玩家也不能移动(因为无限摩擦规则),所以什么都不会移动。如果没有涉及不可移动的对象,则将堆栈中的所有对象移动一个网格单位。

【讨论】:

  • 感谢 Dialecticus,我认为搜索堆栈可以解决问题。
【解决方案2】:

据我了解,您使用的是 2d 或 3d 空间,并且您的对象没有放置在某种网格上(即坐标是浮点数)。在这种情况下,有两种解决方案:

解决方案 #1:

使用物理引擎,例如 PhysX。

解决方案 #2:

  1. 重复 10 或 20 次或直到不再有碰撞:
    1.1 找到所有重叠(碰撞)的物体。这包括播放器和盒子。还有盒子与其他盒子碰撞。
    1.2 为每个对象创建“移动”向量(多少对象应移动以响应碰撞)m 并将其初始化为全零(x: 0, y: 0, z: 0)。
    1.3 对于每对碰撞(重叠)对象 A 和 B,计算将它们推开的向量(比如“pushAwayVector”)。将该向量添加到 A.move 和 B.move。请记住,物体是相互推开的,因此您应该注意符号和大小。即A.move += pushAway*0.5f; B.move += -0.5f*pushAway;。不要替换 .move 为 pushAway 向量,而是添加 pushAway 来移动。否则结果将不太可靠。你也可以考虑物体的质量,像这样:A.move += (B.mass/(A.mass + B.mass))*pushAway; B.move += -(A.mass/(A.mass+B.mass))*pushAway;,在这种情况下,较轻的物体会更难推重物体;
    1.4 处理完所有重叠对象后,对所有对象执行obj.position += obj.move;

请注意,在每种情况下,盒子都不能保证保持精确的相对位置。但是当玩家移动时它们会被推开,并且会阻挡玩家的移动。

请注意,使用物理引擎会产生更接近您想要的结果。

另一种解决方案是,一旦玩家接触到一个盒子,找到相互碰撞的一组盒子和一个玩家,然后移除不会受到当前玩家移动影响的盒子。但是,我不喜欢这种解决方案——它很混乱,缺乏优雅,尽管它会保持相对的对象位置(这也看起来不切实际)。

我建议使用物理引擎。

【讨论】:

  • 感谢您对 SigTerm 的回答,我会检查您的任何想法是否可行。 SigTerm:“据我了解,您使用的是 2d 或 3d 空间,并且您的对象没有放置在某种网格上(即坐标是浮点数)”第三维无关紧要,因为包含框的用户是无论如何都在地面上不断移动(即盒子太大以至于用户无论如何都无法跳上它们)
  • 糟糕,我忘了提一点,我的问题是还有一些叫做砖块的物体会阻挡用户移动。
  • @ILikeGameProgramming:对于不可移动的物体,永远不要改变移动向量。 IE。用于碰撞对象 A 和 B 如果 B 不可移动 A.move += pushAway; 并且 B.move 保持不变。其余的都是一样的。
  • 其实我不是很理解那种推脱的想法。现在我正在尝试移动玩家击中的每一个可移动的东西,但不知何故我得到了一个无限循环。
  • 我如何实际计算 pushAway?那是碰撞物体之间的重叠区域还是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多