fix(ignore): 放宽栅栏判定并加入静态形状诊断
静态障碍不再只认三角形:非三角形静态碰撞代理直接视为障碍,三角形按法线 |nz|<0.5 判定;新增 __hornetNoClip__.DebugFence(true) 打印静态形状样本(cat/type/三角/nz/是否跳过),用于定位未生效原因。
This commit is contained in:
1 parent
f3db51cf4b
commit
63c08ab165
3 files changed
+159
-27
No files matched your search
@@ -6638,19 +6638,29 @@
|
||||
}
|
||||
|
||||
// 三角形是否「陡」:法线 z 分量接近 0(墙/栅栏/悬崖立面)
|
||||
function IsSteepTriangle(Shape) {
|
||||
if (!Shape || Shape[FShapeType] !== TRIANGLE_TYPE) return false;
|
||||
function IsTriangle(Shape) {
|
||||
return !!(Shape && Shape[FShapeType] === TRIANGLE_TYPE);
|
||||
}
|
||||
|
||||
// 返回法线 z 分量(-1..1);读不到返回 null
|
||||
function TriangleNormalZ(Shape) {
|
||||
if (!IsTriangle(Shape)) return null;
|
||||
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
|
||||
if (!A || !B || !C) return false;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return false;
|
||||
if (!A || !B || !C) return null;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return null;
|
||||
var ABx = B.f20_1 - A.f20_1, ABy = B.g20_1 - A.g20_1, ABz = B.h20_1 - A.h20_1;
|
||||
var ACx = C.f20_1 - A.f20_1, ACy = C.g20_1 - A.g20_1, ACz = C.h20_1 - A.h20_1;
|
||||
var Nx = ABy * ACz - ABz * ACy;
|
||||
var Ny = ABz * ACx - ABx * ACz;
|
||||
var Nz = ABx * ACy - ABy * ACx;
|
||||
var Len = Math.sqrt(Nx * Nx + Ny * Ny + Nz * Nz);
|
||||
if (!(Len > 1e-6)) return false;
|
||||
return Math.abs(Nz / Len) < FENCE_NORMAL_Z;
|
||||
if (!(Len > 1e-6)) return null;
|
||||
return Nz / Len;
|
||||
}
|
||||
|
||||
function IsSteepTriangle(Shape) {
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
return Nz !== null && Math.abs(Nz) < FENCE_NORMAL_Z;
|
||||
}
|
||||
|
||||
// 静态几何:category 含 bit4,且不是坦克部件
|
||||
@@ -6660,6 +6670,30 @@
|
||||
return !IsTankShape(Shape);
|
||||
}
|
||||
|
||||
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
|
||||
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
|
||||
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
|
||||
function IsFenceLike(Shape) {
|
||||
if (!IsStaticShape(Shape)) return false;
|
||||
if (!IsTriangle(Shape)) return true;
|
||||
return IsSteepTriangle(Shape);
|
||||
}
|
||||
|
||||
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
|
||||
var FenceSampleKeys = {};
|
||||
function RecordFenceSample(Shape) {
|
||||
if (window.__hornetFenceDebug__ !== true) return;
|
||||
var Cat = Shape[FShapeCategory];
|
||||
var Type = Shape[FShapeType];
|
||||
var Tri = IsTriangle(Shape);
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
|
||||
if (FenceSampleKeys[Key]) return;
|
||||
FenceSampleKeys[Key] = 1;
|
||||
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
|
||||
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
|
||||
}
|
||||
|
||||
// ===== 判定:这一对形状要不要跳过 =====
|
||||
function ShouldSkip(ShapeA, ShapeB) {
|
||||
var Local = GetLocalPhysics();
|
||||
@@ -6687,13 +6721,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ② 忽略栅栏(只跳过陡峭静态三角形,保留地面/缓坡)
|
||||
// ② 忽略栅栏(静态障碍;地面/缓坡保留)
|
||||
if (Stat.ignoreFence && Local) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB) && IsSteepTriangle(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA) && IsSteepTriangle(ShapeA))) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) {
|
||||
Stat.skippedFence++;
|
||||
return true;
|
||||
}
|
||||
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
|
||||
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
|
||||
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -6808,6 +6845,13 @@
|
||||
IsTankOwner: IsTankOwner,
|
||||
IsTankShape: IsTankShape,
|
||||
IsSteepTriangle: IsSteepTriangle,
|
||||
IsFenceLike: IsFenceLike,
|
||||
// 诊断:__hornetNoClip__.DebugFence(true) 后撞一次墙,控制台会打印静态形状样本
|
||||
DebugFence: function (On) {
|
||||
window.__hornetFenceDebug__ = On !== false;
|
||||
FenceSampleKeys = {};
|
||||
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
|
||||
},
|
||||
GetStat: function () {
|
||||
return {
|
||||
running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence,
|
||||
|
||||
+53
-9
@@ -6638,19 +6638,29 @@
|
||||
}
|
||||
|
||||
// 三角形是否「陡」:法线 z 分量接近 0(墙/栅栏/悬崖立面)
|
||||
function IsSteepTriangle(Shape) {
|
||||
if (!Shape || Shape[FShapeType] !== TRIANGLE_TYPE) return false;
|
||||
function IsTriangle(Shape) {
|
||||
return !!(Shape && Shape[FShapeType] === TRIANGLE_TYPE);
|
||||
}
|
||||
|
||||
// 返回法线 z 分量(-1..1);读不到返回 null
|
||||
function TriangleNormalZ(Shape) {
|
||||
if (!IsTriangle(Shape)) return null;
|
||||
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
|
||||
if (!A || !B || !C) return false;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return false;
|
||||
if (!A || !B || !C) return null;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return null;
|
||||
var ABx = B.f20_1 - A.f20_1, ABy = B.g20_1 - A.g20_1, ABz = B.h20_1 - A.h20_1;
|
||||
var ACx = C.f20_1 - A.f20_1, ACy = C.g20_1 - A.g20_1, ACz = C.h20_1 - A.h20_1;
|
||||
var Nx = ABy * ACz - ABz * ACy;
|
||||
var Ny = ABz * ACx - ABx * ACz;
|
||||
var Nz = ABx * ACy - ABy * ACx;
|
||||
var Len = Math.sqrt(Nx * Nx + Ny * Ny + Nz * Nz);
|
||||
if (!(Len > 1e-6)) return false;
|
||||
return Math.abs(Nz / Len) < FENCE_NORMAL_Z;
|
||||
if (!(Len > 1e-6)) return null;
|
||||
return Nz / Len;
|
||||
}
|
||||
|
||||
function IsSteepTriangle(Shape) {
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
return Nz !== null && Math.abs(Nz) < FENCE_NORMAL_Z;
|
||||
}
|
||||
|
||||
// 静态几何:category 含 bit4,且不是坦克部件
|
||||
@@ -6660,6 +6670,30 @@
|
||||
return !IsTankShape(Shape);
|
||||
}
|
||||
|
||||
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
|
||||
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
|
||||
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
|
||||
function IsFenceLike(Shape) {
|
||||
if (!IsStaticShape(Shape)) return false;
|
||||
if (!IsTriangle(Shape)) return true;
|
||||
return IsSteepTriangle(Shape);
|
||||
}
|
||||
|
||||
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
|
||||
var FenceSampleKeys = {};
|
||||
function RecordFenceSample(Shape) {
|
||||
if (window.__hornetFenceDebug__ !== true) return;
|
||||
var Cat = Shape[FShapeCategory];
|
||||
var Type = Shape[FShapeType];
|
||||
var Tri = IsTriangle(Shape);
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
|
||||
if (FenceSampleKeys[Key]) return;
|
||||
FenceSampleKeys[Key] = 1;
|
||||
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
|
||||
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
|
||||
}
|
||||
|
||||
// ===== 判定:这一对形状要不要跳过 =====
|
||||
function ShouldSkip(ShapeA, ShapeB) {
|
||||
var Local = GetLocalPhysics();
|
||||
@@ -6687,13 +6721,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ② 忽略栅栏(只跳过陡峭静态三角形,保留地面/缓坡)
|
||||
// ② 忽略栅栏(静态障碍;地面/缓坡保留)
|
||||
if (Stat.ignoreFence && Local) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB) && IsSteepTriangle(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA) && IsSteepTriangle(ShapeA))) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) {
|
||||
Stat.skippedFence++;
|
||||
return true;
|
||||
}
|
||||
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
|
||||
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
|
||||
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -6808,6 +6845,13 @@
|
||||
IsTankOwner: IsTankOwner,
|
||||
IsTankShape: IsTankShape,
|
||||
IsSteepTriangle: IsSteepTriangle,
|
||||
IsFenceLike: IsFenceLike,
|
||||
// 诊断:__hornetNoClip__.DebugFence(true) 后撞一次墙,控制台会打印静态形状样本
|
||||
DebugFence: function (On) {
|
||||
window.__hornetFenceDebug__ = On !== false;
|
||||
FenceSampleKeys = {};
|
||||
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
|
||||
},
|
||||
GetStat: function () {
|
||||
return {
|
||||
running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence,
|
||||
|
||||
+53
-9
@@ -116,19 +116,29 @@
|
||||
}
|
||||
|
||||
// 三角形是否「陡」:法线 z 分量接近 0(墙/栅栏/悬崖立面)
|
||||
function IsSteepTriangle(Shape) {
|
||||
if (!Shape || Shape[FShapeType] !== TRIANGLE_TYPE) return false;
|
||||
function IsTriangle(Shape) {
|
||||
return !!(Shape && Shape[FShapeType] === TRIANGLE_TYPE);
|
||||
}
|
||||
|
||||
// 返回法线 z 分量(-1..1);读不到返回 null
|
||||
function TriangleNormalZ(Shape) {
|
||||
if (!IsTriangle(Shape)) return null;
|
||||
var A = Shape[FV0], B = Shape[FV1], C = Shape[FV2];
|
||||
if (!A || !B || !C) return false;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return false;
|
||||
if (!A || !B || !C) return null;
|
||||
if (typeof A.f20_1 !== 'number' || typeof B.f20_1 !== 'number' || typeof C.f20_1 !== 'number') return null;
|
||||
var ABx = B.f20_1 - A.f20_1, ABy = B.g20_1 - A.g20_1, ABz = B.h20_1 - A.h20_1;
|
||||
var ACx = C.f20_1 - A.f20_1, ACy = C.g20_1 - A.g20_1, ACz = C.h20_1 - A.h20_1;
|
||||
var Nx = ABy * ACz - ABz * ACy;
|
||||
var Ny = ABz * ACx - ABx * ACz;
|
||||
var Nz = ABx * ACy - ABy * ACx;
|
||||
var Len = Math.sqrt(Nx * Nx + Ny * Ny + Nz * Nz);
|
||||
if (!(Len > 1e-6)) return false;
|
||||
return Math.abs(Nz / Len) < FENCE_NORMAL_Z;
|
||||
if (!(Len > 1e-6)) return null;
|
||||
return Nz / Len;
|
||||
}
|
||||
|
||||
function IsSteepTriangle(Shape) {
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
return Nz !== null && Math.abs(Nz) < FENCE_NORMAL_Z;
|
||||
}
|
||||
|
||||
// 静态几何:category 含 bit4,且不是坦克部件
|
||||
@@ -138,6 +148,30 @@
|
||||
return !IsTankShape(Shape);
|
||||
}
|
||||
|
||||
// 「栅栏类」= 静态几何里除地面/缓坡以外的部分:
|
||||
// · 非三角形静态体(盒/柱等碰撞代理)→ 视为障碍
|
||||
// · 三角形且法线接近水平(墙/栅栏/悬崖立面)→ 视为障碍
|
||||
function IsFenceLike(Shape) {
|
||||
if (!IsStaticShape(Shape)) return false;
|
||||
if (!IsTriangle(Shape)) return true;
|
||||
return IsSteepTriangle(Shape);
|
||||
}
|
||||
|
||||
// ===== 诊断(控制台 __hornetFenceDebug__ = true 开启)=====
|
||||
var FenceSampleKeys = {};
|
||||
function RecordFenceSample(Shape) {
|
||||
if (window.__hornetFenceDebug__ !== true) return;
|
||||
var Cat = Shape[FShapeCategory];
|
||||
var Type = Shape[FShapeType];
|
||||
var Tri = IsTriangle(Shape);
|
||||
var Nz = TriangleNormalZ(Shape);
|
||||
var Key = Cat + '/' + Type + '/' + (Nz === null ? '-' : Nz.toFixed(2));
|
||||
if (FenceSampleKeys[Key]) return;
|
||||
FenceSampleKeys[Key] = 1;
|
||||
console.log('[忽略][栅栏样本] cat=' + Cat + ' type=' + Type + ' 三角=' + Tri +
|
||||
' nz=' + (Nz === null ? '-' : Nz.toFixed(2)) + ' 跳过=' + IsFenceLike(Shape));
|
||||
}
|
||||
|
||||
// ===== 判定:这一对形状要不要跳过 =====
|
||||
function ShouldSkip(ShapeA, ShapeB) {
|
||||
var Local = GetLocalPhysics();
|
||||
@@ -165,13 +199,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ② 忽略栅栏(只跳过陡峭静态三角形,保留地面/缓坡)
|
||||
// ② 忽略栅栏(静态障碍;地面/缓坡保留)
|
||||
if (Stat.ignoreFence && Local) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB) && IsSteepTriangle(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA) && IsSteepTriangle(ShapeA))) {
|
||||
if ((TankA && OwnerOf(ShapeA) === Local && IsFenceLike(ShapeB)) ||
|
||||
(TankB && OwnerOf(ShapeB) === Local && IsFenceLike(ShapeA))) {
|
||||
Stat.skippedFence++;
|
||||
return true;
|
||||
}
|
||||
// 诊断:本车与静态形状配对但没跳过 → 记录样本,便于定位分类/法线
|
||||
if (TankA && OwnerOf(ShapeA) === Local && IsStaticShape(ShapeB)) RecordFenceSample(ShapeB);
|
||||
if (TankB && OwnerOf(ShapeB) === Local && IsStaticShape(ShapeA)) RecordFenceSample(ShapeA);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -286,6 +323,13 @@
|
||||
IsTankOwner: IsTankOwner,
|
||||
IsTankShape: IsTankShape,
|
||||
IsSteepTriangle: IsSteepTriangle,
|
||||
IsFenceLike: IsFenceLike,
|
||||
// 诊断:__hornetNoClip__.DebugFence(true) 后撞一次墙,控制台会打印静态形状样本
|
||||
DebugFence: function (On) {
|
||||
window.__hornetFenceDebug__ = On !== false;
|
||||
FenceSampleKeys = {};
|
||||
console.log('[忽略] 栅栏诊断 = ' + (window.__hornetFenceDebug__ ? '开(撞墙后看 [忽略][栅栏样本])' : '关'));
|
||||
},
|
||||
GetStat: function () {
|
||||
return {
|
||||
running: Stat.running, mode: Stat.mode, ignoreFence: Stat.ignoreFence,
|
||||
|
||||
Reference in new issue
Block a user