体素世界中的碰撞检测

时间:2017-04-03 21:16:40

标签: c++ collision-detection voxel

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

// 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);
    }
}

基本思想是确定实体将从哪个方向击中表面,然后将一个“单位”放回到该方向。但显然我做错了,因为它总会将实体移回到它产生的位置,有效地将它保持在产生点。

这也可能更容易,我正在思考它。

2 个答案:

答案 0 :(得分:1)

考虑一个坐标的if - 语句:

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

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

假设dir.x < 0。然后,您将跳过第一个if,输入第二个,x将设置为1。 如果dir.x >= 0,您将输入第一个ifx将设置为-1。现在x < 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;

如果您愿意,可以将其浓缩为

class Reaction(models.Model):
    first_object = models.ForeignKey(Object, related_name='first_object')
    second_object = models.ForeignKey(Object, related_name='second_object')
    result_object = models.ForeignKey(Object, related_name='result_object')
    class Meta:
        unique_together = (('first_object', 'second_object',),)

答案 1 :(得分:1)

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

但更重要的是一个逻辑问题可以解释&#34;波动&#34;你描述(可悲的是你没有提供任何镜头,所以这是我最好的猜测)

根据您发布的代码:

首先检查实体是否已接地。如果是这样,你继续检查是否有碰撞,最后,如果没有,你设置位置。

你必须反过来。

  1. 保存旧位置
  2. 检查是否接地
  3. 将位置设置为新位置!
  4. 进行碰撞检测
  5. 如果您发生了碰撞,请重置为旧位置!
  6. 基本上是这样的:

    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
        }
    }
    

    这应该让你开始:)

    我想详细说明一下:

    如果先检查碰撞然后再设置位置,则会创建一个&#34;无限循环&#34;当你碰撞时第一次碰撞/撞击,然后如果发生碰撞(有),你就会回到原来的位置。基本上只是数学上的不准确会让你移动,因为每次检查都会让你回到原来的位置。