DEV/flutter (dart)

Flutter/Flame 2D 횡 스크롤 게임 만들기 예시 2 (Flutter/Flame 2D Horizontal Scroll Game Example 2)

석봉 2023. 3. 8. 18:08

지난 글...

https://seokbong.tistory.com/184

 

Flutter/Flame 2D 횡 스크롤 게임 만들기 예시 1

1. 시작 Flutter를 시작하면서 게임을 만들어 보고 싶었다. (사실 바닐라JS로 하려고 했었는데... Flutter 시작한 김에 만들어 보려고 한다.) 프로젝트 이전에 Flame와 친해질 필요가 있었고 (당장 Flutter

seokbong.tistory.com

 


 

저번 글에서 기본적인 세팅과 케릭터 생성을 해보았다.

 

이번에는 케릭터를 좌 / 우로 이동 가능하게 만들고 점프를 할 수 있는 기능을 추가 할 것이다.

 

사실 이번 시간에는 코드만 길 뿐 내용은 단순하다.

 

Player.dart 파일만 수정하면 이동하는 기능 구현이 가능하다.

 

하단 코드의 주석을 읽으면서 차근 차근 추가해보자.

Player.dart 에 기능 추가하기

import 'package:flame/components.dart';
import 'package:flutter/services.dart';
import '../../seokbongRoom.dart';

// SpriteAnimationComponent : Flame 엔진에서 스프라이트 에니메이션을 처리하는 데 사용.
// KeyboardHandler : 키보드 이벤트를 처리하기 위한 메소드 구현.
// HasGameRef :
class Player extends SpriteAnimationComponent with KeyboardHandler, HasGameRef<SeokbongRoom> {
  Player({
    required super.position,
  }) : super(size: Vector2.all(64), anchor: Anchor.center);

  // Player의 X축 속도 및 이동속도 지정
  final Vector2 velocity = Vector2.zero();
  final double moveSpeed = 300;

  // Player의 y축(점프) 속도 및 여부 확인
  bool isJumping = false;
  bool isFalling = false;

  final double jumpSpeed = -500;
  final double gravity = 1000;
  // Player의 좌, 우 이동방향 저장
  int horizontalDirection = 0;

  // SpriteAnimation 초기화 및 로드 (게임 오브젝트가 로드되면 호출)
  @override
  Future<void> onLoad() async {
    // SpriteAnimation : 스프라이트 시퀀스를 처리하고 애니메이션을 구현하는 데 사용.
    // SpriteAnimation.fromFrameData() : SpriteAnimation 객체 생성.
    // game.images.fromCache() : 이미지 로드.
    animation = SpriteAnimation.fromFrameData(
      game.images.fromCache('ember.png'),
      SpriteAnimationData.sequenced(
        amount: 4,    // 스프라잍트 수
        stepTime: 0.12,   //스프라이트의 시간 간격
        textureSize: Vector2.all(16),   // 스프라이트 텍스처 사이즈
      ),
    );
  }

  // 점프 기능 추가
  void jump() {
    // 점프 중 인 경우, return
    if (isJumping || isFalling) return;

    isJumping = true;
    velocity.y = jumpSpeed;
  }

  // 키보드 이벤트 처리
  // keysPressed 매개 변수를 통해 현재 눌린 키 목록을 가져옴.
  @override
  bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
    horizontalDirection = 0;

    // 좌 화살표가 눌린 경우 horizontalDirection -1
    horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.arrowLeft))
        ? -1
        : 0;
    // 우 화살표가 눌린 경우 horizontalDirection +1
    horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.arrowRight))
        ? 1
        : 0;
    if (event is RawKeyDownEvent && (event.logicalKey == LogicalKeyboardKey.space || event.logicalKey == LogicalKeyboardKey.arrowUp)) {
      jump();
    }

    // 이벤트 처리를 완료함
    return true;
  }

  // 게임 오브젝트가 업데이트 될 때마다 호출됨.
  @override
  void update(double dt) {
    // 방향 * 이동속도
    velocity.x = horizontalDirection * moveSpeed;

    // 좌우 벽에 닿았는지 확인
    // 벽에서 팅겨냄, (*주의) 키를 계속 누르고 있으면 계속 해당 방향을 향함
    // 아래 코드를 지워도 문제는 없음. (케릭터가 벽을 넘어갈 뿐)
    if (position.x <= 0) { // 좌측 벽에 닿은 경우
      horizontalDirection = 1; // 오른쪽으로 이동하도록 방향을 변경
      position.x = 0; // 위치를 벽에 붙도록 수정
    } else if (position.x + size.x >= game.size.x) { // 우측 벽에 닿은 경우
      horizontalDirection = -1; // 왼쪽으로 이동하도록 방향을 변경
      position.x = game.size.x - size.x; // 위치를 벽에 붙도록 수정
    }

    // 점프 중인데 땅에 착지한 경우
    if (isJumping) {
      velocity.y += gravity * dt;
      if (velocity.y >= 0) {
        isJumping = false;
        isFalling = true;
      }
    } else if (isFalling) {
      velocity.y += gravity * dt;
      // 플레이어가 바닥에 닿았을 때
      // gameRef.size.y : 화면 높이
      // size.y : 케릭터 높이
      final ground = gameRef.size.y - (size.y / 2);
      if (position.y + (size.y / 2) >= ground) {
        isFalling = false;
        velocity.y = 0;
        position.y = ground - size.y / 2;
      }
    }

    // 플레이어 이동 (dt는 마지막 프레임으로 부터 경가된 시간[초])
    position += velocity * dt;

    // horizontalDirection에 따라 스프라이트를 좌/우 반전
    if (horizontalDirection < 0 && scale.x > 0) {
      flipHorizontally();
    } else if (horizontalDirection > 0 && scale.x < 0) {
      flipHorizontally();
    }

    // 스프라이트 애니메이션 업데이트
    super.update(dt);
  }
}

 

결론

위 글을 쓰면서 누락된 부분이 존재할 수 있다.

 

코드를 작성하면서 쓴 글이 아니라 이해 부탁 바란다...ㅠ

(나도 다른 글 읽을 때 누락되면 짜증나서 보통 글을 쓰면서 진행하는데 이번에는 그러지 못하였다...)

 

대신 해당 프로젝트의 FULL CODE를 남긴다.

https://github.com/Seokhyeon-Park/side-scrolling-game-sample

 

GitHub - Seokhyeon-Park/side-scrolling-game-sample

Contribute to Seokhyeon-Park/side-scrolling-game-sample development by creating an account on GitHub.

github.com

 

이것으로 횡 스크롤 2D 게임의 가장 기본적인 구성을 갖춘 예시 코드를 모두 완성하였다.

 

다음에는 X-Y축 모두 이동이 가능한 코드를 만들면서 좀 더 자세하게 글을 써보도록 하겠다.

(라고 말하고 안한거 많음 주의)