gravity_simulation.dart 3.67 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
import 'package:flutter/foundation.dart';

7
import 'simulation.dart';
8

9
// Examples can assume:
10
// late AnimationController _controller;
11

Ian Hickson's avatar
Ian Hickson committed
12 13 14
/// A simulation that applies a constant accelerating force.
///
/// Models a particle that follows Newton's second law of motion. The simulation
15
/// ends when the position exceeds a defined threshold.
16
///
17
/// {@tool snippet}
18 19 20 21 22 23
///
/// This method triggers an [AnimationController] (a previously constructed
/// `_controller` field) to simulate a fall of 300 pixels.
///
/// ```dart
/// void _startFall() {
24
///   _controller.animateWith(GravitySimulation(
25 26 27 28 29 30 31
///     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
///   ));
/// }
/// ```
32
/// {@end-tool}
33 34 35 36
///
/// This [AnimationController] could be used with an [AnimatedBuilder] to
/// animate the position of a child as if it was falling.
///
37 38 39 40 41 42 43 44 45 46 47 48
/// 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.
///
49 50 51 52
/// See also:
///
///  * [Curves.bounceOut], a [Curve] that has a similar aesthetics but includes
///    a bouncing effect.
53
class GravitySimulation extends Simulation {
Ian Hickson's avatar
Ian Hickson committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  /// 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,
72
    double velocity,
73
  ) : assert(endDistance >= 0),
74
      _a = acceleration,
Ian Hickson's avatar
Ian Hickson committed
75 76
      _x = distance,
      _v = velocity,
77
      _end = endDistance;
Ian Hickson's avatar
Ian Hickson committed
78

79 80 81 82 83
  final double _x;
  final double _v;
  final double _a;
  final double _end;

84
  @override
85 86
  double x(double time) => _x + _v * time + 0.5 * _a * time * time;

87
  @override
88 89 90 91
  double dx(double time) => _v + time * _a;

  @override
  bool isDone(double time) => x(time).abs() >= _end;
92 93 94

  @override
  String toString() => '${objectRuntimeType(this, 'GravitySimulation')}(g: ${_a.toStringAsFixed(1)}, x₀: ${_x.toStringAsFixed(1)}, dx₀: ${_v.toStringAsFixed(1)}, xₘₐₓ: ±${_end.toStringAsFixed(1)})';
95
}