feat: Add new backend
All checks were successful
Build Docker / Build Image (push) Successful in 36s

This commit is contained in:
2023-11-02 21:06:43 +11:00
parent d32dcc701b
commit 0b6ba921ce
33 changed files with 83 additions and 1752 deletions

25
templates/404.html Normal file
View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Nathan Woodburn</title>
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="stylesheet" href="/assets/css/404.css">
</head>
<body style="background-color:white;">
<p><br><br><br></p>
<h1 style="text-align:center">Space Invaders destroyed this page!</h1>
<t2 style="text-align:center">Take revenge on them!</t2>
<p class="mobile"><br><br><br><br><br><br></p>
<p class="center"><br><br><br>Use <span class="label label-danger">Space</span> to shoot and <span
class="label label-danger"></span>&#160;<span class="label label-danger"></span> to
move!&#160;&#160;&#160;<button class="btn btn-default btn-xs" id="restart">Restart</button> or <button
class="btn btn-default btn-xs" onclick="location.href='javascript:history.back()'" type="button">
Retreat</button></p>
<canvas id="space-invaders">
<script src="/assets/js/404.js"></script>
</body>
</html>

View File

@@ -46,7 +46,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
</head>
<body class="about-body" style="text-align: center;color: rgb(255,255,255);background: transparent;">
{{handshake_scripts}}
{{handshake_scripts | safe}}
<!-- <script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn"></script>
<script src="https://nathan.woodburn/https.js"></script> -->
<div class="profile-container" style="margin-bottom: 2em;margin-top: 5em;"><img class="profile background" src="assets/img/profile.jpg" style="border-radius: 50%;"><img class="profile foreground" src="assets/img/pfront.webp"></div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,76 @@
.center{text-align:center}
#space-invaders {
margin: 0 auto;
display: block;
background: white
}
t2 {
position: relative;
text-transform: uppercase;
letter-spacing: 6px;
font-size: 22px;
text-align: center;
font-weight: 900;
text-decoration: none;
color: black;
position: absolute;
left: 38.5%;
background-size: 120% 100%;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
-moz-background-clip: text;
-moz-text-fill-color: transparent;
-ms-background-clip: text;
-ms-text-fill-color: transparent;
background-clip: text;
background-color: #000000;
animation: 0.2s shake infinite alternate;
}
p.mobile { display: none }
@media (max-width: 640px) {
p.mobile { display: block }
p.desktop { display: none }
}
@keyframes shake {
0% { left: 38.43%; }
2.5% { left: 38.57%; }
5% { left: 38.43%; }
7.5% { left: 38.57%; }
10% { left: 38.43%; }
12.5% { left: 38.57%; }
15% { left: 38.43%; }
17.5% { left: 38.57%; }
20% { left: 38.43%; }
22.5% { left: 38.57%; }
25% { left: 38.43%; }
27.5% { left: 38.57%; }
30% { left: 38.43%; }
32.5% { left: 38.57%; }
35% { left: 38.43%; }
37.5% { left: 38.57%; }
40% { left: 38.43%; }
42.5% { left: 38.57%; }
45% { left: 38.43%; }
47.5% { left: 38.57%; }
50% { left: 38.43%; }
52.5% { left: 38.57%; }
/*55% { left: 38.43%; }
57.5% { left: 38.57%; }
60% { left: 38.43%; }
62.5% { left: 38.57%; }
65% { left: 38.43%; }
67.5% { left: 38.57%; }
70% { left: 38.43%; }
72.5% { left: 38.57%; }
75% { left: 38.43%; }
77.5% { left: 38.57%; }
80% { left: 38.43%; }
82.5% { left: 38.57%; }
85% { left: 38.43%; }
87.5% { left: 38.57%; }
90% { left: 38.43%; }
92.5% { left: 38.57%; }
95% { left: 38.43%; }
97.5% { left: 38.57%; }
100% { left: 38.43%; } */
}

446
templates/assets/js/404.js Normal file
View File

@@ -0,0 +1,446 @@
;(function() {
"use strict";
// General
var canvas,
screen,
gameSize,
game;
// Assets
var invaderCanvas,
invaderMultiplier,
invaderSize = 20,
initialOffsetInvader,
invaderAttackRate,
invaderSpeed,
invaderSpawnDelay = 250;
// Counter
var i = 0,
kills = 0,
spawnDelayCounter = invaderSpawnDelay;
var invaderDownTimer;
// Text
var blocks = [
[3, 4, 8, 9, 10, 15, 16],
[2, 4, 7, 11, 14, 16],
[1, 4, 7, 11, 13, 16],
[1, 2, 3, 4, 5, 7, 11, 13, 14, 15, 16, 17],
[4, 7, 11, 16],
[4, 8, 9, 10, 16]
];
// Game Controller
// ---------------
var Game = function() {
this.level = -1;
this.lost = false;
this.player = new Player();
this.invaders = [];
this.invaderShots = [];
if (invaderDownTimer === undefined) {
invaderDownTimer = setInterval(function() {
for (i = 0; i < game.invaders.length; i++) game.invaders[i].move();
}, 1000 - (this.level * 1.8));
};
}
Game.prototype = {
update: function() {
// Next level
if (game.invaders.length === 0) {
spawnDelayCounter += 1;
if (spawnDelayCounter < invaderSpawnDelay) return;
this.level += 1;
invaderAttackRate -= 0.002;
invaderSpeed += 10;
game.invaders = createInvaders();
spawnDelayCounter = 0;
}
if (!this.lost) {
// Collision
game.player.projectile.forEach(function(projectile) {
game.invaders.forEach(function(invader) {
if (collides(projectile, invader)) {
invader.destroy();
projectile.active = false;
}
});
});
this.invaderShots.forEach(function(invaderShots) {
if (collides(invaderShots, game.player)) {
game.player.destroy();
}
});
for (i = 0; i < game.invaders.length; i++) game.invaders[i].update();
}
// Don't stop player & projectiles.. they look nice
game.player.update();
for (i = 0; i < game.invaderShots.length; i++) game.invaderShots[i].update();
this.invaders = game.invaders.filter(function(invader) {
return invader.active;
});
},
draw: function() {
if (this.lost) {
screen.fillStyle = "rgba(0, 0, 0, 0.03)";
screen.fillRect(0, 0, gameSize.width, gameSize.height);
screen.font = "55px Lucida Console";
screen.textAlign = "center";
screen.fillStyle = "white";
screen.fillText("You lost", gameSize.width / 2, gameSize.height / 2);
screen.font = "20px Lucida Console";
screen.fillText("Points: " + kills, gameSize.width / 2, gameSize.height / 2 + 30);
} else {
screen.clearRect(0, 0, gameSize.width, gameSize.height);
screen.font = "10px Lucida Console";
screen.textAlign = "right";
screen.fillText("Points: " + kills, gameSize.width, gameSize.height - 12);
}
screen.beginPath();
var i;
this.player.draw();
if (!this.lost)
for (i = 0; i < this.invaders.length; i++) this.invaders[i].draw();
for (i = 0; i < this.invaderShots.length; i++) this.invaderShots[i].draw();
screen.fill();
},
invadersBelow: function(invader) {
return this.invaders.filter(function(b) {
return Math.abs(invader.coordinates.x - b.coordinates.x) === 0 &&
b.coordinates.y > invader.coordinates.y;
}).length > 0;
}
};
// Invaders
// --------
var Invader = function(coordinates) {
this.active = true;
this.coordinates = coordinates;
this.size = {
width: invaderSize,
height: invaderSize
};
this.patrolX = 0;
this.speedX = invaderSpeed;
};
Invader.prototype = {
update: function() {
if (Math.random() > invaderAttackRate && !game.invadersBelow(this)) {
var projectile = new Projectile({
x: this.coordinates.x + this.size.width / 2,
y: this.coordinates.y + this.size.height - 5
}, {
x: 0,
y: 2
});
game.invaderShots.push(projectile);
}
},
draw: function() {
if (this.active) screen.drawImage(invaderCanvas, this.coordinates.x, this.coordinates.y);
},
move: function() {
if (this.patrolX < 0 || this.patrolX > 100) {
this.speedX = -this.speedX;
this.patrolX += this.speedX;
this.coordinates.y += this.size.height;
if (this.coordinates.y + this.size.height * 2 > gameSize.height) game.lost = true;
} else {
this.coordinates.x += this.speedX;
this.patrolX += this.speedX;
}
},
destroy: function() {
this.active = false;
kills += 1;
}
};
// Player
// ------
var Player = function() {
this.active = true;
this.size = {
width: 16,
height: 8
};
this.shooterHeat = -3;
this.coordinates = {
x: gameSize.width / 2 - (this.size.width / 2) | 0,
y: gameSize.height - this.size.height * 2
};
this.projectile = [];
this.keyboarder = new KeyController();
};
Player.prototype = {
update: function() {
for (var i = 0; i < this.projectile.length; i++) this.projectile[i].update();
this.projectile = this.projectile.filter(function(projectile) {
return projectile.active;
});
if (!this.active) return;
if (this.keyboarder.isDown(this.keyboarder.KEYS.LEFT) && this.coordinates.x > 0) this.coordinates.x -= 2;
else if (this.keyboarder.isDown(this.keyboarder.KEYS.RIGHT) && this.coordinates.x < gameSize.width - this.size.width) this.coordinates.x += 2;
if (this.keyboarder.isDown(this.keyboarder.KEYS.Space)) {
this.shooterHeat += 1;
if (this.shooterHeat < 0) {
var projectile = new Projectile({
x: this.coordinates.x + this.size.width / 2 - 1,
y: this.coordinates.y - 1
}, {
x: 0,
y: -7
});
this.projectile.push(projectile);
} else if (this.shooterHeat > 12) this.shooterHeat = -3;
} else {
this.shooterHeat = -3;
}
},
draw: function() {
if (this.active) {
screen.rect(this.coordinates.x, this.coordinates.y, this.size.width, this.size.height);
screen.rect(this.coordinates.x - 2, this.coordinates.y + 2, 20, 6);
screen.rect(this.coordinates.x + 6, this.coordinates.y - 4, 4, 4);
}
for (var i = 0; i < this.projectile.length; i++) this.projectile[i].draw();
},
destroy: function() {
this.active = false;
game.lost = true;
}
};
// Projectile
// ------
var Projectile = function(coordinates, velocity) {
this.active = true;
this.coordinates = coordinates;
this.size = {
width: 3,
height: 3
};
this.velocity = velocity;
};
Projectile.prototype = {
update: function() {
this.coordinates.x += this.velocity.x;
this.coordinates.y += this.velocity.y;
if (this.coordinates.y > gameSize.height || this.coordinates.y < 0) this.active = false;
},
draw: function() {
if (this.active) screen.rect(this.coordinates.x, this.coordinates.y, this.size.width, this.size.height);
}
};
// Keyboard input tracking
// -----------------------
var KeyController = function() {
this.KEYS = {
LEFT: 37,
RIGHT: 39,
Space: 32
};
var keyCode = [37, 39, 32];
var keyState = {};
var counter;
window.addEventListener('keydown', function(e) {
for (counter = 0; counter < keyCode.length; counter++)
if (keyCode[counter] == e.keyCode) {
keyState[e.keyCode] = true;
e.preventDefault();
}
});
window.addEventListener('keyup', function(e) {
for (counter = 0; counter < keyCode.length; counter++)
if (keyCode[counter] == e.keyCode) {
keyState[e.keyCode] = false;
e.preventDefault();
}
});
this.isDown = function(keyCode) {
return keyState[keyCode] === true;
};
};
// Other functions
// ---------------
function collides(a, b) {
return a.coordinates.x < b.coordinates.x + b.size.width &&
a.coordinates.x + a.size.width > b.coordinates.x &&
a.coordinates.y < b.coordinates.y + b.size.height &&
a.coordinates.y + a.size.height > b.coordinates.y;
}
function getPixelRow(rowRaw) {
var textRow = [],
placer = 0,
row = Math.floor(rowRaw / invaderMultiplier);
if (row >= blocks.length) return [];
for (var i = 0; i < blocks[row].length; i++) {
var tmpContent = blocks[row][i] * invaderMultiplier;
for (var j = 0; j < invaderMultiplier; j++) textRow[placer + j] = tmpContent + j;
placer += invaderMultiplier;
}
return textRow;
}
// Write Text
// -----------
function createInvaders() {
var invaders = [];
var i = blocks.length * invaderMultiplier;
while (i--) {
var j = getPixelRow(i);
for (var k = 0; k < j.length; k++) {
invaders.push(new Invader({
x: j[k] * invaderSize,
y: i * invaderSize
}));
}
}
return invaders;
}
// Start game
// ----------
window.addEventListener('load', function() {
var invaderAsset = new Image;
invaderAsset.onload = function() {
invaderCanvas = document.createElement('canvas');
invaderCanvas.width = invaderSize;
invaderCanvas.height = invaderSize;
invaderCanvas.getContext("2d").drawImage(invaderAsset, 0, 0);
// Game Creation
canvas = document.getElementById("space-invaders");
screen = canvas.getContext('2d');
initGameStart();
loop();
};
invaderAsset.src = "/assets/img/invader.gif";
});
window.addEventListener('resize', function() {
initGameStart();
});
document.getElementById('restart').addEventListener('click', function() {
initGameStart();
});
function initGameStart() {
if (window.innerWidth > 1200) {
screen.canvas.width = 1200;
screen.canvas.height = 500;
gameSize = {
width: 1200,
height: 500
};
invaderMultiplier = 3;
initialOffsetInvader = 420;
} else if (window.innerWidth > 800) {
screen.canvas.width = 900;
screen.canvas.height = 600;
gameSize = {
width: 900,
height: 600
};
invaderMultiplier = 2;
initialOffsetInvader = 280;
} else {
screen.canvas.width = 600;
screen.canvas.height = 300;
gameSize = {
width: 600,
height: 300
};
invaderMultiplier = 1;
initialOffsetInvader = 140;
}
kills = 0;
invaderAttackRate = 0.999;
invaderSpeed = 20;
spawnDelayCounter = invaderSpawnDelay;
game = new Game();
}
function loop() {
game.update();
game.draw();
requestAnimationFrame(loop);
}
})();

View File

@@ -56,7 +56,7 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
</head>
<body id="page-top" data-bs-spy="scroll" data-bs-target="#mainNav" data-bs-offset="77">
{{handshake_scripts}}
{{handshake_scripts | safe}}
<!-- <script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn"></script>
<script src="https://nathan.woodburn/https.js"></script> --><!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NNXTCKW"

View File

@@ -109,7 +109,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<p class="copyright">Copyright ©&nbsp;Nathan Woodburn 2023</p>
</div>
</footer>
{{handshake_scripts}}
{{handshake_scripts | safe}}
<!-- <script src="https://nathan.woodburn/handshake.js" domain="nathan.woodburn"></script>
<script src="https://nathan.woodburn/https.js"></script> -->
<script src="assets/bootstrap/js/bootstrap.min.js"></script>