This commit is contained in:
33333-33333 2026-06-20 23:27:39 +09:00
commit c6ba3e38a2
21 changed files with 1565 additions and 898 deletions

View file

@ -53,6 +53,8 @@ class AntActor {
this.kind = opts.kind || "worker";
this.homeId = opts.homeId || "";
this.targetId = opts.targetId || "";
this.targetToken = opts.targetToken || 0;
this.targetRef = opts.targetRef || null;
this.x = Number.isFinite(opts.x) ? opts.x : 0;
this.y = Number.isFinite(opts.y) ? opts.y : 0;
this.vx = opts.vx || 0;
@ -60,6 +62,7 @@ class AntActor {
this.r = opts.r || (this.kind === "queen" ? ANT_QUEEN_RADIUS : ANT_WORKER_RADIUS);
this.maxHp = Number.isFinite(opts.maxHp) ? opts.maxHp : (this.kind === "queen" ? ANT_QUEEN_HP : ANT_WORKER_HP);
this.hp = Number.isFinite(opts.hp) ? opts.hp : this.maxHp;
this.hpBarTimer = Number.isFinite(opts.hpBarTimer) ? opts.hpBarTimer : 0;
this.state = opts.state || (this.kind === "queen" ? "founding" : "search");
this.age = opts.age || 0;
this.seed = opts.seed || Math.random() * 1000;
@ -74,30 +77,19 @@ class AntActor {
this.dead = Boolean(opts.dead);
}
serialize() {
return {
id: this.id, kind: this.kind, homeId: this.homeId, targetId: this.targetId,
x: this.x, y: this.y, vx: this.vx, vy: this.vy, r: this.r, hp: this.hp, maxHp: this.maxHp,
state: this.state, age: this.age, seed: this.seed, wanderAngle: this.wanderAngle,
nextTurn: this.nextTurn, returnTimer: this.returnTimer, foundingX: this.foundingX,
foundingY: this.foundingY, foundingDelayUntil: this.foundingDelayUntil, carryLogAt: this.carryLogAt, foundingAttempts: this.foundingAttempts, dead: this.dead,
};
}
static from(worldRef, data) {
return new AntActor(worldRef, data || {});
}
homeNest() {
return (this.world?.items || []).find(it => it && !it.dead && it.id === this.homeId && it.type === "ant_nest") || null;
}
targetTarinai() {
return (this.world?.tarinai || []).find(t => t && !t.dead && t.id === this.targetId) || null;
if (this.targetRef && !this.targetRef.dead && this.targetRef.id === this.targetId && this.targetRef.liveToken === this.targetToken) return this.targetRef;
const live = this.world?.liveTarinaiById?.(this.targetId, this.targetToken) || null;
this.targetRef = live;
return live;
}
activeHaulersForTarget() {
return (this.world?.ants || []).filter(a => a && !a.dead && a.kind === "worker" && a.state === "drag" && a.targetId && a.targetId === this.targetId);
return (this.world?.ants || []).filter(a => a && !a.dead && a.kind === "worker" && a.state === "drag" && a.targetId && a.targetId === this.targetId && a.targetToken === this.targetToken);
}
isLeadHauler() {
@ -116,7 +108,7 @@ class AntActor {
const d = distXY(this.x, this.y, t.x, t.y);
if (d > maxDist) continue;
if ((t.antDraggedTimer || 0) > 0 && (t.antDraggedBy || "") && t.antDraggedBy !== this.id) {
const haulers = (this.world?.ants || []).filter(a => a && !a.dead && a.kind === "worker" && a.state === "drag" && a.targetId === t.id).length;
const haulers = (this.world?.ants || []).filter(a => a && !a.dead && a.kind === "worker" && a.state === "drag" && a.targetId === t.id && a.targetToken === t.liveToken).length;
if (haulers >= ANT_NEST_MAX_OUTSIDE) continue;
}
const weak = clamp((100 - (t.energy || 0)) / 100, 0, 1);
@ -131,9 +123,12 @@ class AntActor {
update(dt) {
if (this.dead) return;
const hpBefore = this.hp;
this.age += dt;
if (this.kind === "queen") return this.updateQueen(dt);
return this.updateWorker(dt);
if (this.kind === "queen") this.updateQueen(dt);
else this.updateWorker(dt);
if (Number.isFinite(hpBefore) && this.hp < hpBefore - 0.01) this.hpBarTimer = Math.max(this.hpBarTimer || 0, 1.25);
this.hpBarTimer = Math.max(0, (this.hpBarTimer || 0) - dt);
}
updateWorker(dt) {
@ -156,6 +151,8 @@ class AntActor {
if (target) {
this.state = "drag";
this.targetId = target.id;
this.targetToken = target.liveToken || 0;
this.targetRef = target;
this.carryLogAt = this.world?.time || 0;
target.antDraggedTimer = Math.max(target.antDraggedTimer || 0, 0.45);
target.antDraggedBy = this.id;
@ -209,6 +206,8 @@ class AntActor {
const target = this.targetTarinai();
if (!target || target.dead || target.insideNestBoxId) {
this.targetId = "";
this.targetToken = 0;
this.targetRef = null;
this.state = "return";
return;
}
@ -225,6 +224,8 @@ class AntActor {
if (dHome < Math.max(18, home.r * 0.66)) {
this.world.completeAntHaul?.(home, target);
this.targetId = "";
this.targetToken = 0;
this.targetRef = null;
this.state = "return";
return;
}
@ -253,7 +254,7 @@ class AntActor {
if ((this.world.time || 0) - (this.carryLogAt || -999) > 8 && Math.random() < dt * 0.04) {
this.carryLogAt = this.world.time || 0;
this.world.log(`${target.name}\u304c\u30a2\u30ea\u306b\u5f15\u3063\u5f35\u3089\u308c\u3066\u3044\u308b\u3002`, "event");
this.world.log(`${target.name}\u304c\u30a2\u30ea\u306b\u5f15\u3063\u5f35\u3089\u308c\u3066\u3044\u308b\u3002`, "event", { participants: [target] });
}
if (this.hp <= 0) this.dieAsCorpse(home);
}
@ -373,12 +374,14 @@ class AntActor {
}
drawHealthBar(ctx) {
if ((this.hpBarTimer || 0) <= 0) return;
const maxHp = Math.max(1, this.maxHp || (this.kind === "queen" ? ANT_QUEEN_HP : ANT_WORKER_HP));
const pct = clamp((this.hp || 0) / maxHp, 0, 1);
const bw = this.kind === "queen" ? 28 : 18;
const bh = this.kind === "queen" ? 4 : 3;
const y = this.y - this.r * (this.kind === "queen" ? 2.0 : 2.6);
ctx.save();
ctx.globalAlpha = clamp((this.hpBarTimer || 0) / 0.65, 0.35, 1);
ctx.fillStyle = "rgba(255,252,242,0.86)";
roundedRect(ctx, this.x - bw / 2 - 1.5, y - 1.5, bw + 3, bh + 3, 4);
ctx.fill();