This commit is contained in:
Luan Nico
2017-12-04 08:16:42 -02:00
parent bc20dc2a0f
commit fca524425b

View File

@ -1,55 +1,151 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui'; 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/gestures.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
abstract class Game { 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); void update(double t);
/// Called when the game is rendering.
/// [canvas] is what you will render your components on.
void render(Canvas canvas); void render(Canvas canvas);
start() { /// Starts the game by injecting render callbacks into the Flutter engine.
var previous = Duration.ZERO; void start({@required PointerDataPacketCallback onInput}) {
_previousOnBeginFrame = window.onBeginFrame;
_previousOnDrawFrame = window.onDrawFrame;
_previousOnPointerDataPacket = window.onPointerDataPacket;
window.onBeginFrame = (now) { window.onBeginFrame = _onBeginFrame;
var recorder = new PictureRecorder(); window.onDrawFrame = _onDrawFrame;
var canvas = new Canvas( window.onPointerDataPacket = onInput;
recorder,
new Rect.fromLTWH(
0.0, 0.0, window.physicalSize.width, window.physicalSize.height));
Duration delta = now - previous;
if (previous == Duration.ZERO) {
delta = Duration.ZERO;
}
previous = now;
var t = delta.inMicroseconds / Duration.MICROSECONDS_PER_SECOND;
update(t);
render(canvas);
var deviceTransform = new Float64List(16)
..[0] = window.devicePixelRatio
..[5] = window.devicePixelRatio
..[10] = 1.0
..[15] = 1.0;
var builder = new SceneBuilder()
..pushTransform(deviceTransform)
..addPicture(Offset.zero, recorder.endRecording())
..pop();
window.render(builder.build());
window.scheduleFrame();
};
window.scheduleFrame(); 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),
);
Duration delta = now - _previous;
if (_previous == Duration.ZERO) {
delta = Duration.ZERO;
}
_previous = now;
var t = delta.inMicroseconds / Duration.MICROSECONDS_PER_SECOND;
update(t);
render(canvas);
var deviceTransform = new Float64List(16)
..[0] = 1.0 // window.devicePixelRatio
..[5] = 1.0 // window.devicePixelRatio
..[10] = 1.0
..[15] = 1.0;
var builder = new SceneBuilder()
..pushTransform(deviceTransform)
..addPicture(Offset.zero, recorder.endRecording())
..pop();
window.render(builder.build());
}
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 { abstract class GameWidget extends StatelessWidget implements Component {
@ -67,13 +163,12 @@ abstract class GameWidget extends StatelessWidget implements Component {
} }
class GameRenderObjectWidget extends SingleChildRenderObjectWidget { class GameRenderObjectWidget extends SingleChildRenderObjectWidget {
Component component; final Component component;
GameRenderObjectWidget(this.component); GameRenderObjectWidget(this.component);
@override @override
RenderObject createRenderObject(BuildContext context) => RenderObject createRenderObject(BuildContext ctx) => new GameRenderBox(ctx, this.component);
new GameRenderBox(context, this.component);
} }
class GameRenderBox extends RenderBox { class GameRenderBox extends RenderBox {