티스토리 뷰

반응형

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

지난번 포스팅에서 바텀시트를 통해 게임에 객체를 추가해주는 부분을 진행했습니다. 이번 포스팅에서는 펫을 추가해 벽에 닿으면 자동으로 방향을 바꿔 움직이는 기능을 구현해보도록 하겠습니다. 

 

1. 펫 이미지 추가

assets/image 하위에 pet_sheet.png 파일을 추가해 주었습니다.

저는 인터넷에서 아무거나 가져와 사용했고 글을 보시는 분들도 아무 sheet를 구해서 추가해주시면 됩니다.

그리고 나서 pet_component.dart 라는 이름으로 펫 객체로 사용할 클래스를 생성해줍니다.

 

2. 펫 코드 작성

 

<pet_component.dart>

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

class PetComponent extends SpriteAnimationComponent
    with CollisionCallbacks, HasGameRef {
  final Vector2 velocity;

  PetComponent(
      this.velocity,
      Vector2 position,
      Vector2 size, {
        double angle = -pi / 4,
      }) : super(
    position: position,
    size: size,
    angle: angle,
    anchor: Anchor.center,
  );

  @override
  Future<void> onLoad() async {
    add(RectangleHitbox());
    animation = await gameRef.loadSpriteAnimation(
      'pet_sheet.png',
      SpriteAnimationData.sequenced(
        amount: 4,
        stepTime: 0.2,
        textureSize: Vector2.all(16),
      ),
    );
  }

  @override
  void update(double dt) {
    super.update(dt);
    position += velocity * dt;
  }

  @override
  void onCollisionStart(
      Set<Vector2> intersectionPoints,
      PositionComponent other,
      ) {
    super.onCollisionStart(intersectionPoints, other);
    velocity.negate();
    flipHorizontally();
  }
}

펫 컴포넌트는 움직이는 이미지 이며, 충돌감지를 해야하므로 SpriteAnimationComponent와 CollisionCallbacks 를 추가해줍니다.

 

PetComponent의 인자로 받는 velocity는 펫이 움직일 방향 및 속도에 대한 값이며 , position은 초기 위치, size는 펫의 크기를 의미합니다.

 

@override
Future<void> onLoad() async {
  add(RectangleHitbox());
  animation = await gameRef.loadSpriteAnimation(
    'pet_sheet.png',
    SpriteAnimationData.sequenced(
      amount: 4,
      stepTime: 0.2,
      textureSize: Vector2.all(16),
    ),
  );
}

제가 사용할 pet_sheet.png는 168 x 16 짜리 이미지이고 8칸으로 나누어져 있습니다.

이 8칸 중 앞의 4칸만 사용할 것이며 각 칸의 이미지 크기는 16 x 16 이므로 위와 같이 셋팅해주겠습니다.

 

@override
void update(double dt) {
  super.update(dt);
  position += velocity * dt;
}

위 함수는 객체를 업데이트 시켜주는 함수입니다. Flame은 모든 컴포넌트들을 동시에 업데이트를 시켜주고 dt 값은 delta라고 읽는데 마지막으로 업데이트 시켜준 후 경과된 시간을 의미합니다.

position += velocity * dt;

즉, 위 코드는  '컴포넌트의 방향 및 속도' x '이전 업데이트 후 경과된 시간 ' 이라고 볼 수 있습니다.

 

이제는 충돌을 감지하기 위한 부분을 살펴보겠습니다.

@override
void onCollisionStart(
    Set<Vector2> intersectionPoints,
    PositionComponent other,
    ) {
  super.onCollisionStart(intersectionPoints, other);
  velocity.negate();
  flipHorizontally();
}

 

위 함수는 충돌이 '시작된' 시점을 감지합니다. 즉, 벽과의 충돌을 감지해서 방향을 바꿔주는 부분입니다.

velocity.negate();

 위 부분이 컴포넌트의 방향을 반대로 역전 시켜주는 부분입니다.

예를 들어 velocity가 Vector2(100, 0); 이었다면 Vector2(-100, 0); 으로 바꿔준다는 의미입니다.

flipHorizontally();

 방향만 바꾼다면 펫은 전진했다가 후진을 하게될 뿐입니다. 컴포넌트를 돌려 반대로 움직이게끔 해주기 위해 위 함수를 추가해줍니다.

가로 방향으로 뒤집어 주겠다는 함수입니다.

 

3. 화면에 추가

 

이제 컴포넌트를 완성했으니 화면에 넣어주겠습니다.

(코드도 살짝 정리해 줬습니다.)

<henry_some_one.dart> 

class MyStaticGame extends FlameGame with HasCollisionDetection {

  List<int> list;
  MyStaticGame({required this.list});

  @override
  Color backgroundColor() => const Color(0x00000000);

  final GameBackGround _backGround = GameBackGround();
  // 플레이어의 사이즈
  final playerSize = Vector2(150, 100);
  // 플레이어의 위치
  final playerPosition = Vector2(200, 600);
  // 펫의 사이즈
  final petSize = Vector2(64, 64);
  // 펫의 위치
  final petPosition = Vector2(200, 700);

  @override
  Future<void> onLoad() async {
    // 화면 고정
    // await add(ScreenHitbox());
    await add(_backGround);
    // 플레이어의 위치 및 사이즈 input
    await add(AnimatedPlayer(playerPosition, playerSize));
    await add(
      PetComponent(Vector2(-100, 0), petPosition, petSize, angle: pi),
    );
  }

  @override
  void update(double dt) {
    super.update(dt);
    if(list.isEmpty) return;
    Vector2 position = Vector2(list.last * 50, 100);
    add(Item(position, index: list.last));
  }
}

 

우선 중복 충돌을 막기위해 

// await add(ScreenHitbox());

위 부분을 주석처리 해줬습니다.

game_background.dart 에서 이미 ScreenHitbox()를 적용해 놨기 때문입니다.

 

await add(
  PetComponent(Vector2(-100, 0), petPosition, petSize, angle: pi),
);

그리고 위 부분이 실직적으로 펫을 넣어주는 부분입니다.

velocity 값을 Vector2(-100, 0) 으로 주었기 때문에 이 펫은 x 축을 기준으로만 움직입니다.

처음에는 왼쪽으로 출발했다가 벽을만나면 오른쪽으로 가게 될것입니다. 

 

이 코드를 실행한 결과는 아래와 같습니다.

 

위와 같이 정상적으로 움직이는 것을 볼 수 있습니다. 

 

 

 

.

.

.

.

 

 

4개의 포스팅에 걸쳐 간단한 게임을 만들어 보았습니다 😃

처음 기획과 비교하면 상당히 간소해졌지만 여기까지만 문제없이 구현한다면 나머지는 제 포스팅을 봐주시는 분들이 추가해 보셔도 좋을거같습니다!

Flutter에서 게임을 만들어 본다는 개념이 많이 생소했고 막상 구현을 하면서도 익숙하지 않은 개념들이 많아 힘들었지만 어찌됐건 마무리를 지을 수 있었습니다.

앞으로 Flame에 관련해서 좀 더 공부하겠지만 포스팅으로 올리게 될지는 모르겠습니다 😂 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함