고급

미니게임 (로그라이크 성장)

무기를 고르고 움직이는 플레이어가 몰려오는 몬스터를 자동 공격하며, 경험치 보석을 먹고 카드로 성장하는 생존형 로그라이크 미니게임입니다.

동작

미니게임 (로그라이크 성장) 실행 화면

검, 화살, 마법, 소환 중 하나의 무기를 선택하고 전투를 시작합니다. 플레이어를 드래그해 움직이면 몬스터가 계속 따라오고, 가장 가까운 몬스터를 자동으로 공격합니다. 몬스터를 처치하면 경험치 보석이 떨어지고, 보석에 가까이 가면 자석 범위 안에서 끌려옵니다. 경험치가 가득 차면 게임을 잠시 멈추고 희귀도가 붙은 성장 카드 3장을 보여줍니다. 카드를 선택하면 공격력, 체력, 자석 범위, 액티브 스킬 같은 능력이 올라가고 다음 스테이지로 이어집니다.

예제 코드

실시간 생존형 로그라이크 게임

로그라이크 생존
무기 Stage 1 레벨 1
EXP 0/3
스탯
  • 공격력 2
  • 공속 0.42초
  • 사거리 220
  • 이동속도 170
  • 체력 100/100
  • 피해감소 0%
  • 자석 78
  • 경험치 +0%
  • 재생 0%
  • 언데드 0
무기 선택

시작 무기를 고르면 전투가 시작됩니다.

전투 시작을 누른 뒤 화면을 클릭하면 플레이어가 이동합니다.

예제 코드 기능별 설명

코드를 나누어 읽기

import

dart:async은 실시간 게임 루프에, dart:math는 몬스터 스폰 위치와 카드 무작위 선택에 사용합니다. material.dart는 GestureDetector, CustomPaint, 버튼과 카드 UI를 제공합니다.

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

데이터 클래스

Weapon, Enemy, Bullet, ExpGem, UpgradeCard는 게임 안의 주요 대상을 작은 모델로 나눈 것입니다. 이렇게 나누면 이동, 충돌, 성장 로직을 객체별로 읽을 수 있습니다.

class Weapon { ... }
class Enemy { ... }
class Bullet { ... }
class ExpGem { ... }
class UpgradeCard { ... }

상태 변수

player는 캐릭터 위치, enemies는 몬스터 목록, bullets는 투사체 목록, gems는 경험치 보석 목록입니다. level, stage, exp, hp는 화면 상단과 스탯 패널에 표시되는 진행 상태입니다.

Offset player = const Offset(180, 180);
List<Enemy> enemies = [];
List<Bullet> bullets = [];
List<ExpGem> gems = [];

게임 루프

Timer.periodic으로 약 16ms마다 tick을 호출합니다. 이 안에서 플레이어 이동, 몬스터 추적, 투사체 이동, 경험치 흡수, 스폰 타이밍을 함께 갱신합니다.

timer = Timer.periodic(
  const Duration(milliseconds: 16),
  (_) => tick(0.016),
);

자동 공격과 몬스터 추적

몬스터는 플레이어 방향으로 계속 이동하고, 플레이어는 가장 가까운 몬스터를 향해 자동으로 투사체를 발사합니다. 버튼을 누르는 전투가 아니라 계속 움직이는 전투입니다.

final target = enemies.first;
final delta = target.position - player;
bullets.add(Bullet(
  position: player,
  velocity: direction * weapon.projectileSpeed,
  damage: weapon.damage + damageBonus,
));

경험치와 카드 성장

몬스터가 죽으면 경험치 보석을 만들고, 보석은 자석 범위 안에서 플레이어 쪽으로 끌려옵니다. 경험치가 가득 차면 전투를 멈추고 희귀도 카드 3장을 보여줍니다.

if (enemy.hp <= 0) {
  gems.add(ExpGem(enemy.position, 2 + stage * 0.5));
}
if (exp >= expNeed) {
  cards = buildCards();
}

CustomPainter

게임 화면은 일반 위젯을 많이 쌓기보다 CustomPainter로 한 번에 그립니다. 배경 격자, 플레이어, 몬스터, 투사체, 보석, 체력 바가 같은 캔버스에 그려집니다.

CustomPaint(
  painter: RoguePainter(
    player: player,
    enemies: enemies,
    bullets: bullets,
    gems: gems,
  ),
)