This commit is contained in:
33333-33333 2026-07-01 14:41:05 +09:00
commit 4d3fc2cd47
84 changed files with 3429 additions and 3480 deletions

View file

@ -91,6 +91,27 @@
return true;
}
function applyNormalBounce(obj, nx, ny, vx, vy, restitution, fallbackImpulse, minBounceSpeed, spinKick, spinLimit) {
const toward = vx * nx + vy * ny;
if (toward < 0) {
obj.vx = vx - (1 + restitution) * toward * nx;
obj.vy = vy - (1 + restitution) * toward * ny;
} else {
obj.vx = vx + nx * fallbackImpulse;
obj.vy = vy + ny * fallbackImpulse;
}
if (minBounceSpeed > 0) {
const normalSpeed = (obj.vx || 0) * nx + (obj.vy || 0) * ny;
if (normalSpeed < minBounceSpeed) {
const add = minBounceSpeed - normalSpeed;
obj.vx = (obj.vx || 0) + nx * add;
obj.vy = (obj.vy || 0) + ny * add;
}
}
if (Number.isFinite(obj.spinVelocity) && spinKick) obj.spinVelocity = clamp((obj.spinVelocity || 0) + (nx >= 0 ? -1 : 1) * spinKick, -spinLimit, spinLimit);
return true;
}
function bounceInsideWorld(obj, worldRef, opts = {}) {
if (!obj || !worldRef) return false;
const p = Math.max(opts.padding ?? 28, CONFIG.worldPadding || 30);
@ -112,14 +133,9 @@
if (rect.oriented) return circleBounceOffOrientedRect(obj, rect, radius, restitution, worldRef, opts);
const hitRadius = Math.max(2, Number(radius || obj.r || obj.radius || 12) || 12);
const minBounceSpeed = Math.max(0, Number(opts.minBounceSpeed ?? rect.minBounceSpeed ?? 0) || 0);
const ensureMinNormalSpeed = (nx, ny) => {
if (!(minBounceSpeed > 0)) return;
const normalSpeed = (obj.vx || 0) * nx + (obj.vy || 0) * ny;
if (normalSpeed >= minBounceSpeed) return;
const add = minBounceSpeed - normalSpeed;
obj.vx = (obj.vx || 0) + nx * add;
obj.vy = (obj.vy || 0) + ny * add;
};
const fallbackImpulse = Math.max(0, Number(opts.fallbackImpulse ?? 36) || 0);
const spinKick = Number(opts.spinKick ?? 7.0);
const spinLimit = Math.max(0, Number(opts.spinLimit ?? 46) || 46);
const cx = clamp(obj.x, rect.left, rect.right);
const cy = clamp(obj.y, rect.top, rect.bottom);
let dx = obj.x - cx;
@ -147,23 +163,13 @@
ny = candidates[0].ny;
} else if (Math.abs(vx) >= Math.abs(vy)) nx = vx >= 0 ? -1 : 1;
else ny = vy >= 0 ? -1 : 1;
const toward = vx * nx + vy * ny;
if (nx < 0) obj.x = expanded.left - 0.5;
else if (nx > 0) obj.x = expanded.right + 0.5;
if (ny < 0) obj.y = expanded.top - 0.5;
else if (ny > 0) obj.y = expanded.bottom + 0.5;
if (nx) obj.y = clamp(obj.y, expanded.top, expanded.bottom);
if (ny) obj.x = clamp(obj.x, expanded.left, expanded.right);
if (toward < 0) {
obj.vx = vx - (1 + restitution) * toward * nx;
obj.vy = vy - (1 + restitution) * toward * ny;
} else {
obj.vx = vx + nx * 36;
obj.vy = vy + ny * 36;
}
ensureMinNormalSpeed(nx, ny);
if (Number.isFinite(obj.spinVelocity)) obj.spinVelocity = clamp((obj.spinVelocity || 0) + (nx >= 0 ? -1 : 1) * 7.0, -46, 46);
return true;
return applyNormalBounce(obj, nx, ny, vx, vy, restitution, fallbackImpulse, minBounceSpeed, spinKick, spinLimit);
}
if (d < 0.001) {
const left = Math.abs(obj.x - rect.left);
@ -181,22 +187,12 @@
const ny = dy / d;
const vx = obj.vx || 0;
const vy = obj.vy || 0;
const toward = vx * nx + vy * ny;
obj.x = cx + nx * (hitRadius + 0.5);
obj.y = cy + ny * (hitRadius + 0.5);
if (toward < 0) {
obj.vx = vx - (1 + restitution) * toward * nx;
obj.vy = vy - (1 + restitution) * toward * ny;
} else {
obj.vx = vx + nx * 36;
obj.vy = vy + ny * 36;
}
ensureMinNormalSpeed(nx, ny);
if (Number.isFinite(obj.spinVelocity)) obj.spinVelocity = clamp((obj.spinVelocity || 0) + (nx >= 0 ? -1 : 1) * 7.0, -46, 46);
return true;
return applyNormalBounce(obj, nx, ny, vx, vy, restitution, fallbackImpulse, minBounceSpeed, spinKick, spinLimit);
}
function resolveKinematicBounceFenceCollision(item, worldRef, dt = 0.016, opts = {}) {
function resolveFenceBounce(item, worldRef, dt = 0.016, opts = {}) {
if (!item || !worldRef?.nearbySolidObstacleRects) return false;
const speed = Math.hypot(item.vx || 0, item.vy || 0);
const radius = Math.max(4, (item.r || item.radius || 12) + (opts.obstaclePadding ?? 2));
@ -238,7 +234,7 @@
item.x += (item.vx || 0) * dt;
item.y += (item.vy || 0) * dt;
bounceInsideWorld(item, worldRef, opts);
resolveKinematicBounceFenceCollision(item, worldRef, dt, opts);
resolveFenceBounce(item, worldRef, dt, opts);
const ice = (worldRef?.groundType || "soil") === "ice";
const baseFriction = ice ? Math.max(Number(opts.frictionBase ?? 0.68), 0.93) : (opts.frictionBase ?? 0.68);
const frictionRate = ice ? Math.min(Number(opts.frictionRate ?? 1), 0.55) : (opts.frictionRate ?? 1);