Basic physics simulations in Flutter

Ever wondered how you could merge the concepts of physics straight into your Flutter application? Well, look no further since this Answer has got you covered! After reading this, you'll be ready to dive into more advanced applications using simulations.

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's physics module

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.

Flutter's physics library
Flutter's physics library

Basic simulation walkthrough

Let's delve into the provided code to understand how it creates a simple physics simulation using Flutter's animation and physics packages.

Necessary Flutter imports

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
void main() {
runApp(PhysicsSimulation());
}
  • In this part, we import the required Flutter packages: flutter/material.dart for widgets and UI elements, and flutter/physics.dart for physics simulations.

Stateful widgets

class PhysicsSimulation extends StatefulWidget {
@override
_PhysicsSimulationState createState() => _PhysicsSimulationState();
}
  • Here, we define a StatefulWidget named PhysicsSimulation. It allows us to create a widget whose state can change over time. This could be due to interactivity or other customizations.

PhysicsSimulationState class

class _PhysicsSimulationState extends State<PhysicsSimulation>
with SingleTickerProviderStateMixin {
AnimationController _controller;
SpringSimulation _simulation;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
_controller.addListener(() {
_simulation = SpringSimulation(
SpringDescription(
mass: 1.0,
stiffness: 50.0,
damping: 1.0,
),
_controller.value,
200.0,
_controller.velocity,
);
setState(() {});
});
_simulation = SpringSimulation(
SpringDescription(
mass: 1.0,
stiffness: 50.0,
damping: 1.0,
),
0.0,
200.0,
0.0,
);
_controller.animateWith(_simulation);
}
  • In the _PhysicsSimulationState class, we extend the class SingleTickerProviderStateMixin to provide the _controller with a ticker that allows it to receive updates whenever the animation is ticking.

  • In the initState method, we initialize the _controller, which is responsible for controlling our animation. We then add a listener to _controller, so that whenever the animation value changes, the listener gets executed. Inside the listener, we update the _simulation object based on changing positions and velocity.

  • The _simulation object represents a spring simulation that basically represents the physics behavior of the animation. It uses the SpringDescription class so that we can define the properties of the spring, like mass, stiffness, and damping.

  • In this example, we set the mass to 1.0, stiffness to 50.0, and damping to 1.0. These values determine how our animation runs, including the smoothness and movement of the

  • The _controller.value represents the current position and _controller.velocity represents the current velocity of the animation. We use these values to update the _simulation object.

  • After setting up the _controller and _simulation, we call _controller.animateWith(_simulation) to start the animation with the defined spring simulation.

dispose method

@override
void dispose() {
_controller.dispose();
super.dispose();
}
  • In the dispose method, we ensure to dispose of the _controller to release extra resources, which helps avoid memory leaks.

build method

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: Text('Simple Physics Simulation'),
centerTitle: true,
backgroundColor: Colors.blueGrey[900],
),
body: Center(
child: Container(
width: 100,
height: 100,
color: Colors.blue[800],
margin: EdgeInsets.only(left: _simulation.x(_controller.value)),
),
),
),
);
}
  • In the build method, we create our UI finally. We use a MaterialApp as the root widget with a Scaffold as its home. The Scaffold provides a kind of a basic structure, including the app bar and the body content.

  • The app bar displays the title "Simple Physics Simulation."

  • In the body, we center a Container with a size of 100 x 100 and a background color of Colors.blue[800]. The container's horizontal position is set by _simulation.x(_controller.value), which calculates the position of the container based on the changing animation value.

  • As the animation runs, the container will move horizontally just like a spring. This results in a pretty cool smooth motion effect.

Complete code

A very basic and easy-to-implement physics simulation is now ready! We can test it using the executable code below.

Feel free to experiment with the code and then click "Run".

import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';

void main() {
  runApp(PhysicsSimulation());
}

class PhysicsSimulation extends StatefulWidget {
  @override
  _PhysicsSimulationState createState() => _PhysicsSimulationState();
}

class _PhysicsSimulationState extends State<PhysicsSimulation>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  SpringSimulation _simulation;

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(vsync: this);

    _controller.addListener(() {
    
      _simulation = SpringSimulation(
        SpringDescription(
          mass: 1.0,
          stiffness: 50.0,
          damping: 1.0,
        ),
        _controller.value, 
        200.0,
        _controller.velocity,
      );

      setState(() {});
    });

    _simulation = SpringSimulation(
      SpringDescription(
        mass: 1.0,
        stiffness: 50.0,
        damping: 1.0,
      ),
      0.0,
      200.0,
      0.0,
    );

    _controller.animateWith(_simulation);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    
    return MaterialApp(

      home: Scaffold(
        backgroundColor: Colors.grey[100],
        appBar: AppBar(
          title: Text('Simple Physics Simulation'),
          centerTitle: true,
          backgroundColor: Colors.blueGrey[900],
        ),

        body: Center(

          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue[800],
            margin: EdgeInsets.only(left: _simulation.x(_controller.value)),
          ),
        ),
      ),
    );
  }
}

Starting screen

This is how our screen is rendered initially.

Simulation in action

Let's see gravity take over our Flutter application now!

End notes

This is a basic example of a physics-based animation in Flutter. The animation controller and spring simulation work together to create a simple physics simulation that animates the container's position in response to the defined physics properties.

Note: Don't forget to read the advanced physics simulations in Flutter Answer!

Explore other Flutter Answers

Note: Explore the Flutter series here!

Let’s test your knowledge!

Question

What does the stiffness parameter refer to in the SpringSimulation?

Show Answer

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved