Learn how to create an exciting game in Flutter where players catch falling apples. This step-by-step guide covers game mechanics, character movement, collision detection, and more.
Welcome to an exciting mini-project where you’ll learn to build a simple yet engaging game using Flutter! In this project, you’ll create a game where a character moves left and right to catch apples falling from the top of the screen. This project will help you understand key game mechanics such as character movement, collision detection, and score tracking. Let’s dive in!
In “Catch the Apples,” the player controls a character that moves horizontally across the bottom of the screen. Apples fall from random positions at the top, and the player’s goal is to catch as many apples as possible. Each apple caught increases the score, while missing an apple decreases the player’s lives. The game ends when the player runs out of lives.
First, let’s set up the basic structure of our game using Flutter.
Create a Flutter Project: Start by creating a new Flutter project. You can name it catch_the_apples
.
Set Up the Main Game Screen: Use a Stack
widget to layer the character and apples. The Stack
allows us to position widgets on top of each other, which is perfect for our game layout.
import 'package:flutter/material.dart';
void main() {
runApp(CatchTheApplesGame());
}
class CatchTheApplesGame extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Catch the Apples'),
),
body: GameScreen(),
),
);
}
}
class GameScreen extends StatefulWidget {
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
@override
Widget build(BuildContext context) {
return Stack(
children: [
// Add game elements here
],
);
}
}
Next, we’ll add the character sprite and implement movement controls.
Insert the Character Sprite: You can use an image of a basket or any character you like. Place it at the bottom of the screen.
Implement Movement Controls: Use touch input or arrow keys to move the character left and right.
class _GameScreenState extends State<GameScreen> {
double characterPosition = 0.0;
void moveCharacter(double direction) {
setState(() {
characterPosition += direction;
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
bottom: 10,
left: characterPosition,
child: GestureDetector(
onHorizontalDragUpdate: (details) {
moveCharacter(details.delta.dx);
},
child: Image.asset('assets/character.png', width: 50),
),
),
],
);
}
}
Now, let’s code the apples to spawn at random positions at the top and move downward.
Spawn Apples Randomly: Use a timer to create apples at random intervals and positions.
Animate Falling Motion: Use an animation controller to handle the falling motion.
import 'dart:async';
import 'dart:math';
class _GameScreenState extends State<GameScreen> {
List<Widget> apples = [];
Random random = Random();
void startAppleFall() {
Timer.periodic(Duration(seconds: 1), (timer) {
setState(() {
double startPosition = random.nextDouble() * MediaQuery.of(context).size.width;
apples.add(Positioned(
top: 0,
left: startPosition,
child: FallingApple(),
));
});
});
}
@override
void initState() {
super.initState();
startAppleFall();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
...apples,
Positioned(
bottom: 10,
left: characterPosition,
child: GestureDetector(
onHorizontalDragUpdate: (details) {
moveCharacter(details.delta.dx);
},
child: Image.asset('assets/character.png', width: 50),
),
),
],
);
}
}
class FallingApple extends StatefulWidget {
@override
_FallingAppleState createState() => _FallingAppleState();
}
class _FallingAppleState extends State<FallingApple> with SingleTickerProviderStateMixin {
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 5),
vsync: this,
)..forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Positioned(
top: _controller.value * MediaQuery.of(context).size.height,
child: child,
);
},
child: Image.asset('assets/apple.png', width: 30),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
To make the game interactive, we need to detect when the character catches an apple.
Detect Collisions: Check if the apple’s position overlaps with the character’s position.
Increase Score and Remove Apples: When an apple is caught, increase the score and remove the apple from the screen.
void checkCollision() {
setState(() {
apples.removeWhere((apple) {
// Check if apple is caught
// Increase score and remove apple if caught
});
});
}
Let’s display the current score at the top of the screen.
Text
widget to show the score.int score = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned(
top: 20,
left: 20,
child: Text('Score: $score', style: TextStyle(fontSize: 24)),
),
...apples,
Positioned(
bottom: 10,
left: characterPosition,
child: GestureDetector(
onHorizontalDragUpdate: (details) {
moveCharacter(details.delta.dx);
},
child: Image.asset('assets/character.png', width: 50),
),
),
],
);
}
To add more challenge, let’s implement a lives system.
Decrease Lives: Reduce lives when an apple is missed.
End Game: Stop the game when lives reach zero.
int lives = 3;
void checkCollision() {
setState(() {
apples.removeWhere((apple) {
// Check if apple is caught
// Increase score and remove apple if caught
// Decrease lives if missed
});
if (lives <= 0) {
// End game
}
});
}
Finally, let’s add some finishing touches to make the game more enjoyable.
Background Music and Sound Effects: Add sounds for catching apples and background music.
Start and Game Over Screens: Create screens to start the game and show when the game is over.
void showGameOverScreen() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Game Over'),
content: Text('Your score: $score'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
// Restart game
},
child: Text('Play Again'),
),
],
);
},
);
}
Here’s the complete code for the “Catch the Apples” game. Make sure to replace assets/character.png
and assets/apple.png
with your own images.
// Complete code goes here
Now that you’ve built the basic game, try customizing it! Here are some ideas:
Below is a diagram of the game layout, showing the character, falling apples, and score display.
graph TD; A[Game Screen] --> B[Character] A --> C[Apples] A --> D[Score Display] C -->|Fall| B B -->|Catch| D
Congratulations! You’ve just built a fun and interactive game using Flutter. This project has taught you about game mechanics, character movement, collision detection, and more. Keep experimenting and adding your own features to make the game even more exciting!