Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/.cspell/flame_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,31 @@
Artboard # What a project file is called within Rive
Aseprite # Animated sprite editor and pixel art tool https://www.aseprite.org/
Audioplayers # A Flutter plugin to play multiple simultaneously audio files https://github.com/bluefireteam/audioplayers
Battlezone # a 1980 Atari tank game in wireframe 3D
BGUG # Break Guns Using Gems, a game by BlueFire https://github.com/bluefireteam/bgug
Bodymovin # An After Effects extension to export Lottie animations https://aescripts.com/bodymovin/
emberquest # Ember Quest, our platformer tutorial game
firstgid # first global tile id of a Tiled tileset
Hermione # A character from the book Harry Potter
Kenobi # Eminent Jedi Master, General of the Republic Army, Obi-Wan Kenobi
Nakama # An open-source server designed to power modern games and apps https://github.com/Allan-Nava/nakama-flutter
objectgroup # Tiled object layer element
Overmind # A character in the game StarCraft
padracing # A pad racing game by BlueFire https://github.com/flame-engine/flame/tree/main/examples/games/padracing
Prosser # A character from the book The Hitchhiker's Guide to the Galaxy
renderorder # Tiled map attribute
riverpod # A state management library for Flutter https://github.com/rrousselGit/riverpod
spineboy # Name of a famous character used as an example for Spine https://en.esotericsoftware.com/spine-examples-spineboy
spineboys # Plural of spineboy
Spritecow # A handy tool for locating sprites within a spritesheet http://www.spritecow.com/
Supabase # Supabase, one of our sponsors https://supabase.com/
terminui # A terminal UI library for Flutter
texturepacker # a packed spritesheet format
tilecount # Tiled tileset attribute
tileheight # Tiled map attribute
Tilemap # What tile maps are called within Tiled
tilewidth # Tiled map attribute
tintcolor # Tiled layer attribute
typled # A grid map and sprite sheet tool https://github.com/erickzanardo/typled
vantablack # brand name for a famous super-black ink known as the darkest ever made
Weasley # Ron Weasley, a character from the book Harry Potter
Expand Down
16 changes: 15 additions & 1 deletion .github/.cspell/gamedev_dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# general development-adjacent terms and expressions
AABB # axis aligned bounding box
abelian # Abelian Group, also known as commutative group
affector # something that changes a particle over its life
affectors # plural of affector
alignof # alignment of
ARGB # alpha red green blue
arities # plural of arity
Expand All @@ -13,10 +15,13 @@ bitfield # data structure consisting of adjacent bits
broadphase # common division of collision detection between broad and narrow phases
cathetus # the non-hypotenuse sides of a right triangle
clusterized # past tense of clusterize
colormap # a texture of flat colors that a model kit's meshes share
flipbook # a sequence of frames shown in turn
gles # OpenGL for Embedded Systems
glsl # OpenGL Shading Language
gltf # OpenGL Transmission Format, a file format for 3D models
goldens # test files used as reference for Golden Tests
GTAO # ground truth ambient occlusion
highp # high float precission setting on glsl fragment shaders
hitbox # the collision box around objects for the purposes of collision detection
hitboxes # plural of hitbox
Expand All @@ -26,6 +31,8 @@ IHDR # PNG header chunk
ints # short for integers
jank # stutter or inconsistent gap or timing
lerp # short for linear interpolation
libm # the C math library
lightmap # a texture holding precomputed lighting
LTRBR # left top right bottom radius
LTWH # left top width height
mediump # medium GLSL float precision
Expand All @@ -37,7 +44,10 @@ pathfinding # computer algorithm to find the best path through a world or maze
perlin # Perlin Noise, a type of noise generating algorithm
platformers # plural of platformer, a genre of video game
quadtree # a tree-based data structure where each node has exactly 4 children
rasterizer # converts primitives into pixels
rasterizing
redrawer # the callback that redraws a frame
Reinhard # Reinhard tone mapping operator
respawn # when the player character dies and is brought back after some time and penalties
respawned # past tense of respawn
retarget # to direct (something) toward a different target
Expand All @@ -48,6 +58,7 @@ scrollers # plural of scroller, a genre of video game
shaderbundle # a file extension used to bundle shaders for GLSL
slerp # short for spherical linear interpolation, a method to interpolate quaternions
spritesheet # a single image packing multiple sprites, normally in a grid
SSAO # screen-space ambient occlusion
ssin # sine of a rotation multiplied by the scale factor
subfolders # plural of subfolders
sublists # plural of sublist
Expand All @@ -57,13 +68,16 @@ texel # texture pixel (unit of texture map)
texels # plural of texel
tileset # image with a collection of tiles. in games, tiles are small square sprites laid out in a grid to form the game map
tilesets # plural of tileset
tonemap # map HDR colors to the display range
truecolor # truecolor rendering
uncapturederror # dumb webgpu javascript name
unorm # unsigned normalized integer
unproject # map a screen point back into the scene
viewports # plural of viewport
WASD # movement keys on a keyboard
WBMP # wireless bitmap image format
webgpu # gpu standard for web browsers
WebP # WebP image format
WGSL # WGSL shader language
wgslbundle # WGSL shader bundle format
wgslbundle # WGSL shader bundle format
xorshift # a family of fast pseudorandom number generators
1 change: 1 addition & 0 deletions .github/.cspell/people_usernames.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ feroult # github.com/feroult
fröber # github.com/Brixto
gnarhard # github.com/gnarhard
Hoodead # github.com/kornellapu
kazuma # author of the helicopter model on poly.pizza
kenney # kenney.nl
Klingsbo # github.com/spydon
Kornél # github.com/kornellapu
Expand Down
19 changes: 19 additions & 0 deletions .github/.cspell/words_dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
# actual english words (or common abbreviations) missing from CSpell
autofocused # focused automatically, as a widget given autofocus
behaviour # British spelling of behavior
bloodlust
centimetres # British spelling of centimeters
collidable
collidables
colour # British spelling of color
colours # British spelling of colors
crossfading # blending one animation clip into the next
despawn # remove a spawned entity from the game
despawned # removed from the game after being spawned
gamepads
grayscale
hoverable
Hoverables
inactives
invertibly # in a way that can be inverted
layouting
licence # British spelling of license (the noun)
neighbour # British spelling of neighbor
neighbouring # British spelling of neighboring
neighbours # British spelling of neighbors
normalises # British spelling of normalizes
NTSC
orientable
platformer
Expand All @@ -24,9 +38,14 @@ renderable
rerasterize
rescan
Roboto
scroller # as in side-scroller, a game that scrolls sideways
starfighter # a small combat spacecraft
subclassing
tappable
thumbstick
trackpad
underutilize
unflipped # not flipped
unshields # takes a shield off
unticked # not advanced by a tick
untinted
8 changes: 8 additions & 0 deletions doc/bridge_packages/bridge_packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ with their games.
Create texture atlases for games (bridge package for [FireAtlas]).
:::

:::{package} flame_flutter3d

A 3D layer under a Flame game, with HDR post-processing and one shared game loop (bridge package for
[flutter3d]).
:::

:::{package} flame_forge2d

A Box2D physics engine (bridge package for [Forge2D]).
Expand Down Expand Up @@ -100,6 +106,7 @@ Load Typled sprite atlases with edge-repeated padding (bridge package for [Typle
[AudioPlayers]: https://github.com/bluefireteam/audioplayers
[Bloc]: https://github.com/felangel/bloc
[FireAtlas]: https://github.com/flame-engine/fire-atlas
[flutter3d]: https://pub.dev/packages/flutter3d
[Forge2D]: https://github.com/flame-engine/forge2d
[gamepads]: https://github.com/flame-engine/gamepads
[Lottie]: https://pub.dev/packages/lottie
Expand All @@ -119,6 +126,7 @@ flame_audio <flame_audio/flame_audio.md>
flame_behaviors <flame_behaviors/flame_behaviors.md>
flame_bloc <flame_bloc/flame_bloc.md>
flame_fire_atlas <flame_fire_atlas/flame_fire_atlas.md>
flame_flutter3d <flame_flutter3d/flame_flutter3d.md>
flame_forge2d <flame_forge2d/flame_forge2d.md>
flame_gamepads <flame_gamepads/flame_gamepads.md>
flame_isolate <flame_isolate/flame_isolate.md>
Expand Down
150 changes: 150 additions & 0 deletions doc/bridge_packages/flame_flutter3d/flame_flutter3d.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# flame_flutter3d

**flame_flutter3d** puts a [flutter3d] scene under a Flame game. Flame keeps running the game and
drawing its own layer: components, effects, collisions, input, overlays. flutter3d draws the 3D
layer beneath it, with its own renderer and post-processing chain. Neither engine reimplements the
other, and both run on Flame's clock.

flutter3d draws through Flutter GPU (Impeller) on desktop and mobile, through WebGL2 or WebGPU in a
browser, and through a software rasterizer when there is no GPU at all, which is what the package's
tests use.


## One game, two layers

Mix `HasFlutter3d` into the game and show it with `Flutter3dFlameWidget` instead of `GameWidget`:

```dart
import 'package:flame/game.dart';
import 'package:flame_flutter3d/flame_flutter3d.dart';
import 'package:flutter3d/flutter3d.dart';

class MyGame extends FlameGame with HasFlutter3d {
@override
void onOpen3d() {
scene.add(LightNode(name: 'sun'));
world.add(
Object3dComponent(
node: MeshNode(crateMesh, crateMaterial),
scene: scene,
plane: BridgePlane.ground(),
),
);
}
}

// In the widget tree:
Flutter3dFlameWidget(game: MyGame())
```

`Flutter3dFlameWidget` stacks Flame's `GameWidget` over a flutter3d `SceneSurface`. Flame is on top
because it needs raw input, and `HasFlutter3d` gives the game a transparent background so the 3D
layer shows through. The game owns its `scene`, `camera3d`, `device` and `renderer`, and builds the
world in `onOpen3d`, which runs once after the game has loaded.


## One loop

There is no second ticker. A `BridgeClock` component sits in the game and draws the 3D frame after
Flame's components have updated, so a `MoveEffect` that moved a component this frame is drawn in 3D
this frame. `BridgePriority` names the order the bridge's own components run in: input, actors,
physics, your components, Flame's camera, the camera sync, sound, and the clock last.

`HasFixedStep` runs a game's own logic in fixed steps, so the same second of play gives the same
result at 30 and at 120 frames per second. The physics and the actor system step inside those
steps, and bodies are drawn between two steps rather than jumping from one to the next.


## Where a Flame point is in 3D

`BridgePlane` is the one place a Flame `Vector2` and a flutter3d `Vector3` mean the same point.
`BridgePlane.ground()` lays Flame's world flat for a top-down game, where Flame's `y` becomes the
scene's `z`; `BridgePlane.backdrop()` stands it up for a side-scroller. `CurvilinearSpace` bends it
along a road, and `WrapSpace` makes its edges meet.

`Object3dComponent` keeps a Flame `PositionComponent` and a scene node in step, in whichever
direction a `SyncDirection` names. Position, angle, scale, visibility, opacity and a tint cross, and
Flame's effects, hitboxes and children work on it as on any other component. A component that did
not move writes nothing, so a still prop does not trigger a shadow redraw.

Other components cover what a game usually needs next:

- `InstancedObject3dComponent` draws many components of one shape as one draw call.
- `Node3dComponent` is a component in full 3D, moved by `Move3dEffect`, `Rotate3dEffect` and
`Scale3dEffect`.
- `SpriteBillboardComponent` stands a Flame `Sprite` or `SpriteAnimation` in the scene facing the
camera.
- `RigidBodyComponent`, `ActorComponent` and `CharacterBodyComponent` carry a flutter3d body or
actor across, and `CollisionBridge` reports its contacts through Flame's own
`CollisionCallbacks`.
- `Object3dComponent.follows` takes any Flame position provider, so a `flame_forge2d` body can be
drawn in 3D.
- `TiledWorld3d` stands a Tiled map, the one `flame_tiled` reads, up in 3D.
- `ChaseCamera` and `CameraSyncController` move the 3D camera; given an `eyeOffset`, Flame's own
camera (`follow`, `setBounds`, zoom) drives a perspective one.
- `ProjectedViewfinder` and `Tap3dCallbacks` make Flame's taps land on what the player sees under a
perspective camera.


## Post-processing

The 3D layer renders in HDR and goes through a post-processing chain before it is composited under
Flame. `HasFlutter3d.renderSettings` is read before every frame, so a game turns effects on and off
by returning different settings:

```dart
class MyGame extends FlameGame with HasFlutter3d {
bool cinematic = false;

@override
RenderSettings renderSettings() => RenderSettings(
fog: fog3d,
tonemapCurve: TonemapCurve.agx,
bloom: const BloomSettings(intensity: 0.08),
ambientOcclusion: const AmbientOcclusionSettings(
enabled: true,
method: AmbientOcclusionMethod.gtao,
),
antiAlias: const AntiAliasSettings(
enabled: true,
temporal: TemporalSettings(enabled: true),
),
depthOfField: DepthOfFieldSettings(enabled: cinematic),
);
}
```

What is available: tone mapping (Neutral, ACES, AgX, Reinhard), exposure and auto exposure, local
exposure, bloom, SSAO and GTAO, screen-space reflections, contact shadows, light shafts, volumetric
fog, depth of field, motion blur, temporal anti-aliasing, color grading through a LUT, and spatial
upscaling. Each setting is documented in the [flutter3d API reference].


## Running on the web

A web build draws through WebGL2. To try WebGPU first and fall back to WebGL2 where the browser has
no adapter, build with:

```shell
flutter build web --dart-define=FLUTTER3D_WEBGPU=true
```

The flag is off by default because it adds the WebGPU backend to the bundle, which costs about
368 KiB of JavaScript.

On desktop and mobile, Flutter GPU has to be enabled for the platform, or the 3D layer draws
nothing: `FLTEnableFlutterGPU` and `FLTEnableImpeller` in `Info.plist` on macOS and iOS, and
`io.flutter.embedding.android.EnableFlutterGPU` in `AndroidManifest.xml` on Android.


## Examples

- [The package example](https://github.com/flame-engine/flame/tree/main/packages/flame_flutter3d/example):
a Flame HUD over a 3D yard, a cube Flame steers, and a crate whose landing Flame hears.
- The `flame_flutter3d` stories in the [Flame examples](https://examples.flame-engine.org):
post-processing, the shared loop, and a Tiled map in 3D.
- [River Sortie](https://github.com/flame-engine/flame/tree/main/examples/games/river_sortie): a
small River Raid-style game built on the bridge.

[flutter3d]: https://pub.dev/packages/flutter3d
[flutter3d API reference]: https://flutter3d.pleion.dev/docs
61 changes: 61 additions & 0 deletions examples/assets/tiles/maze_3d.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="9" height="9" tilewidth="16" tileheight="16" infinite="0" nextlayerid="5" nextobjectid="2">
<tileset firstgid="1" name="maze" tilewidth="16" tileheight="16" tilecount="3" columns="3"/>
<layer id="1" name="floor" width="9" height="9" tintcolor="#2a2f3a">
<properties>
<property name="depth" type="float" value="0.1"/>
<property name="elevation" type="float" value="-0.1"/>
<property name="merged" type="bool" value="true"/>
</properties>
<data encoding="csv">
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1
</data>
</layer>
<layer id="2" name="walls" width="9" height="9" tintcolor="#3050ff">
<properties>
<property name="depth" type="float" value="0.8"/>
<property name="solid" type="bool" value="true"/>
</properties>
<data encoding="csv">
2,2,2,2,2,2,2,2,2,
2,0,0,0,0,0,0,0,2,
2,0,2,2,0,2,2,0,2,
2,0,0,0,0,0,0,0,2,
2,2,0,2,0,2,0,2,2,
2,0,0,0,0,0,0,0,2,
2,0,2,2,0,2,2,0,2,
2,0,0,0,0,0,0,0,2,
2,2,2,2,2,2,2,2,2
</data>
</layer>
<layer id="3" name="dots" width="9" height="9" tintcolor="#ffd040">
<properties>
<property name="depth" type="float" value="0.15"/>
<property name="elevation" type="float" value="0.2"/>
</properties>
<data encoding="csv">
0,0,0,0,0,0,0,0,0,
0,3,3,3,3,3,3,3,0,
0,3,0,0,3,0,0,3,0,
0,3,3,3,3,3,3,3,0,
0,0,3,0,3,0,3,0,0,
0,3,3,3,3,3,3,3,0,
0,3,0,0,3,0,0,3,0,
0,3,3,3,0,3,3,3,0,
0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="4" name="actors">
<object id="1" name="player" x="72" y="120">
<point/>
</object>
</objectgroup>
</map>
Loading
Loading