Set Up a New Flutter Project
Create a new Flutter project in your IDE or by running flutter create bubble_blast.
Replace the contents of main.dart with the code in this guide, step by step.
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
Set Up the Main App Widget
Create the main app entry point. This widget initializes the app with a title and theme.
Use MaterialApp to set the app theme and home page.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bubble Blast',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const BubbleBlastGame(),
);
}
}
Define the Bubble Class
Create a Bubble class to represent each bubble.
The class includes properties for x and y coordinates, size, color, and velocity.
class Bubble {
double x;
double y;
double size;
bool isPopped;
Color color;
double velocity;
Bubble({
required this.x,
required this.y,
this.size = 60,
this.isPopped = false,
required this.color,
this.velocity = 1,
});
}
Set Up the Game State in BubbleBlastGame
Create a StatefulWidget to manage game state.
Initialize variables like bubbles, score, and timers for bubble generation and game timing.
class BubbleBlastGame extends StatefulWidget {
const BubbleBlastGame({Key? key}) : super(key: key);
@override
_BubbleBlastGameState createState() => _BubbleBlastGameState();
}
Implement the Game Logic (Start, End, Generate Bubbles)
Start and end the game using functions that reset the score, time, and bubble list.
Create a timer to generate bubbles and decrease the remaining time.
void startGame() {
setState(() {
bubbles.clear();
score = 0;
timeLeft = 60;
isGameRunning = true;
});
bubbleGenerator = Timer.periodic(const Duration(milliseconds: 800), (timer) {
if (isGameRunning) generateBubble();
});
gameTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
setState(() {
if (timeLeft > 0) timeLeft--;
else endGame();
});
});
}
Display Bubbles on the Screen
Generate random bubbles with varying colors and velocities.
Add each bubble to the screen in a stack, with gestures to pop them.
void generateBubble() {
if (!isGameRunning) return;
setState(() {
double screenWidth = MediaQuery.of(context).size.width;
Bubble bubble = Bubble(
x: random.nextDouble() * (screenWidth - 60),
y: MediaQuery.of(context).size.height,
color: bubbleColors[random.nextInt(bubbleColors.length)],
velocity: 2 + random.nextDouble() * 2,
);
bubbles.add(bubble);
});
}
Update Bubble Positions and Handle Bubble Popping
Move bubbles upwards by updating their y position based on velocity.
Remove bubbles that move off-screen and update the score when they are popped.
void updateBubbles() {
if (!isGameRunning) return;
setState(() {
for (var bubble in bubbles) {
if (!bubble.isPopped) bubble.y -= bubble.velocity;
}
bubbles.removeWhere((bubble) => bubble.y < -bubble.size);
});
}
void popBubble(int index) {
if (!bubbles[index].isPopped) {
setState(() {
bubbles[index].isPopped = true;
score += 10;
});
Future.delayed(const Duration(milliseconds: 200), () {
setState(() {
bubbles.removeAt(index);
});
});
}
}
Build the Game UI
Create a UI layout with a background gradient, bubbles, score display, and a button to start the game.
Add interactivity by allowing users to tap on bubbles to pop them.
@override
Widget build(BuildContext context) {
if (isGameRunning) {
WidgetsBinding.instance.addPostFrameCallback((_) => updateBubbles());
}
return Scaffold(
body: Stack(
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.lightBlue[200]!,
Colors.blue[400]!,
],
),
),
),
...bubbles.asMap().entries.map((entry) {
int index = entry.key;
Bubble bubble = entry.value;
return Positioned(
left: bubble.x,
top: bubble.y,
child: GestureDetector(
onTapDown: (_) => popBubble(index),
child: AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: bubble.isPopped ? 0.0 : 1.0,
child: Container(
width: bubble.size,
height: bubble.size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: bubble.color,
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.3),
blurRadius: 5,
spreadRadius: 2,
),
],
),
),
),
),
);
}).toList(),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
scoreDisplay,
if (isGameRunning) timeDisplay,
],
),
),
),
if (!isGameRunning) startButton,
],
),
);
}