Обнаружение столкновений OBB;SAT неверно;three.js - PullRequest
0 голосов
/ 13 сентября 2018

Я реализую коллизию OBB, используя Three.JS и TypeScript.Я успешно реализовал метод обнаружения коллизий, но я решил следовать за реализацией в Lua, чтобы создать ответ на коллизию.

Мой код:

private static getAxes(rot: number){
        let playerParallelAxis = new Vector3(Math.sin(rot), 0, Math.cos(rot));
        let playerPerpendicularAxis = new Vector3(Math.cos(rot), 0, Math.sin(rot));

        let blockParallelAxis = new Vector3(0, 0, 1);
        let blockPerpendicularAxis = new Vector3(1, 0, 0);

        return [playerParallelAxis, playerPerpendicularAxis, blockParallelAxis, blockPerpendicularAxis];
    }

    private static getCorners(pos: Vector3, rot?: number){
        let corners: Array<Vector3> = new Array();
        if(isNaN(rot)){
            corners.push(pos.clone());
            corners.push(pos.clone().add(new Vector3(0, 0, 1)));
            corners.push(pos.clone().add(new Vector3(1, 0, 1)));
            corners.push(pos.clone().add(new Vector3(1, 0, 0)));
        }else{

            const radius = Math.sqrt(0.75 * 0.75 + 0.5 * 0.5);
            const phi = Math.PI / 2;
            const theta = Math.atan(0.5/0.75);

             //front right
             corners.push(new Vector3().setFromSpherical(new Spherical(radius, phi, rot - theta)).add(pos).setY(0));

             //front left
             corners.push(new Vector3().setFromSpherical(new Spherical(radius, phi, rot + theta)).add(pos).setY(0));

             //back left
             corners.push(new Vector3().setFromSpherical(new Spherical(radius, phi,  Math.PI + rot - theta)).add(pos).setY(0));

             //back right
             corners.push(new Vector3().setFromSpherical(new Spherical(radius, phi,  Math.PI + rot + theta)).add(pos).setY(0));
        }
        return corners;
    }

    private static isPositionBlock(pos: Vector3){
        for(let i = 0; i < blockPositions.length; i ++){
            if(blockPositions[i].equals(pos)) return true;
        }
        return false;
    }
static test(playerPos: Vector3, playerRot: number){
    playerPos.add(new Vector3(0.5, 0, 0.5));
    let blockPos = playerPos.clone().floor();
    let blockPositions: Array<Vector3> = new Array();
    for(let x = blockPos.x - 1; x <= blockPos.x + 1; x ++){
        for(let z = blockPos.z - 1; z <= blockPos.z + 1; z ++){
            let testPos = new Vector3(x, 0, z);
            if(this.isPositionBlock(testPos)){
                blockPositions.push(testPos);
            }
        }
    }
    let correctionArray: Array<Vector3> = new Array();
    if(blockPositions.length){
        for(let i = 0; i < blockPositions.length; i ++){
            let collisionCorrection = TestCollision.collide(playerPos, playerRot, blockPositions[i]);
            if(collisionCorrection.x !== 0 || collisionCorrection.z !== 0){
                correctionArray.push(collisionCorrection);
            }

        }
    }
    return correctionArray;
}
static collide(playerPos: Vector3, playerRot: number, blockPos: Vector3){
    const between = (val: number, min: number, max: number ): boolean => {
        return min <= val && max >= val;
    };

    let playerCorners = TestCollision.getCorners(playerPos, playerRot);
    let blockCorners = TestCollision.getCorners(blockPos);

    let axes = TestCollision.getAxes(playerRot);

    let mtvs: Array<Vector3> = new Array();

    for(let i = 0; i < axes.length; i ++){

        let playerScalars: Array<number> = new Array();
        let blockScalars: Array<number> = new Array();

        for(let k = 0; k < axes.length; k ++){
            //playerScalars.push(TestCollision.dot(axes[i], playerCorners[k]));
            //blockScalars.push(TestCollision.dot(axes[i], blockCorners[k]));
            playerScalars.push(playerCorners[k].dot(axes[i]));
            blockScalars.push(blockCorners[k].dot(axes[i]));
        }

        let playerMax = Math.max.apply(null, playerScalars);
        let playerMin = Math.min.apply(null, playerScalars);

        let blockMax = Math.max.apply(null, blockScalars);
        let blockMin = Math.min.apply(null, blockScalars);

        // if(blockMin > playerMax || blockMax < playerMin){
        //     return new Vector3(); //there is no collision.
        // }
        if(between(playerMin, blockMin, blockMax) || between(blockMin, playerMin, playerMax)){
            return new Vector3();
        }
        let overlap = playerMax - blockMin;
        if(playerMax > blockMax){
            overlap = - (blockMax - playerMin);
        }

        mtvs.push(axes[i].clone().multiplyScalar(overlap)); //clone not needed??    
    }

    let distance = mtvs[0].lengthSq();
    let shortestVec = mtvs[0];
    for(let i = 1; i < mtvs.length; i++){
        let squareLength = mtvs[i].lengthSq();
        if(squareLength < distance){
            distance = squareLength;
            shortestVec = mtvs[i];
        }
    }
    return shortestVec;
}

Я вызываю тестовую функцию с клонированным вектором, и, насколько мне известно, все позиционные данные верны,

Ложный результатприходит в этой ситуации.http://prntscr.com/ktwsqq Передний правый угол резервуара пересекает пустой блок рядом с заполненным.Поэтому я считаю, что это связано с playerParallelAxis, так как эта ось должна легко доказать, что столкновения нет.

Реализация Lua здесь: https://www.youtube.com/watch?v=IELWpIGtjRg, и код захватывается с помощью скриншотов, так как автор этого не сделалпотрудитесь опубликовать код на GitHub.

https://prnt.sc/kti65j https://prnt.sc/kti5wc

Вот весь класс в ветви разработки: https://github.com/DakotaLarson/Tanks-Client/blob/develop/src/arena/CollisionHandler.ts

Кодвызывается из класса Player в подкаталоге player каталога, содержащего CollisionHandler.

Если у вас есть какие-либо вопросы или вам нужны дополнительные объяснения, дайте мне знать!

РЕДАКТИРОВАТЬ 9/15/18 Мне удалось найти решение, используя код, который я уже имел в классе.Не спрашивайте меня, почему приведенный выше код не работает.Я, честно говоря, понятия не имею.Код вставляется здесь: https://github.com/DakotaLarson/Tanks-Client/blob/develop/src/arena/CollisionHandler.ts

РЕДАКТИРОВАТЬ 4/8/19 Я переместил этот код в три класса: https://github.com/DakotaLarson/BattleTanks-Client/tree/master/src/arena/collision

...