paint-brush
Flame 게임에 HUD를 추가하는 방법~에 의해@eugene-kleshnin
1,737 판독값
1,737 판독값

Flame 게임에 HUD를 추가하는 방법

~에 의해 Eugene Kleshnin8m2023/03/20
Read on Terminal Reader
Read this story w/o Javascript

너무 오래; 읽다

이것은 Flame 엔진을 사용하여 간단한 플랫폼 게임을 구축하는 방법을 배우는 4부 시리즈의 마지막 부분입니다. 이 부분에서는 캐릭터가 수집할 수 있는 코인, 플레이어가 보유한 코인 수를 표시하는 HUD 및 승리 화면을 추가하겠습니다.

People Mentioned

Mention Thumbnail
featured image - Flame 게임에 HUD를 추가하는 방법
Eugene Kleshnin HackerNoon profile picture
0-item

이것은 Flame 엔진을 사용하여 간단한 플랫폼 게임을 구축하는 방법을 배우는 4부 시리즈의 마지막 부분입니다. 우리는 The Boy라는 애니메이션 플레이어 캐릭터를 추가하는 방법, Tiled 편집기를 사용하여 스크롤 가능한 게임 레벨을 만드는 방법, 충돌 감지를 통해 중력과 점프를 추가하는 방법( 1 부, 2 , 3부 )을 이미 알고 있습니다.


이 부분에서는 캐릭터가 수집할 수 있는 코인, 플레이어가 보유한 코인 수를 표시하는 HUD, 모든 코인이 수집되면 표시되는 승리 화면을 추가하겠습니다.


동전 추가

우리는 동전(또는 그 문제에 대한 다른 게임 개체)을 생성할 위치를 게임에 알려야 합니다. 짐작하셨겠지만, 플랫폼을 추가한 것과 비슷한 방식으로 Tiled 편집기를 사용하여 다른 객체 레이어를 추가할 것입니다. 하지만 두 가지 차이점이 있습니다.


  1. 플랫폼을 사용하여 스프라이트 이미지를 레벨 데이터에 구운 것입니다. 이 방법은 동전에는 그다지 적합하지 않습니다. 플레이어가 개체를 수집한 후에 개체를 제거해야 하기 때문입니다. 따라서 게임에서 동전이 어디에 표시되어야 하는지 알기 위해 생성 지점을 추가하고 Flame 구성 요소를 사용하여 렌더링을 수행합니다.


  2. 플랫폼의 경우 모든 크기의 직사각형을 사용했지만 동전의 경우 타일 1개 크기의 생성 지점을 추가합니다. 하지만 동전을 한 줄씩 추가하고 싶다면(안녕 마리오), 게임 코드를 수정하고 동전 개체를 추가할 때 생성 지점의 크기를 고려하면 쉽게 추가할 수 있습니다. 하지만 이 시리즈의 목적상 코인 생성 지점은 1x1이라고 가정합니다.


Tiled 편집기에서 레벨을 열고 Coins라는 새 개체 레이어를 만듭니다. 그런 다음 직사각형 도구를 사용하여 게임 엔진을 사용하여 동전 구성 요소를 추가할 수 있도록 지도 전체에 여러 생성 지점을 추가합니다. 내 레벨은 이제 다음과 같습니다.


동전 생성 지점


우리 게임은 다소 단순하며 이러한 빈 직사각형이 게임 런타임에서 동전으로 바뀔 것이라는 점을 덧붙이고 싶습니다. 하지만 더 많은 객체 유형을 추가하면 구별하기가 어려워집니다. 다행히 Tiled에는 모든 개체에 시각적 단서를 추가할 수 있는 "타일 삽입"이라는 도구가 있지만 이러한 이미지는 게임에서 렌더링되지 않습니다.


좋습니다. 레벨을 저장하고 IDE로 돌아갑니다. Coin 클래스를 /objects/ 폴더에 추가해 보겠습니다.

 class Coin extends SpriteAnimationComponent with HasGameRef<PlatformerGame> { late final SpriteAnimation spinAnimation; late final SpriteAnimation collectAnimation; Coin(Vector2 position) : super(position: position, size: Vector2.all(48)); @override Future<void> onLoad() async { spinAnimation = SpriteAnimation.fromFrameData( game.images.fromCache(Assets.COIN), SpriteAnimationData.sequenced( amount: 4, textureSize: Vector2.all(16), stepTime: 0.12, ), ); collectAnimation = SpriteAnimation.fromFrameData( game.images.fromCache(Assets.COIN), SpriteAnimationData.range( start: 4, end: 7, amount: 8, textureSize: Vector2.all(16), stepTimes: List.filled(4, 0.12), loop: false ), ); animation = spinAnimation; final hitbox = RectangleHitbox() ..collisionType = CollisionType.passive; add(hitbox); return super.onLoad(); } }


회전 및 수집을 위한 2개의 서로 다른 애니메이션과 나중에 플레이어와의 충돌을 확인하기 위한 RectangleHitbox 가 있습니다.


다음으로, game.dart 로 돌아가서 spawnObjects 메서드를 수정하여 코인을 생성합니다.

 final coins = tileMap.getLayer<ObjectGroup>("Coins"); for (final coin in coins!.objects) { add(Coin(Vector2(coin.x, coin.y))); }


게임을 실행하고 추가된 코인을 확인하세요.

게임은 각 스폰 지점에 CoinComponent를 추가했습니다.


이제 플레이어가 수집하면 사라지게 만들어 보겠습니다.


coin.dart 로 돌아가서 collect 방법을 추가하세요 :

 void collect() { animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; }


이 메서드가 호출되면 회전하는 애니메이션을 수집하는 애니메이션으로 전환하고, 완료되면 게임에서 이 구성 요소를 제거합니다.


그런 다음 theboy.dart 클래스 로 이동하여 onCollisionStart 메서드를 재정의합니다.

 @override void onCollisionStart(Set<Vector2> intersectionPoints, PositionComponent other) { if (other is Coin) { other.collect(); } super.onCollisionStart(intersectionPoints, other); }


onCollision 대신 onCollisionStart 사용하는 이유는 충돌 콜백이 한 번만 실행되기를 원하기 때문입니다.


이제 The Boy와 충돌하면 동전이 사라집니다. 수집된 코인 수를 추적하는 사용자 인터페이스를 추가해 보겠습니다.


HUD 추가

HUD(헤드업 디스플레이)는 단순히 게임에 대한 모든 정보(체력, 탄약 등)를 표시하는 상태 표시줄입니다. 수집된 각 코인에 대해 코인 아이콘을 표시하겠습니다.


단순화를 위해 코인 수를 변수에 저장하겠습니다. 그러나 보다 복잡한 인터페이스를 위해서는 편리한 방법으로 게임 상태를 업데이트하고 관찰할 수 있는 Flame_bloc 패키지를 사용하는 것이 좋습니다.


HUD 로직을 포함할 새 클래스를 추가하세요: lib/hud.dart

 class Hud extends PositionComponent with HasGameRef<PlatformerGame> { Hud() { positionType = PositionType.viewport; } void onCoinsNumberUpdated(int total) { final coin = SpriteComponent.fromImage( game.images.fromCache(Assets.HUD), position: Vector2((50 * total).toDouble(), 50), size: Vector2.all(48)); add(coin); } }


여기서 흥미로운 두 가지 사항은 다음과 같습니다.


  1. HUD를 화면 모서리에 고정하기 위해 positionType PositionType.viewport 로 설정했습니다. 그렇게 하지 않으면 카메라 움직임으로 인해 HUD가 레벨에 따라 움직이게 됩니다.
  2. onCoinsNumberUpdated 메소드는 플레이어가 코인을 수집할 때마다 호출됩니다. total 매개변수를 사용하여 다음 동전 아이콘의 오프셋을 계산한 다음 계산된 위치에 새 동전 스프라이트를 추가합니다.


다음으로 game.dart 파일 로 돌아가서 새 클래스 변수를 추가합니다.

 int _coins = 0; // Keeps track of collected coins late final Hud hud; // Reference to the HUD, to update it when the player collects a coin


그런 다음 onLoad 메서드 하단에 Hud 구성 요소를 추가합니다 .

 hud = Hud(); add(hud);


그리고 새로운 메소드를 추가하세요:

 void onCoinCollected() { _coins++; hud.onCoinsNumberUpdated(_coins); }


마지막으로 Coincollect 메소드 에서 호출합니다 .

 void collect() { game.onCoinCollected(); animation = collectAnimation; collectAnimation.onComplete = () => { removeFromParent() }; }

훌륭합니다. 이제 HUD에 우리가 수집한 코인의 개수가 표시됩니다!


왼쪽 상단의 HUD에는 수집된 코인이 표시됩니다.


승리 화면

마지막으로 추가하고 싶은 것은 플레이어가 모든 코인을 수집하면 표시되는 승리 화면입니다.


PlatformerGame 클래스 에 새 const를 추가합니다 .

 late int _totalCoins;


그리고 레벨에 있는 동전의 수를 여기에 할당합니다. spawnObjects 메서드 맨 아래에 다음 줄을 추가합니다 .

 _totalCoins = coins.objects.length;


그리고 이것을 onCoinCollected 메소드의 맨 아래에 추가하십시오.


import 'package:flutter/material.dart'; 추가해야 할 수도 있습니다. 수동으로.

 if (_coins == _totalCoins) { final text = TextComponent( text: 'U WIN!', textRenderer: TextPaint( style: TextStyle( fontSize: 200, fontWeight: FontWeight.bold, color: Colors.white, ), ), anchor: Anchor.center, position: camera.viewport.effectiveSize / 2, )..positionType = PositionType.viewport; add(text); Future.delayed(Duration(milliseconds: 200), () => { pauseEngine() }); }


여기에서는 코인 카운터가 레벨의 코인 수와 같은지 확인하고, 일치하면 게임 화면 상단에 Win 라벨을 추가합니다. 그런 다음 게임을 일시 중지하여 플레이어의 움직임을 중지합니다. 또한 일시 중지되기 전에 레이블이 렌더링되도록 200ms 지연을 추가했습니다.


다음과 같아야 합니다.

마지막 코인을 모으면 승리 화면이 표시됩니다.


그리고 그게 바로 게임이에요! 물론, 지금은 완성된 게임처럼 보이지는 않지만, 제가 설명한 모든 내용을 통해 더 많은 레벨, 적 또는 기타 수집 가능한 항목을 추가하는 것은 상당히 쉬울 것입니다.


요약

이 부분으로 시리즈가 마무리됩니다.


Flame 엔진에는 물리 엔진 Forge2D, 입자, 효과, 게임 메뉴, 오디오 등을 포함하여 내가 다루지 않은 더 많은 기능이 있습니다. 하지만 이 시리즈를 완료한 후에는 엔진이 어떤 것인지 이해하게 되었고, 더 복잡한 게임을 만드는 방법을 이해하고 있습니다.


Flame은 강력하면서도 사용하기 쉽고 배우기 쉬운 도구입니다. Box2D와 같은 다른 멋진 기능을 가져올 수 있는 모듈식이며 적극적으로 유지 관리됩니다. 그러나 Flame의 가장 큰 장점 중 하나는 Flutter를 기반으로 구축되었다는 것입니다. 즉, 약간의 추가 작업으로 다중 플랫폼 지원을 제공한다는 의미입니다. 그러나 Flutter 확장 기능이 있다는 것은 모든 Flutter 문제가 Flame에서도 지속된다는 것을 의미합니다. 예를 들어, Flutter의 앤티앨리어싱 버그는 몇 년 동안 해결되지 않은 채 공개되어 왔으며 우리가 만든 게임에서도 이를 발견할 수 있습니다. 하지만 전반적으로 시도해 볼 가치가 있는 게임을 제작하기 위한 훌륭한 도구입니다.


시리즈의 다른 이야기:

이 튜토리얼의 전체 코드는 내 github 에서 찾을 수 있습니다.

자원

각 파트의 마지막에는 제가 배운 멋진 제작자와 리소스 목록을 추가하겠습니다.