refactor(agent-office): wire real AgentSprite import, remove Phase 1 stub
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user