【问题标题】:Collision detection in voxel world体素世界中的碰撞检测
【发布时间】:2017-04-05 03:37:12
【问题描述】:

我现在有点坚持我的基本体素物理学。它非常非常不稳定,我很确定我的数学在某个地方被打破了,但让我们看看你要说什么:

// SOMEWHERE AT CLASS LEVEL (so not being reinstantiated every frame, but persisted instead!)
glm::vec3 oldPos;

// ACTUAL IMPL
glm::vec3 distanceToGravityCenter =
        this->entity->getPosition() -
        ((this->entity->getPosition() - gravityCenter) * 0.005d); // TODO multiply by time

if (!entity->grounded) {
    glm::vec3 entityPosition = entity->getPosition();

    if (getBlock(floorf(entityPosition.x), floorf(entityPosition.y), floorf(entityPosition.z))) {
        glm::vec3 dir = entityPosition - oldPos; // Actually no need to normalize as we check for lesser, bigger or equal to 0

        std::cout << "falling dir: " << glm::to_string(dir) << std::endl;

        // Calculate offset (where to put after hit)
        int x = dir.x;
        int y = dir.y;
        int z = dir.z;

        if (dir.x >= 0) {
            x = -1;
        } else if (dir.x < 0) {
            x = 1;
        }

        if (dir.y >= 0) {
            y = -1;
        } else if (dir.y < 0) {
            y = 1;
        }

        if (dir.z >= 0) {
            z = -1;
        } else if (dir.z < 0) {
            z = 1;
        }

        glm::vec3 newPos = oldPos + glm::vec3(x, y, z);
        this->entity->setPosition(newPos);
        entity->grounded = true; // If some update happens, grounded needs to be changed
    } else {
        oldPos = entity->getPosition();
        this->entity->setPosition(distanceToGravityCenter);
    }
}

基本想法是确定实体从哪个方向撞击表面,然后将其定位为一个“单元”回到那个方向。但显然我做错了什么,因为这总是会将实体移回它的来源点,有效地将其保持在生成点。

这可能会容易得多,我想多了。

【问题讨论】:

  • if (dir.x &gt;= 0) { x = -1; } if (dir.x &lt; 0) { x = 1; } - 这对我来说似乎毫无用处......x 最终将永远是1。你的意思是else ifedit这会导致你描述的行为,所以我会回答。
  • @CompuChip 当然,一个愚蠢的错误消失了,还有多少其他人潜伏在那里?但这不是唯一的问题,它仍然非常非常不稳定。

标签: c++ collision-detection voxel


【解决方案1】:

正如@CompuChip 已经指出的,您的ifs 可以进一步简化。

但更重要的是一个逻辑问题可以解释你描述的“断断续续”(遗憾的是你没有提供任何镜头,所以这是我最好的猜测)

根据您发布的代码:

首先检查实体是否接地。如果是,则继续检查是否存在碰撞,最后,如果没有,则设置位置。

你必须稍微反转一下。

  1. 保存旧位置
  2. 检查是否接地
  3. 已将位置设置为新位置!
  4. 进行碰撞检测
  5. 如果您记录了碰撞,请重置为旧位置!

所以基本上:

glm::vec3 distanceToGravityCenter =
        this->entity->getPosition() -
        ((this->entity->getPosition() - gravityCenter) * 0.005d); // TODO multiply by time

oldPos = entity->getPosition(); // 1.

if (!entity->grounded) { // 2.
    this->fallingStar->setPosition(distanceToGravityPoint); // 3

    glm::vec3 entityPosition = entity->getPosition();

    if (getBlock(floorf(entityPosition.x), floorf(entityPosition.y), floorf(entityPosition.z))) { // 4, 5
        this->entity->setPosition(oldPos);
        entity->grounded = true; // If some update happens, grounded needs to be changed
    }
}

这应该让你开始:)

我想详细说明一下:

如果您首先检查碰撞,然后设置位置,您会在第一次碰撞/碰撞时创建一个“无限循环”,然后如果发生碰撞(确实存在),您将设置回旧位置。基本上只是数学上的不准确会让你移动,因为每次检查你都会回到原来的位置。

【讨论】:

    【解决方案2】:

    考虑您的坐标之一的if-语句:

    if (dir.x >= 0) {
        x = -1;
    }
    
    if (dir.x < 0) {
        x = 1;
    }
    

    假设dir.x &lt; 0。然后你将跳过第一个if,输入第二个,x 将被设置为 1。 如果dir.x &gt;= 0,您将输入第一个if,而x 将设置为-1。现在x &lt; 0 为真,因此您也将输入第二个ifx 再次设置为 1。

    您可能想要将x 设置为1 或-1,具体取决于dir.x。你应该只在第一个没有输入的时候执行第二个if,所以你需要一个else if

    if (dir.x >= 0) {
        x = -1;
    } else if (dir.x < 0) {
        x = 1;
    }
    

    如果你愿意,可以浓缩成

    x = (dir.x >= 0) ? -1 : 1;
    

    【讨论】:

      猜你喜欢
      • 2017-05-28
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 2013-08-25
      • 1970-01-01
      • 2015-02-01
      • 2014-02-04
      • 1970-01-01
      相关资源
      最近更新 更多