refactor(animation): Canvas 레이어 z-index 정리 및 애니메이션 개선
- 캐릭터 z=2, 몬스터 z=1, 이펙트 z=3으로 레이어 순서 정리 - walking composer 업데이트 - 게임 화면 및 애니메이션 카드 개선
This commit is contained in:
@@ -24,6 +24,33 @@ enum AsciiAnimationType {
|
|||||||
resurrection,
|
resurrection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 특수 애니메이션 타이밍 상수
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/// 특수 애니메이션 프레임 수
|
||||||
|
const specialAnimationFrameCounts = {
|
||||||
|
AsciiAnimationType.levelUp: 5,
|
||||||
|
AsciiAnimationType.questComplete: 4,
|
||||||
|
AsciiAnimationType.actComplete: 4,
|
||||||
|
AsciiAnimationType.resurrection: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 특수 애니메이션 프레임 간격 (밀리초)
|
||||||
|
const specialAnimationFrameIntervals = {
|
||||||
|
AsciiAnimationType.levelUp: 300,
|
||||||
|
AsciiAnimationType.questComplete: 350,
|
||||||
|
AsciiAnimationType.actComplete: 400,
|
||||||
|
AsciiAnimationType.resurrection: 600,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 특수 애니메이션 총 지속 시간 (밀리초)
|
||||||
|
int getSpecialAnimationDuration(AsciiAnimationType type) {
|
||||||
|
final frames = specialAnimationFrameCounts[type] ?? 1;
|
||||||
|
final interval = specialAnimationFrameIntervals[type] ?? 200;
|
||||||
|
return frames * interval;
|
||||||
|
}
|
||||||
|
|
||||||
/// TaskType을 AsciiAnimationType으로 변환
|
/// TaskType을 AsciiAnimationType으로 변환
|
||||||
AsciiAnimationType taskTypeToAnimation(TaskType taskType) {
|
AsciiAnimationType taskTypeToAnimation(TaskType taskType) {
|
||||||
return switch (taskType) {
|
return switch (taskType) {
|
||||||
|
|||||||
@@ -115,13 +115,13 @@ class CanvasBattleComposer {
|
|||||||
|
|
||||||
return AsciiLayer(
|
return AsciiLayer(
|
||||||
cells: cells,
|
cells: cells,
|
||||||
zIndex: 1,
|
zIndex: 2, // 몬스터(z=1) 위에 캐릭터 표시
|
||||||
offsetX: charX,
|
offsetX: charX,
|
||||||
offsetY: charY,
|
offsetY: charY,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 몬스터 레이어 생성 (z=1)
|
/// 몬스터 레이어 생성 (z=1, 캐릭터보다 뒤)
|
||||||
AsciiLayer _createMonsterLayer(BattlePhase phase, int subFrame) {
|
AsciiLayer _createMonsterLayer(BattlePhase phase, int subFrame) {
|
||||||
final monsterFrames = _getAnimatedMonsterFrames(
|
final monsterFrames = _getAnimatedMonsterFrames(
|
||||||
monsterCategory,
|
monsterCategory,
|
||||||
@@ -155,7 +155,7 @@ class CanvasBattleComposer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 이펙트 레이어 생성 (z=2)
|
/// 이펙트 레이어 생성 (z=3, 캐릭터/몬스터 위에 표시)
|
||||||
AsciiLayer? _createEffectLayer(BattlePhase phase, int subFrame) {
|
AsciiLayer? _createEffectLayer(BattlePhase phase, int subFrame) {
|
||||||
final effect = getWeaponEffect(weaponCategory);
|
final effect = getWeaponEffect(weaponCategory);
|
||||||
final effectLines = _getEffectLines(effect, phase, subFrame);
|
final effectLines = _getEffectLines(effect, phase, subFrame);
|
||||||
@@ -176,7 +176,7 @@ class CanvasBattleComposer {
|
|||||||
|
|
||||||
return AsciiLayer(
|
return AsciiLayer(
|
||||||
cells: cells,
|
cells: cells,
|
||||||
zIndex: 2,
|
zIndex: 3,
|
||||||
offsetX: effectX,
|
offsetX: effectX,
|
||||||
offsetY: effectY,
|
offsetY: effectY,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -65,12 +65,7 @@ class CanvasWalkingComposer {
|
|||||||
// 바닥 레이어(Y=7) 위에 서있도록
|
// 바닥 레이어(Y=7) 위에 서있도록
|
||||||
final charY = frameHeight - cells.length - 1;
|
final charY = frameHeight - cells.length - 1;
|
||||||
|
|
||||||
return AsciiLayer(
|
return AsciiLayer(cells: cells, zIndex: 1, offsetX: charX, offsetY: charY);
|
||||||
cells: cells,
|
|
||||||
zIndex: 1,
|
|
||||||
offsetX: charX,
|
|
||||||
offsetY: charY,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 문자열 스프라이트를 AsciiCell 2D 배열로 변환
|
/// 문자열 스프라이트를 AsciiCell 2D 배열로 변환
|
||||||
@@ -87,27 +82,11 @@ class CanvasWalkingComposer {
|
|||||||
|
|
||||||
const _walkingFrames = [
|
const _walkingFrames = [
|
||||||
// 프레임 1: 오른발 앞
|
// 프레임 1: 오른발 앞
|
||||||
[
|
[r' o ', r' /|\ ', r' /| '],
|
||||||
r' o ',
|
|
||||||
r' /|\ ',
|
|
||||||
r' / | ',
|
|
||||||
],
|
|
||||||
// 프레임 2: 모음
|
// 프레임 2: 모음
|
||||||
[
|
[r' o ', r' /|\ ', r' |\ '],
|
||||||
r' o ',
|
|
||||||
r' /|\ ',
|
|
||||||
r' / \ ',
|
|
||||||
],
|
|
||||||
// 프레임 3: 왼발 앞
|
// 프레임 3: 왼발 앞
|
||||||
[
|
[r' o ', r' /|\ ', r' /| '],
|
||||||
r' o ',
|
|
||||||
r' /|\ ',
|
|
||||||
r' | \ ',
|
|
||||||
],
|
|
||||||
// 프레임 4: 모음
|
// 프레임 4: 모음
|
||||||
[
|
[r' o ', r' /|\ ', r' |\ '],
|
||||||
r' o ',
|
|
||||||
r' /|\ ',
|
|
||||||
r' / \ ',
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -476,8 +476,11 @@ class _GamePlayScreenState extends State<GamePlayScreen>
|
|||||||
_specialAnimation = AsciiAnimationType.resurrection;
|
_specialAnimation = AsciiAnimationType.resurrection;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. 애니메이션 종료 후 게임 재개 (5프레임 × 600ms = 3초)
|
// 3. 애니메이션 종료 후 게임 재개
|
||||||
Future.delayed(const Duration(milliseconds: 3000), () async {
|
final duration = getSpecialAnimationDuration(
|
||||||
|
AsciiAnimationType.resurrection,
|
||||||
|
);
|
||||||
|
Future.delayed(Duration(milliseconds: duration), () async {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_specialAnimation = null;
|
_specialAnimation = null;
|
||||||
|
|||||||
@@ -118,13 +118,8 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
int? _lastEventTimestamp;
|
int? _lastEventTimestamp;
|
||||||
bool _showCriticalEffect = false;
|
bool _showCriticalEffect = false;
|
||||||
|
|
||||||
// 특수 애니메이션 프레임 수
|
// 특수 애니메이션 프레임 수는 ascii_animation_type.dart의
|
||||||
static const _specialAnimationFrameCounts = {
|
// specialAnimationFrameCounts 상수 사용
|
||||||
AsciiAnimationType.levelUp: 5,
|
|
||||||
AsciiAnimationType.questComplete: 4,
|
|
||||||
AsciiAnimationType.actComplete: 4,
|
|
||||||
AsciiAnimationType.resurrection: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -242,7 +237,7 @@ class _AsciiAnimationCardState extends State<AsciiAnimationCard> {
|
|||||||
if (_animationMode == AnimationMode.special) {
|
if (_animationMode == AnimationMode.special) {
|
||||||
_currentFrame++;
|
_currentFrame++;
|
||||||
final maxFrames =
|
final maxFrames =
|
||||||
_specialAnimationFrameCounts[_currentSpecialAnimation] ?? 5;
|
specialAnimationFrameCounts[_currentSpecialAnimation] ?? 5;
|
||||||
// 마지막 프레임에 도달하면 특수 애니메이션 종료
|
// 마지막 프레임에 도달하면 특수 애니메이션 종료
|
||||||
if (_currentFrame >= maxFrames) {
|
if (_currentFrame >= maxFrames) {
|
||||||
_currentSpecialAnimation = null;
|
_currentSpecialAnimation = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user