flutter3d
Showcase Changelog 38 packages API reference

Two engines, one Stack: the source

since 0.7.0 The Flame bridge

Regions the guide quotes: live (line 67), flame-layer (line 91), flutter3d-layer (line 96), unconnected (line 101).

1/// Flame's own layer and flutter3d's own layer, drawn side by side and not
2/// yet talking to each other — the state every other page in this category
3/// starts connecting.
4///
5/// Quoted by `flame_overview.md` and shown whole in the Source tab.
6library;
7
8import 'dart:math' as math;
9
10import 'package:flame/components.dart';
11import 'package:flame_flutter3d/flame_flutter3d.dart';
12import 'package:flutter/widgets.dart';
13import 'package:flutter3d/flutter3d.dart';
14import 'package:flutter3d_showcase/src/demo/demo.dart';
15import 'package:flutter3d_showcase/src/demo/flame_layer.dart';
17final class FlameOverviewDemo extends ShowcaseDemo {
18 late final double _flameX;
19 late final double _cubeX;
21 late final Scene _scene;
22 late final MeshNode _cube;
23 late final TransparentFlameGame _game;
24 late final Widget _body = flameOrbit(
25 _context,
26 Flutter3dFlameWidget(
27 game: _game,
28 camera: _context.camera,
29 existing: (device: _context.device, renderer: _context.renderer),
30 buildScene: (GraphicsDevice device) => _scene,
31 ),
32 );
33 late final DemoContext _context;
34 double _clock = 0.0;
36 @override
37 void configureView(DemoContext context) {
38 context.orbit
39 ..distance = 3.2
40 ..pitch = 0.3
41 ..yaw = 0.6;
42 context.orbit.target.setValues(0.0, 0.0, 0.0);
43 }
45 @override
46 Scene build(DemoContext context) {
47 _context = context;
48 final (double flameX, double cubeX) = _run();
49 _flameX = flameX;
50 _cubeX = cubeX;
52 _cube = MeshNode(
53 DeviceMesh.upload(
54 context.device,
55 CuboidShape(size: Vector3(0.8, 0.8, 0.8)).build(),
56 ),
57 Material(name: 'cube', baseColor: Vector4(0.5, 0.6, 0.8, 1.0)),
58 name: 'cube',
59 );
60 _scene = Scene()
61 ..add(_cube)
62 ..add(
63 LightNode(name: 'sun', intensity: 2.5)
64 ..setLocalForward(Vector3(-0.3, -0.6, -0.4)),
65 );
67 // Built once, kept: the widget below is rebuilt every frame, and a game
68 // made afresh each time would restart before it drew anything.
69 _game = TransparentFlameGame();
70 final _Slider slider = _Slider();
71 _game
72 ..add(flameCaption('Flame: a component its own game moves'))
73 ..add(slider)
74 ..add(
75 flameCaption(
76 'flutter3d: a cube its own scene turns',
77 at: Vector2(16.0, 88.0),
78 ),
79 );
80 return _scene;
81 }
83 @override
84 void update(DemoContext context, double dt) {
85 _clock += dt;
86 context.orbit.syncProjectionDepth(context.camera);
87 _cube.setRotation(Quaternion.axisAngle(Vector3(0.0, 1.0, 0.0), _clock));
88 }
90 static (double, double) _run() {
91 // Flame's own layer: a plain PositionComponent, the same class every
92 // sprite and shape in a Flame game already is. Nothing here has heard of
93 // flutter3d.
94 final flameShape = PositionComponent(position: Vector2(2.0, 0.0));
96 // flutter3d's own layer: a cube placed at a spot of its own, on the far
97 // side of the origin from the Flame shape. Nothing here has heard of
98 // Flame.
99 const double cubeX = 9.0;
101 // Ticking the Flame side does not move it towards the cube, and moving
102 // the cube (above) never touched the Flame shape at all: no bridge sits
103 // between them yet. That is every other page in this category, one
104 // mechanism at a time.
105 flameShape.update(1 / 60);
106 final double flameX = flameShape.position.x;
108 return (flameX, cubeX);
109 }
111 /// The Flame game the page runs, for a test that steps it without a window.
112 @visibleForTesting
113 TransparentFlameGame get game => _game;
115 @override
116 Widget? customBody(BuildContext buildContext, DemoContext context) => _body;
118 @override
119 void verify(Scene scene, FrameResult frame) {
120 if (frame.drawCalls < 1) {
121 throw StateError('the cube marker was not drawn');
122 }
123 if (_flameX != 2.0) {
124 throw StateError(
125 'the Flame shape should not have moved on its own, got $_flameX',
126 );
127 }
128 if (_cubeX != 9.0) {
129 throw StateError('the flutter3d cube should be at its own spot');
130 }
131 }
134/// A square that Flame's own game slides to and fro across the top.
135final class _Slider extends PositionComponent {
136 _Slider() : super(position: Vector2(16.0, 40.0), size: Vector2.all(36.0));
138 double _t = 0.0;
140 @override
141 void update(double dt) {
142 super.update(dt);
143 _t += dt;
144 position.x = 16.0 + 160.0 * (0.5 - 0.5 * math.cos(_t * 1.5));
145 }
147 @override
148 void render(Canvas canvas) =>
149 canvas.drawRect(size.toRect(), Paint()..color = const Color(0xFFE8A33D));