Set Up Basic Flutter Project
Set the app orientation and initialize the app.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
runApp(const BalloonBlaster());
}
class BalloonBlaster extends StatelessWidget {
const BalloonBlaster({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Balloon Blaster',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const GameScreen(),
);
}
}
Define Balloon and Arrow Classes
Create basic classes to define Balloon and Arrow objects.
These classes store attributes for each balloon and arrow in the game.
import 'dart:math';
class Balloon {
double x, y;
final Color color;
final double speed;
final int points;
bool isPopped;
Balloon({
required this.x,
required this.y,
required this.color,
required this.speed,
this.points = 100,
this.isPopped = false,
});
}
class Arrow {
double x, y;
Offset velocity;
final double angle;
Arrow({
required this.x,
required this.y,
required this.velocity,
required this.angle,
});
}
Set Up Game Screen Widget
Create GameScreen widget to manage the game interface and state.
This widget will control game elements like score, levels, and balloons.
class GameScreen extends StatefulWidget {
const GameScreen({super.key});
@override
GameScreenState createState() => GameScreenState();
}
class GameScreenState extends State<GameScreen> with TickerProviderStateMixin {
// Game variables
double _bowX = 0, _bowY = 0;
double _arrowAngle = 0, _power = 0;
bool _isDragging = false;
int _score = 0;
List<Balloon> _balloons = [];
List<Arrow> _arrows = [];
int _level = 1, _remainingArrows = 10;
bool _isGameActive = false;
}
Initialize Game and Balloons
Set up the game initializer and balloon spawner.
Initialize game variables and create balloons based on the level.
void _startGame() {
setState(() {
_balloons.clear();
_arrows.clear();
_remainingArrows = 10;
_score = 0;
_level = 1;
_spawnBalloons();
_isGameActive = true;
});
}
void _spawnBalloons() {
final random = Random();
for (int i = 0; i < 5 + _level; i++) {
_balloons.add(Balloon(
x: random.nextDouble() * MediaQuery.of(context).size.width,
y: MediaQuery.of(context).size.height + random.nextDouble() * 200,
color: Colors.primaries[random.nextInt(Colors.primaries.length)],
speed: 2.0 + (_level * 0.5) + random.nextDouble(),
points: 100 + (_level * 10),
));
}
}
Create Game Loop for Continuous Updates
Implement a game loop to update positions and check collisions.
This loop keeps the game active by updating balloon and arrow positions.
void _startGameLoop() {
Timer.periodic(const Duration(milliseconds: 16), (timer) {
_updateGame();
});
}
void _updateGame() {
setState(() {
for (var balloon in _balloons) {
if (!balloon.isPopped) balloon.y -= balloon.speed;
}
for (var arrow in _arrows) {
arrow.x += arrow.velocity.dx;
arrow.y += arrow.velocity.dy;
arrow.velocity = Offset(arrow.velocity.dx, arrow.velocity.dy + 0.2);
}
_checkCollisions();
});
}
Add Collision Detection
Detect collisions between arrows and balloons.
Update score when a collision is detected.
void _checkCollisions() {
for (var arrow in _arrows) {
for (var balloon in _balloons) {
if (!balloon.isPopped && _checkCollision(arrow, balloon)) {
balloon.isPopped = true;
_score += balloon.points;
Future.delayed(const Duration(milliseconds: 100), () {
setState(() => _balloons.remove(balloon));
});
break;
}
}
}
}
bool _checkCollision(Arrow arrow, Balloon balloon) {
final dx = arrow.x - balloon.x;
final dy = arrow.y - balloon.y;
return sqrt(dx * dx + dy * dy) < 30;
}
Shooting Mechanism for Arrows
Implement functionality for shooting arrows.
Trigger an arrow with a calculated angle and power based on user drag.
void _shootArrow() {
if (_remainingArrows <= 0) return;
final velocity = Offset(cos(_arrowAngle) * _power * 20, sin(_arrowAngle) * _power * 20);
_arrows.add(Arrow(x: _bowX, y: _bowY, velocity: velocity, angle: _arrowAngle));
_remainingArrows--;
}
Game Over and Game Painter for Graphics
Add game-over dialog and custom painter for game graphics.
Display the final score and restart option on game over.
void _showGameOver() {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Game Over'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [Text('Score: $_score'), Text('Level: $_level')],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Play Again'),
),
],
),
);
}