이제 총알 컴포넌트를 추가할 차례다. 튜토리얼에서는 패닝을 통해 우주선을 조종하고 있기에, 우주선을 조종하는 동안 총알을 발사하고, 우주선을 멈추면 발사도 멈추는 형식으로 구현하도록 안내하고 있다.
총알 컴포넌트를 구성하는 코드는 다음과 같다.
class Bullet extends SpriteAnimationComponent
with HasGameReference<FirstFlameGame> {
Bullet({super.position})
: super(size: Vector2(25, 50), anchor: Anchor.center);
@override
Future<void> onLoad() async {
await super.onLoad();
animation = await game.loadSpriteAnimation(
'bullet.png',
SpriteAnimationData.sequenced(
amount: 4,
stepTime: .2,
textureSize: Vector2(8, 16),
),
);
return super.onLoad();
}
@override
void update(double dt) {
super.update(dt);
position.y += dt * -500;
if (position.y < -height) {
removeFromParent();
}
}
}
총알 컴포넌트를 로드할 때, bullet.png 파일을 부른다. 이 때, bullet.png 파일을 0.2초 간격으로 프레임이 재생되는 8 x 16 크기의 애니메이션 스프라이트로 만든다.
매 프레임마다 총알 컴포넌트의 위치를 업데이트 해주는데, 기존에 있던 y축 위치에서 -500 만큼 위치가 변한다. y축은 위로 갈 수록 음의 값이다. 즉 매 프레임마다 총알은 500 픽셀만큼 위로 올라간다. 총알이 화면에서 벗어나면 removeFromParent() 함수를 호출해서 컴포넌트를 제거한다.
이후, 플레이어가 총알 컴포넌트를 사용하도록 해야 한다. 플레이어 컴포넌트에 발사와 발사 중지 함수를 추가한다.
class Player extends SpriteAnimationComponent
with HasGameReference<FirstFlameGame> {
void startShooting() {}
void stopShooting() {}
}
현재는 함수만 만들고 그 내부 함수의 구현은 뒤로 미룬다. 그리고 패닝 입력을 감지할 때 발사와 발사 중지 행동이 발동되도록 한다.
class FirstFlameGame extends FlameGame with PanDetector {
@override
void onPanStart(DragStartInfo info) {
player.startShooting();
}
@override
void onPanEnd(DragEndInfo info) {
player.stopShooting();
}
}
패닝이 시작될 때, player가 발사를 시작하도록 하고, 패닝이 종료되면 발사를 중지하도록 한다.
이제 player 컴포넌트가 어떻게 총알 컴포넌트를 처리할 것인지 구현해야한다.
class Player extends SpriteAnimationComponent
with HasGameReference<SpaceShooterGame> {
late final SpawnComponent _bulletSpawner;
@override
Future<void> onLoad() async {
// 기존 구현부 생략
// ...
_bulletSpawner = SpawnComponent(
period: .2,
selfPositioning: true,
factory: (index) {
return Bullet(position: position + Vector2(0, -height / 2));
},
autoStart: false,
);
game.add(_bulletSpawner);
}
void startShooting() {
_bulletSpawner.timer.start();
}
void stopShooting() {
_bulletSpawner.timer.stop();
}
}
Player를 로드할 때 SpawnComponent 를 설정한다. 0.2초마다 factory 함수를 통해 총알 컴포넌트를 생성한다. autoStart: false 값을 통해 _bulletSpawner가 생성되자마자 총알을 발사하는 것이 아니라 start() 함수를 통해 시작되기까지 대기하게 만든다.
factory 함수에서 bullet 컴포넌트를 만드는데, 총알이 생성되는 위치는 Player의 y축 위치에서 플레이어 높이의 절반만큼 위쪽에서, 즉 우주선 상단의 중앙에서 생성되도록 한다.
그 후 만들어진 _bulletSpawner를 game에 추가한다. SpawnComponent 안의 selfPositioning은 찾아보니 factory 함수 내에서 직접 컴포넌트의 생성 위치를 정하고 싶을 때 true로 설정한다고 한다.
이후, startShooting과 StopShooting에 _bulletSpawner.timer.start()와 _bulletSpawner.timer.stop()을 집어 넣는다.
이러면 게임이 시작될 때 Player 컴포넌트를 호출하고, Player 컴포넌트는 _bulletSpawner를 만들고 대기시킨다. Game에서 패닝 입력을 감지하면 Player 컴포넌트의 startShooting 함수를 호출하고, Player의 startShooting 함수는 _bulletSpawner를 작동시켜서 총알을 발사하고, 패닝 입력이 사라지면 Game은 Player의 stopShooting 함수를 호출해 _bulletSpawner를 정지시켜 총알의 발사를 정지시킨다.