refactor(shared): animation, l10n, theme 모듈을 core에서 shared로 이동
- core/animation → shared/animation - core/l10n → shared/l10n - core/constants/ascii_colors → shared/theme/ascii_colors - import 경로 업데이트
This commit is contained in:
175
lib/src/shared/animation/canvas/canvas_special_composer.dart
Normal file
175
lib/src/shared/animation/canvas/canvas_special_composer.dart
Normal file
@@ -0,0 +1,175 @@
|
||||
import 'package:asciineverdie/src/shared/animation/ascii_animation_type.dart';
|
||||
import 'package:asciineverdie/src/shared/animation/canvas/ascii_cell.dart';
|
||||
import 'package:asciineverdie/src/shared/animation/canvas/ascii_layer.dart';
|
||||
|
||||
/// Canvas용 특수 이벤트 애니메이션 합성기
|
||||
///
|
||||
/// 레벨업, 퀘스트 완료, Act 완료, 부활 등
|
||||
class CanvasSpecialComposer {
|
||||
const CanvasSpecialComposer();
|
||||
|
||||
/// 프레임 상수
|
||||
static const int frameWidth = 60;
|
||||
static const int frameHeight = 8;
|
||||
|
||||
/// 레이어 기반 프레임 생성
|
||||
List<AsciiLayer> composeLayers(
|
||||
AsciiAnimationType type,
|
||||
int frameIndex,
|
||||
int globalTick,
|
||||
) {
|
||||
return switch (type) {
|
||||
AsciiAnimationType.levelUp => _composeLevelUp(frameIndex, globalTick),
|
||||
AsciiAnimationType.questComplete => _composeQuestComplete(
|
||||
frameIndex,
|
||||
globalTick,
|
||||
),
|
||||
AsciiAnimationType.actComplete => _composeActComplete(
|
||||
frameIndex,
|
||||
globalTick,
|
||||
),
|
||||
AsciiAnimationType.resurrection => _composeResurrection(
|
||||
frameIndex,
|
||||
globalTick,
|
||||
),
|
||||
_ => [AsciiLayer.empty()],
|
||||
};
|
||||
}
|
||||
|
||||
/// 레벨업 애니메이션
|
||||
List<AsciiLayer> _composeLevelUp(int frameIndex, int globalTick) {
|
||||
final layers = <AsciiLayer>[
|
||||
_createEffectBackground(globalTick, '*'),
|
||||
_createCenteredSprite(_levelUpFrames[frameIndex % _levelUpFrames.length]),
|
||||
];
|
||||
return layers;
|
||||
}
|
||||
|
||||
/// 퀘스트 완료 애니메이션
|
||||
List<AsciiLayer> _composeQuestComplete(int frameIndex, int globalTick) {
|
||||
final layers = <AsciiLayer>[
|
||||
_createEffectBackground(globalTick, '+'),
|
||||
_createCenteredSprite(
|
||||
_questCompleteFrames[frameIndex % _questCompleteFrames.length],
|
||||
),
|
||||
];
|
||||
return layers;
|
||||
}
|
||||
|
||||
/// Act 완료 애니메이션
|
||||
List<AsciiLayer> _composeActComplete(int frameIndex, int globalTick) {
|
||||
final layers = <AsciiLayer>[
|
||||
_createEffectBackground(globalTick, '~'),
|
||||
_createCenteredSprite(
|
||||
_actCompleteFrames[frameIndex % _actCompleteFrames.length],
|
||||
),
|
||||
];
|
||||
return layers;
|
||||
}
|
||||
|
||||
/// 부활 애니메이션
|
||||
List<AsciiLayer> _composeResurrection(int frameIndex, int globalTick) {
|
||||
final layers = <AsciiLayer>[
|
||||
_createEffectBackground(globalTick, '.'),
|
||||
_createCenteredSprite(
|
||||
_resurrectionFrames[frameIndex % _resurrectionFrames.length],
|
||||
),
|
||||
];
|
||||
return layers;
|
||||
}
|
||||
|
||||
/// 이펙트 배경 레이어 생성 (z=0)
|
||||
AsciiLayer _createEffectBackground(int globalTick, String effectChar) {
|
||||
final cells = List.generate(
|
||||
frameHeight,
|
||||
(_) => List.filled(frameWidth, AsciiCell.empty),
|
||||
);
|
||||
|
||||
// 반짝이는 이펙트
|
||||
for (var y = 0; y < frameHeight; y++) {
|
||||
for (var x = 0; x < frameWidth; x++) {
|
||||
final offset = (x + y + globalTick) % 8;
|
||||
if (offset == 0) {
|
||||
cells[y][x] = AsciiCell.fromChar(effectChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AsciiLayer(cells: cells, zIndex: 0);
|
||||
}
|
||||
|
||||
/// 중앙 정렬 스프라이트 레이어 생성 (z=1)
|
||||
AsciiLayer _createCenteredSprite(List<String> lines) {
|
||||
final cells = _spriteToCells(lines);
|
||||
|
||||
// 중앙 정렬
|
||||
final spriteWidth = lines.isEmpty ? 0 : lines[0].length;
|
||||
final offsetX = (frameWidth - spriteWidth) ~/ 2;
|
||||
final offsetY = (frameHeight - cells.length) ~/ 2;
|
||||
|
||||
return AsciiLayer(
|
||||
cells: cells,
|
||||
zIndex: 1,
|
||||
offsetX: offsetX,
|
||||
offsetY: offsetY,
|
||||
);
|
||||
}
|
||||
|
||||
/// 문자열 스프라이트를 AsciiCell 2D 배열로 변환
|
||||
List<List<AsciiCell>> _spriteToCells(List<String> lines) {
|
||||
return lines.map((line) {
|
||||
return line.split('').map(AsciiCell.fromChar).toList();
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 레벨업 프레임 (5프레임)
|
||||
// ============================================================================
|
||||
|
||||
const _levelUpFrames = [
|
||||
[r' * ', r' \|/ ', r' o ', r' /|\ ', r' / \ '],
|
||||
[r' * * ', r' \|/ ', r' O ', r' </|\> ', r' / \ '],
|
||||
[r' * * * ', r' \|/ ', r' O ', r' <\|/> ', r' / \ '],
|
||||
[r' * * * * ', r' LEVEL ', r' UP! ', r' \O/ ', r' / \ '],
|
||||
[r'* * * * *', r' LEVEL ', r' UP! ', r' \O/ ', r' | | '],
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// 퀘스트 완료 프레임 (4프레임)
|
||||
// ============================================================================
|
||||
|
||||
const _questCompleteFrames = [
|
||||
[r' [?] ', r' | ', r' o ', r' /|\ ', r' / \ '],
|
||||
[r' [???] ', r' | ', r' o! ', r' /|\ ', r' / \ '],
|
||||
[r' [DONE] ', r' ! ', r' \o/ ', r' | ', r' / \ '],
|
||||
[r' +[DONE]+', r' \!/ ', r' \o/ ', r' | ', r' / \ '],
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// Act 완료 프레임 (4프레임)
|
||||
// ============================================================================
|
||||
|
||||
const _actCompleteFrames = [
|
||||
[r'=========', r' ACT ', r' CLEAR ', r' o ', r' /|\ '],
|
||||
[r'~~~~~~~~~', r' ACT ', r' CLEAR! ', r' \o/ ', r' | '],
|
||||
[r'*~*~*~*~*', r' ACT ', r' CLEAR!! ', r' \O/ ', r' / \ '],
|
||||
[r'*********', r' ACT ', r' CLEAR!! ', r' \O/ ', r' | | '],
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// 부활 프레임 (5프레임)
|
||||
// ============================================================================
|
||||
|
||||
const _resurrectionFrames = [
|
||||
// 프레임 1: R.I.P 묘비
|
||||
[r' ___ ', r' |RIP| ', r' | | ', r'__|___|__'],
|
||||
// 프레임 2: 빛 내림
|
||||
[r' \|/ ', r' -|R|- ', r' | | ', r'__|___|__'],
|
||||
// 프레임 3: 일어남
|
||||
[r' \o/ ', r' --|-- ', r' | | ', r'__|___|__'],
|
||||
// 프레임 4: 서있음
|
||||
[r' o ', r' /|\ ', r' / \ ', r'_________'],
|
||||
// 프레임 5: 부활 완료
|
||||
[r' REVIVED ', r' \o/ ', r' | ', r'___/ \___'],
|
||||
];
|
||||
Reference in New Issue
Block a user