diff --git a/lib/components/controls_component.dart b/lib/components/controls_component.dart
index 1f2a65d..511a7d4 100644
--- a/lib/components/controls_component.dart
+++ b/lib/components/controls_component.dart
@@ -1,8 +1,6 @@
import 'package:angular/angular.dart';
import 'package:angular_components/angular_components.dart';
-import 'package:rules_of_living/service/configuration_service.dart';
import 'package:rules_of_living/service/engine_service.dart';
-import 'package:rules_of_living/src/Engine.dart';
@Component(
selector: 'sim-controls',
@@ -17,13 +15,12 @@ import 'package:rules_of_living/src/Engine.dart';
styleUrls: const ["controls_component.css"],
)
class ControlsComponent {
- final EngineService engineService;
+ final EngineService engine;
- Engine get engine => engineService.engine;
- ControlsComponent(this.engineService);
+ ControlsComponent(this.engine);
void onStartClicked() {
- engine.running = !engine.running;
+ engine.toggleRunning();
}
void onStepClicked() {
@@ -35,8 +32,7 @@ class ControlsComponent {
}
void onRandomClicked() {
- engine.running = false;
- engine.addPattern();
+ engine.addRandomPattern();
}
void onClearClicked() {
diff --git a/lib/components/controls_component.html b/lib/components/controls_component.html
index 30ddf55..42e79f7 100644
--- a/lib/components/controls_component.html
+++ b/lib/components/controls_component.html
@@ -1,7 +1,7 @@
-
+
diff --git a/lib/components/simulation_component.dart b/lib/components/simulation_component.dart
index e64fa82..12b7844 100644
--- a/lib/components/simulation_component.dart
+++ b/lib/components/simulation_component.dart
@@ -8,7 +8,6 @@ import 'package:rules_of_living/service/engine_service.dart';
templateUrl: "simulation_component.html",
directives: [coreDirectives],
providers: [],
-// styleUrls: const ['package:angular_components/app_layout/layout.scss.css'],
)
class SimulationComponent implements OnInit {
final EngineService engineService;
@@ -26,16 +25,10 @@ class SimulationComponent implements OnInit {
canvas.context2D.fillRect(0, 0, canvas.width, canvas.height);
canvas.context2D.setFillColorRgb(0, 255, 0);
canvas.context2D.fillText('''
- If you see this\n
- the app is broken :(
+ If you see this
+
+ the canvas did not load correctly :(
''', canvas.width / 2 - 50, canvas.height / 2);
- engineService.create(canvas);
-
- html.window.animationFrame.then(animFrame);
- }
-
- void animFrame(num now) {
- engineService.engine.process(now);
- html.window.animationFrame.then(animFrame);
+ engineService.canvas = canvas;
}
}
diff --git a/lib/service/engine_service.dart b/lib/service/engine_service.dart
index 5107f3c..d7b0bed 100644
--- a/lib/service/engine_service.dart
+++ b/lib/service/engine_service.dart
@@ -5,7 +5,45 @@ import 'package:rules_of_living/src/Engine.dart';
class EngineService {
Engine _engine;
- Engine get engine => _engine;
+ Engine get engine => _engine ?? createEngine(null);
+
+ Engine createEngine(html.CanvasElement canvas) {
+ _engine = Engine(canvas);
+ return _engine;
+ }
+
+ void set canvas(html.CanvasElement canvas) => engine.canvas = canvas;
+ html.CanvasElement get canvas => engine.canvas;
+
+ void run() {
+ engine.running = true;
+ }
+
+ void stop() {
+ engine.running = false;
+ }
+
+ void toggleRunning() {
+ engine.running = !engine.running;
+ }
+
+ void step() {
+ engine.step();
+ }
+
+ void reset() {
+ engine.reset();
+ }
+
+ void addRandomPattern() {
+ engine.running = false;
+ engine.addPattern();
+ }
+
+ void clear() {
+ engine.clear();
+ }
+
+ bool get isRunning => engine.running;
- void create(html.CanvasElement canvas) => _engine = Engine(canvas);
}
diff --git a/lib/src/Engine.dart b/lib/src/Engine.dart
index 6f7ff16..539e6d2 100644
--- a/lib/src/Engine.dart
+++ b/lib/src/Engine.dart
@@ -6,7 +6,7 @@ class Engine {
// Elapsed Time Counter - useful for Safety Timeout
Stopwatch _elapsed = new Stopwatch();
- // Game Tick Rate - *does* impact game speed
+ // Game Tick Rate - *does* impact game speed TODO add configurable option
int _MS_PER_STEP = 1000 ~/ 3;
// Max Frame (i.e. Rendering) rate - does *not* impact game speed
@@ -15,16 +15,31 @@ class Engine {
// ms stuck in updateloop after which game will declare itself unresponsive
final int SAFETY_TIMEOUT = 2000;
+ // Grid Size TODO add as configurable option
+ static final GRID_X = 100;
+ static final GRID_Y = 100;
+
num _updateLag = 0.0;
num _drawLag = 0.0;
- final html.CanvasElement canvas;
- Grid _grid = new Grid(100, 100);
- bool _running = false;
+ /// The Canvas to Paint on
+ ///
+ /// Manually define or change the canvas the engine should render to. Should
+ /// be used if no canvas was defined at engine creation and it should be
+ /// rendered later.
+ html.CanvasElement canvas;
+ Grid _grid = new Grid(GRID_X, GRID_Y);
+ bool running = false;
- Engine(this.canvas) {
+ Engine([this.canvas]) {
_elapsed.start();
_grid.addPattern(amount: 15, dispersal: 5);
+ html.window.animationFrame.then(animFrame);
+ }
+
+ void animFrame(num now) {
+ process(now);
+ html.window.animationFrame.then(animFrame);
}
void reset() {
@@ -33,7 +48,7 @@ class Engine {
}
void clear() {
- _grid = new Grid(100, 100);
+ _grid = new Grid(GRID_X, GRID_Y);
running = false;
}
@@ -58,19 +73,32 @@ class Engine {
}
}
+ /// Update Engine Logic
+ ///
+ /// Updates the logic of the engine by one tick. Should usually not be called
+ /// directly, since it is automatically taken care of by the processing function.
+ /// If simulation should be advanced manually one time, prefer using step().
void update() {
-// print("updating");
if (!_grid.update()) running = false;
}
+ /// Advances Logic One Update
+ ///
+ /// Moves logic of the engine one step forward and pauses the
+ /// simulation. Does not automatically re-render the new state
+ /// (though this should usually not pose a problem).
void step() {
running = false;
_grid.update();
}
+ /// Renders the Current Simulation State
+ ///
+ /// Renders the simulation once. Will usually automatically be called by
+ /// the internal engine processing. Does not do anything if no canvas is
+ /// defined.
void render([num interp]) {
-// print("rendering");
- _grid.render(canvas, interp);
+ if(canvas != null) _grid.render(canvas, interp);
}
void addPattern(
@@ -92,7 +120,4 @@ class Engine {
void toggleEdgeRendering() {
_grid.renderEdges = !_grid.renderEdges;
}
-
- void set running(bool on) => _running = on;
- bool get running => _running;
}
diff --git a/test/app_test.dart b/test/app_test_disable.dart
similarity index 100%
rename from test/app_test.dart
rename to test/app_test_disable.dart
diff --git a/test/service/engine_service_test.dart b/test/service/engine_service_test.dart
new file mode 100644
index 0000000..9d4a226
--- /dev/null
+++ b/test/service/engine_service_test.dart
@@ -0,0 +1,19 @@
+@TestOn('browser')
+
+import 'package:test/test.dart';
+import 'package:rules_of_living/service/engine_service.dart';
+
+void main() {
+ EngineService sut;
+ setUp(() {
+ sut = EngineService();
+ });
+
+ test("EngineService creates an engine on demand", () {
+ expect(sut.engine, isNotNull);
+ });
+
+ test("EngineService returns the cached engine on subsequent requests", () {
+ expect(sut.engine, allOf(isNotNull, equals(sut.engine)));
+ });
+}
diff --git a/test/src/engine_test.dart b/test/src/engine_test.dart
new file mode 100644
index 0000000..0712ba8
--- /dev/null
+++ b/test/src/engine_test.dart
@@ -0,0 +1,32 @@
+import 'dart:html' as html;
+
+@TestOn('browser')
+
+import 'package:rules_of_living/src/Engine.dart';
+import 'package:test/test.dart';
+
+void main() {
+ Engine sut;
+ setUp(() {
+ sut = Engine();
+ });
+
+ test("Engine can be instantiated without canvas", () {
+ expect(sut, isNot(throwsNoSuchMethodError));
+ });
+
+ test("Engine does not throw errors when calling render directly", () {
+ // anonymous function necessary since throws can not use functions with args
+ expect(() => sut.render(), isNot(throwsNoSuchMethodError));
+ });
+
+ test("Engine does not throw errors when processing without attached canvas", () {
+ // anonymous function necessary since throws can not use functions with args
+ expect(() => sut.process(1000), isNot(throwsNoSuchMethodError));
+ });
+
+ test("setCanvas allows setting a canvas for an engine at any point", () {
+ sut.canvas = new html.CanvasElement();
+ expect(sut.canvas, isNotNull);
+ });
+}
\ No newline at end of file