Bring the flappy-bird example up to date
This commit is contained in:
parent
a3484d4a07
commit
a8e542a394
|
@ -12,6 +12,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
<script>Syndicate.bootModule(Main.__SYNDICATE__bootProc);</script>
|
<script>Main.main();</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/// SPDX-License-Identifier: GPL-3.0-or-later
|
/// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
||||||
|
|
||||||
import { $QuitDataspace, Double, Facet, Inbound, Outbound, floatValue } from '@syndicate-lang/core';
|
import { Record, Dataspace, Double, floatValue, Ref, stringify } from '@syndicate-lang/core';
|
||||||
activate import { WindowEvent, template, Anchor } from '@syndicate-lang/html';
|
import { boot as bootHtml, WindowEvent, template, Anchor } from '@syndicate-lang/html';
|
||||||
activate import { PeriodicTick } from '@syndicate-lang/timer';
|
import { boot as bootTimer, PeriodicTick } from '@syndicate-lang/timer';
|
||||||
|
|
||||||
assertion type Position(x, y);
|
assertion type Position(x, y);
|
||||||
assertion type GameOver();
|
assertion type GameOver();
|
||||||
|
@ -20,127 +20,168 @@ const PILLAR_GAP = 158;
|
||||||
const FIELD_HEIGHT = 561;
|
const FIELD_HEIGHT = 561;
|
||||||
const PILLAR_HEAD_HEIGHT = 40;
|
const PILLAR_HEAD_HEIGHT = 40;
|
||||||
|
|
||||||
boot {
|
export function main() {
|
||||||
spawn named 'game-factory' {
|
Dataspace.boot(mainDs => {
|
||||||
on start spawnGame(thisFacet);
|
bootHtml(mainDs);
|
||||||
during GameOver() => {
|
bootTimer(mainDs);
|
||||||
on stop spawnGame(thisFacet);
|
spawn named 'game-factory' {
|
||||||
on message WindowEvent('+keypress', $_e) => send message Reset();
|
spawnGame(mainDs);
|
||||||
on message WindowEvent('+click', $_e) => send message Reset();
|
at mainDs {
|
||||||
|
during GameOver() => {
|
||||||
|
on stop spawnGame(mainDs);
|
||||||
|
on message WindowEvent('+keypress', $_e) => send message Reset();
|
||||||
|
on message WindowEvent('+click', $_e) => send message Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnGame<T>(thisFacet: Facet<T>) {
|
function spawnGame(mainDs: Ref) {
|
||||||
spawn dataspace named 'GameInstance' {
|
spawn named 'GameInstance' {
|
||||||
spawn named 'game-instance-control' {
|
const gameDs = create new Dataspace();
|
||||||
during GameOver() => assert Outbound(GameOver());
|
|
||||||
on message Inbound(Reset()) => send message $QuitDataspace;
|
at gameDs {
|
||||||
|
during GameOver() => at mainDs {
|
||||||
|
assert GameOver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
at mainDs {
|
||||||
|
stop on message Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn named 'score' {
|
spawn linked named 'score' {
|
||||||
let ui = new Anchor();
|
let ui = new Anchor();
|
||||||
field score: number = 0;
|
field score: number = 0;
|
||||||
|
|
||||||
assert Score(this.score);
|
at gameDs {
|
||||||
|
assert Score(score.value);
|
||||||
on start react {
|
on message IncreaseScore() => score.value++;
|
||||||
assert Outbound(ui.html('#board-area',
|
|
||||||
template`<h1 class="score">${this.score}</h1>`));
|
|
||||||
stop on asserted GameOver() => react {
|
|
||||||
assert Outbound(ui.html('#board-area',
|
|
||||||
template`<h1 class="score">${this.score}<br/>GAME OVER</h1>`));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
on message IncreaseScore() => this.score++;
|
react {
|
||||||
|
at mainDs {
|
||||||
|
assert ui.html('#board-area', template`<h1 class="score">${score.value}</h1>`);
|
||||||
|
}
|
||||||
|
at gameDs {
|
||||||
|
stop on asserted GameOver() => react {
|
||||||
|
at mainDs {
|
||||||
|
assert ui.html(
|
||||||
|
'#board-area',
|
||||||
|
template`<h1 class="score">${score.value}<br/>GAME OVER</h1>`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn named 'flappy' {
|
spawn linked named 'flappy' {
|
||||||
let ui = new Anchor();
|
let ui = new Anchor();
|
||||||
field xpos: number = 0;
|
field xpos: number = 0;
|
||||||
field ypos: number = 312;
|
field ypos: number = 312;
|
||||||
field yvel: number = 0;
|
field yvel: number = 0;
|
||||||
|
|
||||||
assert Position(Double(this.xpos), Double(this.ypos));
|
at gameDs {
|
||||||
|
assert Position(Double(xpos.value), Double(ypos.value));
|
||||||
|
|
||||||
assert Outbound(
|
on (ypos.value > BOARD_HEIGHT - FLAPPY_HEIGHT) {
|
||||||
ui.html('#board-area',
|
ypos.value = BOARD_HEIGHT - FLAPPY_HEIGHT;
|
||||||
template`<div class="flappy"
|
react {
|
||||||
style="${`transform: rotate(${2 * this.yvel}deg);
|
assert GameOver();
|
||||||
top: ${this.ypos}px`}"></div>`));
|
}
|
||||||
|
|
||||||
on (this.ypos > BOARD_HEIGHT - FLAPPY_HEIGHT) {
|
|
||||||
this.ypos = BOARD_HEIGHT - FLAPPY_HEIGHT;
|
|
||||||
react {
|
|
||||||
assert GameOver();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
on start react {
|
at mainDs {
|
||||||
stop on asserted GameOver();
|
assert ui.html(
|
||||||
|
'#board-area',
|
||||||
|
template`<div class="flappy"
|
||||||
|
style="${`transform: rotate(${2 * yvel.value}deg);
|
||||||
|
top: ${ypos.value}px`}"></div>`);
|
||||||
|
}
|
||||||
|
|
||||||
on message Inbound(WindowEvent('+keypress', $_e)) => this.yvel = -10;
|
react {
|
||||||
on message Inbound(WindowEvent('+click', $_e)) => this.yvel = -10;
|
at gameDs {
|
||||||
|
stop on asserted GameOver();
|
||||||
|
}
|
||||||
|
|
||||||
const ms_per_tick = 1000.0 / 60;
|
at mainDs {
|
||||||
on message Inbound(PeriodicTick(Double(ms_per_tick))) => {
|
on message WindowEvent('+keypress', $_e) => yvel.value = -10;
|
||||||
this.xpos += 0.15 * ms_per_tick;
|
on message WindowEvent('+click', $_e) => yvel.value = -10;
|
||||||
this.ypos = (this.ypos + this.yvel);
|
|
||||||
this.yvel += ms_per_tick * 0.05;
|
const ms_per_tick = 1000.0 / 60;
|
||||||
|
const ms_per_tick_d = Double(ms_per_tick);
|
||||||
|
on message PeriodicTick(ms_per_tick_d) => {
|
||||||
|
xpos.value += 0.15 * ms_per_tick;
|
||||||
|
ypos.value = (ypos.value + yvel.value);
|
||||||
|
yvel.value += ms_per_tick * 0.05;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn named 'border-scroll' {
|
spawn linked named 'border-scroll' {
|
||||||
let ui = new Anchor();
|
let ui = new Anchor();
|
||||||
field pos: number = 0;
|
field pos: number = 0;
|
||||||
on asserted Position($xpos, _) => this.pos = floatValue(xpos) % 23;
|
at gameDs {
|
||||||
assert Outbound(ui.html(
|
on asserted Position($xpos, _) => pos.value = floatValue(xpos) % 23;
|
||||||
'#board-area',
|
}
|
||||||
template`<div class="scrolling-border" style="${`background-position-x: ${-this.pos}px`}"></div>`,
|
at mainDs {
|
||||||
0));
|
assert ui.html(
|
||||||
|
'#board-area',
|
||||||
|
template`<div class="scrolling-border" style="${`background-position-x: ${-pos.value}px`}"></div>`,
|
||||||
|
0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spawn named 'pipe-factory' {
|
spawn linked named 'pipe-factory' {
|
||||||
field nextPipe: number = 0;
|
field nextPipe: number = 0;
|
||||||
on asserted Score(this.nextPipe) => spawnPipe(thisFacet, this.nextPipe++);
|
at gameDs {
|
||||||
|
on asserted Score(nextPipe.value) => spawnPipe(nextPipe.value++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnPipe<T>(thisFacet: Facet<T>, i: number) {
|
function spawnPipe(i: number) {
|
||||||
spawn named ['pipe', i] {
|
const xlocation = (i + 1) * 324;
|
||||||
let ui = new Anchor();
|
|
||||||
|
|
||||||
const xlocation = (i + 1) * 324;
|
spawn linked named ['pipe', i] {
|
||||||
|
let ui = new Anchor();
|
||||||
|
field xpos: number = xlocation;
|
||||||
|
|
||||||
const upperHeight =
|
const upperHeight =
|
||||||
Math.random() * (FIELD_HEIGHT - PILLAR_GAP - PILLAR_HEAD_HEIGHT * 6)
|
Math.random() * (FIELD_HEIGHT - PILLAR_GAP - PILLAR_HEAD_HEIGHT * 6)
|
||||||
+ PILLAR_HEAD_HEIGHT * 3;
|
+ PILLAR_HEAD_HEIGHT * 3;
|
||||||
const lowerHeight = FIELD_HEIGHT - upperHeight - PILLAR_GAP;
|
const lowerHeight = FIELD_HEIGHT - upperHeight - PILLAR_GAP;
|
||||||
|
|
||||||
stop on (this.xpos < -(PILLAR_WIDTH + FLAPPY_XPOS));
|
stop on (xpos.value < -(PILLAR_WIDTH + FLAPPY_XPOS));
|
||||||
|
|
||||||
on start react { stop on (this.xpos <= 0) send message IncreaseScore(); };
|
at gameDs {
|
||||||
|
react {
|
||||||
|
stop on (xpos.value <= 0) send message IncreaseScore();
|
||||||
|
}
|
||||||
|
|
||||||
field xpos: number = xlocation;
|
on asserted Position($flappyXpos, _) =>
|
||||||
on asserted Position($xpos, _) => this.xpos = xlocation - floatValue(xpos);
|
xpos.value = xlocation - floatValue(flappyXpos);
|
||||||
|
|
||||||
on asserted Position($xpos, $ypos) => {
|
on asserted Position($xpos, $ypos) => {
|
||||||
if (touchingPillar(floatValue(xpos), floatValue(ypos))) {
|
if (touchingPillar(floatValue(xpos), floatValue(ypos))) {
|
||||||
react {
|
react {
|
||||||
assert GameOver();
|
assert GameOver();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert Outbound(ui.html(
|
at mainDs {
|
||||||
'#board-area',
|
assert ui.html(
|
||||||
template`<div class="pillars">
|
'#board-area',
|
||||||
<div class="pillar pillar-upper"
|
template`<div class="pillars">
|
||||||
style="${`left: ${this.xpos + FLAPPY_XPOS}px; height: ${upperHeight}px;`}"></div>
|
<div class="pillar pillar-upper"
|
||||||
<div class="pillar pillar-lower"
|
style="${`left: ${xpos.value + FLAPPY_XPOS}px; height: ${upperHeight}px;`}"></div>
|
||||||
style="${`left: ${this.xpos + FLAPPY_XPOS}px; height: ${lowerHeight}px;`}"></div>
|
<div class="pillar pillar-lower"
|
||||||
</div>`));
|
style="${`left: ${xpos.value + FLAPPY_XPOS}px; height: ${lowerHeight}px;`}"></div>
|
||||||
|
</div>`);
|
||||||
|
}
|
||||||
|
|
||||||
function touchingPillar(xpos: number, ypos: number): boolean {
|
function touchingPillar(xpos: number, ypos: number): boolean {
|
||||||
const inHorizontalRange =
|
const inHorizontalRange =
|
||||||
|
|
Loading…
Reference in New Issue