lag r
This commit is contained in:
parent
d875df8600
commit
2741b93dea
31 changed files with 751 additions and 546 deletions
|
|
@ -3,6 +3,46 @@
|
|||
(function (global) {
|
||||
const World = global.World;
|
||||
if (!World) throw new Error("World is not available for mixin: world_update.js");
|
||||
|
||||
const REALTIME_ITEM_TYPES = new Set(["ball", "genkotsu", "firecracker"]);
|
||||
const PIN_ITEM_TYPES = new Set(["pushpin", "oshibyo"]);
|
||||
|
||||
function itemUpdateInterval(item) {
|
||||
if (!item || item.dead) return Infinity;
|
||||
if (REALTIME_ITEM_TYPES.has(item.type)) return 0;
|
||||
if (PIN_ITEM_TYPES.has(item.type)) return 0;
|
||||
if ((item.dropTimer || 0) > 0 || Math.hypot(item.vx || 0, item.vy || 0) > 0.08) return 0;
|
||||
if (item.type === "zunchi") return 2.4;
|
||||
if (item.type === "grass") return 3.0 + stableUnit(item.id || item.seed || "grass", "grass-update") * 2.2;
|
||||
if (item.type === "duplicator") return 2.0;
|
||||
if (item.type === "water") return 1.8;
|
||||
if (item.type === "trace" || item.type === "splat") return 1.2;
|
||||
if (item.type === "ant_corpse") return 3.5;
|
||||
if (typeof isServingFoodType === "function" && isServingFoodType(item.type)) return 5.0;
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
function updateItemsScheduled(worldRef, dt) {
|
||||
let ran = 0;
|
||||
for (const it of worldRef.items || []) {
|
||||
if (!it || it.dead) continue;
|
||||
const interval = itemUpdateInterval(it);
|
||||
if (!Number.isFinite(interval)) continue;
|
||||
if (interval <= 0) {
|
||||
it.update(dt, worldRef);
|
||||
ran += 1;
|
||||
continue;
|
||||
}
|
||||
it._scheduledUpdateDt = Math.min(10, (it._scheduledUpdateDt || 0) + dt);
|
||||
if (it._scheduledUpdateDt < interval) continue;
|
||||
const scheduledDt = it._scheduledUpdateDt;
|
||||
it._scheduledUpdateDt = 0;
|
||||
it.update(scheduledDt, worldRef);
|
||||
ran += 1;
|
||||
}
|
||||
return ran;
|
||||
}
|
||||
|
||||
function markSpatialDirtyIfMoved(worldRef, list, reason = "moved", threshold = 0.35) {
|
||||
if (!worldRef || !Array.isArray(list) || !list.length) return false;
|
||||
const thresholdSq = threshold * threshold;
|
||||
|
|
@ -30,7 +70,9 @@
|
|||
return moved;
|
||||
}
|
||||
Object.defineProperties(World.prototype, Object.getOwnPropertyDescriptors({
|
||||
environmentScores() {
|
||||
environmentScores(force = false) {
|
||||
const nowScore = this.time || 0;
|
||||
if (!force && this.environmentScoreCache && nowScore < (this.nextEnvironmentScoreAt || 0)) return this.environmentScoreCache;
|
||||
const alive = this.tarinai || [];
|
||||
const avgStress = alive.length ? alive.reduce((sum, t) => sum + (t.stress || 0), 0) / alive.length : 0;
|
||||
let fightPressure = 0;
|
||||
|
|
@ -52,7 +94,9 @@
|
|||
const foodSpoilage = this.foodSpoilagePenalty || 0;
|
||||
const hygiene = clamp(100 - zunchi * 2.0 - splat * 1.2 - trace * 0.30 - antCorpse * 0.65 - blood * 1.8 - diseaseCount * 8.0 - foodSpoilage, 0, 100);
|
||||
const happiness = clamp(100 - Math.max(0, 100 - security) * 0.32 - Math.max(0, 100 - hygiene) * 0.24 - avgStress * 0.42, 0, 100);
|
||||
return { security, hygiene, happiness };
|
||||
this.environmentScoreCache = { security, hygiene, happiness };
|
||||
this.nextEnvironmentScoreAt = nowScore + 3.0;
|
||||
return this.environmentScoreCache;
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -186,7 +230,7 @@
|
|||
if (d < bestD && d <= Math.max(60, (it.r || 24) * 2.0)) { best = it; bestD = d; }
|
||||
}
|
||||
if (!best) return null;
|
||||
const owner = (this.tarinai || []).find(t => t && !t.dead && t.id === best.ownerId) || null;
|
||||
const owner = this.liveTarinaiById?.(best.ownerId) || null;
|
||||
return { bed: best, owner };
|
||||
},
|
||||
|
||||
|
|
@ -253,11 +297,9 @@
|
|||
this.spatialDirtyMarksThisFrame = 0;
|
||||
this.ensureSpatial?.("update-start");
|
||||
|
||||
const quality = this.performanceQuality?.() || {};
|
||||
const perf = Number(quality.level ?? this.performanceLevel?.() ?? 0) || 0;
|
||||
this.beginFramePerformanceBudgets?.(quality);
|
||||
this.beginFramePerformanceBudgets?.();
|
||||
const itemCountBefore = this.items.length;
|
||||
for (const it of this.items) it.update(dt, this);
|
||||
updateItemsScheduled(this, dt);
|
||||
const itemsMoved = markSpatialDirtyIfMoved(this, this.items, "items-moved", 0.25);
|
||||
if (this.itemCounts?.ball) {
|
||||
this.ensureSpatial?.("ball-ball-collisions");
|
||||
|
|
@ -274,7 +316,7 @@
|
|||
t.update(dt);
|
||||
}
|
||||
const now = this.time || 0;
|
||||
const bedConflictInterval = Number(quality.bedConflictInterval || 0.12) || 0.12;
|
||||
const bedConflictInterval = 3.2;
|
||||
if (now >= (this.nextBedConflictCheckAt || 0)) {
|
||||
this.nextBedConflictCheckAt = now + bedConflictInterval;
|
||||
this.workStats && (this.workStats.bedConflictRuns = (this.workStats.bedConflictRuns || 0) + 1);
|
||||
|
|
@ -286,7 +328,7 @@
|
|||
this.ensureSpatial?.("post-tarinai-update");
|
||||
this.limitBallChasers();
|
||||
this.resolveBallInteractions(dt);
|
||||
const collisionInterval = Number(quality.collisionInterval || 0.04) || 0.04;
|
||||
const collisionInterval = 1.8;
|
||||
if (now >= (this.nextTarinaiCollisionCheckAt || 0)) {
|
||||
this.nextTarinaiCollisionCheckAt = now + collisionInterval;
|
||||
this.workStats && (this.workStats.collisionRuns = (this.workStats.collisionRuns || 0) + 1);
|
||||
|
|
@ -296,7 +338,7 @@
|
|||
}
|
||||
|
||||
this.compactTimer += dt;
|
||||
const compactInterval = perf >= 2 ? 0.95 : 0.58;
|
||||
const compactInterval = 2.5;
|
||||
let itemsCompacted = false;
|
||||
if (this.compactTimer >= compactInterval) {
|
||||
itemsCompacted = this.compactItems();
|
||||
|
|
@ -307,20 +349,20 @@
|
|||
}
|
||||
|
||||
this.countsTimer += dt;
|
||||
const countsInterval = perf >= 2 ? 0.85 : 0.42;
|
||||
const countsInterval = 2.0;
|
||||
if (this.countsTimer >= countsInterval || itemsCompacted || this.items.length !== itemCountBefore) {
|
||||
this.updateItemCounts();
|
||||
this.updateEffectCounts();
|
||||
this.countsTimer = 0;
|
||||
}
|
||||
|
||||
if ((this.outOfBoundsCheckAt || -999) + 1.0 <= this.time) {
|
||||
if ((this.outOfBoundsCheckAt || -999) + 5.0 <= this.time) {
|
||||
this.outOfBoundsCheckAt = this.time;
|
||||
this.sanitizeOutOfBounds();
|
||||
}
|
||||
|
||||
this.drawSortTimer += dt;
|
||||
const sortInterval = perf >= 2 ? 0.16 : perf === 1 ? 0.11 : 0.07;
|
||||
const sortInterval = 0.25;
|
||||
if (this.drawSortTimer >= sortInterval) {
|
||||
this.drawListDirty = true;
|
||||
this.drawSortTimer = 0;
|
||||
|
|
@ -343,8 +385,7 @@
|
|||
}
|
||||
|
||||
|
||||
const grassCount = this.itemCounts.grass || 0;
|
||||
if (grassCount < Math.min(108, this.grassLimit ? this.grassLimit() : (CONFIG.grassLimit ?? 360)) && Math.random() < dt * 0.109) {
|
||||
if (Math.random() < dt * 0.109) {
|
||||
const spot = this.findGrassPlantingSpot(rand(60, this.w - 60), rand(60, this.h - 60), {
|
||||
allowOriginal: true,
|
||||
minRadius: 28,
|
||||
|
|
@ -355,7 +396,8 @@
|
|||
const sprout = new Item("grass", spot.x, spot.y);
|
||||
sprout.amount = rand(30, 62);
|
||||
sprout.growth = rand(0.18, 0.38);
|
||||
this.addItem?.(sprout, "grass-spawn") || this.items.push(sprout);
|
||||
if (this.addItem) this.addItem(sprout, "grass-spawn");
|
||||
else this.items.push(sprout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,28 +419,28 @@
|
|||
const far = Math.max(360, Math.max(this.w || 1000, this.h || 720) * 0.75);
|
||||
let changedItems = false;
|
||||
const repairPoint = (obj, radius = 12) => {
|
||||
if (!obj) return "delete";
|
||||
if (!Number.isFinite(obj.x) || !Number.isFinite(obj.y)) return "delete";
|
||||
if (!obj) return "missing";
|
||||
const safeW = Math.max(pad * 2 + 1, Number(this.w || 1000) || 1000);
|
||||
const safeH = Math.max(pad * 2 + 1, Number(this.h || 720) || 720);
|
||||
if (!Number.isFinite(obj.x)) obj.x = safeW * 0.5;
|
||||
if (!Number.isFinite(obj.y)) obj.y = safeH * 0.5;
|
||||
const minX = pad - radius;
|
||||
const maxX = (this.w || 1000) - pad + radius;
|
||||
const maxX = safeW - pad + radius;
|
||||
const minY = pad - radius;
|
||||
const maxY = (this.h || 720) - pad + radius;
|
||||
const maxY = safeH - pad + radius;
|
||||
if (obj.x >= minX && obj.x <= maxX && obj.y >= minY && obj.y <= maxY) return "ok";
|
||||
if (obj.x < -far || obj.x > (this.w || 1000) + far || obj.y < -far || obj.y > (this.h || 720) + far) return "delete";
|
||||
obj.x = clamp(obj.x, pad, (this.w || 1000) - pad);
|
||||
obj.y = clamp(obj.y, pad, (this.h || 720) - pad);
|
||||
obj.x = clamp(obj.x, pad, safeW - pad);
|
||||
obj.y = clamp(obj.y, pad, safeH - pad);
|
||||
if (Number.isFinite(obj.vx)) obj.vx *= -0.18;
|
||||
if (Number.isFinite(obj.vy)) obj.vy *= -0.18;
|
||||
return "moved";
|
||||
};
|
||||
for (const it of this.items || []) {
|
||||
const result = repairPoint(it, it.r || 12);
|
||||
if (result === "delete") { it.amount = 0; changedItems = true; }
|
||||
else if (result === "moved") changedItems = true;
|
||||
if (result === "moved") changedItems = true;
|
||||
}
|
||||
for (const ef of this.effects || []) {
|
||||
const result = repairPoint(ef, ef.size || 12);
|
||||
if (result === "delete") ef.life = 0;
|
||||
repairPoint(ef, ef.size || 12);
|
||||
}
|
||||
const safeW = Math.max(pad * 2 + 1, Number(this.w || 1000) || 1000);
|
||||
const safeH = Math.max(pad * 2 + 1, Number(this.h || 720) || 720);
|
||||
|
|
@ -412,18 +454,34 @@
|
|||
};
|
||||
for (const t of this.tarinai || []) {
|
||||
if (!t || t.dead) continue;
|
||||
if (t.state === "sunbath" || (t.sunbathTimer || 0) > 0.04) {
|
||||
const fallbackX = Number.isFinite(t.sunbathAnchorX) ? t.sunbathAnchorX : (Number.isFinite(t._lastSunbathDrawX) ? t._lastSunbathDrawX : (Number.isFinite(t._lastValidX) ? t._lastValidX : pad));
|
||||
const fallbackY = Number.isFinite(t.sunbathAnchorY) ? t.sunbathAnchorY : (Number.isFinite(t._lastSunbathDrawY) ? t._lastSunbathDrawY : (Number.isFinite(t._lastValidY) ? t._lastValidY : pad));
|
||||
t.sunbathAnchorX = clamp(fallbackX, pad, safeW - pad);
|
||||
t.sunbathAnchorY = clamp(fallbackY, pad, safeH - pad);
|
||||
if (!Number.isFinite(t.x)) t.x = t.sunbathAnchorX;
|
||||
if (!Number.isFinite(t.y)) t.y = t.sunbathAnchorY;
|
||||
}
|
||||
const result = repairPoint(t, t.radius || 22);
|
||||
if (result === "delete" || result === "moved") repairTarinai(t);
|
||||
if (result === "missing" || result === "moved") repairTarinai(t);
|
||||
if (t.state === "sunbath" || (t.sunbathTimer || 0) > 0.04) {
|
||||
t.sunbathAnchorX = clamp(Number.isFinite(t.sunbathAnchorX) ? t.sunbathAnchorX : t.x, pad, safeW - pad);
|
||||
t.sunbathAnchorY = clamp(Number.isFinite(t.sunbathAnchorY) ? t.sunbathAnchorY : t.y, pad, safeH - pad);
|
||||
t.x = t.sunbathAnchorX;
|
||||
t.y = t.sunbathAnchorY;
|
||||
t.vx = 0;
|
||||
t.vy = 0;
|
||||
t._lastSunbathDrawX = t.x;
|
||||
t._lastSunbathDrawY = t.y;
|
||||
t._lastValidX = t.x;
|
||||
t._lastValidY = t.y;
|
||||
}
|
||||
}
|
||||
let changedAnts = false;
|
||||
for (const ant of this.ants || []) {
|
||||
if (!ant || ant.dead) continue;
|
||||
const result = repairPoint(ant, ant.kind === "queen" ? 18 : 10);
|
||||
if (result === "delete") {
|
||||
ant.dead = true;
|
||||
changedAnts = true;
|
||||
continue;
|
||||
}
|
||||
if (result === "missing") continue;
|
||||
if (result === "moved") {
|
||||
ant.vx = 0;
|
||||
ant.vy = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue