โ† Back to list

๐Ÿ‘พ Flutter Retro Game Series: Part 2โ€Šโ€”โ€ŠBuilding Space Invaders with AI-like Enemies & Retro FX

๐Ÿš€ The Battle Continues: From Tetris to Space Invaders

Piyush Kumar ยท 2025-07-22 10:51 ยท 0 claps ยท 2.9 min read
#flutter-game-development #retrogames #flutter-game #flutter #2d-game-development
Open on Medium โ†—
Wiki topics: AI ยท AI ยท General ๐Ÿ“ฑ ยท Mobile Development ๐Ÿ”ญ ยท Astronomy & Space

๐Ÿ‘พ Flutter Retro Game Series: Part 2 โ€” Building Space Invaders with AI-like Enemies & Retro FX

๐Ÿš€ The Battle Continues: From Tetris to Space Invaders

Welcome to Part 2 of the Flutter Retro Game Series. After diving deep into matrix logic and falling blocks in Tetris, weโ€™re now taking to the skies with a classic: Space Invaders.

This game adds a whole new dimension โ€” literally. With dynamic enemies, animated backgrounds, auto-shooting mechanics, and layered difficulty, this project pushes Flutterโ€™s widget system to new heights.

๐Ÿ“บ Watch the gameplay demo:

[embed]

๐Ÿ‘พ Game Features at a Glance

The game includes:

  • ๐Ÿš€ Smooth player spaceship movement
  • ๐Ÿ‘พ Enemies with types, health, and behavior
  • ๐Ÿ’ฅ Bullet collision system
  • ๐ŸŒ€ Animated starfield + galaxy effects
  • ๐Ÿ”„ Leveling and increasing difficulty
  • โค๏ธ Lives, score, and game state management
  • ๐ŸŽฎ Responsive gesture-based controls

๐Ÿ‘จโ€๐Ÿš€ Player Control โ€” Pan Gestures

We use GestureDetector to move the spaceship:

void _handlePanUpdate(DragUpdateDetails details) {
  final deltaX = details.delta.dx;
  final newX = _gameState.playerPosition.dx + deltaX * 4;

  _gameState = _gameState.copyWith(
    playerPosition: Offset(
      newX.clamp(20, _gameSize.width - 20), 
      _gameState.playerPosition.dy,
    ),
  );
}

Key Points:

  • Multiplied deltaX for faster movement
  • clamp keeps the ship on-screen
  • Players can only move horizontally

๐Ÿ’ฅ Bullet System โ€” Auto Fire Every 300ms

Bullets are created from the shipโ€™s current position:

void _autoShoot() {
  if (!_canShoot()) return;

  _lastShot = DateTime.now();
  final bullet = Bullet(
    position: Offset(
      _gameState.playerPosition.dx,
      _gameState.playerPosition.dy - 10,
    ),
    velocity: Offset(0, -1),
  );

  _gameState = _gameState.copyWith(
    bullets: [..._gameState.bullets, bullet],
  );
}

Fun fact: We trigger HapticFeedback.lightImpact() on every shot for tactile feel.

๐Ÿ‘พ Spawning Enemies โ€” Random with Types

Every few seconds, we add new enemies with unique behavior:

void _spawnEnemy() {
  final random = Random();
  final x = random.nextDouble() * (_gameSize.width - 40) + 20;
  final enemyType = EnemyType.values[random.nextInt(3)];

  final enemy = Enemy(
    position: Offset(x, -20),
    velocity: Offset((random.nextDouble() - 0.5) * 50, 0),
    type: enemyType,
    health: enemyType.health,
  );

  _gameState = _gameState.copyWith(
    enemies: [..._gameState.enemies, enemy],
  );
}

Enemy Types:

enum EnemyType {
  scout(health: 1, points: 10),
  fighter(health: 2, points: 25),
  bomber(health: 3, points: 50);
}
  • Scouts are weak and fast
  • Fighters take two hits
  • Bombers are tougher, slow-moving threats

๐Ÿง  Collision Logic โ€” Bullet vs. Enemy

We check for collisions on every game tick:

bool _isColliding(Offset a, Offset b, double radius) {
  return (a - b).distance < radius;
}

Enemy Damage Handling:

for (final bullet in bullets) {
  for (final enemy in enemies) {
    if (_isColliding(bullet.position, enemy.position, 20)) {
      enemy.health--;
      if (enemy.health <= 0) {
        enemies.remove(enemy);
        score += enemy.type.points;
      }
    }
  }
}

๐ŸŒŒ Rendering with CustomPainter

We render everything manually using Canvas. Hereโ€™s how the player is drawn:

void _drawPlayer(Canvas canvas, Offset position) {
  final paint = Paint()..color = Colors.cyan;
  final path = Path()
    ..moveTo(position.dx, position.dy - 15)
    ..lineTo(position.dx - 15, position.dy + 15)
    ..lineTo(position.dx + 15, position.dy + 15)
    ..close();

  canvas.drawPath(path, paint);
}

๐Ÿ“ˆ Level Progression

Every 30 seconds, we bump the difficulty.

void _nextLevel() {
  _gameState = _gameState.copyWith(level: _gameState.level + 1);
}

This affects enemy speed dynamically:

enemy.position.dy += (_enemySpeed + _gameState.level * 10) * deltaTime;

๐ŸŽฎ Try It Live!

๐Ÿš€ **Play the Game in Your Browser** No install required โ€” jump in and defend the galaxy right from your browser!

Clone the repo, open the project, and shoot some aliens! Customize the game loop, enemy types, or add power-ups.

๐Ÿ”— GitHub Repo

This game proves that Flutter can do real-time game mechanics, render dynamic visuals, and support rich interactions โ€” all without a game engine.

More games are coming in this retro series โ€” stay tuned!

๐Ÿ“ฌ Stay Connected

Got questions? Ideas? PRs? Please leave a comment or reach out to me on GitHub.

Would you like to continue this format for Part 3, or would you prefer me to help structure it as a YouTube tutorial script?


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
2c815aef40a2
slug
flutter-retro-game-series-part-2-building-space-invaders-with-ai-like-enemies-retro-fx-2c815aef40a2
url
https://medium.com/@piyushhh01/flutter-retro-game-series-part-2-building-space-invaders-with-ai-like-enemies-retro-fx-2c815aef40a2
canonical_url
https://medium.com/@piyushhh01/flutter-retro-game-series-part-2-building-space-invaders-with-ai-like-enemies-retro-fx-2c815aef40a2
author_url
https://medium.com/@piyushhh01
status
ok
fetched_at
2026-07-17 01:49:50