Skip to content
Snippets Groups Projects
Commit 903a3bd2 authored by Paolo.Brasolin's avatar Paolo.Brasolin
Browse files

feat: #be #fe continue integrating API and refactoring Foe

parent bdc2fdf9
No related branches found
No related tags found
No related merge requests found
......@@ -105,17 +105,11 @@ const apiPlugin: FastifyPluginCallback = (fastify, options, next) => {
},
},
handler: async (request, reply) => {
const game = await connection<Types.Game>("games")
const games = await connection<Types.Game>("games")
.where("id", request.params.id)
.first();
if (game === undefined) {
reply.code(404).send();
} else {
const games = await connection<Types.Game>("games")
.update(request.body)
.returning("*");
reply.code(200).send(games[0]);
}
.update(request.body)
.returning("*");
reply.code(200).send(games[0]);
},
});
......@@ -136,7 +130,7 @@ const apiPlugin: FastifyPluginCallback = (fastify, options, next) => {
handler: async (request, reply) => {
const clues = await connection
.table("clues")
.insert(request.body)
.insert({ game_id: request.params.id, ...request.body })
.returning<Types.Clue[]>("*");
reply.code(200).send(clues[0]);
......@@ -158,17 +152,11 @@ const apiPlugin: FastifyPluginCallback = (fastify, options, next) => {
},
},
handler: async (request, reply) => {
const clue = await connection<Types.Clue>("clues")
const clues = await connection<Types.Clue>("clues")
.where("id", request.params.id)
.first();
if (clue === undefined) {
reply.code(404).send();
} else {
const clues = await connection<Types.Clue>("clues")
.update(request.body)
.returning("*");
reply.code(200).send(clues[0]);
}
.update(request.body)
.returning("*");
reply.code(200).send(clues[0]);
},
});
......
......@@ -36,6 +36,6 @@ export const Shot = Type.Object({
});
export const GameUpdate = Type.Omit(Game, ["id"]);
export const ClueCreate = Type.Pick(Clue, ["game_id", "word_id"]);
export const ClueCreate = Type.Pick(Clue, ["word_id"]);
export const ClueUpdate = Type.Pick(Clue, ["began_at", "ended_at"]);
export const ShotCreate = Type.Omit(Shot, ["id"]);
export const ShotCreate = Type.Omit(Shot, ["id", "game_id"]);
import "phaser";
import FightScene from "./fight_scene";
interface WordObject {
id: string;
image: string;
ocr_confidence: number;
ocr_transcript: string;
}
import * as Types from "../../../backend/src/types";
class Clue extends Phaser.GameObjects.Sprite {
word: WordObject;
word: Types.Word;
scene: FightScene;
constructor(scene: FightScene, word: WordObject) {
constructor(scene: FightScene, word: Types.Word) {
// TODO: set positions
super(scene, 400, 300, word.id);
scene.add.existing(this);
this.setAlpha(0);
scene.add.existing(this);
this.scene = scene;
this.word = word;
......@@ -26,6 +21,7 @@ class Clue extends Phaser.GameObjects.Sprite {
}
loadTexture() {
// this.scene.textures.remove()
this.scene.textures.addBase64(this.word.id, this.word.image);
this.scene.textures.once(
"addtexture",
......@@ -45,23 +41,35 @@ class Clue extends Phaser.GameObjects.Sprite {
5 +
this.width / 2;
this.setPosition(x, 50);
this.fadeIn();
}
delete() {
this.fadeOut(() => {
this.scene.textures.remove(this.texture); // TODO
this.destroy.bind(this);
});
}
fadeIn(onComplete?: Phaser.Types.Tweens.TweenOnCompleteCallback) {
this.scene.tweens.add({
targets: this,
alpha: 1,
ease: "Linear",
delay: 0,
duration: 100,
onComplete: onComplete,
});
}
delete() {
fadeOut(onComplete?: Phaser.Types.Tweens.TweenOnCompleteCallback) {
this.scene.tweens.add({
targets: this,
alpha: 0,
ease: "Linear",
delay: 0,
duration: 2000,
onComplete: this.destroy.bind(this),
duration: 100,
onComplete: onComplete,
});
}
}
......
import "phaser";
import Clue from "./clue";
import FightScene from "./fight_scene";
const SPECIES = ["bear", "wolf", "deer", "boar"];
......@@ -15,19 +14,17 @@ enum CritterState {
class Critter extends Phaser.Physics.Arcade.Sprite {
state: CritterState;
clue: Clue;
scene: FightScene;
species: string;
body: Phaser.Physics.Arcade.Body;
constructor(scene: FightScene, clue: Clue) {
constructor(scene: FightScene) {
const species = SPECIES[Math.floor(Math.random() * SPECIES.length)];
super(scene, -100, scene.cameras.main.height - 100, species);
scene.add.existing(this);
this.scene = scene;
this.species = species;
this.clue = clue;
let scale = 2;
if (this.species === "deer") {
......@@ -42,12 +39,7 @@ class Critter extends Phaser.Physics.Arcade.Sprite {
this.setScale(scale);
this.move();
this.scene.physics.add.overlap(this.scene.player, this, () => {
this.escape();
this.clue.delete();
});
this.walk();
}
preUpdate(time, delta) {
......@@ -68,7 +60,7 @@ class Critter extends Phaser.Physics.Arcade.Sprite {
return this.x + this.width * 0.5 < 0;
}
move() {
walk() {
this.state = CritterState.Moving;
this.flipX = true;
this.play({ key: this.species + "_walk", repeat: -1 });
......@@ -78,14 +70,14 @@ class Critter extends Phaser.Physics.Arcade.Sprite {
flee() {
this.state = CritterState.Fleeing;
this.flipX = false;
this.play(this.species + "_run");
this.play({ key: this.species + "_run", repeat: -1 });
this.body.setVelocity(FLEE_VELOCITY, 0);
}
escape() {
this.state = CritterState.Escaping;
this.flipX = true;
this.play(this.species + "_run");
this.play({ key: this.species + "_run", repeat: -1 });
this.body.setVelocity(ESCAPE_VELOCITY, 0);
}
}
......
......@@ -165,11 +165,12 @@ export default class FightScene extends Phaser.Scene {
initAndBindGuessPreview(this);
this.beGame = (await backend.createGame()).data;
this.beGame.began_at = new Date().toISOString();
await backend.updateGame(this.beGame.id, {
began_at: this.beGame.began_at,
ended_at: null,
});
this.beGame = (
await backend.updateGame(this.beGame.id, {
began_at: new Date().toISOString(),
ended_at: null,
})
).data;
gameStart(this);
}
......@@ -204,20 +205,6 @@ export default class FightScene extends Phaser.Scene {
});
}
shootSpear(foe: Foe | null, hit: boolean) {
const scene = this;
if (foe === null || !hit) {
this.showMissMessage();
new Spear(this, this.player, undefined);
} else {
this.showHitMessage();
// TODO: ew.
foe.clue.delete();
// scene.foes.splice(scene.foes.indexOf(foe), 1); // FIXME
new Spear(this, this.player, foe.critter);
}
}
initCluesGroup() {
const bounds = new Phaser.Geom.Rectangle(
0,
......@@ -252,6 +239,23 @@ export default class FightScene extends Phaser.Scene {
// console.log(similarity, match.beWord.ocr_transcript);
return result;
}
submitTranscription(transcription: string) {
const { score, match } = this.findMatchingFoe(transcription);
// TODO: visual near misses based on score
if (match === null) {
// NOOP
} else if (score < 0.9) {
match.handleFailure();
this.showMissMessage();
new Spear(this, this.player, undefined);
} else {
this.foes.splice(this.foes.indexOf(match), 1);
match.handleSuccess();
this.showHitMessage();
new Spear(this, this.player, match.critter);
}
}
}
// TODO: remove any
......@@ -325,30 +329,25 @@ function initAndBindGuessPreview(scene: FightScene) {
event.keyCode === Phaser.Input.Keyboard.KeyCodes.ENTER &&
textEntry.text.length > 0
) {
submitTranscription(textEntry.text, scene);
scene.submitTranscription(textEntry.text);
textEntry.text = textEntry.text.substr(0, 0);
}
},
);
}
function submitTranscription(transcription: string, scene: FightScene) {
const { score, match } = scene.findMatchingFoe(transcription);
scene.shootSpear(match, score >= 0.9);
}
function gameStart(scene: any) {
spawn(scene);
}
async function spawn(scene: any) {
await dispatchEnemy(scene);
await spawnFoe(scene);
scene.time.now;
const delay =
(8 * 1000 * (60 * 1000 - scene.time.now)) / 60 / 1000 + 2 * 1000;
setTimeout(() => spawn(scene), Math.max(delay, 2000));
}
async function dispatchEnemy(scene: any) {
async function spawnFoe(scene: any) {
await new Foe(scene).initialize();
}
......@@ -20,9 +20,48 @@ class Foe {
async initialize() {
this.beWord = (await backend.getWord()).data;
// 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.clue = new Clue(this.scene, this.beWord);
this.critter = new Critter(this.scene, this.clue);
this.critter = new Critter(this.scene);
this.scene.foes.push(this);
const overlap = this.scene.physics.add.overlap(
this.scene.player,
this.critter,
() => {
this.scene.physics.world.removeCollider(overlap);
this.critter.escape();
},
);
}
async handleSuccess() {
// TODO: update clue
// TODO: post shot
// TODO: destroy foe
this.clue.delete();
}
async handleFailure() {
// TODO: post shot
// await backend.createShot(this.scene.beGame.id, {
// clue_id: this.beClue.id,
// began_at: "",
// ended_at: new Date().toISOString(),
// typed: "",
// final: "",
// });
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment