Add support for emoji particles in SpriteEffect

- spriteEffect 타입에 emoji 필드 추가 및 spriteUrl을 선택 사항으로 변경
- SpriteEffectInstance 내 이모지 기반 캔버스 텍스처 생성 기능 구현
- SpriteEffectManager 인스턴스 생성 로그에 이모지 정보 출력 대응
- 패키지 버전을 1.4.1으로 업데이트
This commit is contained in:
BaekRyang 2026-03-13 13:24:55 +09:00
parent f3c5ae3669
commit 672dd80b9d
4 changed files with 50 additions and 7 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@baekryang/responsive-image-canvas", "name": "@baekryang/responsive-image-canvas",
"version": "1.3.0", "version": "1.4.1",
"publishConfig": { "publishConfig": {
"registry": "https://git.bnovalab.com/api/packages/baekryang/npm/" "registry": "https://git.bnovalab.com/api/packages/baekryang/npm/"
}, },

View File

@ -78,8 +78,14 @@ export class SpriteEffectInstance {
return mesh; return mesh;
}); });
// 텍스처 비동기 로드 // 이모지 또는 URL 텍스처 로드
if (config.emoji) {
this.createEmojiTexture(config.emoji);
} else if (config.spriteUrl) {
this.loadTexture(config.spriteUrl); this.loadTexture(config.spriteUrl);
} else {
console.error('[SpriteEffectInstance] spriteUrl 또는 emoji 중 하나는 필수입니다.');
}
} }
/** 런타임 설정 업데이트 (maxParticles 제외) */ /** 런타임 설정 업데이트 (maxParticles 제외) */
@ -125,6 +131,38 @@ export class SpriteEffectInstance {
); );
} }
/** 이모지를 Canvas에 렌더링하여 텍스처 생성 */
private createEmojiTexture(emoji: string): void {
const size = 128;
const canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error('[SpriteEffectInstance] Canvas 2D 컨텍스트 생성 실패');
return;
}
ctx.font = '100px serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(emoji, size / 2, size / 2);
const texture = new THREE.CanvasTexture(canvas);
this.texture = texture;
// 각 메쉬에 텍스처 적용 (이모지는 스프라이트 시트 불필요)
for (const mesh of this.meshes) {
const mat = mesh.material as THREE.MeshBasicMaterial;
mat.map = texture;
mat.needsUpdate = true;
}
this.ready = true;
console.log(`[SpriteEffectInstance] 이모지 텍스처 생성 완료: ${emoji}`);
}
/** /**
* 1 * 1
* @param center ( 0-1) * @param center ( 0-1)

View File

@ -67,7 +67,7 @@ export class SpriteEffectManager {
} }
// 새 인스턴스 생성 // 새 인스턴스 생성
console.log('[SpriteEffectManager] 인스턴스 생성:', key, effectConfig.spriteUrl); console.log('[SpriteEffectManager] 인스턴스 생성:', key, effectConfig.emoji ?? effectConfig.spriteUrl);
const instance = new SpriteEffectInstance(effectConfig); const instance = new SpriteEffectInstance(effectConfig);
this.instances.set(key, instance); this.instances.set(key, instance);
this.effectGroup.add(instance.group); this.effectGroup.add(instance.group);

View File

@ -62,7 +62,10 @@ export interface SpriteEffectAreaData {
effects: Array<{ effects: Array<{
id: string; id: string;
trigger: SpriteEffectTrigger; trigger: SpriteEffectTrigger;
spriteUrl: string; /** spriteUrl 또는 emoji 중 하나 필수 */
spriteUrl?: string;
/** 이모지 파티클 (spriteUrl 대신 사용 가능) */
emoji?: string;
blendMode?: SpriteBlendMode; blendMode?: SpriteBlendMode;
maxParticles: number; maxParticles: number;
emitRate?: number; emitRate?: number;
@ -86,8 +89,10 @@ export interface SpriteEffectConfig {
id: string; id: string;
/** 트리거 타입 */ /** 트리거 타입 */
trigger: SpriteEffectTrigger; trigger: SpriteEffectTrigger;
/** 스프라이트 이미지 URL */ /** 스프라이트 이미지 URL (emoji와 택1) */
spriteUrl: string; spriteUrl?: string;
/** 이모지 파티클 (spriteUrl 대신 사용 가능) */
emoji?: string;
/** 블렌드 모드 (기본: 'normal') */ /** 블렌드 모드 (기본: 'normal') */
blendMode?: SpriteBlendMode; blendMode?: SpriteBlendMode;
/** 최대 파티클 수 */ /** 최대 파티클 수 */