Today we'll be learning how Flutter provides its users with a thrilling experience in being able to apply concepts of physics to their animations. Before we dive right in, let's have a brief recap of what Flutter offers.
Flutter is a UI development toolkit primarily used for building applications for various platforms using a single codebase. It is completely open-source and is a product of Google.
Simply put, this means that developers can write the code once and use it on different platforms without having to start from scratch for each one.
Note: We offer various courses if you aim to continue your journey in learning Flutter!
Flutter needs a programming language to build and run applications. Dart is used as the primary language for developing applications with the Flutter framework. We will be using Dart in our code as well.
Note: Before proceeding with the answer, ensure that your Flutter setup is complete.
A physics simulation is a computer-based model that replicates the behavior of physical systems in a virtual environment. It basically tries to copy how real-world things move and interact with each other based on the rules of physics. Therefore, this helps us see how objects would behave in different situations without having to do actual physical experiments.
Flutter offers a physics library that contains different simulations that work differently based on physics concepts. For instance, gravity simulation works by implementing a gravity environment to aid falls, while a spring simulation focuses on the stiffness of the spring or the mass of the object.
If you aim to get ahold of the basics first, feel free to check out our answer on basic physics simulations in Flutter.
In this Flutter code, we will create an exciting physics animation with bouncing balls. Our animation demonstrates the behavior of five balls, each with its own set of physics properties, bouncing in response to the physics simulation.
initState methodIn the initState method, we initialize the animation controllers and the corresponding stiffness, damping, and color for each ball. We use the addListener method of the animation controllers to build our UI again whenever the animation value changes. We then use controller.animateWith to trigger the physics-based animation for each ball. The animation will cause the balls to move based on our defined properties, resulting in a bouncing motion.
@overridevoid initState() {super.initState();ball1Data = BallData(stiffness: 100, damping: 1, color: Colors.blue);ball2Data = BallData(stiffness: 200, damping: 1.2, color: Colors.red);ball3Data = BallData(stiffness: 300, damping: 1.4, color: Colors.green);ball4Data = BallData(stiffness: 400, damping: 1.6, color: Colors.yellow);ball5Data = BallData(stiffness: 500, damping: 1.8, color: Colors.orange);for (var ballData in [ball1Data, ball2Data, ball3Data, ball4Data, ball5Data]) {ballData.controller = AnimationController(vsync: this, upperBound: 500)..addListener(() {setState(() {});});ballData.controller.animateWith(ballData.simulation);}}
The user interface consists of a Column widget that includes an app bar and the main body. We divide our body into two sections. The first one contains a Text widget titled "Bouncing Balls," displayed in a white and bolded font using properties like fontWeight, color, and fontSize. The second section is a Container with a dark background color, simulating the floor where the balls bounce. Inside this container, we have a Stack widget to help position the balls.
@overrideWidget build(BuildContext context) {return MaterialApp(home: Scaffold(backgroundColor: Colors.black,appBar: AppBar(title: Text('Cool Physics Animation',style: TextStyle(fontSize: 24),),centerTitle: true,backgroundColor: Colors.blueGrey[900],elevation: 0,),body: Column(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [Padding(padding: const EdgeInsets.symmetric(vertical: 20.0),child: Text('Bouncing Balls',style: TextStyle(fontSize: 32,color: Colors.white,fontWeight: FontWeight.bold,),),),Container(width: double.infinity,height: 300,color: Colors.blueGrey[900],child: Stack(children: [Positioned(left: 50,top: ball1Data.controller.value,child: BallWidget(color: ball1Data.color),),Positioned(left: 120,top: ball2Data.controller.value * 1.5,child: BallWidget(color: ball2Data.color),),Positioned(left: 190,top: ball3Data.controller.value * 0.8,child: BallWidget(color: ball3Data.color),),Positioned(left: 260,top: ball4Data.controller.value * 1.2,child: BallWidget(color: ball4Data.color),),Positioned(left: 330,top: ball5Data.controller.value * 0.5,child: BallWidget(color: ball5Data.color),),],),),],),),);}
BallWidget custom widgetWe create a custom widget called BallWidget to represent the balls. The widget takes the color argument determining the ball's appearance. It's displayed as a circular container with our given color.
class BallWidget extends StatelessWidget {final Color color;BallWidget({this.color});@overrideWidget build(BuildContext context) {return Container(width: 50,height: 50,decoration: BoxDecoration(shape: BoxShape.circle,color: color,),);}}
Note: Stateless widgets remain the same throughout while stateful widgets are subject to change due to interactivity.
AnimationControllerThe animation controllers and spring simulations work together to create the physics-based bouncing animation for each ball. The AnimationController updates the animation values, and the setState method rebuilds UI to show the moving balls.
Basically, the physics simulation is based on the spring equation, which in turn moves the balls.
0.0 is the starting
300.0 is the ending
10 is the velocity
class BallData {AnimationController controller;final SpringSimulation simulation;final double stiffness;final double damping;final Color color;BallData({this.stiffness, this.damping, this.color}): simulation = SpringSimulation(SpringDescription(mass: 1,stiffness: stiffness,damping: damping,),0.0,300.0,10,);}
Note: You can change the settings of the physics simulation to see how the effect on the shapes changes.
Hurray! Our explanation is now complete, and we're ready to put together our code. The given code is completely executable, and you can experiment with it to see how these simulations work.
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
const port = 8080;
// Enable CORS for all routes
app.use(cors());
// Serve the Flutter web application
app.use(express.static(path.join(__dirname, 'build/web')));
// Start the server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
This is how our application starts initially.
Our animation is ready! Let's see how the balls move due to the spring simulation.
Similar to the previous concept, we can make use of the GravitySimulation module to create a Flutter application with the force of gravity. The values can be changed according to our needs.
Here's how it works.
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
const port = 8080;
// Enable CORS for all routes
app.use(cors());
// Serve the Flutter web application
app.use(express.static(path.join(__dirname, 'build/web')));
// Start the server
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
We implement a gravity simulation to create a falling animation for multiple squares. The GravitySimulation class is used to model this.
We initialize three AnimationController instances to drive the animations and three GravitySimulation instances with different acceleration values for our squares.
The square positions are updated using the controller.value and the GravitySimulation.x(controller.value) methods within a Positioned widget. This causes the squares to fall with gravity-based animations on the screen.
This is how our application starts initially.
Our animation is ready! Let's see how different gravity values work on each square.
Physics simulations in computer science can have amazing advantages, including but not limited to the list mentioned below.
Use cases |
Realistic object movement in games and simulations |
Natural-looking cloth and hair animations in animations and movies |
Accurate physics-based collisions for game development |
Dynamic fluid and particle effects in visual effects and simulations |
Understanding complex physical phenomena in scientific research |
Precise engineering simulations for structural analysis |
Note: Explore the Flutter series here!
How does the SpringSimulation differ from the GravitySimulation?
Free Resources