feat(agent-office): add SpriteLoader with procedural fallback for Phase 2

This commit is contained in:
2026-04-27 08:32:19 +09:00
parent 7dd2cc9793
commit 71fe91cc85

View File

@@ -0,0 +1,77 @@
// src/pages/agent-office/canvas/SpriteLoader.js
import { ProceduralSprite } from './ProceduralSprite.js';
/**
* 스프라이트 로더 — PNG 스프라이트시트가 있으면 사용, 없으면 프로시저럴 폴백
*
* 스프라이트시트 규격 (Phase 2):
* - 프레임 크기: 16×32px
* - 행: 방향 (0=down, 1=up, 2=right)
* - 열: 상태별 프레임 (idle 2 | walk 4 | type 2 | wait 2 | break 2 = 12열)
*/
export class SpriteLoader {
constructor() {
this.sprites = new Map(); // agentId → { image: Image, loaded: boolean }
}
/** PNG 스프라이트시트 로드 시도 */
async tryLoad(agentId, url) {
return new Promise((resolve) => {
const img = new Image();
img.onload = () => {
this.sprites.set(agentId, { image: img, loaded: true });
resolve(true);
};
img.onerror = () => {
resolve(false); // 폴백 사용
};
img.src = url;
});
}
hasSprite(agentId) {
return this.sprites.has(agentId) && this.sprites.get(agentId).loaded;
}
/**
* 에이전트 1프레임 그리기 (스프라이트 또는 프로시저럴)
*/
draw(ctx, agentId, state, direction, frame, x, y, scale) {
if (this.hasSprite(agentId)) {
this._drawFromSheet(ctx, agentId, state, direction, frame, x, y, scale);
} else {
ProceduralSprite.draw(ctx, agentId, state, direction, frame, x, y, scale);
}
}
_drawFromSheet(ctx, agentId, state, direction, frame, x, y, scale) {
const { image } = this.sprites.get(agentId);
const frameW = 16;
const frameH = 32;
// 방향 → 행
const dirRow = direction === 'up' ? 1 : direction === 'right' || direction === 'left' ? 2 : 0;
// 상태 → 열 오프셋
const stateOffsets = { idle: 0, walk: 2, type: 6, wait: 8, break_anim: 10 };
const mappedState = state === 'working' ? 'type' : state === 'waiting' ? 'wait'
: state === 'reporting' ? 'type' : state === 'break' ? 'break_anim'
: state === 'walk' ? 'walk' : 'idle';
const colOffset = stateOffsets[mappedState] || 0;
const srcX = (colOffset + frame) * frameW;
const srcY = dirRow * frameH;
const destW = frameW * scale;
const destH = frameH * scale;
ctx.save();
if (direction === 'left') {
ctx.translate(x, 0);
ctx.scale(-1, 1);
ctx.translate(-x, 0);
}
ctx.drawImage(image, srcX, srcY, frameW, frameH, x - destW / 2, y - destH, destW, destH);
ctx.restore();
}
}