/// Shared Flutter renderer shell for driving the Wolf3D engine from a widget tree. library; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:wolf_3d_dart/wolf_3d_engine.dart'; /// Base widget for renderers that present frames from a [WolfEngine]. abstract class BaseWolfRenderer extends StatefulWidget { /// Engine instance that owns world state and the shared framebuffer. final WolfEngine engine; /// Optional key handler invoked by the focused renderer shell. final void Function(KeyEvent event)? onKeyEvent; /// Creates a renderer bound to [engine]. const BaseWolfRenderer({ required this.engine, this.onKeyEvent, super.key, }); } /// Base [State] implementation that provides a ticker-driven render loop. abstract class BaseWolfRendererState extends State with SingleTickerProviderStateMixin { /// Per-frame ticker used to advance the engine and request renders. late final Ticker gameLoop; /// Focus node used by the enclosing [KeyboardListener]. final FocusNode focusNode = FocusNode(); Duration _lastTick = Duration.zero; @override void initState() { super.initState(); gameLoop = createTicker(_tick)..start(); focusNode.requestFocus(); } void _tick(Duration elapsed) { if (!widget.engine.isInitialized) return; if (_lastTick == Duration.zero) { _lastTick = elapsed; return; } Duration delta = elapsed - _lastTick; _lastTick = elapsed; widget.engine.tick(delta); performRender(); } @override void dispose() { gameLoop.dispose(); focusNode.dispose(); super.dispose(); } /// Renders the latest engine state into the concrete renderer's output type. void performRender(); /// Builds the visible viewport widget for the latest rendered frame. Widget buildViewport(BuildContext context); /// Background color used by the surrounding scaffold. Color get scaffoldColor; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: scaffoldColor, body: KeyboardListener( focusNode: focusNode, autofocus: true, onKeyEvent: (event) { widget.onKeyEvent?.call(event); }, child: Center( child: buildViewport(context), ), ), ); } }