플러터로 게임 만들어 보기 마지막 포스팅 입니다.
이번 글은 지난 번 처리했던 몹에 Bullet를 추가해서 각 몹에 맞는 Bullet가 표시 되도록 처리해 보겠습니다.
이 글에서 다루는 코드는 다음 Repository에서 확인할 수 있습니다.
Flutter_flame_game
적의 Bullet 처리
이번 처리는 지난번 Bullet 컴포넌트를 만들고 Player 컴포넌트에 추가 했던 것과 동일 합니다.
EnemyBullet 컴포넌트를 만들고 각각의 Enemy 컴포넌트에 추가하면 끝 입니다. Bullet의 종류별로 각 Enemy 컴포넌트에서 사용 될 수 있도록 Enemy 처리와 동일하게
각각의 EnemyBullet을 구현해서 처리해보겠습니다.
사용된 Sprites 이미지는 다음과 같습니다.
[components/enemies_bullet.dart]
import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame_game/components/player.dart';
import 'package:flame_game/game/my_game.dart';
abstract class EnemiesBullet extends PositionComponent
with CollisionCallbacks, HasGameRef<MyGame> {
final double _speed = 300;
@override
void onMount() {
super.onMount();
// player 객체 사이즈의 반지름 0.8배 작은 원형 히트박스 추가
final shape = CircleHitbox.relative(
0.8,
parentSize: size,
position: size / 2,
anchor: Anchor.center,
);
add(shape);
}
@override
void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
super.onCollision(intersectionPoints, other);
// Player 충돌시
if (other is Player) {
destroy();
}
}
@override
void update(double dt) {
super.update(dt);
position.y += dt * _speed;
// 스크린 세로 사이즈 범위 밖으로 사라지면 객체 제거
if (position.y > gameRef.size.y) {
destroy();
}
}
void destroy() {
removeFromParent();
}
}
class EnemyBullet01 extends EnemiesBullet {
EnemyBullet01() {
size = Vector2(5, 13);
}
@override
Future<void>? onLoad() async {
var bullerImage = await gameRef.images.load("Bullets.png");
var bullet = SpriteComponent.fromImage(bullerImage,
srcPosition: Vector2(58, 0), srcSize: Vector2(4, 12));
add(bullet);
}
}
class EnemyBullet02 extends EnemiesBullet {
EnemyBullet02() {
size = Vector2(7, 10);
}
@override
Future<void>? onLoad() async {
var bullerImage = await gameRef.images.load("Bullets.png");
var bullet = SpriteComponent.fromImage(bullerImage,
srcPosition: Vector2(35, 0), srcSize: Vector2(6, 9));
add(bullet);
}
}
class EnemyBullet03 extends EnemiesBullet {
EnemyBullet03() {
size = Vector2(11, 11);
}
@override
Future<void>? onLoad() async {
var bullerImage = await gameRef.images.load("Bullets.png");
var bullet = SpriteComponent.fromImage(bullerImage,
srcPosition: Vector2(66, 0), srcSize: Vector2(10, 10));
add(bullet);
}
}
Bullet의 속도가 300 고정인 추상 클래스인 EnemiesBullet 클래스를 확장해서 각각 EnemyBullet01, EnemyBullet02, EnemyBullet03 컴포넌트를 구현하였고, 이제 각 Enemy 컴포넌트에 추가 하기만 하면 됩니다.
[components/enemy.dart]
class NormalEnemy01 extends Enemy {
double bulletTime = 0;
NormalEnemy01()
// enemy 정보
: super(const EnemyModel(
speed: 200,
isHMove: false,
killPoint: 1,
level: 1,
isBoss: false)) {
size = Vector2(20, 17);
}
@override
Future<void>? onLoad() async {
// 기본 이미지
var enemySprite = await gameRef.loadSprite("Enemies.png",
srcPosition: Vector2(125, 67), srcSize: Vector2(12, 11));
// hit 되었을때 이미지
var enemyHitSprite = await gameRef.loadSprite("Enemies.png",
srcPosition: Vector2(125, 95), srcSize: Vector2(12, 11));
sprites = <int, Sprite>{
// 기본 이미지
1: enemySprite,
// hit 이미지
2: enemyHitSprite,
};
current = 1;
return super.onLoad();
}
// update()에 Bullet 추가
@override
void update(double dt) {
super.update(dt);
bulletTime += dt;
// 1.3초 마다 한번씩 발사
if (bulletTime < 1.3) return;
bulletTime = 0;
EnemiesBullet bullet = EnemyBullet01()
// Bullet의 위치 설정
..position = position.clone()
// Bullet의 기준점 설정
..anchor = Anchor.center;
gameRef.add(bullet);
}
}
Enemy컴포넌트가 각각 개별로 설계 되어 있기 때문에 각 Enemy Level에 맞게 동시에 여러개의 Bullet이 표시 되도록 커스텀하게 처리도 가능할 것 입니다.
그리고 Player 컴포넌트에서도 EnemiesBullet 컴포넌트와 충돌시 GameOver 되도록 처리 해야 합니다.
[components/player.dart]
@override
void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
super.onCollision(intersectionPoints, other);
// Enemy or EnemiesBullet 충돌시
if (other is Enemy || other is EnemiesBullet) { // other is EnemiesBullet 조건 추가
_playerComponent.current = PlayerDirection.boom;
}
}
[최종 게임 영상]
https://user-images.githubusercontent.com/13028129/215684893-a80a1991-7fb0-413f-aebd-c7ae0006b949.mp4
지금 까지 Flutter의 flame 미니멀리스트의 게임 엔진을 이용해서 간단한 2D Vertical Scrolling Game을 만들어 보았습니다.
flame 자체적으로 제공 되는 기능은 이 밖에도 이펙트 효과, 카메라 처리 등 다양 하기에 잘 활용하면 실제 릴리즈 해도 될만큼 퀄리티 높은 게임 제작이 가능할 것 입니다.
추가로 모바일 뿐 아니라 데스크탑과 웹 플랫폼 모두 지원하기 때문에 웹 게임도 간단하게 제작 가능합니다.
[Web 구동 화면]
위 코드는 다음 Repository에서 확인할 수 있습니다.