Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 基本三维碰撞检测问题_Java_Collision Detection_Game Engine_Game Physics_Voxel - Fatal编程技术网

Java 基本三维碰撞检测问题

Java 基本三维碰撞检测问题,java,collision-detection,game-engine,game-physics,voxel,Java,Collision Detection,Game Engine,Game Physics,Voxel,我正在尝试为一个应用程序实现基本的碰撞检测 我正在开发基于体素的3D Java游戏。我正在努力实施 此站点的算法: , 但我似乎不能把它弄对。我的问题 他所说的“将球员的位置转换为”是什么意思 体素空间'。我应该把玩家的坐标四舍五入到 最近的块,因此播放器所在的体素就是该块 球员的中锋在哪里?在我的游戏中,玩家 当前是一个体素大小的立方体 那个网站上的家伙写道,他只需要检查一个 用于碰撞的体素。但如果我只检查中心的体素 球员的中心在,那么球员的中心需要 在他撞到东西之前先把它们交叉。这是不应该

我正在尝试为一个应用程序实现基本的碰撞检测 我正在开发基于体素的3D Java游戏。我正在努力实施 此站点的算法: , 但我似乎不能把它弄对。我的问题 他所说的“将球员的位置转换为”是什么意思 体素空间'。我应该把玩家的坐标四舍五入到 最近的块,因此播放器所在的体素就是该块 球员的中锋在哪里?在我的游戏中,玩家 当前是一个体素大小的立方体

那个网站上的家伙写道,他只需要检查一个 用于碰撞的体素。但如果我只检查中心的体素 球员的中心在,那么球员的中心需要 在他撞到东西之前先把它们交叉。这是不应该的 像那样,对吗?如果球员的中锋在 非活动体素,但玩家立方体的一部分相交 一个活动体素,我应该检查哪个体素

我意识到这篇文章很混乱,但我希望你能理解 理解我的问题。如果您想看一些代码,这里是我的CollisionHandler类:(由于我一直遇到的问题,它还没有真正遵循上面站点的算法。它现在只关心沿x轴的碰撞)


如何处理碰撞是您的设计决定,按照您认为最自然的方式进行(详细说明如下):

最接近玩家位置的单个体素是基础,通过使碰撞检测对体素进行检查,您可以从中轻松衍生出更复杂的方法。然后,您可以轻松地扩展它以检查多个相邻体素,从而为玩家提供您想要的大小

例如,您可以将播放器视为圆柱体,并检查圆柱体覆盖的圆下方的所有体素。如果你检测到(例如)圆圈下方的单个熔岩体素,你可以应用熔岩伤害(无论你的游戏使用什么地面属性)

另一个需要试验的问题是海拔高度。你是用覆盖体素的最高值、最低值还是某种平均值来确定玩家当前所在的位置(或者飞行时与地面相撞的高度)

没有单一的方法可以让你“感觉良好”。你需要做一点实验,找出你认为游戏的物理模型是“自然”的

如果您的物理允许快速移动,您可能需要扩展碰撞检查,以检查两个游戏步骤之间对象覆盖的整个形状,以避免子弹穿过障碍物等奇怪现象。因为从技术上讲,它们的移动速度非常快,即使它们的运动矢量与障碍物明显相交,也永远不会在障碍物内找到位置

所以“将玩家坐标转换为体素空间”可以是任何意思,它没有详细定义方法。对于初始测试,您的“四舍五入到最近的区块”可能足够好,对于最终游戏,您可能需要应用上面概述的一些概念,使其物理“感觉正确”

public class CollisionHandler {
private static final float COLLISION_TOLERANCE = 0.4f;
private boolean xCol, yCol, zCol = false;

public void handleCollisions(ChunkManager chunkManager,
        FPCameraController player, float delta) {

    Vector3D playerPos = player.getPosition();
    Vector3D collision = findCollisionVector(player, chunkManager);

    if (collidesWithWorld()) {
        if (!(player.isFalling() && isGrounded(playerPos, chunkManager))) {
            player.setCollisionVector(collision);
            player.translateX(-playerPos.subtract(playerPos.round()).getX());
        }else{
            //123456
        }
    } else {
        if (player.isFalling()) {
            if (isGrounded(playerPos, chunkManager)) {
                float overlap = getYOverlap(player, chunkManager);
                player.translateY(overlap);
                player.setYSpeed(0);
                player.setIsFalling(false);
            } else {
                player.applyGravity(delta);
            }
        } else {
            if (!isGrounded(playerPos, chunkManager)) {
                player.setIsFalling(true);
                player.applyGravity(delta);
            }
        }

    }
}

private boolean collidesWithWorld() {
    return xCol || yCol || zCol;
}

/*
 * Returns a collision vector. Dot with velocity and then subtract it from
 * the player velocity.
 */
private Vector3D findCollisionVector(FPCameraController player,
        ChunkManager chunkManager) {

    Vector3D playerPos = player.getPosition();
    Vector3D distance = playerPos.subtract(playerPos.floor()).abs();

    Vector3D collisions = new Vector3D(1, 1, 1);
    float xDirection = (getCollisionDirection(distance.getX()));
    // float yDirection = (getCollisionDirection(distance.getY()));
    // float zDirection = (getCollisionDirection(distance.getZ()));

    try {
        Vector3D collision = getCollisionNormal(chunkManager, playerPos,
                xDirection, 'x');

        if (collision != null) {
            collisions = collision;
            xCol = true;
        } else {
            xCol = false;
        }

        // collision = getCollisionNormal(chunkManager, playerPos,
        // yDirection,
        // 'y');
        // if (collision != null) {
        // collisions.cross(collision);
        // yCol = true;
        // } else {
        // yCol = false;
        // }
        //
        // collision = getCollisionNormal(chunkManager, playerPos,
        // zDirection,
        // 'z');
        // if (collision != null) {
        // collisions.cross(collision);
        // zCol = true;
        // } else {
        // zCol = false;
        // }
    } catch (OutsideOfWorldException e) {
        e.printStackTrace();
    }

    return collisions;
}

/*
 * Returns the normal of the colliding block, given the axis and
 * direction.
 */
private static Vector3D getCollisionNormal(ChunkManager chunkManager,
        Vector3D playerPos, float direction, char axis)
        throws OutsideOfWorldException {
    Block b;
    Vector3D blockPos;
    if (direction != 0) {
        Vector3D dirVector;
        if (axis == 'x') {
            dirVector = new Vector3D(direction, 0, 0);
        } else if (axis == 'y') {
            dirVector = new Vector3D(0, direction, 0);
        } else if (axis == 'z') {
            dirVector = new Vector3D(0, 0, direction);
        } else {
            return null;
        }
        blockPos = playerPos.add(dirVector);

        b = chunkManager.getBlock(blockPos);

        if (b.isActive()) {

            return Plane3D.getBlockNormal(blockPos, direction, axis);
        }
    }
    return null;
}

private static float getCollisionDirection(float distance) {
    if (distance > COLLISION_TOLERANCE) {
        return 1;
    } else if (distance < COLLISION_TOLERANCE) {
        return -1;
    }
    return 0;
}

private static boolean isGrounded(Vector3D playerPosition,
        ChunkManager chunkManager) {
    try {
        return chunkManager.getBlock(
                playerPosition.add(new Vector3D(0, -1, 0))).isActive();
    } catch (OutsideOfWorldException e) {
        e.printStackTrace();
    }
    return true;
}

private static float getYOverlap(FPCameraController player,
        ChunkManager chunkManager) {
    Vector3D playerPosition = player.getPosition();
    Vector3D blockPosition = player.getLowestBlockPos();
    Block collisionBlock = null;

    try {
        collisionBlock = chunkManager.getBlock(blockPosition);

        // +" "+blockPosition);

        if (collisionBlock.isActive()) {
            float distance = playerPosition.subtract(blockPosition).getY();

            distance += player.getHeight();

            return -distance;

        }
    } catch (OutsideOfWorldException e) {
        e.printStackTrace();
    }

    return 0;
}
}
    public static Vector3D getBlockNormal(Vector3D blockPos, float direction,
        char axis) {
    float offset = Block.BLOCK_RENDER_SIZE / 2f;

    Vector3D pointA = null;
    Vector3D pointB = null;
    Vector3D pointC = null;

    Vector3D a = blockPos.round();

    a = a.addScalar(Block.BLOCK_RENDER_SIZE / 2f);
    float factor = -direction;
    if (axis == 'x') {
        pointA = a.add(new Vector3D(factor * offset, -offset, -offset));
        pointB = a.add(new Vector3D(factor * offset, offset, -offset));
        pointC = a.add(new Vector3D(factor * offset, -offset, offset));
    } else if (axis == 'y') {
        pointA = a.add(new Vector3D(-offset, factor * offset, offset));
        pointB = a.add(new Vector3D(offset, factor * offset, offset));
        pointC = a.add(new Vector3D(offset, factor * offset, -offset));
    } else if (axis == 'z') {
        pointA = a.add(new Vector3D(-offset, -offset, factor * offset));
        pointB = a.add(new Vector3D(offset, -offset, factor * offset));
        pointC = a.add(new Vector3D(offset, offset, factor * offset));
    } else {
        return null;
    }

    Vector3D v = new Vector3D(pointB.getX() - pointA.getX(), pointB.getY()
            - pointA.getY(), pointB.getZ() - pointA.getZ()).normalize();
    Vector3D w = new Vector3D(pointC.getX() - pointA.getX(), pointC.getY()
            - pointA.getY(), pointC.getZ() - pointA.getZ()).normalize();
    Vector3D normal = v.cross(w).scale(-1);

    return normal.scale(factor);

}