Skip to content

Instantly share code, notes, and snippets.

@keithjohnston
Last active September 20, 2023 01:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keithjohnston/89c1111c0a9f237c8232a3b05ade4ecc to your computer and use it in GitHub Desktop.
Save keithjohnston/89c1111c0a9f237c8232a3b05ade4ecc to your computer and use it in GitHub Desktop.
Flame example
import 'dart:io' show Platform;
import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flame/input.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyWidget());
}
class PointerTracker {
static var isTrackpadScroll = false;
}
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return Listener(
onPointerPanZoomStart: (PointerPanZoomStartEvent event) {
PointerTracker.isTrackpadScroll = true;
},
onPointerPanZoomEnd: (PointerPanZoomEndEvent event) {
PointerTracker.isTrackpadScroll = false;
},
child: const GameWidget.controlled(
gameFactory: MyGame.new,
),
);
}
}
class MyGame extends FlameGame with ScrollDetector, ScaleDetector {
final world = World();
late final CameraComponent cameraComponent;
late double startZoom;
SpriteComponent? dragComp;
static const zoomPerScrollUnit = 0.02;
final viewportResolution = Vector2(1000, 1000);
MyGame();
double clampZoom(double zoom) {
return zoom.clamp(.05, 3.0);
}
@override
void onScroll(PointerScrollInfo info) {
cameraComponent.viewfinder.zoom = clampZoom(
cameraComponent.viewfinder.zoom +
info.scrollDelta.game.y.sign * zoomPerScrollUnit * -1);
}
@override
void onScaleStart(ScaleStartInfo info) {
dragComp = null;
Iterable<Component> comps = componentsAtPoint(info.eventPosition.game);
// You must iterate through all the components or things will go sideways!
for (var comp in comps) {
if (!PointerTracker.isTrackpadScroll && comp is SpriteComponent && dragComp == null) {
dragComp = comp;
}
}
startZoom = cameraComponent.viewfinder.zoom;
}
@override
void onScaleUpdate(ScaleUpdateInfo info) {
final delta = info.delta.game;
final zoom = cameraComponent.viewfinder.zoom;
final currentScale = info.scale.global;
if (!currentScale.isIdentity()) {
cameraComponent.viewfinder.zoom = clampZoom(startZoom * currentScale.y);
} else {
final comp = dragComp;
if (PointerTracker.isTrackpadScroll) {
return;
}
if (comp != null) {
Vector2 newPos = comp.position;
newPos.translate(delta.x / zoom, delta.y / zoom);
comp.position = newPos;
debugPrint('updating sprite');
debugPrint('new pos: ' + newPos.toString());
return;
}
debugPrint('updating camera');
Vector2 newPos = cameraComponent.viewfinder.position;
newPos.translate(-delta.x / zoom, -delta.y / zoom);
debugPrint('new pos: ' + newPos.toString());
cameraComponent.viewfinder.position = newPos;
}
}
@override
void onScaleEnd(ScaleEndInfo info) {
dragComp = null;
}
@override
Future<void> onLoad() async {
cameraComponent = CameraComponent.withFixedResolution(
world: world,
width: viewportResolution.x,
height: viewportResolution.y,
);
await addAll([world, cameraComponent]);
final rand = Random();
for (int i = 0; i < 50; i++) {
final sprite = await Sprite.load('circle.png');
SpriteComponent comp = SpriteComponent()
..sprite = sprite
..size = Vector2(100, 74)
..position = Vector2(
rand.nextDouble() * 1000 - 500, rand.nextDouble() * 1000 - 500);
world.add(comp);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment