Skip to content

Instantly share code, notes, and snippets.

@Fake-User
Last active April 12, 2024 22:43
Show Gist options
  • Save Fake-User/28ee5c5252940b9b6773d695735f09fb to your computer and use it in GitHub Desktop.
Save Fake-User/28ee5c5252940b9b6773d695735f09fb to your computer and use it in GitHub Desktop.
Invaders Must Die
<!DOCTYPE html>
<html lang="en">
<!--
Veeery funny hickup, I was pushing lasers into the enemies array instead of the lasers arrary.
But I got it fixed and it's kind working, so I'm gonna keep playing with it today
You can find a live version at:
https://invaders-must-die.pages.dev
I don't really use Github, but I'll be updating the source code on Gitlab:
https://gitlab.com/Fake.User/invaders-must-die
-->
<head>
<meta charset="UTF-8">
<style>
@font-face{
font-family: retro-gaming;
src: url("/assets/retro-gaming.woff2");
}
html, body{
margin: 0;
padding: 0
}
body{
background-color: #000;
color: #fff;
height: 100lvh;
width: 100vw;
overflow: hidden;
font-family: retro-gaming;
font-size: 30px;
letter-spacing: 0.09em;
}
#canvas-wrapper{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
box-sizing: border-box;
}
#game{
height: 95%;
aspect-ratio: 3 / 2;
border: 2px solid #444;
border-radius: 4px;
box-sizing: border-box;
position: relative;
}
#title{
position: absolute;
top: 50%;
left: 50%;
translate: -50% -50%;
text-align: center;
border: 4px solid #fff;
padding: 4px 16px;
}
#top-bar{
height: 10%;
width: 100%;
position: absolute;
padding: 1%;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
#lives{
display: grid;
grid-template-columns: 40px 40px 40px;
}
.life{
background-image: url("https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/life.webp");
background-size: cover;
width: 40px;
aspect-ratio: 1 / 1;
}
#canvas{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
@media (max-aspect-ratio: 3 / 2) {
#game{
width: 95%;
height: auto;
}
}
</style>
</head>
<body>
<div id="canvas-wrapper">
<div id="game">
<div id="title">PRESS&nbsp[&nbspSPACE&nbsp]<br/>TO&nbspSTART</div>
<div id="top-bar">
<div id="score">0</div>
<div id="lives">
<div id="life1" class="life"></div>
<div id="life2" class="life"></div>
<div id="life3" class="life"></div>
</div>
</div>
<canvas id="canvas"></canvas>
</div>
</div>
<script>
/*---CANVAS CONFIG---*/
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const dpr = window.devicePixelRatio;
let rSize;
let enemyYSpeed = 0.1;
let enemyXSpeed = rSize * 0.0001;
let enemyDirection = "left";
ctx.strokeStyle = "#fff"; //debug lines
let score = 0;
function canvasConfig(){
canvas.width = document.getElementById("canvas").offsetWidth * dpr;
canvas.height = document.getElementById("canvas").offsetHeight * dpr;
rSize = (canvas.width / 17);
};
canvasConfig();
/*---DEBUG---*/
let debug = false;
function dubugArc(x, y, radius){
ctx.beginPath();
ctx.arc(x, y, radius, 0, 7);
ctx.stroke();
};
/*---BACKGROUND---*/
class Background{
constructor(){
this.y = 0;
this.scale = canvas.width * (16 / 9);
this.img = bg;
};
update(){
this.y += 1;
if(this.y > this.scale){this.y = this.y - this.scale};
};
draw(){
ctx.drawImage(this.img, 0, this.y - this.scale, canvas.width, this.scale);
ctx.drawImage(this.img, 0, this.y, canvas.width, this.scale);
};
};
/*---PLAYER---*/
class Player{
constructor(){
this.x = canvas.width / 2;
this.y = canvas.height - rSize;
this.size = rSize / 2;
this.img = playerImg;
};
update(){
if(playerDirection === "left"){this.x -= 8};
if(playerDirection === "right"){this.x += 8};
if(this.x - this.size < 0){this.x = this.size};
if(this.x + this.size > canvas.width){this.x = canvas.width - this.size};
};
draw(){
ctx.drawImage(this.img, (this.x - this.size), (this.y - this.size), this.size * 2, this.size * 2);
if(debug){dubugArc(this.x, this.y, this.size)};
};
};
/*---Lasers---*/
class Laser{
constructor(x, y, state){
this.x = x;
this.y = y;
this.size = 30;
this.img = laser;
this.state = state;
};
update(){
this.y -= 10;
console.log(this.y);
if(this.y - this.size < 0){
this.state = "dead";
};
};
draw(){
ctx.drawImage(this.img, (this.x - this.size), (this.y - this.size), this.size * 2, this.size * 2);
};
};
let lasers = [];
function instanceLasers(){
for(let i = 0; i < 5; i++){
lasers.push(new Laser(0, 0, "dead"));
};
};
/*---ENEMIES---*/
class Enemy{
constructor(x, y, type){
this.x = x;
this.y = y;
this.size = rSize / 2;
this.img = type;
this.alive = true;
};
update(){
//if(Math.random() > 0.999){this.alive = false}; //test death
if(!this.alive){return};
if(this.x - this.size - 2 < 0 && enemyDirection === "left"){enemyDirection = "right"};
if(this.x + this.size + 2 > canvas.width && enemyDirection === "right"){enemyDirection = "left"};
if(enemyDirection === "left"){this.x -= 2}
else{this.x += 2};
this.y += 0.1;
for(let i = 0; i < 5; i++){
if(lasers[i].state === "alive"){
if(((Math.abs(this.x - lasers[i].x) ** 2) + (Math.abs(this.y - lasers[i].y) ** 2)) < (this.size ** 2)){
this.alive = false;
lasers[i].state = "dead";
score += 10;
document.getElementById("score").innerHTML = score;
}
};
};
};
draw(){
if(!this.alive){return};
ctx.drawImage(this.img, (this.x - this.size), (this.y - this.size), this.size * 2, this.size * 2);
if(debug){dubugArc(this.x, this.y, this.size)};
};
};
function instanceEnemies(){
enemies = []; // clear array for new wave
for(let i = 0; i < 55; i++){
let x = rSize * (i % 11) + (rSize * 3.5);
let y = 0;
let type;
switch(true){
case(i < 11): y = rSize; type = enemy1; break;
case(i < 22): y = rSize * 2; type = enemy2; break;
case(i < 33): y = rSize * 3; type = enemy2; break;
case(i < 44): y = rSize * 4; type = enemy3; break;
default: y = rSize * 5; type = enemy3; break;
}
enemies.push(new Enemy(x, y, type));
};
};
/*---GAME LOOP---*/
let gameStarted = false;
let left = false;
let right = false;
let playerDirection = "";
let currentLaser = 0;
window.addEventListener("keydown", e => {
switch(true){
case(e.key === " "):
e.preventDefault();
if(initialized){
if(gameStarted){
if(lasers[currentLaser].state === "dead"){
console.log(lasers[currentLaser]);
lasers[currentLaser].state = "alive";
lasers[currentLaser].x = player.x;
lasers[currentLaser].y = player.y;
currentLaser += 1;
if(currentLaser >= 5){currentLaser = 0};
};
}
else{
gameStarted = true;
document.getElementById("title").style.display = "none";
animate();
};
};
break;
case(e.key === "ArrowLeft"):
e.preventDefault();
left = true;
playerDirection = "left";
break;
case(e.key === "ArrowRight"):
e.preventDefault();
right = true; playerDirection = "right";
break;
case(e.key === "r" || e.key === "R"):
if(gameStarted){
player.x = canvas.width / 2;
instanceEnemies();
};
};
});
window.addEventListener("keyup", e => {
switch(true){
case(e.key === "ArrowLeft" && right):
e.preventDefault(); left = false;
playerDirection = "right";
break;
case(e.key === "ArrowRight" && left):
e.preventDefault();
right = false;
playerDirection = "left";
break;
case(e.key === "ArrowLeft" || e.key === "ArrowRight"):
left = false;
right = false;
playerDirection = "";
break;
};
});
function frame(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
background.update(); background.draw();
player.update(); player.draw();
for(let i = 0; i < lasers.length; i++){
if(lasers[i].state === "alive"){
lasers[i].update(); lasers[i].draw();
};
};
for(let i = 0; i < enemies.length; i++){enemies[i].update(); enemies[i].draw()};
};
function animate(){
frame();
requestAnimationFrame(animate);
};
/*---LOAD & INITIALIZE---*/
let initialized = false;
let player;
let background;
let enemies = [];
function initialize(){
player = new Player;
background = new Background;
instanceLasers();
instanceEnemies();
initialized = true;
frame();
};
let assetsLoaded = 0;
function assetLoad(){
assetsLoaded += 1;
if(assetsLoaded === 6){ // 6 => all textures loaded
initialize();
};
};
const bg = new Image();
bg.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/background.webp";
bg.onload = assetLoad;
const playerImg = new Image();
playerImg.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/player.webp";
playerImg.onload = assetLoad;
const enemy1 = new Image();
enemy1.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/enemy1.webp";
enemy1.onload = assetLoad;
const enemy2 = new Image();
enemy2.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/enemy2.webp";
enemy2.onload = assetLoad;
const enemy3 = new Image();
enemy3.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/enemy3.webp";
enemy3.onload = assetLoad;
const laser = new Image();
laser.src = "https://pub-ea11fb88729b4a258ad84a56a927787c.r2.dev/laser.webp";
laser.onload = assetLoad;
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment