我正在使用Three.JS和TypeScript实现OBB冲突。我成功实现了一种检测碰撞的方法,但是我决定遵循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
这是develop分支上的整个课程:https://github.com/DakotaLarson/Tanks-Client/blob/develop/src/arena/CollisionHandler.ts
从包含CollisionHandler的目录的player子目录中的Player类调用代码。
如果您有任何疑问或需要进一步说明,请告诉我!
修改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