diff --git a/lib/game/Game.dart b/lib/game/Game.dart new file mode 100644 index 0000000..1c23630 --- /dev/null +++ b/lib/game/Game.dart @@ -0,0 +1,64 @@ +import 'dart:html'; + +class Game { + List> grid; + CanvasElement canvas; + CanvasRenderingContext2D ctx; + + double _oscill = 0.0; + bool _fwd = true; + + Game(CanvasElement this.canvas) { + grid = buildGrid(5,5, new Color(255, 100, 255)); + ctx = this.canvas.getContext('2d'); + } + + void update([num dt]) {} + + void draw([num interp]) { +// CanvasRenderingContext2D ctx = this.canvas.getContext('2d'); +// print(grid.toString()); + int brickW = (canvas.width ~/ grid[0].length); + int brickH = (canvas.height ~/ grid.length); + + ctx.clearRect(0, 0, canvas.width, canvas.height); + for(int y=0;y> buildGrid(int w, int h, Color col) { + List> grid = new List(h); + + + for(int y = 0; y< h; y++) { + grid[y] = new List(w); + for(int x = 0; x< w; x++) { + grid[y][x] = col; + } + } + return grid; + } +} + +class Color { + final int r; + final int g; + final int b; + + const Color(this.r, this.g, this.b); + +} + +// Create 2d array +// fill with random colors +// cycle colors +// set one color to random new one \ No newline at end of file diff --git a/lib/game/LoopExample.dart b/lib/game/LoopExample.dart new file mode 100644 index 0000000..e547a8b --- /dev/null +++ b/lib/game/LoopExample.dart @@ -0,0 +1,8 @@ +import 'package:browserloop/game/Game.dart'; + +abstract class LoopExample{ + Game game; + + void stop() {} + void start() {} +} \ No newline at end of file diff --git a/lib/src/00-oldcode.dart b/lib/src/00-oldcode.dart new file mode 100644 index 0000000..0d534af --- /dev/null +++ b/lib/src/00-oldcode.dart @@ -0,0 +1,64 @@ +import 'dart:html' as html; +import 'dart:math' as math; + +html.CanvasRenderingContext2D ctx; +html.CanvasElement el; + +math.Random rng = new math.Random(); +int GRIDNUM = 10; +int animID = 0; + +// These are the functions to start the animation and stop the animation. +// (They are connected to the start/stop buttons in the demo setup.) +var _stop = () => html.window.cancelAnimationFrame(animID); +var _start = () => html.window.requestAnimationFrame(eventloop); + +// This is what ticks every frame of the animation. +void eventloop(currentTime) { + print(currentTime.toString()); + ctx.setFillColorRgb(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255)); + int BRICKSIZE = (el.width ~/ GRIDNUM); + int x = rng.nextInt(GRIDNUM) * BRICKSIZE; + int y = rng.nextInt(GRIDNUM) * BRICKSIZE; + ctx.fillRect(x, y, (BRICKSIZE), (BRICKSIZE)); + + animID = html.window.requestAnimationFrame( + eventloop); // recursive call to our eventloop - calls it forever as soon as browser is willing to give us his time +} + +void main() { + _demoSetup(); +} + +//buttons and canvas setup +void _demoSetup() { + el = new html.CanvasElement(width: 480, height: 480); + html.querySelector('#basic_output').append(el); + ctx = el.getContext('2d'); + var _clear = () { + _stop(); + ctx.setFillColorRgb(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255)); + ctx.fillRect(0, 0, el.width, el.height); + ctx.setFillColorRgb(rng.nextInt(255), rng.nextInt(255), rng.nextInt(255)); + }; + var _changeGrid = (int delta) { + _clear(); + int newgrid = GRIDNUM + delta; + GRIDNUM = (newgrid == 0) ? GRIDNUM : newgrid; + _start(); + }; + _clear(); + + html.querySelector('#basic_start').onClick.listen((e) { + print('started'); + _stop(); + _start(); + }); + html.querySelector('#basic_stop').onClick.listen((e) => _stop()); + html + .querySelector('#basic_reset') + .onClick + .listen((e) => _clear()); + html.querySelector('#basic_plus').onClick.listen((e) => _changeGrid(-5)); + html.querySelector('#basic_minus').onClick.listen((e) => _changeGrid(5)); +} diff --git a/lib/src/01-WhileLoop.dart b/lib/src/01-WhileLoop.dart new file mode 100644 index 0000000..fb2d6fe --- /dev/null +++ b/lib/src/01-WhileLoop.dart @@ -0,0 +1,31 @@ +import 'package:browserloop/game/Game.dart'; +import 'package:browserloop/game/LoopExample.dart'; + +/// The most basic update loop possible. +/// +/// Best not to use this loop since it has a tendency to +/// crash your browser and not load correctly at all. +/// The way to get this to run would be the setInterval method +/// simple is either through setInterval in Javascript: +/// https://www.w3schools.com/howto/howto_js_animate.asp +/// or through the Timer API in Dart, especially +/// with Timer.periodic(16, callbackFunction); +/// To see how I got it running for the example, +/// see file 02-AnimationFrameWhile.dart +class WhileLoop implements LoopExample { + Game game; + + WhileLoop(Game this.game) { + eventloop(); + } + + void eventloop() { + while(true) { + game.update(); + } + } + + void update() { + print("i am updating"); + } +} \ No newline at end of file diff --git a/lib/src/02-AnimationFrameWhile.dart b/lib/src/02-AnimationFrameWhile.dart new file mode 100644 index 0000000..1f2b11c --- /dev/null +++ b/lib/src/02-AnimationFrameWhile.dart @@ -0,0 +1,32 @@ +import 'dart:html'; +import 'package:browserloop/game/Game.dart'; +import 'package:browserloop/game/LoopExample.dart'; + +/// The most basic update loop possible. +/// +/// Note that this is technically cheating since it is using +/// animationFrames to improve browser performance for the examples in the +/// blog post. The real, actual simplest code is in file 01-WhileLoop.dart +class WhileLoop implements LoopExample { + Game game; + num id; + + WhileLoop(Game this.game) { + window.requestAnimationFrame(eventloop); + } + + void eventloop(num time) { + game.update(); + game.draw(); + + id = window.requestAnimationFrame(eventloop); + } + + void stop() { + window.cancelAnimationFrame(id); + } + + void start() { + window.requestAnimationFrame(eventloop); + } +} \ No newline at end of file diff --git a/lib/src/03-FixedLoopVariableRender.dart b/lib/src/03-FixedLoopVariableRender.dart new file mode 100644 index 0000000..95c65c7 --- /dev/null +++ b/lib/src/03-FixedLoopVariableRender.dart @@ -0,0 +1,52 @@ +import 'dart:html'; + +import 'package:browserloop/game/Game.dart'; +import 'package:browserloop/game/LoopExample.dart'; + +class FixedLoopVariableRender implements LoopExample { + static final double MS_PER_UPDATE = 1000.0; + static final double SAFE_GUARD = 500.0; + Stopwatch elapsed = new Stopwatch(); + double lag = 0.0; + Game game; + num id; + + FixedLoopVariableRender(this.game) { + + elapsed.start(); + window.requestAnimationFrame(eventloop); + } + + void eventloop(num time) { + lag += elapsed.elapsedMilliseconds; + elapsed.reset(); + + while (lag >= MS_PER_UPDATE && elapsed.elapsedMilliseconds < SAFE_GUARD) { + update(); + lag -= MS_PER_UPDATE; + } + render(lag / MS_PER_UPDATE); + id = window.requestAnimationFrame(eventloop); + + } + + void update() { + print('updating'); + game.update(); + return; + } + + void render(double interp) { + print('rendering, interp:$interp'); + game.draw(interp); + return; + } + + void stop() { + window.cancelAnimationFrame(id); + } + + void start() { + window.requestAnimationFrame(eventloop); + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..d0f6684 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,15 @@ +name: browserloop +description: An absolute bare-bones web app. +version: 0.0.1 +#homepage: https://www.example.com +#author: marty + +environment: + sdk: '>=2.0.0-dev.67.0 <3.0.0' + +#dependencies: +# path: ^1.4.1 + +dev_dependencies: + build_runner: ^0.9.0 + build_web_compilers: ^0.4.0 diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/web/favicon.ico @@ -0,0 +1 @@ + diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..5ef061d --- /dev/null +++ b/web/index.html @@ -0,0 +1,23 @@ + + + + Browserloop + + + + + + + + + +
+
+ + + + + + + + diff --git a/web/main.dart b/web/main.dart new file mode 100644 index 0000000..ab6e6c8 --- /dev/null +++ b/web/main.dart @@ -0,0 +1,110 @@ +import 'dart:html'; +import 'package:browserloop/game/Game.dart'; +import 'package:browserloop/game/LoopExample.dart'; +import 'package:browserloop/src/03-FixedLoopVariableRender.dart'; +import 'package:browserloop/src/02-AnimationFrameWhile.dart'; + +List examples = [ + Example("While Loop Example","#while_output"), + Example("Fixed Update, Variable Render","#variable_output") +]; +LoopExample active; + +class Example { + final String query; + final String name; + CanvasElement canvas = CanvasElement(width: 480, height: 480); + LoopExample loop; + + Example(this.name, this.query); +} + +void main() { + examples.forEach((ex) { + appendToDOM(ex); + }); + resetPlaceHolders(); +} + +void appendToDOM(Example example) { + querySelector(example.query).append(example.canvas); + example.canvas.onClick.forEach(activate); + print("${example.query} appended"); +} + +void readdToDOM(Example example) { + querySelector(example.query).children.clear(); + print("${example.query} removed"); + appendToDOM(example); +} + +void resetPlaceHolders([Example current]) { + examples.forEach((Example ex) { + if(current == null || ex != current) { + if(ex.loop != null) { + ex.loop.stop(); + ex.loop = null; + } + ex.canvas = new CanvasElement(width: ex.canvas.width,height: ex.canvas.height); + readdToDOM(ex); + + CanvasRenderingContext2D ctx = ex.canvas.context2D; + Point c = Point(ex.canvas.width/2, ex.canvas.height/2); + ctx.setFillColorRgb(255, 150, 10); + ctx.fillRect(0, 0, ex.canvas.width, ex.canvas.height); + + ctx.beginPath(); + ctx.moveTo(c.x-25, c.y-25); + ctx.lineTo(c.x+25, c.y+25); + ctx.lineTo(c.x-25, c.y+75); + ctx.closePath(); + ctx.lineWidth = 10; + ctx.setStrokeColorRgb(155, 155, 155); + ctx.setFillColorRgb(255, 255, 255); + ctx.stroke(); + ctx.fill(); + ctx.fillText(ex.name, c.x - ctx.measureText(ex.name).width/2, c.y - 50); + + print("reset ${ex.query}"); + } + }); +} + +void activate(MouseEvent e) { + if(e.target is! CanvasElement) return; + CanvasElement c = (e.target as CanvasElement); + + examples.forEach((Example ex) { + if (ex.canvas == c) { + resetPlaceHolders(ex); + switch (ex.query) { + case "#while_output": + ex.loop = new WhileLoop(new Game(c)); + break; + case "#variable_output": + ex.loop = new FixedLoopVariableRender(new Game(c)); + break; + } + + querySelector(ex.query).append(new ButtonElement() + ..text = "start" + ..onClick.listen((e) { + ex.loop.stop(); + ex.loop.start(); + })); + querySelector(ex.query).append(new ButtonElement() + ..text = "stop" + ..onClick.listen((e) { + ex.loop.stop(); + })); +// querySelector('#reset').onClick.listen((e) => ex.loop.game.reset()); +// querySelector('#plus').onClick.listen((e) => _changeGrid(-5)); +// querySelector('#minus').onClick.listen((e) => _changeGrid(5)); + } + }); + +} + + + +//when a button is clicked delete all the other Loops containing games and replace them with a canvas (fn above) \ No newline at end of file