Skip to content

Instantly share code, notes, and snippets.

@AldeRoberge
Created October 24, 2020 20:35
Show Gist options
  • Save AldeRoberge/f1dc348ae5d436f710f594ade344c597 to your computer and use it in GitHub Desktop.
Save AldeRoberge/f1dc348ae5d436f710f594ade344c597 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Jeux - S.T.A.R.S</title>
<link rel="stylesheet" type="text/css" href="css/style.css"/>
<style>
.game-canvas {
border: 1px solid #d3d3d3;
background-color: #f1f1f1;
}
.dialog {
background-color: #161616;
}
</style>
</head>
<body onload="startGame()">
<!-- The game canvas will be generated here -->
<br>
<br>
<div class="center credits">
<h3>Utilisation</h3>
<p>Souris = bouger dans le monde</p>
<p>M = rendre la musique en sourdine</p>
<h3>Débug</h3>
<p>A = Skipper le niveau</p>
<br>
<p>2020 - Les Jeux Pequno Brouette</p>
</div>
<!--
_____ _______ _____ _____
/ ____|__ __| /\ | __ \ / ____|
| (___ | | / \ | |__) | | (___
\___ \ | | / /\ \ | _ / \___ \
____) | | |_ / ____ \ _| | \ \ _ ____) |
|_____(_) |_(_)_/ \_(_)_| \_(_)_____/
Surely
This
Acronym
Reads
S.T.A.R.S.
https://en.wikipedia.org/wiki/Recursive_acronym
-->
<script>
let debugDraw = false;
const worldObjects = [];
let myGamePiece;
let objectSpawner;
const gameUpdateRate = 1;
// Sounds
let shieldSound;
let hurtSound;
let healSound;
let deathSound;
let ammoCollectSound;
let enemyDestroySound;
let shootSound;
let music;
let victory;
let phaseHandler;
// World scroll
let isWorldScrolling = true;
function startGame() {
myGamePiece = new PlayerObject(gameWidth / 2, gameHeight / 2);
myGameArea.start();
objectSpawner = new StarSpawner();
shieldSound = new Audio("audio/shield.wav");
hurtSound = new Audio("audio/hurt.wav");
healSound = new Audio("audio/heal.wav");
ammoCollectSound = new Audio("audio/ammo.wav");
deathSound = new Audio("audio/death.wav");
victory = new Audio("audio/victory.wav");
enemyDestroySound = new Audio("audio/enemyDestroySound.wav");
shootSound = new Audio("audio/shoot.wav");
music = new Audio("audio/music.mp3");
}
let isGamePaused = false;
let score = 0;
let scoreCountText;
let bullets = 0;
let ammoText;
let level = 0;
let levelText;
let debug = "";
let debugText;
// Game is ended, player has no more health
let isGameEnded = false;
let isGameEndedFail = false;
const maxHealth = 20;
let currentHealth = 0;
let drawHealthBar = false;
// Goes from 255 to 0 to show player hurt (255 = white, 0 = red (hurt))
let damageIndicator = 255;
// The player is hurt / damaged
function HitPlayer(damage) {
damageIndicator = 0; // See Player update method
if (isPlayerShielded) {
isPlayerShielded = false;
} else {
currentHealth -= damage;
}
hurtSound.play();
if (currentHealth < 0) {
deathSound.play();
isGameEnded = true;
isGameEndedFail = true;
ShowCursor(true);
setDialog("");
music.pause();
}
}
// The player is healed
function HealPlayer(heal) {
damageIndicator = 255;
healSound.play();
drawHealthBar = true;
currentHealth += heal;
if (currentHealth >= maxHealth) {
currentHealth = maxHealth;
}
}
function CollectAmmo(number) {
bullets += number;
ammoCollectSound.play();
}
window.addEventListener("click", go);
let isGameStarted = false;
let skipTitleCard = false;
function go() {
if (!isGameStarted) {
isGameStarted = true;
music.play();
ShowCursor(false);
const showTextDelay = 3500;
new UIText(gameWidth / 2, gameHeight / 2, "Les Jeux Péquno Brouette", "25px Segoe UI", "white", showTextDelay);
new UIText(gameWidth / 2, gameHeight / 1.85, "PRÉSENTENT", "20px Segoe UI", "white", showTextDelay);
// Debug
debugText = new UIText(gameWidth / 2, 200, "Debug : " + debug, "0px Arial", "white", -1);
if (skipTitleCard) {
phaseHandler = new PhaseHandler();
beginGame(true);
} else {
setTimeout(function () {
let textShowLength = showTextDelay * 1.5;
new UIText(gameWidth / 2, gameHeight / 2, "S. T. Δ. R. S.", "75px Segoe UI", "white", textShowLength / 1.5);
new UIText(gameWidth / 2, gameHeight / 2 + 25, "L'ÉPREUVE GALACTIQUE", "25px Segoe UI", "white", textShowLength / 1.5);
setTimeout(function () {
beginGame(false);
}, textShowLength + 1000);
}, showTextDelay + 1000);
}
}
}
function beginGame(isSkipTitle) {
const stopBlinkingTime = 800;
// Shows the score
ammoText = new UIText(gameWidth - 100, 50, "Balles : " + bullets, "30px Segoe UI", "white", -1);
ammoText.blink(true);
scoreCountText = new UIText(100, 50, "Points : " + score, "30px Segoe UI", "white", -1);
scoreCountText.blink(true);
levelText = new UIText(gameWidth / 2, 50, "Niveau : " + level, "20px Segoe UI", "white", -1);
levelText.blink(true);
setTimeout(function () {
scoreCountText.blink(false);
ammoText.blink(false);
levelText.blink(false);
if (!isSkipTitle) {
phaseHandler = new PhaseHandler();
}
}, stopBlinkingTime);
}
function setDebug(text) {
debug = text;
}
var gameWidth = 1200;
var gameHeight = 800;
var myGameArea = {
canvas: document.createElement("canvas"),
start: function () {
myGameArea.canvas.setAttribute('class', 'center')
this.canvas.width = gameWidth;
this.canvas.height = gameHeight;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
setInterval(updateGameArea, gameUpdateRate);
window.addEventListener('mousemove', function (e) {
myGameArea.x = e.pageX;
myGameArea.y = e.pageY;
})
},
clear: function () {
this.context.fillStyle = "black";
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function ShowCursor(b) {
if (b) {
myGameArea.canvas.style.cursor = "auto"; //hide the original cursor
} else {
myGameArea.canvas.style.cursor = "none"; //hide the original cursor
}
}
function UIText(x, y, text, font, color, destroyAfter) {
let displayText = text;
let timeLived = 0;
this.setText = function (text) {
displayText = text;
}
this.blink = function (isBlinking) {
this.isBlinking = isBlinking;
}
const blinkTimeLength = 100;
let blinkTime = 0;
this.update = function (gameTick, ctx) {
timeLived += gameTick;
if (destroyAfter > 0 && timeLived > destroyAfter) {
console.log("Destroyed text.");
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
}
blinkTime += gameTick;
if (blinkTime > blinkTimeLength * 2) {
blinkTime = 0;
}
if (this.isBlinking && blinkTime > blinkTimeLength) {
return;
}
ctx.textAlign = "center";
ctx.fillStyle = color;
ctx.font = font;
ctx.fillText(displayText, x, y);
}
worldObjects.push(this);
}
let previousX = 0;
let playerXOffset = 0;
let previousY = 0;
let playerYOffset = 0;
function PlayerObject(x, y) {
this.name = "Player";
// The final size of the player
let losangeEndSize = 20;
// The size of the player
let losangeSize = 500;
this.x = x;
this.y = y;
this.Shoot = function () {
if (bullets > 0) {
bullets--;
shootSound.play();
worldObjects.push(new BulletObject(myGamePiece.x, myGamePiece.y, 1));
} else {
console.log("Does not have enough bullets...");
}
}
this.update = function (gameTick, ctx) {
losangeSize -= gameTick / 2;
if (losangeSize <= losangeEndSize) {
losangeSize = losangeEndSize;
}
// Draw the main triangle
if (damageIndicator < 255) {
damageIndicator += 1;
}
ctx.fillStyle = "rgb(255," + damageIndicator + "," + damageIndicator + ")";
// LIMIT THE X AND Y SO THE PLAYER DOES NOT GO AWAY FROM THE CANVAS
/**
* YOU'RE BOUND TO THIS PRISON SHELL, SLAVE
*/
// Clamp X
if (this.x < 20) {
this.x = 20;
} else if (this.x > gameWidth - 20) {
this.x = gameWidth - 20;
}
// Clamp Y
if (this.y < 20) {
this.y = 20;
} else if (this.y > gameHeight - 20) {
this.y = gameHeight - 20;
}
// Calculate offset (to move the stars)
playerXOffset = previousX - this.x;
previousX = this.x;
playerYOffset = previousY - this.y;
previousY = this.y;
ctx.beginPath();
ctx.moveTo(this.x, this.y - losangeSize);
ctx.lineTo(this.x - losangeSize, this.y + losangeSize);
ctx.lineTo(this.x + losangeSize, this.y + losangeSize);
ctx.fill();
// Draw the red propellers
ctx.fillStyle = "red";
ctx.beginPath();
ctx.moveTo(this.x - losangeSize, this.y + losangeSize);
ctx.lineTo(this.x - (losangeSize / 2), this.y + losangeSize * 2);
ctx.lineTo(this.x, this.y + losangeSize);
ctx.fill();
ctx.beginPath();
ctx.moveTo(this.x + losangeSize, this.y + losangeSize);
ctx.lineTo(this.x + (losangeSize / 2), this.y + losangeSize * 2);
ctx.lineTo(this.x, this.y + losangeSize);
ctx.fill();
// Draw the orange (flickering) propellers
ctx.fillStyle = "orange";
const flickeringHeight = this.y + (losangeSize * 2) - (Math.random() * 15) - 0.25;
ctx.beginPath();
ctx.moveTo(this.x - losangeSize, this.y + losangeSize);
ctx.lineTo(this.x - (losangeSize / 2), flickeringHeight);
ctx.lineTo(this.x, this.y + losangeSize);
ctx.fill();
ctx.beginPath();
ctx.moveTo(this.x + losangeSize, this.y + losangeSize);
ctx.lineTo(this.x + (losangeSize / 2), flickeringHeight);
ctx.lineTo(this.x, this.y + losangeSize);
ctx.fill();
// Draw the healthbar
if (drawHealthBar) {
const sizeFactor = 2;
const barSize = maxHealth * sizeFactor;
ctx.fillStyle = "red";
ctx.fillRect(this.x - barSize / 2, this.y + losangeSize * 2.5, barSize, 10);
ctx.fillStyle = "green";
ctx.fillRect(this.x - barSize / 2, this.y + losangeSize * 2.5, currentHealth * sizeFactor, 10);
ctx.beginPath();
ctx.textAlign = "center";
ctx.fillStyle = "white";
ctx.font = "bold 10px Arial";
ctx.fillText(currentHealth, this.x, this.y + 58);
}
//Draw the player shield
if (isPlayerShielded) {
let shieldRadius = 50;
let cercle = new Path2D();
cercle.arc(this.x, this.y + 20, shieldRadius, 0, 2 * Math.PI);
ctx.fillStyle = "rgb(0,255,217, 0.25)";
ctx.fill(cercle);
}
}
}
function StarSpawner() {
const spawnStarTime = 5;
let spawnStarIndex = 0;
this.update = function (tickDelta) {
spawnStarIndex += tickDelta;
if (spawnStarIndex > spawnStarTime) {
// Dont stack-spawn stars if the world isnt scrolling
if (isWorldScrolling) {
spawnStarIndex = 0;
const starRadius = 1;
const x = Math.random() * gameWidth;
const y = -(starRadius / 2);
worldObjects.push(new StarObject(x, y, starRadius));
}
}
}
worldObjects.push(this);
}
function TextPhase(phaseHandler, text, textColor, font, time, delay) {
this.start = function () {
console.log("Started text phase...");
setDialog(text, textColor, font);
}
let tickIndex = 0;
this.update = function (tickDelta) {
tickIndex += tickDelta;
if (tickIndex > time) {
clearDialog();
phaseHandler.nextPhase(delay);
}
}
}
function IntroPhase(enemies, phaseHandler, text, textColor, font) {
this.start = function () {
console.log("Started intro phase...");
setDialog(" ", "green", "30px Arial");
}
let tickIndex = 0;
this.update = function (tickDelta) {
tickIndex += tickDelta;
if (tickIndex > 2000) {
tickIndex = 0;
worldObjects.push(new HealObject(gameWidth / 2 - 20, -5));
phaseHandler.nextPhase(1000);
}
}
}
function RecompensePhase(heal, bullets, shield, phaseHandler) {
this.start = function () {
console.log("Started recompense phase...");
}
this.update = function (tickDelta) {
// Spawn healing obj
if (heal > 0) {
heal--;
const x = GetRandomObjectSpawnPositionX();
worldObjects.push(new HealObject(x, -10));
}
// Spawn bullets obj
if (bullets > 0) {
bullets--;
const x = GetRandomObjectSpawnPositionX();
worldObjects.push(new AmmoObject(x, -10));
}
// Spawn shield obj
if (shield > 0) {
shield--;
worldObjects.push(new ShieldObject(gameWidth / 2 + 20, -5));
}
// No more power-ups
if (heal === 0 && bullets === 0 && shield === 0) {
setDialog("")
phaseHandler.nextPhase(2000);
}
}
}
function WallPhase(endAfterNumberOfBeats, speed, frequency) {
this.frequency = frequency;
this.enemySpeed = speed;
this.start = function () {
console.log("Started wall phase...");
}
let beatIndex = 0;
let isBeat = false;
this.update = function (tickDelta) {
score++;
function SpawnWall() {
console.log("Spawning wall...");
beatIndex++;
if (beatIndex > endAfterNumberOfBeats && endAfterNumberOfBeats > -1) {
phaseHandler.nextPhase(0);
}
console.log(beatIndex % frequency);
if (beatIndex % frequency !== 0) {
return;
}
let enemyCount = 30;
let enemiesPos = gameWidth / enemyCount;
let holeIndex = Math.floor(Math.random() * enemyCount);
console.log("Hole index is " + holeIndex);
let currentEnemyPos = 0;
for (let i = 0; i < enemyCount; i++) {
currentEnemyPos += enemiesPos;
// Skip hole (two width)
if (i === holeIndex || (i + 1 === holeIndex)) {
continue;
}
//console.log("Spawning enemy at (" + currentEnemyPos + ", -20)");
worldObjects.push(new EnemyObject(currentEnemyPos, -20, 20, 1, speed));
}
}
if (beatFlip && !isBeat) {
isBeat = true;
SpawnWall();
} else if (!beatFlip && isBeat) {
isBeat = false;
SpawnWall();
}
}
}
function BossPhase(phaseHandler) {
this.phaseHandler = phaseHandler;
this.wallPhase = new WallPhase(-1, 0.20, 4);
this.start = function () {
console.log("Started boss phase...");
setDialog("C'EST ASSEZ!!!", "red");
worldObjects.push(new BossEnemyObject(this.phaseHandler, gameWidth / 2, -200, 0, 200));
}
this.update = function (tickDelta) {
this.wallPhase.update(tickDelta);
}
}
function VictoryPhase(phaseHandler) {
this.start = function () {
console.log("Started boss phase...");
music.pause();
victory.play();
isGameEnded = true;
}
this.update = function (tickDelta) {
}
}
function EasyPhase(enemies, phaseHandler, spawnTime, message, color, enemySpeed, waveLength, delay) {
this.start = function () {
console.log("Started easy phase...");
setDialog(message, color, "30px Arial");
}
let tickIndex = 0;
let tickCount = 0;
this.update = function (tickDelta) {
score++;
tickIndex += tickDelta;
if (tickIndex > spawnTime) {
tickCount++;
tickIndex = 0;
const x = GetRandomObjectSpawnPositionX();
worldObjects.push(new EnemyObject(x, -20, 20, 1, enemySpeed));
}
if (tickCount > waveLength) {
setDialog("")
phaseHandler.nextPhase(delay);
}
}
}
function GetRandomObjectSpawnPositionX() {
let ret = Math.random() * gameWidth;
let clampLimit = 10;
// Clamp to left
if (ret < clampLimit) {
ret = clampLimit;
}
// Clamp to right
if (ret > gameWidth - clampLimit) {
return gameWidth - clampLimit;
}
return ret;
}
function GetRandomObjectSpawnPositionY() {
return Math.random() * gameHeight;
}
function FeelMyWrathPhase(enemies, phaseHandler, text, textColor, font) {
this.phaseHandler = phaseHandler;
this.enemies = enemies;
let tickIndex = 0;
this.start = function () {
setDialog(text, textColor, font);
}
let tickCount = 0;
this.update = function (tickDelta) {
score++;
tickIndex += tickDelta;
if (tickIndex > 10) {
tickCount++;
tickIndex = 0;
const x = GetRandomObjectSpawnPositionX();
worldObjects.push(new EnemyObject(x, -5, 10, 1, 1));
}
if (tickCount > 1000) {
phaseHandler.nextPhase(1000);
}
}
}
function PhaseHandler() {
let currentPhaseIndex = -1;
let phase0 = new IntroPhase(100, this);
let phase1 = new TextPhase(this, " ", "Green", "30px Arial", 10, 1000);
let phase2 = new EasyPhase(100, this, 50, " ", "white", 0.75, 300, 500);
let phase3 = new TextPhase(this, "Pas mal du tout!", "Green", "30px Arial", 2500, 400);
let phase4 = new EasyPhase(100, this, 100, "Et si j'y vais comme ça?", "orange", 1.5, 200, 0);
let phase5 = new FeelMyWrathPhase(100, this, "C'EST TA FIN!!!", "red", "30px Arial");
let phase6 = new RecompensePhase(0, 0, 1, this);
let phase7 = new WallPhase(10, 0.25, 2);
let phase8 = new RecompensePhase(10, 10, 10, this)
let phase9 = new BossPhase(this);
let phase10 = new VictoryPhase();
let isInBetweenPhases = false;
let timeBeforeNextPhase = 0;
this.nextPhase = function (delay) {
level++;
setDialog("");
isInBetweenPhases = true;
timeBeforeNextPhase = delay;
}
this.update = function (tickDelta) {
if (isInBetweenPhases) {
if (timeBeforeNextPhase > 0) {
// Wait for next phase...
timeBeforeNextPhase -= 1;
} else {
// Ready for next phase
isInBetweenPhases = false;
currentPhaseIndex++;
GetCurrentPhase().start();
}
return;
}
isWorldScrolling = true;
GetCurrentPhase().update(tickDelta);
}
// TODO
//this.nextPhase(1000);
this.nextPhase(1);
function GetCurrentPhase() {
switch (currentPhaseIndex) {
case 0:
return phase0;
case 1:
return phase1;
case 2:
return phase2;
case 3:
return phase3;
case 4:
return phase4;
case 5:
return phase5;
case 6:
return phase6;
case 7:
return phase7;
case 8:
return phase8;
case 9:
return phase9;
case 10:
return phase10;
case 11:
return phase11;
case 12:
return phase12;
case 13:
return phase13;
}
}
worldObjects.push(this);
}
// Returns the distance between two points
function CalculateDistance(x1, y1, x2, y2) {
const a = x1 - x2;
const b = y1 - y2;
return Math.sqrt(a * a + b * b);
}
function AmmoObject(x, y) {
this.name = "AmmoObject";
this.x = x;
this.y = y;
this.update = function (tickDelta, ctx) {
if (isWorldScrolling) this.y += 0.5;
// Destroy this object if it is outside the bounds of the world
if (this.y > gameHeight) {
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
let distanceToPlayer = CalculateDistance(this.x, this.y, myGamePiece.x, myGamePiece.y);
if (distanceToPlayer < 20) {
CollectAmmo(1);
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
}
DrawHexagon(ctx, this.x, this.y, 20, "#ffb600");
}
}
let isPlayerShielded = false;
function ShieldPlayer() {
shieldSound.play();
isPlayerShielded = true;
}
function ShieldObject(x, y) {
this.name = "Shield";
this.x = x;
this.y = y;
this.update = function (tickDelta, ctx) {
if (isWorldScrolling) this.y += 0.5;
// Destroy this object if it is outside the bounds of the world
if (this.y > gameHeight) {
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
let distanceToPlayer = CalculateDistance(this.x, this.y, myGamePiece.x, myGamePiece.y);
if (distanceToPlayer < 20) {
ShieldPlayer();
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
}
let size = 10;
let fillStyle = "#0028ff";
DrawHexagon(ctx, this.x, this.y, size, fillStyle);
}
}
// Draws an exagon
function DrawHexagon(ctx, x, y, size, fillStyle) {
ctx.beginPath();
ctx.moveTo(x + size * Math.cos(0), y + size * Math.sin(0));
for (let side = 0; side < 7; side++) {
ctx.lineTo(x + size * Math.cos(side * 2 * Math.PI / 6), y + size * Math.sin(side * 2 * Math.PI / 6));
}
ctx.fillStyle = fillStyle;
ctx.fill();
}
function HealObject(x, y) {
this.name = "Heal";
this.x = x;
this.y = y;
this.update = function (tickDelta, ctx) {
if (isWorldScrolling) this.y += 0.5;
// Destroy this object if it is outside the bounds of the world
if (this.y > gameHeight) {
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
let distanceToPlayer = CalculateDistance(this.x, this.y, myGamePiece.x, myGamePiece.y);
if (distanceToPlayer < 20) {
HealPlayer(maxHealth);
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
}
DrawHexagon(ctx, this.x, this.y, 10, "#2cff00");
}
}
function BulletObject(x, y, speed) {
this.name = "Bullet";
this.x = x;
this.y = y;
this.update = function (tickDelta, ctx) {
if (this.y < 0) {
console.log("Bullet was outside of this world.")
// Destroy this object if it is outside the bounds of the world
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
for (var obj2 in worldObjects) {
let obj = worldObjects[obj2];
if (obj.name === "BossEnemyObject") {
let distance = CalculateDistance(this.x, this.y, obj.x, obj.y);
console.log("Distance to boss is " + distance + " my " + x + ", " + y + ", his " + obj.x + ", " + obj.y);
if (distance < obj.size) {
obj.damage(obj.size);
console.log("Collision with enemy");
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
}
}
// Draw the star
let cercle = new Path2D();
cercle.arc(this.x, this.y, 2, 0, 2 * Math.PI);
ctx.fillStyle = "gray";
ctx.fill(cercle);
if (isWorldScrolling) this.y -= tickDelta * speed;
}
}
function BossEnemyObject(phaseHandler, x, y, finalY, size) {
this.name = "BossEnemyObject";
this.x = x;
this.y = y;
this.maxHealth = 5;
this.currentHealth = this.maxHealth;
this.finalY = finalY;
this.size = size;
this.phaseHandler = phaseHandler;
this.damage = function () {
enemyDestroySound.play();
this.currentHealth -= 1;
console.log("Damagin! Current health : " + this.currentHealth);
if (this.currentHealth > 20) {
setDialog("ARRGGGHHHH!!!", "red");
} else if (this.currentHealth > 15) {
setDialog("FINI!!!!!!", "red");
} else if (this.currentHealth > 10) {
setDialog("L'UNIVERS M'APPARTIENT", "red");
}else if (this.currentHealth > 10) {
setDialog("JE SUIS LE SEUL À POUVOIR TE BATTRE", "red");
} else if (this.currentHealth > 5) {
setDialog("SALE VERMINE", "red");
} else if (this.currentHealth <= 0) {
setDialog("", "red");
console.log("BOSS DIED");
worldObjects.splice(worldObjects.indexOf(this), 1);
this.phaseHandler.nextPhase(0);
}
}
this.update = function (tickDelta, ctx) {
ctx.fillStyle = "red";
let cercle = new Path2D();
cercle.arc(this.x, this.y, size, 0, 2 * Math.PI);
ctx.fill(cercle);
if (this.y < this.finalY) {
this.y += 1;
}
const sizeFactor = 5;
const barSize = this.maxHealth * sizeFactor;
ctx.fillStyle = "red";
ctx.fillRect(this.x - barSize / 2, this.y + size + 20, barSize, 10);
ctx.fillStyle = "green";
ctx.fillRect(this.x - barSize / 2, this.y + size + 20, this.currentHealth * sizeFactor, 10);
}
}
function EnemyObject(x, y, size, damage, speed) {
this.name = "Enemy";
this.x = x;
this.y = y;
this.damage = function () {
enemyDestroySound.play();
worldObjects.splice(worldObjects.indexOf(this), 1);
}
this.update = function (tickDelta, ctx) {
if (this.y > gameHeight) {
// Destroy this object if it is outside the bounds of the world
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
let distanceToPlayer = CalculateDistance(this.x, this.y, myGamePiece.x, myGamePiece.y);
if (distanceToPlayer < size) {
HitPlayer(damage);
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
}
ctx.fillStyle = "red";
ctx.beginPath();
ctx.moveTo(this.x - size, this.y + size);
ctx.lineTo(this.x - (size / 2), this.y + size * 2);
ctx.lineTo(this.x, this.y + size);
ctx.fill();
if (isWorldScrolling) this.y += tickDelta * speed;
}
}
// A star is an aesthetic object
function StarObject(x, y, radius) {
this.name = "Star";
this.radius = radius;
this.x = x;
this.y = y;
this.z = 1;
this.update = function (tickDelta, context) {
if (this.y > gameHeight) {
// Destroy this object
worldObjects.splice(worldObjects.indexOf(this), 1);
return;
}
// Update position
if (isWorldScrolling) {
this.y += tickDelta / 2;
// Offset according to player pos'
this.x -= playerXOffset / 90;
this.y += playerYOffset / 50;
}
// Draw the star
let cercle = new Path2D();
cercle.arc(this.x, this.y, radius, 0, 2 * Math.PI);
context.fillStyle = "gray";
context.fill(cercle);
}
}
let dialogFont = "";
let dialogColor = "";
let dialogText = "";
// Shows a dialog at the bottom of the screen
function setDialog(text, color, font) {
if (text) {
dialogText = text;
} else {
dialogText = " ";
}
if (color) {
dialogColor = color;
}
if (font) {
dialogFont = font;
}
}
// No dialog to be displayed
function clearDialog() {
dialogText = "";
}
// Draws the dialog (every frame)
function drawDialogView(ctx) {
if (dialogText) {
ctx.beginPath();
ctx.textAlign = "center";
ctx.fillStyle = dialogColor;
ctx.font = dialogFont;
ctx.fillText(dialogText, gameWidth / 2, gameHeight - 20);
}
}
let lastUpdateTime = 0;
let beginRender = new Date();
let isMusicPaused = false;
window.addEventListener('mousedown', function (event) {
console.log("Shooting!");
myGamePiece.Shoot();
});
// Register key input
window.addEventListener('keyup', function (event) {
if (event.defaultPrevented) {
return;
}
const key = event.key || event.keyCode;
if (key === 'm' || key === 'M') {
if (!isMusicPaused) {
music.volume = 0;
isMusicPaused = true;
} else {
music.volume = 1;
isMusicPaused = false;
}
}
if (key === 'Escape' || key === 'Esc' || key === 'Space') {
console.log("Pausing game");
isGamePaused = !isGamePaused;
if (!isGameEnded) {
if (isGamePaused) {
ShowCursor(true);
music.pause();
} else {
ShowCursor(false);
music.play();
}
}
}
if (key === 'a' || key === 'A') {
console.log("Skipping this phase");
phaseHandler.nextPhase(0);
}
});
let beatFlip = false;
let beatCount = 0;
// Updates the game
function updateGameArea() {
const context = myGameArea.context;
if (isGamePaused) {
return;
}
myGameArea.clear();
if (!isGameStarted) {
//jeu avec titre, description, musique et bouton “Démarrer”
context.textAlign = "center";
context.fillStyle = "white";
context.font = "50px Arial ";
context.fillStyle = "magenta";
context.fillText("S. T. Δ. R. S.", gameWidth / 2, gameHeight / 2);
context.textAlign = "center";
context.font = "31px Arial";
var gradient = context.createLinearGradient(0, 0, gameWidth, 0);
gradient.addColorStop(0.25, "blue");
gradient.addColorStop(0.50, "magenta");
gradient.addColorStop(0.75, "white");
context.fillStyle = gradient;
context.fillText("L'épreuve galactique", gameWidth / 2, gameHeight / 2 + 40);
context.textAlign = "center";
context.fillStyle = "gray";
context.font = "20px Arial";
context.fillText("CLIQUEZ POUR DÉMARRER", gameWidth / 2, gameHeight / 2 + 250);
// Mute
context.textAlign = "center";
context.fillStyle = "rgb(48,48,48)";
context.font = "15px Arial";
context.fillText("M pour rendre la musique en sourdine", gameWidth / 2, gameHeight - 20);
return;
}
if (myGameArea.x && myGameArea.y) {
myGamePiece.x = myGameArea.x;
myGamePiece.y = myGameArea.y;
}
if (ammoText && scoreCountText) {
ammoText.setText("Balles : " + bullets);
scoreCountText.setText("Points : " + score);
levelText.setText("Niveau : " + level);
debugText.setText("Debug : " + debug);
}
if (isGameEnded) {
context.beginPath();
context.textAlign = "center";
context.font = "30px Arial";
if (isGameEndedFail) {
context.fillStyle = "red";
context.fillText("MISSION ÉCHOUÉE", gameWidth / 2, gameHeight / 2 - 20);
} else {
context.fillStyle = "green";
context.fillText("MISSION RÉUSSIE", gameWidth / 2, gameHeight / 2 - 20);
}
context.font = "20px Arial";
context.fillText("Pointage : " + score, gameWidth / 2, gameHeight / 2);
return;
}
worldObjects.forEach(element => {
//console.log("Updating " + element);
element.update(lastUpdateTime, context);
// Clear the graph path before repainting
myGameArea.context.beginPath();
}
);
// Draw the game object on top of everything else
myGamePiece.update(lastUpdateTime, context);
drawDialogView(context);
const endRender = new Date();
lastUpdateTime = (endRender.getMilliseconds() - beginRender.getMilliseconds()) / gameUpdateRate;
if (lastUpdateTime < 0) {
lastUpdateTime = 0;
}
//console.log("render : " + endRender.getMilliseconds() + ", " + beginRender.getMilliseconds())
beginRender = new Date();
beatCount += 1;
// Counts the beat in the song
if (beatCount > 166.75) {
beatCount = 0;
beatFlip = beatFlip !== true;
// Time the console logs to the sound of the music :)
if (beatCount % 8 === 0) {
if (debugDraw) console.log("Updating " + worldObjects.length + " objects with time delta " + lastUpdateTime);
}
}
setDebug(beatFlip + ", " + beatCount);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment