puzzle racer WIP

puzzle-racer-road-translate
Thibault Duplessis 2021-03-06 13:19:57 +01:00
parent c7cfc0c925
commit be6e80dfa3
7 changed files with 115 additions and 73 deletions

View File

@ -24,14 +24,17 @@ final class RacerJson(stormJson: StormJson, sign: StormSign, lightUserSync: Ligh
// full race data
def data(race: RacerRace, player: RacerPlayer) =
Json.obj(
"race" -> Json.obj(
"id" -> race.id.value,
"moves" -> race.moves
),
"player" -> player,
"puzzles" -> race.puzzles
) ++ state(race)
Json
.obj(
"race" -> Json
.obj(
"id" -> race.id.value,
"moves" -> race.moves
)
.add("alreadyStarted" -> race.hasStarted),
"player" -> player,
"puzzles" -> race.puzzles
) ++ state(race)
// socket updates
def state(race: RacerRace) = Json

View File

@ -40,6 +40,8 @@ case class RacerRace(
def startsInMillis = startsAt.map(d => d.getMillis - nowMillis)
def hasStarted = startsInMillis.pp.exists(_ <= 0)
lazy val moves = puzzles.foldLeft(0) { case (m, p) =>
m + p.line.size / 2
}

View File

@ -0,0 +1,63 @@
.racer {
&__countdown {
@extend %box-radius, %popup-shadow, %flex-center-nowrap;
background: $c-bg-zebra;
z-index: 100;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 2em 3em;
&__lights {
display: flex;
flex-flow: column;
background-color: #3a3a3a;
width: 60px;
height: 160px;
border-radius: 15px;
margin-right: 2em;
light {
width: 40px;
height: 40px;
margin-top: 10px;
margin-left: 10px;
vertical-align: middle;
border-radius: 100%;
display: block;
opacity: 0.3;
transition: all 1s;
&.active {
opacity: 1;
}
&.red {
background: $c-red;
&.active {
box-shadow: 0 0 2em $c-red, 0 0 4em $c-red;
}
}
&.orange {
background: $c-brag;
&.active {
box-shadow: 0 0 2em $c-brag, 0 0 4em $c-brag;
}
}
&.green {
background: $c-good;
&.active {
box-shadow: 0 0 2em $c-good, 0 0 4em $c-good;
}
}
}
}
&__seconds {
@extend %flex-center;
font-family: 'storm';
font-size: 8em;
color: $c-font;
margin-bottom: -0.23em;
}
}
}

View File

@ -1,4 +1,5 @@
@import 'race';
@import 'countdown';
.racer {
&__race {
@ -18,65 +19,19 @@
'board side';
}
&__countdown {
@extend %box-radius, %popup-shadow, %flex-center-nowrap;
background: $c-bg-zebra;
z-index: 100;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 2em 3em;
&__started {
@extend %flex-column;
&__lights {
display: flex;
flex-flow: column;
background-color: #3a3a3a;
width: 60px;
height: 160px;
border-radius: 15px;
margin-right: 2em;
justify-content: stretch;
text-align: center;
light {
width: 40px;
height: 40px;
margin-top: 10px;
margin-left: 10px;
vertical-align: middle;
border-radius: 100%;
display: block;
opacity: 0.3;
transition: all 1s;
&.active {
opacity: 1;
}
&.red {
background: $c-red;
&.active {
box-shadow: 0 0 2em $c-red, 0 0 4em $c-red;
}
}
&.orange {
background: $c-brag;
&.active {
box-shadow: 0 0 2em $c-brag, 0 0 4em $c-brag;
}
}
&.green {
background: $c-good;
&.active {
box-shadow: 0 0 2em $c-good, 0 0 4em $c-good;
}
}
}
i {
font-size: 15em;
line-height: 1.2em;
}
&__seconds {
@extend %flex-center;
font-family: 'storm';
font-size: 8em;
color: $c-font;
margin-bottom: -0.23em;
p {
margin: 3em 0;
}
}
}

View File

@ -57,6 +57,7 @@ export default class StormCtrl {
lichess.socket = new lichess.StrongSocket(`/racer/${this.race.id}`, false);
lichess.pubsub.on('socket.in.racerState', this.serverUpdate);
this.startCountdown();
console.log(this.race);
}
serverUpdate = (data: UpdatableData) => {

View File

@ -25,6 +25,7 @@ export interface RacerData extends UpdatableData {
export interface Race {
id: string;
moves: number;
alreadyStarted?: boolean;
}
export interface Player {

View File

@ -47,16 +47,20 @@ const chessground = (ctrl: RacerCtrl): VNode =>
const renderPlay = (ctrl: RacerCtrl): VNode[] => [
renderRace(ctrl),
h('div.puz-board.main-board', [
chessground(ctrl),
ctrl.promotion.view(),
ctrl.countdownSeconds() ? renderCountdown(ctrl.countdownSeconds()) : undefined,
]),
h('div.puz-side', [
ctrl.run.clock.startAt ? renderSolved(ctrl.run) : renderStart(),
ctrl.isPlayer() ? renderClock(ctrl.run, ctrl.endNow) : renderJoin(ctrl),
h('div.puz-side__table', [renderCombo(config)(ctrl.run)]),
]),
...(ctrl.race.alreadyStarted
? [renderStarted()]
: [
h('div.puz-board.main-board', [
chessground(ctrl),
ctrl.promotion.view(),
ctrl.countdownSeconds() ? renderCountdown(ctrl.countdownSeconds()) : undefined,
]),
h('div.puz-side', [
ctrl.run.clock.startAt ? renderSolved(ctrl.run) : renderStart(),
ctrl.isPlayer() ? renderClock(ctrl.run, ctrl.endNow) : renderJoin(ctrl),
h('div.puz-side__table', [renderCombo(config)(ctrl.run)]),
]),
]),
];
const renderCountdown = (seconds: number) =>
@ -94,3 +98,16 @@ const renderStart = () =>
'div.puz-side__top.puz-side__start',
h('div.puz-side__start__text', [h('strong', 'Puzzle Racer'), h('span', 'Waiting to start')])
);
const renderStarted = () =>
h('div.racer__started.box.box-pad', [
h('i', { attrs: { 'data-icon': '~' } }),
h('p', 'This race has already started!'),
h(
'a.storm--dup__reload.button',
{
attrs: { href: '/racer' },
},
'New race'
),
]);