diff --git a/packages/flappy-bird-demo/src/index.js b/packages/flappy-bird-demo/src/index.js
index 48fa803..10c291d 100644
--- a/packages/flappy-bird-demo/src/index.js
+++ b/packages/flappy-bird-demo/src/index.js
@@ -17,6 +17,8 @@
// along with this program. If not, see .
//---------------------------------------------------------------------------
+import { $QuitDataspace, Inbound, Outbound, Dataspace } from "@syndicate-lang/core";
+
let UI = activate require("@syndicate-lang/driver-browser-ui");
// @jsx UI.html
// @jsxFrag UI.htmlFragment
@@ -27,7 +29,6 @@ assertion type Position(x, y);
assertion type GameOver();
assertion type Score(count);
message type IncreaseScore();
-
message type Reset();
const BOARD_HEIGHT = 567;
@@ -39,143 +40,10 @@ const PILLAR_GAP = 158;
const FIELD_HEIGHT = 561;
const PILLAR_HEAD_HEIGHT = 40;
-function newGame() {
- spawn named 'score' {
- let ui = new UI.Anchor();
- field this.score = 0;
-
- stop on message Reset();
-
- assert Score(this.score);
-
- on start react {
- assert ui.html('#board-area',
{this.score}
);
- stop on asserted GameOver() react {
- assert ui.html('#board-area', {this.score}
GAME OVER
);
- }
- }
-
- on message IncreaseScore() {
- this.score++;
- }
- }
-
- spawn named 'flappy' {
- let ui = new UI.Anchor();
- field this.xpos = 0;
- field this.ypos = 312;
- field this.yvel = 0;
-
- stop on message Reset();
-
- assert Position(this.xpos, this.ypos);
-
- assert ui.html('#board-area', );
-
- on (this.ypos > BOARD_HEIGHT - FLAPPY_HEIGHT) {
- this.ypos = BOARD_HEIGHT - FLAPPY_HEIGHT;
- react {
- assert GameOver();
- }
- }
-
- on start react {
- stop on asserted GameOver();
-
- on message UI.WindowEvent('+keypress', $e) {
- this.yvel = -10;
- }
-
- const ms_per_tick = 1000.0 / 60;
- on message PeriodicTick(ms_per_tick) {
- this.xpos += 0.15 * ms_per_tick;
- this.ypos = (this.ypos + this.yvel);
- this.yvel += ms_per_tick * 0.05;
- }
- }
- }
-
- spawn named 'border-scroll' {
- let ui = new UI.Anchor();
- field this.pos = 0;
- on asserted Position($xpos, _) this.pos = xpos % 23;
- assert ui.html(
- '#board-area',
- , 0);
-
- stop on message Reset();
- }
-
- spawn named 'pipe-factory' {
- on start spawnPipe(0);
- field this.nextPipe = 1;
-
- stop on message Reset();
-
- on asserted Score(this.nextPipe) {
- spawnPipe(this.nextPipe++);
- }
- }
-
- function spawnPipe(i) {
- spawn named ['pipe', i] {
- stop on message Reset();
-
- let ui = new UI.Anchor();
-
- const xlocation = (i + 1) * 324;
-
- const upperHeight =
- Math.random() * (FIELD_HEIGHT - PILLAR_GAP - PILLAR_HEAD_HEIGHT * 6)
- + PILLAR_HEAD_HEIGHT * 3;
- const lowerHeight = FIELD_HEIGHT - upperHeight - PILLAR_GAP;
-
- stop on (this.xpos < -(PILLAR_WIDTH + FLAPPY_XPOS));
-
- on start react stop on (this.xpos <= 0) {
- ^ IncreaseScore();
- }
-
- field this.xpos = xlocation;
- on asserted Position($xpos, _) this.xpos = xlocation - xpos;
-
- on asserted Position($xpos, $ypos) {
- if (touchingPillar(xpos, ypos)) {
- react {
- assert GameOver();
- }
- }
- }
-
- assert ui.html(
- '#board-area',
- );
-
- function touchingPillar(xpos, ypos) {
- const inHorizontalRange =
- (xpos + FLAPPY_WIDTH >= xlocation) && (xpos <= xlocation + PILLAR_WIDTH);
- const aboveGapTop = (ypos <= upperHeight);
- const belowGapBottom = (ypos + FLAPPY_HEIGHT >= upperHeight + PILLAR_GAP);
- return inHorizontalRange && (aboveGapTop || belowGapBottom);
- }
- }
- }
-}
-
spawn named 'game-factory' {
- on start newGame();
-
- // TODO: Use nested dataspaces to clean up restarts
-
+ on start spawnGame();
during GameOver() {
- on stop newGame();
+ on stop spawnGame();
on message UI.WindowEvent('+keypress', $e) {
if (e.key !== ' ') {
^ Reset();
@@ -183,3 +51,130 @@ spawn named 'game-factory' {
}
}
}
+
+function spawnGame() {
+ spawn dataspace named 'GameInstance' {
+ spawn named 'game-instance-control' {
+ during GameOver() assert Outbound(GameOver());
+ on message Inbound(Reset()) {
+ ^ $QuitDataspace;
+ }
+ }
+
+ spawn named 'score' {
+ let ui = new UI.Anchor();
+ field this.score = 0;
+
+ assert Score(this.score);
+
+ on start react {
+ assert Outbound(ui.html('#board-area', {this.score}
));
+ stop on asserted GameOver() react {
+ assert Outbound(ui.html('#board-area', {this.score}
GAME OVER
));
+ }
+ }
+
+ on message IncreaseScore() {
+ this.score++;
+ }
+ }
+
+ spawn named 'flappy' {
+ let ui = new UI.Anchor();
+ field this.xpos = 0;
+ field this.ypos = 312;
+ field this.yvel = 0;
+
+ assert Position(this.xpos, this.ypos);
+
+ assert Outbound(ui.html('#board-area', ));
+
+ on (this.ypos > BOARD_HEIGHT - FLAPPY_HEIGHT) {
+ this.ypos = BOARD_HEIGHT - FLAPPY_HEIGHT;
+ react {
+ assert GameOver();
+ }
+ }
+
+ on start react {
+ stop on asserted GameOver();
+
+ on message Inbound(UI.WindowEvent('+keypress', $e)) {
+ this.yvel = -10;
+ }
+
+ const ms_per_tick = 1000.0 / 60;
+ on message Inbound(PeriodicTick(ms_per_tick)) {
+ this.xpos += 0.15 * ms_per_tick;
+ this.ypos = (this.ypos + this.yvel);
+ this.yvel += ms_per_tick * 0.05;
+ }
+ }
+ }
+
+ spawn named 'border-scroll' {
+ let ui = new UI.Anchor();
+ field this.pos = 0;
+ on asserted Position($xpos, _) this.pos = xpos % 23;
+ assert Outbound(ui.html(
+ '#board-area',
+ , 0));
+ }
+
+ spawn named 'pipe-factory' {
+ field this.nextPipe = 0;
+ on asserted Score(this.nextPipe) {
+ spawnPipe(this.nextPipe++);
+ }
+ }
+
+ function spawnPipe(i) {
+ spawn named ['pipe', i] {
+ let ui = new UI.Anchor();
+
+ const xlocation = (i + 1) * 324;
+
+ const upperHeight =
+ Math.random() * (FIELD_HEIGHT - PILLAR_GAP - PILLAR_HEAD_HEIGHT * 6)
+ + PILLAR_HEAD_HEIGHT * 3;
+ const lowerHeight = FIELD_HEIGHT - upperHeight - PILLAR_GAP;
+
+ stop on (this.xpos < -(PILLAR_WIDTH + FLAPPY_XPOS));
+
+ on start react stop on (this.xpos <= 0) {
+ ^ IncreaseScore();
+ }
+
+ field this.xpos = xlocation;
+ on asserted Position($xpos, _) this.xpos = xlocation - xpos;
+
+ on asserted Position($xpos, $ypos) {
+ if (touchingPillar(xpos, ypos)) {
+ react {
+ assert GameOver();
+ }
+ }
+ }
+
+ assert Outbound(ui.html(
+ '#board-area',
+ ));
+
+ function touchingPillar(xpos, ypos) {
+ const inHorizontalRange =
+ (xpos + FLAPPY_WIDTH >= xlocation) && (xpos <= xlocation + PILLAR_WIDTH);
+ const aboveGapTop = (ypos <= upperHeight);
+ const belowGapBottom = (ypos + FLAPPY_HEIGHT >= upperHeight + PILLAR_GAP);
+ return inHorizontalRange && (aboveGapTop || belowGapBottom);
+ }
+ }
+ }
+ }
+}