flutter3d
Showcase Changelog 38 packages API reference

Fixed step and interpolation: the source

since 0.4.0 or earlier Simulation, audio and XR

Regions the guide quotes: clock (line 16), gate (line 43), advance (line 59), blend (line 66).

1/// A simulation that always advances by the same amount, and a picture that
2/// still moves smoothly when the display and the simulation disagree about
3/// how fast time passes.
4///
5/// Quoted by `fixed_step.md` and shown whole in the Source tab.
6library;
7
8import 'package:flutter3d/flutter3d.dart';
9import 'package:flutter3d_showcase/src/demo/demo.dart';
10import 'package:flutter3d_sim/flutter3d_sim.dart';
11import 'package:vector_math/vector_math.dart';
13final class FixedStepDemo extends ShowcaseDemo {
14 bool menuOpen = false;
16 final FixedStep _clock = FixedStep(stepSeconds: 1 / 60);
17 final InterpolatedVector3 _position = InterpolatedVector3();
18 int _stepsRun = 0;
20 late final MeshNode _ball;
21 final Vector3 _drawn = Vector3.zero();
23 @override
24 Scene build(DemoContext context) {
25 final material = Material(
26 name: 'marker',
27 baseColor: Vector4(0.8, 0.5, 0.2, 1.0),
28 roughness: 0.6,
29 );
30 _ball = MeshNode(
31 DeviceMesh.upload(context.device, SphereShape(segments: 24).build()),
32 material,
33 name: 'marker',
34 );
35 return Scene()
36 ..add(_ball)
37 ..add(
38 LightNode(name: 'sun', intensity: 3.0)
39 ..setLocalForward(Vector3(-0.4, -1.0, -0.3)),
40 );
41 }
43 /// Whether the step should run at all this frame.
44 ///
45 /// `shouldPause` answers from facts about the player's attention, not from
46 /// a device: a menu open is reason enough on its own, whatever pointer or
47 /// pad is connected.
48 bool get _paused => shouldPause(
49 ready: true,
50 menuOpen: menuOpen,
51 pointerIsTheGate: false,
52 pointerHeld: false,
53 padConnected: false,
54 );
56 @override
57 void update(DemoContext context, double dt) {
58 if (_paused) return;
59 final steps = _clock.advance(dt);
60 for (var i = 0; i < steps; i++) {
61 _stepsRun++;
62 final x = (_stepsRun * _clock.stepSeconds * 1.5) % 2.0 - 1.0;
63 _position.push(Vector3(x, 0.0, 0.0));
64 }
66 _position.read(_clock.alpha, _drawn);
67 _ball.setPositionFrom(_drawn);
68 }
70 @override
71 List<DemoControl> controls(DemoContext context) => <DemoControl>[
72 ToggleControl(
73 'Menu open (pauses the step)',
74 value: () => menuOpen,
75 onChanged: (bool v) => menuOpen = v,
76 ),
77 ];
79 @override
80 void verify(Scene scene, FrameResult frame) {
81 if (frame.drawCalls < 1) {
82 throw StateError('the marker was not drawn');
83 }
84 // One frame of exactly one step's worth of time runs exactly one step:
85 // the accumulator starts empty and this page's step is 1/60 second.
86 if (_stepsRun != 1) {
87 throw StateError(
88 'a 1/60s frame should have run exactly one fixed step, ran $_stepsRun',
89 );
90 }
91 }