From c29359f7ceede0fb0860f7cb791483bd4ad802a7 Mon Sep 17 00:00:00 2001 From: Paolo Brasolin <paolo.brasolin@eurac.edu> Date: Wed, 30 Mar 2022 11:11:20 +0200 Subject: [PATCH] feat: #be #fe fully track game events --- backend/src/api.ts | 2 +- backend/src/schemas.ts | 15 ++++++++++++--- frontend/src/js/fight_scene.ts | 26 ++++++++++++++++---------- frontend/src/js/foe.ts | 17 ++++++----------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/backend/src/api.ts b/backend/src/api.ts index 39605ba..df68b72 100644 --- a/backend/src/api.ts +++ b/backend/src/api.ts @@ -177,7 +177,7 @@ const apiPlugin: FastifyPluginCallback = (fastify, options, next) => { handler: async (request, reply) => { const shots = await connection .table("shots") - .insert(request.body) + .insert({ game_id: request.params.id, ...request.body }) .returning<Types.Shot[]>("*"); reply.code(200).send(shots[0]); diff --git a/backend/src/schemas.ts b/backend/src/schemas.ts index 64068e7..b409b29 100644 --- a/backend/src/schemas.ts +++ b/backend/src/schemas.ts @@ -35,7 +35,16 @@ export const Shot = Type.Object({ final: Type.String(), }); -export const GameUpdate = Type.Omit(Game, ["id"]); -export const ClueCreate = Type.Pick(Clue, ["word_id"]); -export const ClueUpdate = Type.Pick(Clue, ["began_at", "ended_at"]); +export const GameUpdate = Type.Partial( + Type.Pick(Game, ["began_at", "ended_at"]), +); + +export const ClueUpdate = Type.Partial( + Type.Pick(Clue, ["began_at", "ended_at"]), +); +export const ClueCreate = Type.Intersect([ + Type.Pick(Clue, ["word_id"]), + ClueUpdate, +]); + export const ShotCreate = Type.Omit(Shot, ["id", "game_id"]); diff --git a/frontend/src/js/fight_scene.ts b/frontend/src/js/fight_scene.ts index e26e475..47741fd 100644 --- a/frontend/src/js/fight_scene.ts +++ b/frontend/src/js/fight_scene.ts @@ -122,7 +122,6 @@ export default class FightScene extends Phaser.Scene { this.beGame = ( await backend.updateGame(this.beGame.id, { began_at: new Date().toISOString(), - ended_at: null, }) ).data; @@ -230,7 +229,6 @@ export default class FightScene extends Phaser.Scene { async endGame() { this.beGame = ( await backend.updateGame(this.beGame.id, { - began_at: this.beGame.began_at, // TODO: make this optional in the type ended_at: new Date().toISOString(), }) ).data; @@ -238,11 +236,11 @@ export default class FightScene extends Phaser.Scene { this.scene.start("game_over"); } - showSubmitFeedback(color: string) { + showSubmitFeedback(color: string, input: string) { const text = this.add.text( this.cameras.main.width / 2, this.cameras.main.height / 2, - this.hud.input.text, + input, { font: "bold 64px Courier", color: color, @@ -300,21 +298,29 @@ export default class FightScene extends Phaser.Scene { } submitTranscription(inputStatus: InputStatus) { + // NOTE: this ain't async to avoid any UX delay const { score, match } = this.findMatchingFoe(inputStatus.final); - // TODO: visual near misses based on score + backend.createShot(this.beGame.id, { + clue_id: match?.beClue?.id || null, + ...inputStatus, + }); if (match === null) { // NOOP - this.showSubmitFeedback("#FFFFFF"); + this.showSubmitFeedback("#FFFFFF", inputStatus.final); } else if (score < 0.9) { + // TODO: visual near misses based on score this.updateScore(-1); match.handleFailure(); - this.showSubmitFeedback("#FF0000"); + this.showSubmitFeedback("#FF0000", inputStatus.final); new Spear(this, this.player, undefined); } else { + backend.updateClue(match.beClue.id, { + ended_at: new Date().toISOString(), + }); this.updateScore(+10); this.popFoe(match); match.handleSuccess(); - this.showSubmitFeedback("#00FF00"); + this.showSubmitFeedback("#00FF00", inputStatus.final); new Spear(this, this.player, match.critter); // TODO: increase score } @@ -323,17 +329,17 @@ export default class FightScene extends Phaser.Scene { createAndBindTypewriter() { this.typewriter ??= new Typewriter(); this.typewriter.setHidden(this.game.device.os.desktop); - this.typewriter.onSubmit = (inputStatus) => { + this.typewriter.onSubmit = async (inputStatus) => { if (inputStatus.began_at === null) return; if (inputStatus.ended_at === null) return; if (inputStatus.final === "") return; + this.hud.input.text = ""; this.submitTranscription({ began_at: inputStatus.began_at.toISOString(), ended_at: inputStatus.ended_at.toISOString(), typed: inputStatus.typed, final: inputStatus.final, }); - this.hud.input.text = ""; }; this.typewriter.onChange = (inputStatus) => { this.hud.input.text = inputStatus.final; diff --git a/frontend/src/js/foe.ts b/frontend/src/js/foe.ts index 04baaa1..411b3d9 100644 --- a/frontend/src/js/foe.ts +++ b/frontend/src/js/foe.ts @@ -21,17 +21,12 @@ class Foe { async initialize() { this.beWord = (await backend.getWord()).data; if (!this.scene.scene.isActive()) return; - // this.beClue = ( - // await backend.createClue(this.scene.beGame.id, { - // word_id: this.beWord.id, - // }) - // ).data; - // this.beClue = ( - // await backend.updateClue(this.beClue.id, { - // began_at: new Date().toISOString(), - // ended_at: null, - // }) - // ).data; + this.beClue = ( + await backend.createClue(this.scene.beGame.id, { + word_id: this.beWord.id, + began_at: new Date().toISOString(), + }) + ).data; this.clue = new Clue(this.scene, this.beWord); this.critter = new Critter(this.scene); -- GitLab