p
This commit is contained in:
parent
d14550dad6
commit
63e10af865
86 changed files with 5400 additions and 1209 deletions
|
|
@ -275,7 +275,7 @@
|
|||
const base = Math.max(1, Number((body?.hazard?.damage ?? global.TarinaiPhysicsBodySystem.scalar(rect.item, "damage", 7)) || 7) || 7);
|
||||
const damage = clamp(base * (solid ? 1.0 : 0.72) + speed * 0.018, 2.0, 18.0);
|
||||
if (typeof worldRef.applyImpactDamage === "function") worldRef.applyImpactDamage(t, damage, "\u6bd2\u30d6\u30ed\u30c3\u30af", { source: rect.item, x: t.x, y: t.y });
|
||||
else if (typeof t.damage === "function") t.damage(damage, "\u6bd2\u30d6\u30ed\u30c3\u30af");
|
||||
else if (typeof t.damage === "function") t.damage(damage, "\u6bd2\u30d6\u30ed\u30c3\u30af", { source: rect.item });
|
||||
t.showHpBar?.(4.8);
|
||||
t.hurtTimer = Math.max(t.hurtTimer || 0, 0.82);
|
||||
t.pokeFlashTimer = Math.max(t.pokeFlashTimer || 0, 0.28);
|
||||
|
|
@ -287,6 +287,63 @@
|
|||
return true;
|
||||
}
|
||||
|
||||
function mechanicalPressureForTarinaiLocal(worldRef, t) {
|
||||
const pressure = worldRef?._mechanicalCrowdPressure;
|
||||
if (!pressure?.active || !pressure.ids || !t) return null;
|
||||
return pressure.ids.has(t.id || t.familyKey || t) ? pressure : null;
|
||||
}
|
||||
|
||||
function consumeMechanicalPressureContactLocal(worldRef, t) {
|
||||
const pressure = mechanicalPressureForTarinaiLocal(worldRef, t);
|
||||
if (!pressure) return true;
|
||||
const budget = Math.max(1, Number(pressure.contactBudget || 8) || 8);
|
||||
if ((pressure.detailedContacts || 0) < budget) {
|
||||
pressure.detailedContacts = (pressure.detailedContacts || 0) + 1;
|
||||
return true;
|
||||
}
|
||||
pressure.skippedContacts = (pressure.skippedContacts || 0) + 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
function cheapMechanicalPressureContactLocal(worldRef, t, rr, opts = {}) {
|
||||
const pressure = mechanicalPressureForTarinaiLocal(worldRef, t);
|
||||
if (!pressure || !Array.isArray(pressure.sources) || !pressure.sources.length) return false;
|
||||
const maxSources = Math.max(1, Math.min(4, Number(opts.maxSources || 2) || 2));
|
||||
const maxRects = Math.max(1, Math.min(12, Number(opts.maxRects || 5) || 5));
|
||||
const x = Number(t.x || 0) || 0;
|
||||
const y = Number(t.y || 0) || 0;
|
||||
let sourceChecks = 0;
|
||||
let rectChecks = 0;
|
||||
let pushed = false;
|
||||
for (const item of pressure.sources) {
|
||||
if (!item || item.dead) continue;
|
||||
const reach = global.TarinaiMechanicalShapeSystem?.reach?.(item) || Math.max(64, Number(item.r || item.radius || 64) || 64);
|
||||
if (distXY(x, y, Number(item.x || 0) || 0, Number(item.y || 0) || 0) > reach + rr + 56) continue;
|
||||
sourceChecks += 1;
|
||||
for (const rect of worldRef.solidObstacleRects?.(item) || []) {
|
||||
rectChecks += 1;
|
||||
if (Geometry.circleOverlapsRect(x, y, rr, rect, 2.0) && worldRef.pushTarinaiOutOfRect(t, rect, rr, { slop: 0.55, pressureCheap: true })) {
|
||||
pushed = true;
|
||||
break;
|
||||
}
|
||||
if (rectChecks >= maxRects) break;
|
||||
}
|
||||
if (pushed || sourceChecks >= maxSources || rectChecks >= maxRects) break;
|
||||
}
|
||||
pressure.degradedContacts = (pressure.degradedContacts || 0) + 1;
|
||||
if (pushed) {
|
||||
t.lastSolidObstacleCollisionAt = worldRef.time || 0;
|
||||
t.vx = clamp(Number(t.vx || 0) || 0, -420, 420) * 0.82;
|
||||
t.vy = clamp(Number(t.vy || 0) || 0, -420, 420) * 0.82;
|
||||
t.impulseVx = clamp(Number(t.impulseVx || 0) || 0, -260, 260) * 0.72;
|
||||
t.impulseVy = clamp(Number(t.impulseVy || 0) || 0, -260, 260) * 0.72;
|
||||
} else {
|
||||
t.vx = clamp(Number(t.vx || 0) || 0, -520, 520) * 0.94;
|
||||
t.vy = clamp(Number(t.vy || 0) || 0, -520, 520) * 0.94;
|
||||
}
|
||||
return pushed;
|
||||
}
|
||||
|
||||
Object.defineProperties(World.prototype, Object.getOwnPropertyDescriptors({
|
||||
nearest(entity, types, maxDist = Infinity) {
|
||||
let best = null, bestD = maxDist;
|
||||
|
|
@ -780,6 +837,17 @@
|
|||
t.lastBounceFenceEffectAt = now;
|
||||
this.effects?.push(new Effect("ring", t.x, t.y, { size: Math.max(18, rr * 1.15), life: 0.18, color: "rgba(82,153,230,0.46)" }));
|
||||
}
|
||||
} else if (r.mechanical && opts.pressureCheap) {
|
||||
const omega = r.rotator ? clamp(Number(r.angularVelocity || 0) || 0, -4.5, 4.5) : 0;
|
||||
const rx = Number(t.x || 0) - Number(r.centerX ?? r.item?.x ?? r.cx ?? 0);
|
||||
const ry = Number(t.y || 0) - Number(r.centerY ?? r.item?.y ?? r.cy ?? 0);
|
||||
const tvx = r.rotator && Math.abs(omega) > 0.012 ? clamp(-ry * omega, -180, 180) : 0;
|
||||
const tvy = r.rotator && Math.abs(omega) > 0.012 ? clamp(rx * omega, -180, 180) : 0;
|
||||
t.vx = clamp(preVx * 0.62 + nx * 46 + tvx * 0.42, -360, 360);
|
||||
t.vy = clamp(preVy * 0.62 + ny * 46 + tvy * 0.42, -360, 360);
|
||||
t.impulseVx = clamp((Number(t.impulseVx || 0) || 0) * 0.45 + nx * 34, -220, 220);
|
||||
t.impulseVy = clamp((Number(t.impulseVy || 0) || 0) * 0.45 + ny * 34, -220, 220);
|
||||
t.surpriseTimer = Math.max(t.surpriseTimer || 0, 0.05);
|
||||
} else if (r.mechanical) {
|
||||
global.TarinaiMechanicalSystem.applySurfaceVelocityToCircle(t, r, nx, ny, preVx, preVy, {
|
||||
damping: r.rotator ? 0.78 : (r.poisonBlock ? 0.74 : 0.80),
|
||||
|
|
@ -809,13 +877,24 @@
|
|||
return false;
|
||||
}
|
||||
const rr = Math.max(8, (Number(t.radius) || 22) * 0.74);
|
||||
const maxStep = Math.max(5, Math.min(12, Number(opts.maxStep || rr * 0.48) || 8));
|
||||
const pressure = mechanicalPressureForTarinaiLocal(this, t);
|
||||
if (pressure && !consumeMechanicalPressureContactLocal(this, t)) {
|
||||
t.x += moveX * 0.72;
|
||||
t.y += moveY * 0.72;
|
||||
const pushed = cheapMechanicalPressureContactLocal(this, t, rr, { maxSources: 2, maxRects: 5 });
|
||||
if (pushed) this.markSpatialDirty?.("tarinai-pressure-cheap-contact");
|
||||
return pushed;
|
||||
}
|
||||
const pressureLight = Boolean(pressure);
|
||||
const maxStep = pressureLight ? Math.max(8, Math.min(16, Number(opts.maxStep || rr * 0.72) || 12)) : Math.max(5, Math.min(12, Number(opts.maxStep || rr * 0.48) || 8));
|
||||
const steps = Math.max(1, Math.min(48, Math.ceil(dist / maxStep)));
|
||||
const stepX = moveX / steps;
|
||||
const stepY = moveY / steps;
|
||||
const fastSweep = dist > rr * 1.25 || Math.hypot(Number(t.vx || 0) || 0, Number(t.vy || 0) || 0) > 170;
|
||||
const sweepMaxChecks = Math.max(opts.light ? (fastSweep ? 18 : 10) : (fastSweep ? 44 : 32), Number(opts.maxChecks || 0) || CONFIG.maxFenceCollisionChecks || 24);
|
||||
const sweepMaxRects = fastSweep ? 108 : 72;
|
||||
const sweepMaxChecks = pressureLight
|
||||
? Math.min(fastSweep ? 16 : 10, Math.max(6, Number(opts.maxChecks || 0) || 10))
|
||||
: Math.max(opts.light ? (fastSweep ? 18 : 10) : (fastSweep ? 44 : 32), Number(opts.maxChecks || 0) || CONFIG.maxFenceCollisionChecks || 24);
|
||||
const sweepMaxRects = pressureLight ? (fastSweep ? 36 : 24) : (fastSweep ? 108 : 72);
|
||||
let collided = false;
|
||||
for (let i = 0; i < steps; i++) {
|
||||
const sx = t.x;
|
||||
|
|
@ -825,8 +904,9 @@
|
|||
const hit = firstSweptCircleObstacleHitLocal(this, t, sx, sy, ex, ey, rr, {
|
||||
searchRadius: Math.max(rr + 110, rr + Math.hypot(stepX, stepY) + 170),
|
||||
maxChecks: sweepMaxChecks,
|
||||
maxRects: sweepMaxRects,
|
||||
});
|
||||
maxRects: sweepMaxRects,
|
||||
mechanicalFallback: !pressureLight,
|
||||
});
|
||||
if (hit && hit.t <= 1) {
|
||||
const safeT = Math.max(0, hit.t - 0.035);
|
||||
t.x = sx + stepX * safeT;
|
||||
|
|
@ -842,6 +922,7 @@
|
|||
maxChecks: sweepMaxChecks,
|
||||
maxRects: sweepMaxRects,
|
||||
slop: 0.30,
|
||||
skipPressureBudget: true,
|
||||
oneWayDx: stepX,
|
||||
oneWayDy: stepY,
|
||||
}) || true;
|
||||
|
|
@ -855,6 +936,7 @@
|
|||
maxChecks: sweepMaxChecks,
|
||||
maxRects: sweepMaxRects,
|
||||
slop: 0.35,
|
||||
skipPressureBudget: true,
|
||||
oneWayDx: stepX,
|
||||
oneWayDy: stepY,
|
||||
});
|
||||
|
|
@ -870,6 +952,10 @@
|
|||
resolveSolidObstacleCollision(t, opts = {}) {
|
||||
if (!t || t.dead || this.isTarinaiHiddenInNestBox(t)) return false;
|
||||
const rr = Math.max(8, (Number(t.radius) || 22) * 0.74);
|
||||
const pressure = mechanicalPressureForTarinaiLocal(this, t);
|
||||
if (pressure && !opts.pressureCheap && !opts.skipPressureBudget && !consumeMechanicalPressureContactLocal(this, t)) {
|
||||
return cheapMechanicalPressureContactLocal(this, t, rr, { maxSources: 2, maxRects: 5 });
|
||||
}
|
||||
this.resolvePoisonBlockContactDamage(t, rr);
|
||||
let pushed = false;
|
||||
let bounced = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue