Hyper Swipe Puzzle Flutter game tutorial thumbnail showing colorful grid-based gameplay, built for Android, iOS, and Web using Flutter by AppMelodies

Build Hyper Swipe Puzzle in Flutter – Addictive 2D Game Tutorial for Android, iOS & Web (No Assets Needed)

Hyper Swipe Puzzle Flutter Game Tutorial

🎯 Build Hyper Swipe Puzzle in Flutter (Full Source Code)

Welcome to AppMelodies.com! Today, we’re building an awesome swipe puzzle game in Flutter, perfect for beginners and mobile devs alike. You’ll learn grid logic, gesture handling, splash/game over screens, and more. Let’s dive in!

🚀 Features:

  • ⚡ Swipe controls
  • 🧱 Obstacles, traps & teleporters
  • 📱 Cross-platform (Android, iOS, Web)
  • 💡 Clean, modern UI
  • 🧠 Dynamic difficulty with levels

🛠️ Steps to Build:

  1. Create new Flutter project (Android Studio or VS Code)
  2. Enable Android, iOS, Web. Select Kotlin (Android)
  3. Replace pubspec.yaml and main.dart below
  4. Run the project and enjoy!

📦 pubspec.yaml

name: hyper_swipe_puzzle
description: A modern swipe puzzle game built with Flutter.
version: 1.0.0+1

environment:
  sdk: ">=2.17.0 <4.0.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
    

🧩 main.dart (Full Game Code)

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

void main() => runApp(HyperSwipePuzzle());

class HyperSwipePuzzle extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hyper Swipe Puzzle',
      debugShowCheckedModeBanner: false,
      home: SplashScreen(),
    );
  }
}

class SplashScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Timer(Duration(seconds: 2), () {
      Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => GameScreen()));
    });
    return Scaffold(
      backgroundColor: Color(0xFF2C2F35),
      body: Center(
        child: Text(
          '🧩 Hyper Swipe Puzzle',
          style: TextStyle(
            fontSize: 34,
            fontWeight: FontWeight.bold,
            color: Colors.white,
            shadows: [
              Shadow(blurRadius: 15, color: Colors.purpleAccent, offset: Offset(0, 0))
            ],
          ),
        ),
      ),
    );
  }
}

class GameScreen extends StatefulWidget {
  @override
  State createState() => _GameScreenState();
}

class _GameScreenState extends State {
  int gridSize = 5;
  int movesLeft = 5;
  int level = 1;
  int timeLeft = 20;
  Timer? timer;

  late Point player;
  late Point goal;
  Set obstacles = {};
  Set traps = {};
  List warps = [];

  @override
  void initState() {
    super.initState();
    _startLevel();
  }

  void _startLevel() {
    gridSize = 5 + (level - 1) ~/ 5;
    player = Point(0, 0);
    do {
      goal = Point(Random().nextInt(gridSize), Random().nextInt(gridSize));
    } while (goal == player);

    Set path = {};
    int x = player.x.toInt();
    int y = player.y.toInt();
    while (x != goal.x.toInt()) {
      x += x < goal.x ? 1 : -1;
      path.add(Point(x, y));
    }
    while (y != goal.y.toInt()) {
      y += y < goal.y ? 1 : -1;
      path.add(Point(x, y));
    }

    int maxObstacles = min(level + 3, gridSize * gridSize - path.length - 2);
    obstacles = {};
    traps = {};
    warps = [];

    while (obstacles.length < maxObstacles) {
      Point obs = Point(Random().nextInt(gridSize), Random().nextInt(gridSize));
      if (obs != player && obs != goal && !path.contains(obs)) {
        obstacles.add(obs);
      }
    }

    if (level >= 3) {
      while (traps.length < 2) {
        Point trap = Point(Random().nextInt(gridSize), Random().nextInt(gridSize));
        if (!obstacles.contains(trap) && trap != player && trap != goal && !path.contains(trap)) {
          traps.add(trap);
        }
      }
    }

    if (level >= 5) {
      while (warps.length < 2) {
        Point warp = Point(Random().nextInt(gridSize), Random().nextInt(gridSize));
        if (!obstacles.contains(warp) && !traps.contains(warp) && warp != player && warp != goal) {
          warps.add(warp);
        }
      }
    }

    movesLeft = path.length + 4;
    timeLeft = 15 + level;
    timer?.cancel();
    if (level >= 10) {
      timer = Timer.periodic(Duration(seconds: 1), (_) {
        setState(() {
          timeLeft--;
          if (timeLeft <= 0) {
            _endGame();
          }
        });
      });
    }

    setState(() {});
  }

  void _endGame() {
    timer?.cancel();
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(builder: (_) => GameOverScreen(score: level - 1)),
    );
  }

  void _handleSwipe(String direction) {
    if (movesLeft == 0) return;
    Point newPos = player;
    switch (direction) {
      case 'up':    if (player.y > 0) newPos = Point(player.x, player.y - 1); break;
      case 'down':  if (player.y < gridSize - 1) newPos = Point(player.x, player.y + 1); break;
      case 'left':  if (player.x > 0) newPos = Point(player.x - 1, player.y); break;
      case 'right': if (player.x < gridSize - 1) newPos = Point(player.x + 1, player.y); break;
    }

    if (!obstacles.contains(newPos)) {
      setState(() {
        player = newPos;
        movesLeft--;

        if (traps.contains(player)) {
          player = Point(0, 0);
        } else if (warps.length == 2 && player == warps[0]) {
          player = warps[1];
        } else if (warps.length == 2 && player == warps[1]) {
          player = warps[0];
        }
      });

      if (player == goal) {
        timer?.cancel();
        Future.delayed(Duration(milliseconds: 300), () {
          level++;
          _startLevel();
        });
      } else if (movesLeft == 0) {
        Future.delayed(Duration(milliseconds: 500), () {
          _endGame();
        });
      }
    }
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  Widget _buildTile(int x, int y) {
    Point pos = Point(x, y);
    Color baseColor = Color(0xFF3A3F45);
    if (player == pos) baseColor = Color(0xFF00FFFF); // Cyan
    else if (goal == pos) baseColor = Color(0xFF66FFCC); // Light green
    else if (obstacles.contains(pos)) baseColor = Colors.redAccent;
    else if (traps.contains(pos)) baseColor = Colors.pinkAccent;
    else if (warps.contains(pos)) baseColor = Colors.indigoAccent;

    return AnimatedContainer(
      duration: Duration(milliseconds: 150),
      margin: EdgeInsets.all(4),
      decoration: BoxDecoration(
        color: baseColor,
        borderRadius: BorderRadius.circular(8),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onVerticalDragEnd: (details) {
        if (details.velocity.pixelsPerSecond.dy < -200) _handleSwipe('up');
        if (details.velocity.pixelsPerSecond.dy > 200) _handleSwipe('down');
      },
      onHorizontalDragEnd: (details) {
        if (details.velocity.pixelsPerSecond.dx < -200) _handleSwipe('left');
        if (details.velocity.pixelsPerSecond.dx > 200) _handleSwipe('right');
      },
      child: Scaffold(
        backgroundColor: Color(0xFF2C2F35),
        body: SafeArea(
          child: Column(
            children: [
              SizedBox(height: 16),
              Text("Level: $level",
                  style: TextStyle(color: Colors.white, fontSize: 22)),
              Text("Moves Left: $movesLeft",
                  style: TextStyle(color: Colors.amberAccent, fontSize: 16)),
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: GridView.builder(
                    physics: NeverScrollableScrollPhysics(),
                    itemCount: gridSize * gridSize,
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                      crossAxisCount: gridSize,
                    ),
                    itemBuilder: (_, index) {
                      int x = index % gridSize;
                      int y = index ~/ gridSize;
                      return _buildTile(x, y);
                    },
                  ),
                ),
              ),
              Padding(
                padding: const EdgeInsets.only(bottom: 30),
                child: Text("Swipe to move tile!",
                    style: TextStyle(color: Colors.white54)),
              )
            ],
          ),
        ),
      ),
    );
  }
}

class GameOverScreen extends StatelessWidget {
  final int score;
  GameOverScreen({required this.score});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xFF2C2F35),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('❌ Game Over',
                style: TextStyle(fontSize: 32, color: Colors.white)),
            SizedBox(height: 20),
            Text('Levels Completed: $score',
                style: TextStyle(fontSize: 24, color: Colors.cyanAccent)),
            SizedBox(height: 30),
            ElevatedButton(
              onPressed: () {
                Navigator.pushReplacement(
                  context,
                  MaterialPageRoute(builder: (_) => GameScreen()),
                );
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.tealAccent,
                padding: EdgeInsets.symmetric(horizontal: 40, vertical: 15),
              ),
              child: Text("Try Again",
                  style: TextStyle(fontSize: 18, color: Colors.black)),
            )
          ],
        ),
      ),
    );
  }
}
    

📱 How to Play:

  • Swipe to move the cyan tile
  • Reach the green tile to win
  • Avoid red blocks and traps
  • Use warps to teleport (from Level 5)
  • Beat the clock (from Level 10)

📸 Add Screenshots:

Add game screenshots using Elementor’s image widget for splash, game, and game over screens.

🔗 Stay Connected:

🌐 Website: appmelodies.com
📺 YouTube: @AppMelodies
📸 Instagram: @appmelodies

💬 Got an Idea?

Send us your next game/app idea—we might feature it in our next tutorial!

Leave a Reply