// 캐릭터 애니메이션 프레임 (8줄 Stone Story RPG 스타일) // 참조: Stone Story RPG - 상세하고 생동감 있는 ASCII 아트 /// 전투 페이즈 enum BattlePhase { /// 대치 상태 (기본) idle, /// 공격 준비 prepare, /// 공격 중 attack, /// 피격 (몬스터가 맞음) hit, /// 복귀 recover, } /// 캐릭터 프레임 데이터 class CharacterFrame { const CharacterFrame(this.lines); /// 프레임 데이터 (3줄) final List lines; /// 방패 오버레이 적용 /// 3줄 캐릭터: [0]=머리, [1]=몸통/팔, [2]=다리 CharacterFrame withShield() { if (lines.length < 2) return this; final newLines = List.from(lines); // 몸통 줄(1번줄, 팔 위치)에 방패 추가 final bodyIdx = 1; if (newLines[bodyIdx].length >= 2) { // 첫 두 문자를 방패로 대체 newLines[bodyIdx] = '[]${newLines[bodyIdx].substring(2)}'; } else { newLines[bodyIdx] = '[]${newLines[bodyIdx]}'; } return CharacterFrame(newLines); } } /// 특정 페이즈와 서브프레임에 해당하는 캐릭터 프레임 반환 CharacterFrame getCharacterFrame(BattlePhase phase, int subFrame) { final frames = switch (phase) { BattlePhase.idle => _idleFrames, BattlePhase.prepare => _prepareFrames, BattlePhase.attack => _attackFrames, BattlePhase.hit => _hitFrames, BattlePhase.recover => _recoverFrames, }; final index = subFrame % frames.length; return frames[index]; } // ============================================================================ // 대기 프레임 (숨쉬기 애니메이션) - 4프레임, 심플 3줄 스타일, 폭 6자 // ============================================================================ const _idleFrames = [ CharacterFrame([ r' o ', r' /|\ ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|\ ', r' | | ', ]), CharacterFrame([ r' o ', r' /|\ ', r' / \ ', ]), CharacterFrame([ r' O ', r' /|\ ', r' / \ ', ]), ]; // ============================================================================ // 준비 프레임 (무기 들기) - 3프레임, 심플 3줄 스타일, 폭 6자 // ============================================================================ const _prepareFrames = [ CharacterFrame([ r' \o ', r' |\ ', r' / \ ', ]), CharacterFrame([ r' _ ', r' \o ', r' / \ ', ]), CharacterFrame([ r' \_ ', r' \o/ ', r' / \ ', ]), ]; // ============================================================================ // 공격 프레임 (전진 + 휘두르기) - 5프레임, 심플 3줄 스타일 // ============================================================================ const _attackFrames = [ CharacterFrame([ r' \_/ ', r' o ', r' /| ', ]), CharacterFrame([ r' _/ ', r' o ', r' /|\ ', ]), CharacterFrame([ r' o-- ', r' /| ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|-- ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|\_ ', r' / \ ', ]), ]; // ============================================================================ // 히트 프레임 (공격 명중) - 3프레임, 심플 3줄 스타일 // ============================================================================ const _hitFrames = [ CharacterFrame([ r' o ', r' /|-* ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|=* ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|~* ', r' / \ ', ]), ]; // ============================================================================ // 복귀 프레임 - 3프레임, 심플 3줄 스타일 // ============================================================================ const _recoverFrames = [ CharacterFrame([ r' o ', r' /|\ ', r' | ', ]), CharacterFrame([ r' o ', r' /|\ ', r' / \ ', ]), CharacterFrame([ r' o ', r' /|\ ', r' / \ ', ]), ];