Skip to content

Instantly share code, notes, and snippets.

@jonahwilliams
Created September 25, 2024 03:12
Show Gist options
  • Save jonahwilliams/9b73ebb7fde76478ef98ddb6d45f1aee to your computer and use it in GitHub Desktop.
Save jonahwilliams/9b73ebb7fde76478ef98ddb6d45f1aee to your computer and use it in GitHub Desktop.
draw atlas painter
diff --git a/bench_flutter/lib/game/game_screen.dart b/bench_flutter/lib/game/game_screen.dart
index 16843e0..87da9d4 100644
--- a/bench_flutter/lib/game/game_screen.dart
+++ b/bench_flutter/lib/game/game_screen.dart
@@ -1,3 +1,5 @@
+import 'dart:ui' as ui;
+
import 'package:bench_flutter/audio/audio_controller.dart';
import 'package:bench_flutter/game/button.dart';
import 'package:bench_flutter/game/game_world.dart';
@@ -22,7 +24,7 @@ class GameScreen extends StatelessWidget {
'assets/images/wood-background.jpg',
fit: BoxFit.cover,
),
- const GameWorldWidget(),
+ const RepaintBoundary(child: GameWorldWidget()),
const RepaintBoundary(child: LogoWidget()),
const _DisappearingButtons(),
Positioned(
diff --git a/bench_flutter/lib/game/game_world.dart b/bench_flutter/lib/game/game_world.dart
index 4516bdc..4da2dff 100644
--- a/bench_flutter/lib/game/game_world.dart
+++ b/bench_flutter/lib/game/game_world.dart
@@ -1,6 +1,8 @@
import 'dart:math';
+import 'dart:ui' as ui;
import 'package:bench_flutter/game/wanderer.dart';
+import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
@@ -63,31 +65,88 @@ class GameWorldWidget extends StatefulWidget {
State<GameWorldWidget> createState() => _GameWorldWidgetState();
}
+Future<ui.Image> loadAsset(String asset) async {
+ ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
+ ui.ImageDescriptor descriptor = await ui.ImageDescriptor.encoded(buffer);
+ ui.Codec codec = await descriptor.instantiateCodec();
+ ui.FrameInfo info = await codec.getNextFrame();
+
+ buffer.dispose();
+ descriptor.dispose();
+ codec.dispose();
+
+ return info.image;
+}
+
class _GameWorldWidgetState extends State<GameWorldWidget>
with SingleTickerProviderStateMixin {
- late AnimationController _controller;
+ late Ticker _ticker;
+ ui.Image? sprite;
@override
Widget build(BuildContext context) {
+ if (sprite == null) {
+ return const Placeholder();
+ }
+
final world = context.watch<GameWorld>();
+ return CustomPaint(painter: WandererPainter(sprite!, world.wanderers));
+ }
- return Stack(
- children: [
- for (final wanderer in world.wanderers)
- PairedWandererWidget(wanderer: wanderer),
- ],
- );
+ @override
+ void initState() {
+ super.initState();
+ loadAsset('assets/images/sprite.png').then((ui.Image image) {
+ setState(() {
+ sprite = image;
+ });
+ });
+ _ticker = createTicker(_onTick);
+ _ticker.start();
}
@override
void dispose() {
- _controller.dispose();
+ _ticker.dispose();
super.dispose();
}
+ void _onTick(Duration elapsed) {
+ final world = Provider.of<GameWorld>(context, listen: false);
+
+ for (final wanderer in world.wanderers) {
+ final dt = (elapsed - wanderer.lastElapsed).inMicroseconds / 1000000;
+ wanderer.update(dt);
+ wanderer.lastElapsed = elapsed;
+ }
+
+ setState(() {
+ //
+ });
+ }
+}
+
+class WandererPainter extends CustomPainter {
+ const WandererPainter(this.sprite, this.wanderers);
+
+ final ui.Image sprite;
+ final List<PairedWanderer> wanderers;
+
+ @override
+ void paint(ui.Canvas canvas, ui.Size size) {
+ var wholeImage = Rect.fromLTWH(0, 0, sprite.width.toDouble(), sprite.height.toDouble());
+ canvas.drawAtlas(sprite, [
+ for (var wanderer in wanderers)
+ ui.RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: wanderer.position.x - 128 / 4, translateY: wanderer.position.y - 128 / 4)
+ ], [
+ for (var _ in wanderers)
+ wholeImage
+ ], null, null, Offset.zero & size, Paint());
+ }
+
@override
- void initState() {
- super.initState();
- _controller = AnimationController(vsync: this);
+ bool shouldRepaint(covariant CustomPainter oldDelegate) {
+ return true;
}
+
}
diff --git a/bench_flutter/lib/game/wanderer.dart b/bench_flutter/lib/game/wanderer.dart
index cc35ce2..6bc9270 100644
--- a/bench_flutter/lib/game/wanderer.dart
+++ b/bench_flutter/lib/game/wanderer.dart
@@ -1,5 +1,4 @@
import 'package:flutter/cupertino.dart';
-import 'package:flutter/scheduler.dart';
import 'package:vector_math/vector_math_64.dart';
class PairedWanderer {
@@ -11,6 +10,8 @@ class PairedWanderer {
final Size worldSize;
+ Duration lastElapsed = Duration.zero;
+
PairedWanderer({
required this.position,
required this.velocity,
@@ -35,48 +36,3 @@ class PairedWanderer {
}
}
}
-
-class PairedWandererWidget extends StatefulWidget {
- final PairedWanderer wanderer;
-
- const PairedWandererWidget({required this.wanderer, super.key});
-
- @override
- State<PairedWandererWidget> createState() => _PairedWandererWidgetState();
-}
-
-class _PairedWandererWidgetState extends State<PairedWandererWidget>
- with SingleTickerProviderStateMixin {
- late Ticker _ticker;
-
- Duration _lastElapsed = Duration.zero;
-
- @override
- void initState() {
- super.initState();
- _ticker = createTicker(_onTick);
- _ticker.start();
- }
-
- @override
- void dispose() {
- _ticker.dispose();
- super.dispose();
- }
-
- @override
- Widget build(BuildContext context) {
- return Positioned(
- left: widget.wanderer.position.x - 128 / 4,
- top: widget.wanderer.position.y - 128 / 4,
- child: Image.asset('assets/images/sprite.png', scale: 2),
- );
- }
-
- void _onTick(Duration elapsed) {
- final dt = (elapsed - _lastElapsed).inMicroseconds / 1000000;
- widget.wanderer.update(dt);
- _lastElapsed = elapsed;
- setState(() {});
- }
-}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment