🎯 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:
- Create new Flutter project (Android Studio or VS Code)
- Enable Android, iOS, Web. Select Kotlin (Android)
- Replace
pubspec.yaml
andmain.dart
below - 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 StatecreateState() => _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!