티스토리 뷰

반응형

✍️ 이 포스팅은 노마드 개발자 글쓰기 스터디의 일환으로 자유 주제를 공부한 내용으로 포스팅 하고있습니다.

지난번 포스팅에서는 프로젝트를 생성하는 데에서 끝냈는데 이번 포스팅에서는 실제로 게임 화면을 띄우고 배경을 넣고 게임 캐릭터를 움직여 보려고 한다.

 

1. 게임 화면 띄우기

우리는 앞서 게임 프로젝트를 패키지로 생성했기 때문에 example 에서 사용을 해보려면 export 과정을 거쳐야 할 필요가 있다.

따라서 패키지 프로젝트 하위에 lib/index.dart 파일을 생성하고 아래와 같이 원하는 파일을 export 해준다.

 

<index.dart>

 

그리고 나서 실제 게임 화면에 보여질 부분을 만들어 준다.

 

<henry_some_one_dart> 

library henry_some_one;

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';

class HenrySomeOneGame extends StatefulWidget {
  const HenrySomeOneGame({Key? key}) : super(key: key);

  @override
  State createState() => _HenrySomeOneGameState();
}

class _HenrySomeOneGameState extends State {
  @override
  Widget build(BuildContext context) {
    return const GameWidget.controlled(
      gameFactory: MyStaticGame.new,
    );
  }
}

class MyStaticGame extends FlameGame with HasCollisionDetection {
  @override
  Color backgroundColor() => const Color(0x00000000);

  @override
  Future onLoad() async {
    // 화면 고정
    add(ScreenHitbox());
  }
}

 

 

여기까지 진행했다면 이제 게임을 띄워줄 준비는 다 된것이다.

이제는 example 프로젝트 하위의 main.dart 코드로 돌아가 위에서 작성한 HenrySomeOne 화면을 호출 해준다.

 

 

<main.dart>

import 'package:flutter/material.dart';
import 'package:henry_some_one/index.dart';
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: SomeOneGameApp(),
    );
  }
}

class SomeOneGameApp extends StatelessWidget {
  const SomeOneGameApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: HenrySomeOneGame(),
    );
  }
}

 

포스팅 초반에 export 해줬던 index.dart 파일을 여기서 import 함으로써 henry_some_one 패키지에서 정의한 위젯을 가져올 수 있다.

 

지금 까지의 과정을 모두 수행하고 앱을 실행시키면 위와같은 빈 화면이 뜨게된다.

그럼 이제부터 배경 화면을 넣어보겠다.

 

 

2. 배경화면 그려주기

패키지 프로젝트 lib 하위에 game_background.dart 파일을 만들어준다.

 

import 'package:flame/collisions.dart';
import 'package:flame/components.dart';

class GameBackGround extends SpriteComponent with HasGameRef {
  @override
  Future<void> onLoad() async {
    super.onLoad();
    add(RectangleHitbox());
    sprite = await gameRef.loadSprite('room.jpeg');
    // var origin = sprite!.originalSize; // <-- 실제사이즈
    // size = origin;

    final gameSize = gameRef.size; // <-- 화면 사이즈
    size = Vector2(gameSize.x, gameSize.y);
  }
}

 

SpriteComponent는 spriteSheet(게임 ui 리소스) 의 기본이 되는 컴포넌트이다.

특정한 이미지를 가져와 게임 화면이라는 도화지에 그린다고 생각하면 편하다.

 

sprite = await gameRef.loadSprite('room.jpeg');

 

위 코드를 통해 이미지를 불러올 수 있는데 .loadSprite는 기본적으로 {root}/assets/images 폴더가 있다고 가정하기 때문에 아래와 같이 폴더 구조를 만들어 준 후 이미지를 넣어줘야 한다.

 

flutter 에서는 이미지를 넣어주는것 만으로는 이미지를 불러올 수 없고 pubspec.yaml 에서 flutter 하위에 경로를 추가 한 뒤 pub get 을 해줘야 이미지를 가져올 수 있다.

room.jpeg는 필자가 아무 이미지나 가져와서 넣은것으로 실제로 그냥 그럴듯한 이미지라면 어떤 이미지든 상관없이 넣으면 된다.

이름또한 마음대로 지정해서 바꿔주면 된다.

 

 

이미지를 실제 사이즈로 넣어줄 수도 있으나 화면 사이즈에 딱 맞는 이미지를 구하기 어려우므로 화면 사이즈만큼 이미지를 늘려주는 코드를 작성한다. 

final gameSize = gameRef.size; // <-- 화면 사이즈
size = Vector2(gameSize.x, gameSize.y);

위와 같이 작성하면 실제 화면 크기만큼의 사이즈를 구해와서 이미지를 셋팅해줄 수 있다.

 

이제 위에서 생성해준 객체를 게임 화면에 올릴 차례이다.

<henry_some_one.dart>

class MyStaticGame extends FlameGame with HasCollisionDetection {
  @override
  Color backgroundColor() => const Color(0x00000000);

  final GameBackGround _backGround = GameBackGround();

  @override
  Future<void> onLoad() async {
    // 화면 고정
    add(ScreenHitbox());
    await add(_backGround);
  }
}

henry_some_one 파일에 

final GameBackGround _backGround = GameBackGround();

위 객체를 생성해서 

await add(_backGround);

 

해줌으로써 실제 게임에 배경이 나타나게 할 수 있다.

게임 내의 모든 구성요소는 저 add() 함수를 통해 input 된다.

이제 다시한번 앱을 구동해보면

출처 : https://www.pinterest.co.kr/pin/750834569143146719/

이렇게 깔끔하게 배경이 들어가는것을 볼 수 있다.

 

이제 위 배경에다가 캐릭터를 넣어보도록 하겠다.

 

3. 캐릭터 넣기

 

이런 ui가 필요한 사이드 프로젝트를 하면서 가장 어려운게 바로 리소스 구하기이다 ㅜㅜ

https://opengameart.org/    

위 사이트 에서는 저작권이 없는 리소스를 가져와 사용할 수 있다. (근데 쓸만한게 별로 없,,읍읍)

https://opengameart.org/content/simple-character-base-16x16  

필자는 위 링크에서 가져왔다.

 

 

우선 플레이어를 만들어주기 위해 animated_player 라는 클래스를 생성했다.

 

그리고 나서 아래와 같이 생긴 이미지를 assets/images/ 폴더에 넣어준다.

 

 

 

<animated_player.dart>

import 'package:flame/collisions.dart';
import 'package:flame/components.dart';

class AnimatedPlayer extends SpriteAnimationComponent
    with CollisionCallbacks, HasGameRef {

  AnimatedPlayer(
    Vector2 position,
    Vector2 size,
  ) : super(
          position: position,
          size: size,
          anchor: Anchor.center,
        );

  @override
  Future<void>? onLoad() async {
    animation = await gameRef.loadSpriteAnimation(
      'animated_player.png',
      SpriteAnimationData.sequenced(
        amount: 4,
        stepTime: 0.5,
        textureSize: Vector2(16, 16),
      ),
    );
    return super.onLoad();
  }
}

 

SpriteAnimationComponent

위 컴포넌트를 통해 우리는 정적인 이미지가 아니라 움직이는 객체를 불러올 수 있게 된다.

 

animation = await gameRef.loadSpriteAnimation(
  'animated_player.png',
  SpriteAnimationData.sequenced(
    amount: 4,
    stepTime: 0.5,
    textureSize: Vector2(16, 16),
  ),
);

요 부분을 잠깐 설명하고 넘어가자면

amount 는 위에서 가져온 sprite sheet를 split할 총 량이다. 위에서 필자가 가져온 이미지는 4 열로 이루어져 있기에 4를 입력해준다.

stemTime은 움직여줄 시간차를 의미한다. 즉 이 애니메이션은 0.5초마다 바뀐다.

textureSize는 위에서 가져온 이미지의 사이즈를 amount만큼 나눈 값이다. 위 이미지를 우클릭 하고 정보 가져오기로 사이즈를 봤을때 아래와 같이 64 x 64 가 나온다. 

그리고 각 4행 4열 이므로 이미지 한칸은 16 x 16 이라는 결론이 나오기 때문에 Vector2(16,16) 이라고 작성해준다.

 

이제 이 이미지를 게임화면에 추가해주면 끝이다. 

 

 

<henry_some_one.dart>

class MyStaticGame extends FlameGame with HasCollisionDetection {
  @override
  Color backgroundColor() => const Color(0x00000000);

  final GameBackGround _backGround = GameBackGround();

  @override
  Future<void> onLoad() async {
    // 화면 고정
    add(ScreenHitbox());
    await add(_backGround);

    // 플레이어의 사이즈
    final playerSize = Vector2(150, 100);
    // 플레이어의 위치
    final playerPosition = Vector2(200, 600);
    // 플레이어의 위치 및 사이즈 input
    add(AnimatedPlayer(playerPosition, playerSize));
  }
}

 

add(AnimatedPlayer(playerPosition, playerSize));

이렇게 add() 함수를 통해 게임의 구성요소를 추가한다. 

이 후 앱을 실행시켜보면 

이렇게 자동으로 움직이는 캐릭터가 생성된다! 

 

오늘 포스팅은 여기까지 이며, 다음 포스팅에서는 플러터 바텀시트를 통해 게임으로 구성요소를 input 하는 방법에 대해 알아보겠다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함