Master Flutter’s explicit animations while building a fun 2048 game
Introduction:
2048 is a popular puzzle game where the goal is to slide tiles on a grid to merge them and create a tile with the number 2048. It is a simple yet addictive game that can be played on a computer or mobile device. In this tutorial, we will learn how to create a 2048 game in Flutter by using explicit animations.
Creating the project:
To get started, create a new Flutter project by opening a terminal and running the following command:
flutter create 2048_game
This will create a new Flutter project with the default template.
Building the UI:
The first thing we need to do is to build the user interface (UI) for our game. We will start by creating a simple grid of tiles that the user can slide around.
To do this, we will use a GridView
widget, which is a scrollable grid of widgets. We will set the crossAxisCount
property to 4, which will create a grid with 4 columns. We will also set the children
property to a list of Container
widgets, which will be used to display the tiles.
Here is the code for the GridView
widget:
GridView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 1.0,
),
children: List.generate(16, (index) {
return Container(
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(5.0),
),
);
}),
)
Next, we will add a label to each tile that displays the number. We will do this by using a Text
widget inside the Container
widget. We will also set the color
property of the Text
widget to white, so that it is visible against the blue background of the tile.
Here is the updated code for the Container
widget:
Container(
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(5.0),
),
child: Center(
child: Text(
'2',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
)
Now, if you run the app, you should see a grid of blue tiles with the number 2 displayed in the center of each one.
Adding animations:
Now that we have the basic UI for our game, we can start adding some animations to make it more interactive. We will use explicit animations, which allow us to specify the start and end values for an animation and control the progress of the animation manually.
To create an explicit animation, we will use the AnimationController
and Animation
classes provided by Flutter. The AnimationController
is responsible for controlling the progress of the animation, and the Animation
is used to define the start and end values for the animation.
Here is some example code for creating an explicit animation:
o create an explicit animation, we will first need to create an AnimationController
object. We can do this by calling the AnimationController
constructor and passing in a value for the vsync
parameter. The vsync
parameter ensures that the animation is only updated when the app is in the foreground, which helps to improve performance.
Here is an example of how to create an AnimationController
object:
AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
}
Next, we will create an Animation
object by calling the Animation
constructor and passing in the AnimationController
as an argument. We will also need to specify the start and end values for the animation.
Here is an example of how to create an Animation
object:
Animation<double> _animation;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
}
Now that we have an AnimationController
and an Animation
, we can use them to control the progress of an animation. To start the animation, we can call the forward()
method on the AnimationController
. To stop the animation, we can call the stop()
method.
Here is an example of how to start and stop an animation:
_animationController.forward(); // start the animation
_animationController.stop(); // stop the animation
We can also use the Animation
object to get the current value of the animation. To do this, we can call the value
property of the Animation
. This property returns a value between the start and end values of the animation, depending on the progress of the animation.
Here is an example of how to get the current value of an animation:
double animationValue = _animation.value;
Finally, we can use the AnimatedBuilder
widget to build a widget tree that depends on the value of the animation. The AnimatedBuilder
widget takes an Animation
object and a builder function as arguments. The builder function is called every time the value of the animation changes, and it is used to build the widget tree that is displayed on the screen.
Here is an example of how to use the AnimatedBuilder
widget:
AnimatedBuilder(
animation: _animation,
builder: (BuildContext context, Widget child) {
return Transform.translate(
offset: Offset(0.0, _animation.value * 100.0), // move the widget up or down based on the value of the animation
child: child,
);
},
child: Container(
width: 100.0,
height: 100.0,
color: Colors.red,
),
)
This example uses the Transform.translate
widget to move the child widget up or down based on the value
In our game, we want to be able to slide the tiles up, down, left, or right when the user swipes in that direction. To do this, we can use the GestureDetector
widget to detect the swipe gesture, and then use an explicit animation to move the tiles smoothly to their new positions.
First, let’s create a Tile
widget that represents a single tile on the grid. We will define this widget as a stateful widget, since we need to be able to update the position of the tile as the animation progresses.
Here is the code for the Tile
widget:
class Tile extends StatefulWidget {
final int value;
final double animationValue;
Tile({
this.value,
this.animationValue,
}); @override
_TileState createState() => _TileState();
}class _TileState extends State<Tile> {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(5.0),
),
child: Center(
child: Text(
widget.value.toString(),
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
);
}
}
Next, let’s create an AnimatedTile
widget that wraps the Tile
widget and applies an animation to it. We will use the AnimatedBuilder
widget to build the Tile
widget based on the value of the animation.
Here is the code for the AnimatedTile
widget:
class AnimatedTile extends StatefulWidget {
final int value;
final AnimationController animationController;
final Animation<double> animation;
AnimatedTile({
this.value,
this.animationController,
this.animation,
}); @override
_AnimatedTileState createState() => _AnimatedTileState();
}class _AnimatedTileState extends State<AnimatedTile> {
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: widget.animation,
builder: (BuildContext context, Widget child) {
return Transform.translate(
offset: Offset(0.0, widget.animation.value * 100.0), // move the widget up or down based on the value of the animation
child: child,
);
},
child: Tile(
value: widget.value,
),
);
}
}
Finally, let’s create a GameScreen
widget that displays the grid of tiles and handles the swipe gestures. We will use a GestureDetector
widget to detect the swipe gestures, and then use an explicit animation to move the tiles smoothly to their new positions.
let’s define the rest of the GameScreen
widget.
The GameScreen
widget will contain an AnimationController
and an Animation
object, which we will use to control the progress of the animation. It will also contain a list of AnimatedTile
widgets, which represent the tiles on the grid.
We will define the GameScreen
widget as a stateful widget, since we need to be able to update the position of the tiles as the animation progresses.
Here is the complete code for the GameScreen
widget:
class GameScreen extends StatefulWidget {
@override
_GameScreenState createState() => _GameScreenState();
}
class _GameScreenState extends State<GameScreen> {
AnimationController _animationController;
Animation<double> _animation;
List<AnimatedTile> _tiles; @override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
_tiles = List.generate(16, (index) {
return AnimatedTile(
value: 2,
animationController: _animationController,
animation: _animation,
);
});
} @override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onVerticalDragEnd: (details) {
if (details.primaryVelocity < 0) {
// swipe up
_animationController.forward();
} else if (details.primaryVelocity > 0) {
// swipe down
_animationController.reverse();
}
},
child: GridView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
childAspectRatio: 1.0,
),
children: _tiles,
),
),
);
}
}
In this example, we use the GestureDetector
widget to detect vertical swipe gestures. When the user swipes up, we start the animation by calling the forward()
method on the AnimationController
. When the user swipes down, we reverse the animation by calling the reverse()
method.
We also use the AnimatedTile
widget to display the tiles on the grid, and we pass the AnimationController
and Animation
objects to each AnimatedTile
widget. This allows each tile to update its position based on the value of the animation.
Now, if you run the app and swipe up or down on the grid of tiles, you should see the tiles slide smoothly to their new positions.
If You wants a full tutorial on this ! Let me know in the comments section, I will happy 😊 to make a full tutorial video on it
Conclusion
we have learned how to create a 2048 game in Flutter by using explicit animations. We started by building the basic user interface (UI) for the game, which consisted of a grid of tiles that the user could slide around. We then used explicit animations, which are controlled using the AnimationController
and Animation
classes, to create a sliding animation for the tiles. We used the GestureDetector
widget to detect swipe gestures, and the AnimatedBuilder
widget to build the tiles based on the value of the animation.
Explicit animations are a powerful tool for creating interactive and engaging user interfaces in Flutter. They allow you to specify the start and end values for an animation and control the progress of the animation manually, which gives you a high degree of control over the animation. By using explicit animations, you can create smooth and seamless transitions between different states in your app, which can greatly enhance the user experience.
That’s it, hope this article was helpful for you!
If you find this article was helpful for you, Please subscribe us for such an amazing articles in future
If You wants a full tutorial on this ! Let me know in the comments section, I will happy to make a full tutorial video on it 😊