import 'package:flame/components.dart'; import 'package:flame/events.dart'; import 'package:flame/experimental.dart'; import 'package:flame/game.dart'; import 'package:flame/input.dart'; import 'package:flame/parallax.dart'; import 'package:flutter/material.dart'; void main() { runApp(GameWidget(game: SpaceShooterGame())); } class SpaceShooterGame extends FlameGame with PanDetector { late Player player; @override Future onLoad() async { final parallax = await loadParallaxComponent( [ ParallaxImageData('stars_0.png'), ParallaxImageData('stars_1.png'), ParallaxImageData('stars_2.png'), ], baseVelocity: Vector2(0, -5), repeat: ImageRepeat.repeat, velocityMultiplierDelta: Vector2(0, 5), ); add(parallax); player = Player(); add(player); add( SpawnComponent( factory: (index) { return Enemy(); }, period: 1, area: Rectangle.fromLTWH(0, 0, size.x, -Enemy.enemySize), ), ); } @override void onPanUpdate(DragUpdateInfo info) { player.move(info.delta.global); } @override void onPanStart(DragStartInfo info) { player.startShooting(); } @override void onPanEnd(DragEndInfo info) { player.stopShooting(); } } class Player extends SpriteAnimationComponent with HasGameReference { Player() : super( size: Vector2(100, 150), anchor: Anchor.center, ); late final SpawnComponent _bulletSpawner; @override Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( 'player.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, textureSize: Vector2(32, 48), ), ); position = game.size / 2; _bulletSpawner = SpawnComponent( period: 0.2, selfPositioning: true, factory: (index) { return Bullet( position: position + Vector2( 0, -height / 2, ), ); }, autoStart: false, ); game.add(_bulletSpawner); } void move(Vector2 delta) { position.add(delta); } void startShooting() { _bulletSpawner.timer.start(); } void stopShooting() { _bulletSpawner.timer.stop(); } } class Bullet extends SpriteAnimationComponent with HasGameReference { Bullet({ super.position, }) : super( size: Vector2(25, 50), anchor: Anchor.center, ); @override Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( 'bullet.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, textureSize: Vector2(8, 16), ), ); } @override void update(double dt) { super.update(dt); position.y += dt * -500; if (position.y < -height) { removeFromParent(); } } } class Enemy extends SpriteAnimationComponent with HasGameReference { Enemy({ super.position, }) : super( size: Vector2.all(enemySize), anchor: Anchor.center, ); static const enemySize = 50.0; @override Future onLoad() async { await super.onLoad(); animation = await game.loadSpriteAnimation( 'enemy.png', SpriteAnimationData.sequenced( amount: 4, stepTime: 0.2, textureSize: Vector2.all(16), ), ); } @override void update(double dt) { super.update(dt); position.y += dt * 250; if (position.y > game.size.y) { removeFromParent(); } } }