scene_dash_v2 0.5.4 copy "scene_dash_v2: ^0.5.4" to clipboard
scene_dash_v2: ^0.5.4 copied to clipboard

ECS gameplay architecture for flutter_scene 3D games: entities, systems, schedules, events, state machines, input, physics, reactive widgets, headless tests.

Scene-Dash v2 #

Scene-Dash v2: the combat sample

Scene-Dash is an ECS-driven gameplay architecture for flutter_scene. It gives Flutter games a runtime for gameplay state, and a way to test that state with nothing rendering.

  • Entities and components sparse sets, queries, deferred structural changes, lifecycle hooks
  • Systems plain functions, ordered by sets and run conditions
  • Schedules startup, update, fixed step, custom run conditions, plus custom schedules you run yourself
  • Resources shared services and state in the world, injected into systems
  • Events and observers decoupled communication between systems
  • States and machines game states with enter/exit behavior and scoped entities and state machines
  • Routines a reusable sequencer for gameplay with an ordered flow: wave directors, objectives, encounters, tutorials
  • Tweens and smoothing GameTween for a value over a duration, smoothTo for a target that keeps moving, both on game time so they pause with it
  • Input buttons, axes, and buffered presses as resources. Widgets write, systems read
  • Widgets WorldBuilder, EntityBuilder, GameStateBuilder read world state straight into the widget tree
  • Scene components components authored in a .fscene read straight off the scene graph, or baked into entities
  • Debug tooling entity descriptions and system profiling
  • Headless testing run systems, schedules, and whole features with no rendering

flutter_scene keeps doing the rendering. Scene-Dash is the gameplay layer on top.

World-reactive widgets #

Use select to read the value your UI needs. Each frame, the widget reads that value again and compares it with the value it last kept. If it changed, the widget rebuilds. For example, this health bar updates when health.current changes:

EntityBuilder<Health, double>(
  entity: player,
  select: (health) => health.current,
  builder: (context, hp) => HealthBar(hp),
  absent: const RespawnCountdown(), // Entity is gone or has no Health.
)

You can also display a value from the whole world, display game state, or react to an event:

WorldBuilder<int>(select: (w) => w.query<Health>(require: const [Enemy]).count(),
    builder: (ctx, n) => Text('$n enemies'))     // any world-derived value

GameStateBuilder<GameStatus>(builder: (ctx, s) => switch (s) { ... })
                                                 // a subtree per game state

WorldEventListener<EnemyKilled>(onEvent: (ctx, e) => shakeScore(ctx),
    child: const ScorePanel())                   // world events into UI

The rest of the widget layer: .matching resolves the entity through the world, .pulse drives transient feedback, every: throttles a heavy select, GameScope reaches the game from any context.

Comparing values with equals #

Values use == by default. Use equals for a custom comparison: true skips the update; false rebuilds. For lists, compare their contents:

import 'package:flutter/foundation.dart' show listEquals;

EntityBuilder<Inventory, List<String>>(
  entity: player,
  select: (inventory) => List<String>.of(inventory.items),
  equals: listEquals,
  builder: (context, items) => Text(items.join(', ')),
)

Copy the list so changes don't overwrite the previous value you're comparing. This controls frame updates; parent rebuilds can still call the builder.

A complete game in one file #

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_scene/scene.dart';
import 'package:scene_dash_v2/scene_dash_v2.dart';
import 'package:vector_math/vector_math.dart' show Vector3;

Future<void> main() async {
  final game = await SceneGame.boot(features: [installCubes]);

  runApp(
    GameScope(                       // provides the game to the subtree
      game: game,
      child: MaterialApp(
        home: Scaffold(
          body: SceneView(           // flutter_scene widget; not wrapped
            game.scene,
            cameraBuilder: _camera,
            onTick: game.onTick,     // forwards frame ticks to the game
          ),
        ),
      ),
    ),
  );
}

Camera _camera(Duration elapsed) =>
    PerspectiveCamera(position: Vector3(0, 3, -6), target: Vector3.zero());

void installCubes(GameBuilder game) {          // a feature: a plain function
  game
    ..addSystem(Schedules.startup, spawnCube, writes: {Orbit, SceneTransform})
    ..addSystem(Schedules.update, orbitCubes, writes: {Orbit, SceneTransform});
}

void spawnCube(World world) => world.spawn(cubeBundle());

void orbitCubes(World world) {                 // a system: a plain function
  world.query2<Orbit, SceneTransform>().each((entity, orbit, transform) {
    orbit.phase += orbit.speed * world.dt;     // dt is schedule-aware
    transform
      ..x = orbit.radius * cos(orbit.phase)
      ..z = orbit.radius * sin(orbit.phase);
  });
}

final class Orbit {                            // a component: a plain class
  final double radius;
  final double speed;
  double phase;
  Orbit({required this.radius, required this.speed, this.phase = 0});
}

List<Object> cubeBundle() => [       // a bundle: a function → the spawn list
  Orbit(radius: 2, speed: 1),
  SceneTransform.zero(),
  NodeRef(Node(mesh: Mesh(CuboidGeometry(Vector3.all(0.8)), UnlitMaterial()))),
];

Hot reload applies edits to system bodies. There is no build step.

Quick start #

flutter channel stable          # flutter_scene needs Flutter 3.47+
flutter pub get                 # resolve the workspace (repo root)
cd examples/combat_sample
flutter run --enable-flutter-gpu

Reference #

docs/reference.md

docs/concept.md for the architecture, docs/integration.md for the flutter_scene bridge.

Packages and examples #

Path Purpose
packages/scene_dash_v2_core Pure-Dart ECS runtime, authoring surface, headless TestGame.
packages/scene_dash_v2 flutter_scene integration: SceneGame.boot, mounting, transform sync, physics bridge, widget layer. Re-exports core, so one import covers both.
examples/scene_game Complete game: Rapier physics, one feature per folder.
examples/headless_example The core without Flutter.
examples/basic_example_tower_defense The middle example: a small complete game, no assets. Three features that never call each other, talking through events and queries. Gameplay pinned headless.
examples/combat_sample Combat slice: KayKit knight against waves of barbarians, lock-on, buyable skills, giants, Rapier ragdolls, authored .fmat materials. Gameplay pinned headless.
benchmarks Query, structural, and record-overhead benchmarks.
examples/scene_game/lib/features/   # feature based structure
├── player/                         #   else you keep beside it (hud/, fx/,
├── projectiles/                    #   common/, main.dart) is your call
├── rocks/
├── collectables/
├── rules/
├── world/
└── decor/

examples/scene_game/lib/features/player/     # every feature, same shape
├── player.dart      # the Feature function: installs this feature's systems
├── data/            # components, bundles, config, resources
├── systems/         # one file per concern, not one file per feature
└── animation/       # optional; clip selection lives with its feature
0
likes
0
points
651
downloads

Publisher

unverified uploader

Weekly Downloads

ECS gameplay architecture for flutter_scene 3D games: entities, systems, schedules, events, state machines, input, physics, reactive widgets, headless tests.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, flutter_scene, scene_dash_v2_core, vector_math

More

Packages that depend on scene_dash_v2