mirror of
				https://github.com/flame-engine/flame.git
				synced 2025-11-04 04:47:13 +08:00 
			
		
		
		
	interop
This commit is contained in:
		
							
								
								
									
										127
									
								
								lib/game.dart
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								lib/game.dart
									
									
									
									
									
								
							@ -1,32 +1,65 @@
 | 
			
		||||
import 'dart:typed_data';
 | 
			
		||||
import 'dart:ui';
 | 
			
		||||
import 'dart:ui' as ui;
 | 
			
		||||
 | 
			
		||||
import 'package:flame/component.dart';
 | 
			
		||||
import 'package:flame/components/component.dart';
 | 
			
		||||
import 'package:flutter/gestures.dart';
 | 
			
		||||
import 'package:flutter/rendering.dart';
 | 
			
		||||
import 'package:flutter/scheduler.dart';
 | 
			
		||||
import 'package:flutter/widgets.dart';
 | 
			
		||||
import 'package:meta/meta.dart';
 | 
			
		||||
 | 
			
		||||
abstract class Game {
 | 
			
		||||
  // these are all the previously held callbacks from the Flutter engine
 | 
			
		||||
  // this is probably a poor solution to injecting our own rendering stuff
 | 
			
		||||
  ui.FrameCallback _previousOnBeginFrame;
 | 
			
		||||
  VoidCallback _previousOnDrawFrame;
 | 
			
		||||
  PointerDataPacketCallback _previousOnPointerDataPacket;
 | 
			
		||||
 | 
			
		||||
  // the previous time (game clock)
 | 
			
		||||
  Duration _previous = Duration.ZERO;
 | 
			
		||||
 | 
			
		||||
  // determines if the game loop should revert back to
 | 
			
		||||
  // the previous Flutter callbacks on the next frame
 | 
			
		||||
  bool _stop = false;
 | 
			
		||||
 | 
			
		||||
  /// Called when the game is updating.
 | 
			
		||||
  ///   [t] is the time since the previous update.
 | 
			
		||||
  void update(double t);
 | 
			
		||||
 | 
			
		||||
  /// Called when the game is rendering.
 | 
			
		||||
  ///   [canvas] is what you will render your components on.
 | 
			
		||||
  void render(Canvas canvas);
 | 
			
		||||
 | 
			
		||||
  start() {
 | 
			
		||||
    var previous = Duration.ZERO;
 | 
			
		||||
  /// Starts the game by injecting render callbacks into the Flutter engine.
 | 
			
		||||
  void start({@required PointerDataPacketCallback onInput}) {
 | 
			
		||||
    _previousOnBeginFrame = window.onBeginFrame;
 | 
			
		||||
    _previousOnDrawFrame = window.onDrawFrame;
 | 
			
		||||
    _previousOnPointerDataPacket = window.onPointerDataPacket;
 | 
			
		||||
 | 
			
		||||
    window.onBeginFrame = (now) {
 | 
			
		||||
    window.onBeginFrame = _onBeginFrame;
 | 
			
		||||
    window.onDrawFrame = _onDrawFrame;
 | 
			
		||||
    window.onPointerDataPacket = onInput;
 | 
			
		||||
 | 
			
		||||
    window.scheduleFrame();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Stops the game by replacing the injected render callbacks with
 | 
			
		||||
  /// the original Flutter callbacks.
 | 
			
		||||
  void stop() => _stop = true;
 | 
			
		||||
 | 
			
		||||
  void _onBeginFrame(Duration now) {
 | 
			
		||||
    var recorder = new PictureRecorder();
 | 
			
		||||
    var canvas = new Canvas(
 | 
			
		||||
      recorder,
 | 
			
		||||
          new Rect.fromLTWH(
 | 
			
		||||
              0.0, 0.0, window.physicalSize.width, window.physicalSize.height));
 | 
			
		||||
      new Rect.fromLTWH(0.0, 0.0, window.physicalSize.width, window.physicalSize.height),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
      Duration delta = now - previous;
 | 
			
		||||
      if (previous == Duration.ZERO) {
 | 
			
		||||
    Duration delta = now - _previous;
 | 
			
		||||
    if (_previous == Duration.ZERO) {
 | 
			
		||||
      delta = Duration.ZERO;
 | 
			
		||||
    }
 | 
			
		||||
      previous = now;
 | 
			
		||||
    _previous = now;
 | 
			
		||||
 | 
			
		||||
    var t = delta.inMicroseconds / Duration.MICROSECONDS_PER_SECOND;
 | 
			
		||||
 | 
			
		||||
@ -34,8 +67,8 @@ abstract class Game {
 | 
			
		||||
    render(canvas);
 | 
			
		||||
 | 
			
		||||
    var deviceTransform = new Float64List(16)
 | 
			
		||||
        ..[0] = window.devicePixelRatio
 | 
			
		||||
        ..[5] = window.devicePixelRatio
 | 
			
		||||
      ..[0] = 1.0 // window.devicePixelRatio
 | 
			
		||||
      ..[5] = 1.0 // window.devicePixelRatio
 | 
			
		||||
      ..[10] = 1.0
 | 
			
		||||
      ..[15] = 1.0;
 | 
			
		||||
 | 
			
		||||
@ -45,13 +78,76 @@ abstract class Game {
 | 
			
		||||
      ..pop();
 | 
			
		||||
 | 
			
		||||
    window.render(builder.build());
 | 
			
		||||
      window.scheduleFrame();
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _onDrawFrame() {
 | 
			
		||||
    if (_stop) {
 | 
			
		||||
      window.onBeginFrame = _previousOnBeginFrame;
 | 
			
		||||
      window.onDrawFrame = _previousOnDrawFrame;
 | 
			
		||||
      // todo  if using touch input to "stop", then an exception is thrown
 | 
			
		||||
      // todo  where the input is "state.down" and never goes to "state.up"
 | 
			
		||||
      window.onPointerDataPacket = _previousOnPointerDataPacket;
 | 
			
		||||
      _stop = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window.scheduleFrame();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BaseGame extends Game {
 | 
			
		||||
 | 
			
		||||
  List<Component> components = new List();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void render(Canvas canvas) {
 | 
			
		||||
    canvas.save();
 | 
			
		||||
    components.forEach((comp) {
 | 
			
		||||
      comp.render(canvas);
 | 
			
		||||
      canvas.restore();
 | 
			
		||||
      canvas.save();
 | 
			
		||||
    });
 | 
			
		||||
    canvas.restore();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void update(double t) {
 | 
			
		||||
    components.forEach((c) => c.update(t));
 | 
			
		||||
    components.removeWhere((c) => c.destroy());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class BaseGameWidget extends GameWidget {
 | 
			
		||||
 | 
			
		||||
  final List<Component> components = new List();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool destroy() {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  bool loaded() {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void render(Canvas canvas) {
 | 
			
		||||
    canvas.save();
 | 
			
		||||
    components.forEach((comp) {
 | 
			
		||||
      comp.render(canvas);
 | 
			
		||||
      canvas.restore();
 | 
			
		||||
      canvas.save();
 | 
			
		||||
    });
 | 
			
		||||
    canvas.restore();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void update(double t) {
 | 
			
		||||
    components.forEach((c) => c.update(t));
 | 
			
		||||
    components.removeWhere((c) => c.destroy());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class GameWidget extends StatelessWidget implements Component {
 | 
			
		||||
  void update(double t);
 | 
			
		||||
 | 
			
		||||
@ -67,13 +163,12 @@ abstract class GameWidget extends StatelessWidget implements Component {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GameRenderObjectWidget extends SingleChildRenderObjectWidget {
 | 
			
		||||
  Component component;
 | 
			
		||||
  final Component component;
 | 
			
		||||
 | 
			
		||||
  GameRenderObjectWidget(this.component);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  RenderObject createRenderObject(BuildContext context) =>
 | 
			
		||||
      new GameRenderBox(context, this.component);
 | 
			
		||||
  RenderObject createRenderObject(BuildContext ctx) => new GameRenderBox(ctx, this.component);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GameRenderBox extends RenderBox {
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user