/* 贪蛇出动 - AI 蛇控制器:觅食/避障/边界回避/随机加速 */ (function () { 'use strict'; window.GS = window.GS || {}; const U = GS.U; class AI { constructor(snake) { this.s = snake; this.decideTimer = U.rand(0, 0.3); this.wanderAngle = snake.angle; this.boostTimer = 0; } update(dt, world, snakes) { const s = this.s; if (s.dead) return; this.decideTimer -= dt; this.boostTimer -= dt; if (this.decideTimer > 0) { s.boosting = this.boostTimer > 0; return; } this.decideTimer = 0.15; const h = s.head; const look = 90 + s.radius * 3; const aheadX = h.x + Math.cos(s.angle) * look; const aheadY = h.y + Math.sin(s.angle) * look; // 1) 边界回避 const margin = 220; let avoid = null; if (aheadX < margin || aheadY < margin || aheadX > world.size - margin || aheadY > world.size - margin) { avoid = Math.atan2(world.size / 2 - h.y, world.size / 2 - h.x); } // 2) 蛇身回避:检查前方采样点是否撞上其他蛇 if (avoid == null) { for (const o of snakes) { if (o === s || o.dead) continue; const segs = o.segments(); const rr = (s.radius + o.radius + 26); for (let i = 0; i < segs.length; i += 2) { if (U.dist2(aheadX, aheadY, segs[i].x, segs[i].y) < rr * rr) { // 向左或向右转,选更开阔的一侧 const left = s.angle - Math.PI / 2, right = s.angle + Math.PI / 2; avoid = this._clearer(left, right, h, snakes, s); break; } } if (avoid != null) break; } } if (avoid != null) { s.targetAngle = avoid; s.boosting = false; return; } // 3) 觅食:找最近金币 let best = null, bestD = 520 * 520; const near = world.grid.query(h.x, h.y, 520); for (const c of near) { const d2 = U.dist2(h.x, h.y, c.x, c.y); if (d2 < bestD) { bestD = d2; best = c; } } if (best) { s.targetAngle = Math.atan2(best.y - h.y, best.x - h.x); } else { // 漫游:小幅随机偏转 this.wanderAngle += U.rand(-0.6, 0.6); s.targetAngle = this.wanderAngle; } // 4) 随机加速:追食或逃跑时小概率冲刺 if (Math.random() < 0.06 && s.score > 30) this.boostTimer = U.rand(0.4, 1.0); s.boosting = this.boostTimer > 0; } _clearer(a1, a2, h, snakes, s) { const score = a => { const px = h.x + Math.cos(a) * 160, py = h.y + Math.sin(a) * 160; let d = 1e9; for (const o of snakes) { if (o === s || o.dead) continue; const segs = o.segments(); for (let i = 0; i < segs.length; i += 3) { const dd = U.dist2(px, py, segs[i].x, segs[i].y); if (dd < d) d = dd; } } return d; }; return score(a1) >= score(a2) ? a1 : a2; } } GS.AI = AI; })();