Я реализую коллизию 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