Last active
September 20, 2023 01:13
-
-
Save keithjohnston/89c1111c0a9f237c8232a3b05ade4ecc to your computer and use it in GitHub Desktop.
Flame example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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