-
Paolo.Brasolin authoredPaolo.Brasolin authored
main.js 12.08 KiB
import * as Phaser from "phaser";
import axios from "axios";
import path from "path";
const BACKEND_URL = new URL(process.env.BACKEND_URL);
const backendEndpointURL = (endpoint) =>
new URL(path.join(BACKEND_URL.pathname, endpoint), BACKEND_URL);
let config = {
type: Phaser.AUTO,
width: 1200,
height: 800,
pixelArt: true,
autoCenter: Phaser.Scale.CENTER_BOTH,
scaleMode: Phaser.Scale.FIT,
physics: {
default: "arcade",
arcade: {
gravity: { y: 200 },
debug: false,
},
},
scene: {
preload: preload,
create: create, // update: updateScene
},
};
let game = new Phaser.Game(config);
function preload() {
this.scale.scaleMode = Phaser.ScaleModes.LINEAR;
this.load.image("b0", "assets/background_layers/Layer_0011_0.png");
this.load.image("b1", "assets/background_layers/Layer_0010_1.png");
this.load.image("b2", "assets/background_layers/Layer_0009_2.png");
this.load.image("b3", "assets/background_layers/Layer_0008_3.png");
this.load.image("b4", "assets/background_layers/Layer_0007_Lights.png");
this.load.image("b5", "assets/background_layers/Layer_0006_4.png");
this.load.image("b6", "assets/background_layers/Layer_0005_5.png");
this.load.image("b7", "assets/background_layers/Layer_0004_Lights.png");
this.load.image("b8", "assets/background_layers/Layer_0003_6.png");
this.load.image("b9", "assets/background_layers/Layer_0002_7.png");
this.load.image("b10", "assets/background_layers/Layer_0001_8.png");
this.load.image("b11", "assets/background_layers/Layer_0000_9.png");
this.load.image("logo", "assets/background_layers/Logo.png");
this.load.image("ground", "assets/background_layers/ground.png");
this.load.spritesheet("oezi", "assets/sprites/player/oezi.png", {
frameWidth: 27,
frameHeight: 35,
});
this.load.spritesheet("deer", "assets/sprites/player/deer.png", {
frameWidth: 72,
frameHeight: 52,
});
this.load.spritesheet("boar", "assets/sprites/player/boar.png", {
frameWidth: 52,
frameHeight: 28,
});
this.load.spritesheet("wolf", "assets/sprites/player/wolf.png", {
frameWidth: 54,
frameHeight: 35,
});
this.load.spritesheet("bear", "assets/sprites/player/bear.png", {
frameWidth: 60,
frameHeight: 31,
});
this.load.spritesheet("spear", "assets/sprites/player/spear.png", {
frameWidth: 31,
frameHeight: 7,
});
this.load.spritesheet("spearhit", "assets/sprites/player/spearhit.png", {
frameWidth: 14,
frameHeight: 33,
});
this.load.spritesheet("hit", "assets/sprites/player/hit-sheet.png", {
frameWidth: 469,
frameHeight: 79,
});
this.load.spritesheet("miss", "assets/sprites/player/misssing-sheet.png", {
frameWidth: 466,
frameHeight: 76,
});
}
let gameRunning = false;
let player;
let scene;
let imageInUse = [];
let enemyNumber = 0;
let ground;
let consecutiveMissing = 0;
let onscreenEnemies = [];
/* game params */
let enemies = ["bear", "wolf", "deer", "boar"];
let maxEnemyNumber = 4;
let enemiesSpeed = 50000;
/**************/
function create() {
scene = this;
// Draw background forest
["b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "b10"].forEach(
(textureKey) => {
this.add
.tileSprite(
0,
0,
this.cameras.main.width,
this.cameras.main.height,
textureKey,
)
.setOrigin(0, 0.2)
.setScale(1.3);
},
);
// Draw foreground grass
this.add
.tileSprite(0, 0, this.cameras.main.width, this.cameras.main.height, "b11")
.setAlpha(0.6)
.setOrigin(0, -0.03);
createAnim("player_idle", "oezi", 1, 5);
createAnim("player_run", "oezi", 6, 13);
createAnim("deer_run", "deer", 0, 5);
createAnim("deer_idle", "deer", 6, 15);
createAnim("deer_walk", "deer", 16, 23);
createAnim("boar_run", "boar", 0, 5);
createAnim("boar_idle", "boar", 6, 13);
createAnim("boar_walk", "boar", 14, 22);
createAnim("wolf_run", "wolf", 0, 5);
createAnim("wolf_idle", "wolf", 6, 15);
createAnim("wolf_walk", "wolf", 16, 23);
createAnim("bear_run", "bear", 12, 16);
createAnim("bear_idle", "bear", 0, 11);
createAnim("bear_walk", "bear", 17, 24);
createAnim("spearAni", "spear", 0, 3);
createAnim("spearHitAni", "spearhit", 0, 8);
createAnim("hit", "hit", 0, 9);
createAnim("missing", "miss", 0, 6);
ground = this.physics.add
.staticImage(0, this.cameras.main.height - 25, "ground")
.setScale(1)
.refreshBody();
ground.setImmovable(true);
ground.body.allowGravity = false;
player = this.physics.add
.sprite(
this.cameras.main.width + 300,
this.cameras.main.height - 100,
"oezi",
)
.setScale(3)
.setInteractive();
player.flipX = true;
player.play({ key: "player_run" });
this.physics.add.collider(player, ground);
let tween = this.tweens.add({
targets: player,
x: this.cameras.main.width - 80,
ease: "Power2",
duration: 2000,
onComplete: function () {
setAnimation(player, "player_idle");
gameRunning = true;
gameStart(this.parent.scene);
},
});
this.scale.displaySize.setAspectRatio(
this.cameras.main.width / this.cameras.main.height,
);
this.scale.refresh();
initAndBindGuessPreview(this);
}
function createAnim(key, refKey, from, to) {
scene.anims.create({
key: key,
frames: scene.anims.generateFrameNumbers(refKey, { start: from, end: to }),
frameRate: 10,
repeat: -1,
});
}
function gameStart(scene) {
let waitTime = 200;
for (let i = 0; i < maxEnemyNumber; i++) {
setTimeout(() => {
dispatchEnemy(scene);
}, waitTime);
waitTime += Math.floor(Math.random() * 4000 + 4000);
}
}
function dispatchEnemy(scene) {
let e = new enemy();
onscreenEnemies.push(e);
axios
.post(backendEndpointURL("GetImage"), {
sessionImages: imageInUse,
})
.then(function (response) {
e.refData = response.data;
imageInUse.push(e.refData.id);
const imageData = `data:image/png;base64,${response.data.image}`;
scene.textures.addBase64(`WORD-${response.data.id}`, imageData);
scene.textures.once(
"addtexture",
function () {
e.run((v) => {
imageInUse.splice(imageInUse.indexOf(e.refData.id), 1);
if (gameRunning) {
setTimeout(() => {
dispatchEnemy(scene);
}, Math.floor(Math.random() * 10000 + 3000));
}
});
},
scene,
);
});
}
class enemy {
refData = null;
run(callback) {
let me = this;
enemyNumber++;
let randomEnemyType = enemies[Math.floor(Math.random() * 4 + 0)];
let scale = 2;
if (randomEnemyType === "deer") {
scale = 2.5;
} else if (randomEnemyType === "bear") {
scale = 3;
}
let flag = scene.add.sprite(400, 300, `WORD-${this.refData.id}`);
let enemy = scene.physics.add
.sprite(-100, scene.cameras.main.height - 100, randomEnemyType)
.setScale(scale)
.setInteractive();
this.sprite = enemy;
enemy.typeName = randomEnemyType;
scene.physics.add.collider(enemy, ground);
enemy.flipX = true;
setAnimation(enemy, enemy.typeName + "_walk");
// TODO: bring animal below grass
enemy.movement = scene.tweens.add({
targets: enemy,
x: scene.cameras.main.width + 300,
duration: enemiesSpeed,
onComplete: function () {
enemy.destroy();
callback(me);
},
onStop: function () {},
});
// here to implement health
scene.physics.add.overlap(player, enemy, (p, nemico) => {
nemico.disableInteractive();
nemico.body.enable = false;
nemico.movement.pause();
nemico.play(nemico.typeName + "_idle");
setTimeout(() => {
nemico.play(nemico.typeName + "_run");
nemico.movement.stop();
scene.tweens.add({
targets: nemico,
x: scene.cameras.main.width + 100,
duration: 2000,
onComplete: function () {
nemico.destroy();
callback(me);
},
});
}, 3000);
});
}
}
function setAnimation(obj, idleKey) {
obj.play({ key: idleKey, repeat: -1 });
}
function initAndBindGuessPreview(scene) {
var textEntry = scene.add.text(10, scene.cameras.main.height / 2 - 32, "", {
font: "bold 64px Courier",
fill: "#ffffff",
});
scene.input.keyboard.on("keydown", function (event) {
if (
event.keyCode === Phaser.Input.Keyboard.KeyCodes.BACKSPACE &&
textEntry.text.length > 0
) {
textEntry.text = textEntry.text.substr(0, textEntry.text.length - 1);
} else if (
event.keyCode === Phaser.Input.Keyboard.KeyCodes.SPACE ||
(event.keyCode >= Phaser.Input.Keyboard.KeyCodes.A &&
event.keyCode <= Phaser.Input.Keyboard.KeyCodes.Z)
) {
textEntry.text += event.key;
} else if (event.keyCode === Phaser.Input.Keyboard.KeyCodes.ENTER) {
submitTranscription(textEntry.text);
textEntry.text = textEntry.text.substr(0, 0);
}
});
}
function shootSpear(enemy, hit) {
let startPoint = new Phaser.Math.Vector2(player.x, player.y);
let controlPoint1 = new Phaser.Math.Vector2(
enemy.x + (player.x - enemy.x) / 2,
scene.cameras.main.height - (player.x - enemy.x),
);
let endPoint = new Phaser.Math.Vector2(
enemy.x + enemy.width * 1.6,
scene.cameras.main.height - 60,
);
let message = scene.add
.sprite(scene.cameras.main.width / 2, scene.cameras.main.height / 2)
.setScale(1);
// hit / missing <--- message
if (!hit) {
endPoint = new Phaser.Math.Vector2(-500, scene.cameras.main.height - 60);
message.play({ key: "missing", repeat: 1 });
message.on("animationcomplete", () => {
message.anims.remove("miss");
message.destroy();
});
} else {
let message = scene.add
.sprite(scene.cameras.main.width / 2, scene.cameras.main.height / 2)
.setScale(1);
message.play({ key: "hit", repeat: 1 });
message.on("animationcomplete", () => {
message.anims.remove("hit");
message.destroy();
});
}
let curve = new Phaser.Curves.QuadraticBezier(
startPoint,
controlPoint1,
endPoint,
);
let graphics = scene.add.graphics();
graphics.lineStyle(1, 0xff00ff, 1);
// curve.draw(graphics); // decomment to see the trajectory
let spear = scene.add.follower(curve);
// console.log(player.x + " " + enemy.x);
if (hit) {
spear.startFollow({
positionOnPath: true,
duration: (scene.cameras.main.width - enemy.x) * 3,
rotateToPath: true,
verticalAdjust: true,
scale: 3,
onComplete: (x, y) => {
console.log("done");
let spearHitObj = scene.add
.sprite(
enemy.x + enemy.width * 1.6 - 10,
scene.cameras.main.height - 60,
)
.setScale(2);
setAnimation(spearHitObj, "spearHitAni");
spear.anims.stop("spearAni");
spear.anims.remove("spearAni");
spear.destroy();
setTimeout(() => {
enemy.flipX = false;
setAnimation(enemy, enemy.typeName + "_run");
enemy.movement.stop();
scene.tweens.add({
targets: enemy,
x: -500,
duration: 5000,
onComplete: function () {
enemy.destroy();
//callback(enemy); // ???
},
});
}, 3000);
setTimeout(() => {
spearHitObj.destroy();
}, 4000);
},
});
} else {
enemy.setInteractive();
enemy.movement.resume();
setAnimation(enemy, enemy.typeName + "_walk");
spear.startFollow({
positionOnPath: true,
duration: 3000,
rotateToPath: true,
verticalAdjust: true,
scale: 3,
});
}
spear.scale = 2;
spear.anims.play("spearAni");
}
function submitTranscription(transcription) {
// TODO: guess the enemy if any
const enemy = onscreenEnemies[0].sprite;
let hit = true;
enemy.disableInteractive();
// here invoke image
enemy.movement.pause();
setAnimation(enemy, enemy.typeName + "_idle");
// let beginTime = new Date().getTime();
// let endTime = new Date().getTime();
// let deltaTime = endTime - beginTime;
hit = transcription == "fuffa";
shootSpear(enemy, hit);
}