fix(animation): ASCII 애니메이션 높낮이/공백 문제 수정

- walkingAnimation, townAnimation 4줄 → 3줄 통일
- character_frames.dart 모든 프레임 폭 6자로 통일
- _compose() 이펙트 Y 위치 동적 계산 (하드코딩 제거)
- withShield() 3줄 캐릭터용으로 수정 (index 3 → index 1)
- BattleComposer 캔버스 시스템 및 배경 합성 추가
- 무기 카테고리별 이펙트, 몬스터 크기/색상 시스템 구현
This commit is contained in:
JiWoong Sul
2025-12-13 18:22:50 +09:00
parent e30177e788
commit 598c25e4c9
14 changed files with 2052 additions and 355 deletions

View File

@@ -0,0 +1,184 @@
import 'package:askiineverdie/src/core/animation/weapon_category.dart';
/// 무기 카테고리별 공격 이펙트 ASCII 프레임
///
/// 각 이펙트는 멀티라인 (최대 5줄, 24자 폭).
/// 캐릭터와 몬스터 사이에 표시됨.
class WeaponEffect {
const WeaponEffect({
required this.prepareFrames,
required this.attackFrames,
required this.hitFrames,
this.hitSound = '*HIT!*',
this.effectHeight = 3,
this.effectYStart = 2,
});
/// 준비 프레임 (멀티라인)
final List<List<String>> prepareFrames;
/// 공격 프레임 (멀티라인)
final List<List<String>> attackFrames;
/// 히트 프레임 (멀티라인)
final List<List<String>> hitFrames;
/// 히트 효과음 텍스트
final String hitSound;
/// 이펙트 높이 (줄 수)
final int effectHeight;
/// 이펙트 시작 Y 위치 (0~7)
final int effectYStart;
}
/// 카테고리별 무기 이펙트 반환
WeaponEffect getWeaponEffect(WeaponCategory category) {
return switch (category) {
WeaponCategory.blunt => _bluntEffect,
WeaponCategory.cable => _cableEffect,
WeaponCategory.projectile => _projectileEffect,
WeaponCategory.energy => _energyEffect,
WeaponCategory.cosmic => _cosmicEffect,
WeaponCategory.unarmed => _unarmedEffect,
};
}
// ============================================================================
// 둔기류 - 휘두르기 (3줄)
// ============================================================================
const _bluntEffect = WeaponEffect(
prepareFrames: [
[r' _', r' /', r' /'],
[r' _/', r' / ', r' / '],
],
attackFrames: [
[r' _/ ', r' / ', r'/ '],
[r' /__ ', r'/ ', r' '],
[r'/__ ', r' ', r' '],
[r'/__=>', r' ', r' '],
],
hitFrames: [
[r' *BASH* ', r'/__=> ', r' '],
[r'*SMASH!*', r' /__ ', r' '],
],
hitSound: '*BASH*',
effectHeight: 3,
effectYStart: 2,
);
// ============================================================================
// 케이블류 - 채찍질 (3줄)
// ============================================================================
const _cableEffect = WeaponEffect(
prepareFrames: [
[r' ', r'~ ', r' ~ '],
[r' ', r'~~ ', r' ~ '],
],
attackFrames: [
[r' ', r'~~~ ', r' ~~ '],
[r' ', r'~~~~ ', r' ~~ '],
[r' ', r'~~~~~> ', r' ~~ '],
[r' ', r'~~~~~~> ', r' ~~'],
],
hitFrames: [
[r' *WHIP*', r'~~~~~~> ', r' ~~'],
[r' *CRACK*', r'~~~~~> ', r' ~~ '],
],
hitSound: '*WHIP*',
effectHeight: 3,
effectYStart: 2,
);
// ============================================================================
// 투척류 - 발사 (3줄)
// ============================================================================
const _projectileEffect = WeaponEffect(
prepareFrames: [
[r' ', r'[=] ', r' '],
[r' ', r'[==] ', r' '],
],
attackFrames: [
[r' ', r' [> ', r' '],
[r' ', r' [>', r' '],
[r' ', r' [>', r' '],
[r' ', r' [>', r' '],
],
hitFrames: [
[r' *CLANG*', r' [>', r' '],
[r' *CRASH* ', r' [> ', r' '],
],
hitSound: '*CLANG*',
effectHeight: 3,
effectYStart: 2,
);
// ============================================================================
// 에너지류 - 빔 발사 (3줄)
// ============================================================================
const _energyEffect = WeaponEffect(
prepareFrames: [
[r' ', r' <*> ', r' '],
[r' == ', r' <**> ', r' == '],
],
attackFrames: [
[r' ==== ', r'==<*>== ', r' ==== '],
[r' ====== ', r'===<*>==', r' ====== '],
[r'========', r'===<*>==', r'========'],
[r'========', r'====<*>=', r'========'],
],
hitFrames: [
[r'==*ZAP*=', r'===<*>==', r'========'],
[r'*BZZT!*=', r'====<*>=', r'========'],
],
hitSound: '*ZAP*',
effectHeight: 3,
effectYStart: 2,
);
// ============================================================================
// 우주급 - 초월적 공격 (5줄)
// ============================================================================
const _cosmicEffect = WeaponEffect(
prepareFrames: [
[r' * ', r' @ @ ', r' @ @ ', r' @ @ ', r' * '],
[r' * * ', r' @ @ ', r' @ @', r' @ @ ', r' * * '],
],
attackFrames: [
[r' * ', r' * * * ', r' * * * *', r' * * * ', r' * '],
[r' *** ', r' * * * *', r'* * * * ', r' * * * *', r' *** '],
[r' ***** ', r' ******* ', r'*********', r' ******* ', r' ***** '],
[r' **VOID**', r'*********', r'*********', r'*********', r' **VOID**'],
],
hitFrames: [
[r'*SINGULAR', r'*********', r'***!!!***', r'*********', r'*DESTROY*'],
[r'!!!VOID!!', r'*********', r'*********', r'*********', r'!!!VOID!!'],
],
hitSound: '***VOID***',
effectHeight: 5,
effectYStart: 1,
);
// ============================================================================
// 맨손 - 기본 펀치 (3줄)
// ============================================================================
const _unarmedEffect = WeaponEffect(
prepareFrames: [
[r' ', r' ', r' '],
[r' ', r' > ', r' '],
],
attackFrames: [
[r' ', r'-> ', r' '],
[r' ', r'---> ', r' '],
[r' ', r'-----> ', r' '],
],
hitFrames: [
[r' *POW* ', r'-----> ', r' '],
[r'*PUNCH*', r'----> ', r' '],
],
hitSound: '*POW*',
effectHeight: 3,
effectYStart: 2,
);