// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/foundation.dart'; import 'simulation.dart'; // Examples can assume: // late AnimationController _controller; /// A simulation that applies a constant accelerating force. /// /// Models a particle that follows Newton's second law of motion. The simulation /// ends when the position exceeds a defined threshold. /// /// {@tool snippet} /// /// This method triggers an [AnimationController] (a previously constructed /// `_controller` field) to simulate a fall of 300 pixels. /// /// ```dart /// void _startFall() { /// _controller.animateWith(GravitySimulation( /// 10.0, // acceleration, pixels per second per second /// 0.0, // starting position, pixels /// 300.0, // ending position, pixels /// 0.0, // starting velocity, pixels per second /// )); /// } /// ``` /// {@end-tool} /// /// This [AnimationController] could be used with an [AnimatedBuilder] to /// animate the position of a child as if it was falling. /// /// The end distance threshold (the constructor's third argument) must be /// specified as a positive number but can be reached in either the positive or /// negative direction. For example (assuming negative numbers represent higher /// physical positions than positive numbers, as is the case with the normal /// [Canvas] coordinate system), if the acceleration is positive ("down") the /// starting velocity is negative ("up"), and the starting distance is zero, the /// particle will climb from the origin, reach a plateau, then fall back towards /// and past the origin. If the end distance threshold is less than the height /// of the plateau, then the simulation will end during the climb; otherwise, it /// will end during the fall, after the particle travels below the origin by /// that distance. /// /// See also: /// /// * [Curves.bounceOut], a [Curve] that has a similar aesthetics but includes /// a bouncing effect. class GravitySimulation extends Simulation { /// Creates a [GravitySimulation] using the given arguments, which are, /// respectively: an acceleration that is to be applied continually over time; /// an initial position relative to an origin; the magnitude of the distance /// from that origin beyond which (in either direction) to consider the /// simulation to be "done", which must be positive; and an initial velocity. /// /// The initial position and maximum distance are measured in arbitrary length /// units L from an arbitrary origin. The units will match those used for [x]. /// /// The time unit T used for the arguments to [x], [dx], and [isDone], /// combined with the aforementioned length unit, together determine the units /// that must be used for the velocity and acceleration arguments: L/T and /// L/T² respectively. The same units of velocity are used for the velocity /// obtained from [dx]. GravitySimulation( double acceleration, double distance, double endDistance, double velocity, ) : assert(acceleration != null), assert(distance != null), assert(velocity != null), assert(endDistance != null), assert(endDistance >= 0), _a = acceleration, _x = distance, _v = velocity, _end = endDistance; final double _x; final double _v; final double _a; final double _end; @override double x(double time) => _x + _v * time + 0.5 * _a * time * time; @override double dx(double time) => _v + time * _a; @override bool isDone(double time) => x(time).abs() >= _end; @override String toString() => '${objectRuntimeType(this, 'GravitySimulation')}(g: ${_a.toStringAsFixed(1)}, x₀: ${_x.toStringAsFixed(1)}, dx₀: ${_v.toStringAsFixed(1)}, xₘₐₓ: ±${_end.toStringAsFixed(1)})'; }