refactor(agent-office): wire real AgentSprite import, remove Phase 1 stub

This commit is contained in:
2026-04-27 08:32:22 +09:00
parent 71fe91cc85
commit f3de315272

View File

@@ -4,86 +4,10 @@ import mapData from '../assets/office-map.json';
import { TileMap } from './TileMap.js';
import { FurnitureRenderer } from './FurnitureRenderer.js';
import { Pathfinder } from './Pathfinder.js';
import { AgentSprite } from './AgentSprite.js';
import { OverlayRenderer } from './OverlayRenderer.js';
import { getTheme } from './themes.js';
// AgentSprite is implemented in Phase 2.
// Until then, use a minimal stub that satisfies the interface expected by OfficeRenderer.
let AgentSprite;
try {
// Dynamic import fallback — wrapping in try/catch for bundler compatibility
AgentSprite = null; // will be set below
} catch (_) {}
/** Phase 2 stub for AgentSprite */
class _AgentSpriteStub {
constructor(id, meta, col, row /*, pathfinder */) {
this.id = id;
this.meta = meta;
this.x = col;
this.y = row;
this.deskCol = col;
this.deskRow = row;
this.state = 'idle';
this.detail = '';
this.notificationCount = 0;
this._animTimer = 0;
this._bobOffset = 0;
}
onStateChange(state, detail /*, waypoints */) {
this.state = state;
this.detail = detail || '';
}
update(dt) {
this._animTimer += dt;
this._bobOffset = Math.sin(this._animTimer * 2) * 2;
}
draw(ctx, scale, offsetX, offsetY, tileSize) {
const ts = tileSize * scale;
const cx = this.x * ts + offsetX + ts / 2;
const cy = this.y * ts + offsetY + ts / 2 + this._bobOffset * scale;
const r = ts * 0.35;
// Simple circle avatar
ctx.save();
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2);
ctx.fillStyle = this.meta.color || '#8b5cf6';
ctx.fill();
ctx.strokeStyle = 'rgba(255,255,255,0.4)';
ctx.lineWidth = scale;
ctx.stroke();
// Emoji label
ctx.font = `${Math.max(10, ts * 0.4)}px serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(this.meta.emoji || '?', cx, cy);
// State indicator dot
const stateColors = {
idle: '#6b7280',
working: '#22c55e',
waiting: '#f59e0b',
reporting: '#3b82f6',
break: '#f97316'
};
const dotColor = stateColors[this.state] || '#6b7280';
ctx.beginPath();
ctx.arc(cx + r * 0.7, cy - r * 0.7, r * 0.25, 0, Math.PI * 2);
ctx.fillStyle = dotColor;
ctx.fill();
ctx.restore();
}
}
// Use the stub until Phase 2 provides a real AgentSprite
AgentSprite = _AgentSpriteStub;
const AGENT_META = {
stock: { displayName: '주식 트레이더', emoji: '📈', color: '#4488cc' },
music: { displayName: '음악 프로듀서', emoji: '🎵', color: '#44aa88' },
@@ -246,12 +170,7 @@ export class OfficeRenderer {
updateAgentState(agentId, state, detail) {
const sprite = this.agents.get(agentId);
if (!sprite) return;
if (typeof sprite.onStateChange === 'function') {
sprite.onStateChange(state, detail, mapData.waypoints);
} else {
sprite.state = state;
sprite.detail = detail || '';
}
}
/** 에이전트 알림 배지 설정 */
@@ -314,11 +233,9 @@ export class OfficeRenderer {
_update(dt) {
for (const sprite of this.agents.values()) {
if (typeof sprite.update === 'function') {
sprite.update(dt);
}
}
}
_render() {
const ctx = this.ctx;
@@ -352,13 +269,11 @@ export class OfficeRenderer {
// 에이전트
for (const sprite of this.agents.values()) {
if (typeof sprite.draw === 'function') {
renderables.push({
zY: sprite.y,
draw: (ctx2) => sprite.draw(ctx2, this.zoom, this.panX, this.panY, mapData.tileSize)
});
}
}
// Y좌표 정렬
renderables.sort((a, b) => a.zY - b.zY);
@@ -368,11 +283,9 @@ export class OfficeRenderer {
// 3. 오버레이 (항상 최상위)
for (const sprite of this.agents.values()) {
if (this.overlayRenderer && typeof this.overlayRenderer.draw === 'function') {
this.overlayRenderer.draw(ctx, sprite, this.theme, this.zoom, this.panX, this.panY, mapData.tileSize);
}
}
}
/** 리사이즈 처리 */
resize() {