fixed issues

This commit is contained in:
33333-33333 2026-06-20 15:55:52 +09:00
commit aea08dc3fb
25 changed files with 1625 additions and 513 deletions

View file

@ -1,3 +1,4 @@
// tarinai_colony_game build 15.4.0: ball collisions, fence hitboxes, and archive throttling
"use strict";
class Item {
@ -122,16 +123,7 @@ class Item {
updateBall(dt, worldRef) {
this.prevX = this.x;
this.prevY = this.y;
const maxSpeed = 1250;
const clampVelocity = () => {
const speed = Math.hypot(this.vx || 0, this.vy || 0);
if (speed > maxSpeed) {
this.vx = (this.vx || 0) / speed * maxSpeed;
this.vy = (this.vy || 0) / speed * maxSpeed;
}
return Math.hypot(this.vx || 0, this.vy || 0);
};
const moving = clampVelocity();
const moving = Math.hypot(this.vx || 0, this.vy || 0);
if (moving > 0.04) {
this.x += (this.vx || 0) * dt;
this.y += (this.vy || 0) * dt;
@ -143,7 +135,6 @@ class Item {
this.resolveBallObstacleCollisions(dt, worldRef);
this.x = clamp(this.x, p, worldRef.w - p);
this.y = clamp(this.y, p, worldRef.h - p);
clampVelocity();
const groundFriction = Math.pow(0.72, dt);
this.vx *= groundFriction;
this.vy *= groundFriction;
@ -156,21 +147,22 @@ class Item {
resolveBallObstacleCollisions(dt, worldRef) {
if (!worldRef?.nearbyItems) return;
const speed = Math.hypot(this.vx || 0, this.vy || 0);
const searchRadius = Math.max(130, (this.r || 18) + speed * Math.max(dt || 0.016, 0.016) + 96);
const searchRadius = Math.max(150, (this.r || 18) + speed * Math.max(dt || 0.016, 0.016) + 120);
const items = worldRef.nearbyItems(this.x, this.y, searchRadius) || [];
let fenceChecks = 0;
const maxFenceChecks = CONFIG.maxFenceCollisionChecks ?? 18;
let solidChecks = 0;
const maxSolidChecks = CONFIG.maxFenceCollisionChecks ?? 24;
for (const it of items) {
if (!it || it === this || it.dead) continue;
if (it.type === "bed") {
this.applyBallHayDrag(it, dt, worldRef);
} else if (it.type === "stone") {
this.resolveBallCircleBounce(it, (it.r || 20) * 1.08 + (this.r || 18), 0.82, worldRef);
} else if (it.type === "fence_v" || it.type === "fence_h") {
if (fenceChecks >= maxFenceChecks) continue;
fenceChecks += 1;
this.resolveBallFenceBounce(it, worldRef);
}
const rects = worldRef.solidObstacleRects ? worldRef.solidObstacleRects(it) : [];
if (!rects.length) continue;
if (solidChecks >= maxSolidChecks) continue;
solidChecks += 1;
for (const rect of rects) this.resolveBallRectBounce(rect, worldRef, it);
}
}
@ -195,7 +187,27 @@ class Item {
let dx = this.x - obstacle.x;
let dy = this.y - obstacle.y;
let d = Math.hypot(dx, dy);
if (d >= hitRadius) return;
if (d >= hitRadius) {
const px = this.prevX;
const py = this.prevY;
if (!Number.isFinite(px) || !Number.isFinite(py)) return;
const sx = this.x - px;
const sy = this.y - py;
const len2 = sx * sx + sy * sy;
if (len2 <= 0.0001) return;
const t = clamp(((obstacle.x - px) * sx + (obstacle.y - py) * sy) / len2, 0, 1);
const cx = px + sx * t;
const cy = py + sy * t;
dx = cx - obstacle.x;
dy = cy - obstacle.y;
d = Math.hypot(dx, dy);
if (d >= hitRadius) return;
if (d < 0.001) {
const speed = Math.hypot(this.vx || 0, this.vy || 0);
if (speed > 0.001) { dx = -(this.vx || 0) / speed; dy = -(this.vy || 0) / speed; d = 1; }
else { dx = -sx / Math.sqrt(len2); dy = -sy / Math.sqrt(len2); d = 1; }
}
}
if (d < 0.001) {
const speed = Math.hypot(this.vx || 0, this.vy || 0);
if (speed > 0.001) { dx = -(this.vx || 0) / speed; dy = -(this.vy || 0) / speed; d = 1; }
@ -219,29 +231,69 @@ class Item {
this.emitBallBounce(worldRef, obstacle);
}
resolveBallFenceBounce(fence, worldRef) {
const vertical = fence.type === "fence_v";
const len = Math.max(112, (fence.r || 42) * 3.55);
const thick = Math.max(10, (fence.r || 42) * 0.31);
const halfLen = len / 2;
const sx1 = vertical ? fence.x : fence.x - halfLen;
const sy1 = vertical ? fence.y - halfLen : fence.y;
const sx2 = vertical ? fence.x : fence.x + halfLen;
const sy2 = vertical ? fence.y + halfLen : fence.y;
const vx = sx2 - sx1;
const vy = sy2 - sy1;
const segLenSq = vx * vx + vy * vy || 1;
const u = clamp(((this.x - sx1) * vx + (this.y - sy1) * vy) / segLenSq, 0, 1);
const cx = sx1 + vx * u;
const cy = sy1 + vy * u;
const hitRadius = (this.r || 18) + thick / 2 + 2;
resolveBallRectBounce(rect, worldRef, source = null) {
if (!rect) return;
const hitRadius = (this.r || 18) + 2;
const cx = clamp(this.x, rect.left, rect.right);
const cy = clamp(this.y, rect.top, rect.bottom);
let dx = this.x - cx;
let dy = this.y - cy;
let d = Math.hypot(dx, dy);
if (d >= hitRadius) return;
if (d >= hitRadius) {
const px = this.prevX;
const py = this.prevY;
const expanded = { left: rect.left - hitRadius, right: rect.right + hitRadius, top: rect.top - hitRadius, bottom: rect.bottom + hitRadius };
if (!Number.isFinite(px) || !Number.isFinite(py) || !worldRef?.segmentIntersectsRect?.(px, py, this.x, this.y, expanded)) return;
let nx = 0;
let ny = 0;
const vx = this.vx || 0;
const vy = this.vy || 0;
const candidates = [];
const sx = this.x - px;
const sy = this.y - py;
if (px < expanded.left && sx > 0) candidates.push({ nx: -1, ny: 0, t: (expanded.left - px) / Math.max(sx, 0.001) });
if (px > expanded.right && sx < 0) candidates.push({ nx: 1, ny: 0, t: (px - expanded.right) / Math.max(-sx, 0.001) });
if (py < expanded.top && sy > 0) candidates.push({ nx: 0, ny: -1, t: (expanded.top - py) / Math.max(sy, 0.001) });
if (py > expanded.bottom && sy < 0) candidates.push({ nx: 0, ny: 1, t: (py - expanded.bottom) / Math.max(-sy, 0.001) });
if (candidates.length) {
candidates.sort((a, b) => a.t - b.t);
nx = candidates[0].nx;
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) this.x = expanded.left - 0.5;
else if (nx > 0) this.x = expanded.right + 0.5;
if (ny < 0) this.y = expanded.top - 0.5;
else if (ny > 0) this.y = expanded.bottom + 0.5;
if (nx) this.y = clamp(this.y, expanded.top, expanded.bottom);
if (ny) this.x = clamp(this.x, expanded.left, expanded.right);
if (toward < 0) {
this.vx = vx - 1.78 * toward * nx;
this.vy = vy - 1.78 * toward * ny;
} else {
this.vx = vx + nx * 18;
this.vy = vy + ny * 18;
}
this.vx *= 0.94;
this.vy *= 0.94;
this.spinVelocity = clamp((this.spinVelocity || 0) + (nx >= 0 ? -1 : 1) * 6.2, -38, 38);
this.emitBallBounce(worldRef, source || rect.item || rect);
return;
}
if (d < 0.001) {
if (vertical) { dx = (this.vx || 0) >= 0 ? -1 : 1; dy = 0; }
else { dx = 0; dy = (this.vy || 0) >= 0 ? -1 : 1; }
const left = Math.abs(this.x - rect.left);
const right = Math.abs(rect.right - this.x);
const top = Math.abs(this.y - rect.top);
const bottom = Math.abs(rect.bottom - this.y);
const m = Math.min(left, right, top, bottom);
if (m === left) { dx = -1; dy = 0; }
else if (m === right) { dx = 1; dy = 0; }
else if (m === top) { dx = 0; dy = -1; }
else { dx = 0; dy = 1; }
d = 1;
}
const nx = dx / d;
@ -252,11 +304,19 @@ class Item {
if (toward < 0) {
this.vx = (this.vx || 0) - 1.78 * toward * nx;
this.vy = (this.vy || 0) - 1.78 * toward * ny;
} else {
this.vx = (this.vx || 0) + nx * 18;
this.vy = (this.vy || 0) + ny * 18;
}
this.vx *= 0.94;
this.vy *= 0.94;
this.spinVelocity = clamp((this.spinVelocity || 0) + (nx >= 0 ? -1 : 1) * 6.2, -38, 38);
this.emitBallBounce(worldRef, fence);
this.emitBallBounce(worldRef, source || rect.item || rect);
}
resolveBallFenceBounce(fence, worldRef) {
const rects = worldRef?.solidObstacleRects ? worldRef.solidObstacleRects(fence) : [];
for (const rect of rects) this.resolveBallRectBounce(rect, worldRef, fence);
}
emitBallBounce(worldRef, obstacle) {