Skip to content

Instantly share code, notes, and snippets.

@primaryobjects
Last active May 19, 2024 23:20
Show Gist options
  • Save primaryobjects/8afac850615fe5b9a0c76206bbb0c81d to your computer and use it in GitHub Desktop.
Save primaryobjects/8afac850615fe5b9a0c76206bbb0c81d to your computer and use it in GitHub Desktop.
Gauntlet-like game created with ChatGPT4o using HTML and Javascript https://jsbin.com/ketusuveve/1/edit?js,output

Gauntlet-like Game

Created with ChatGPT4o

gauntlet

3D Version

A 3D version of the same game with ChatGPT4o

gauntlet3d9

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gauntlet-like Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div id="flash" class="flash"></div>
<script src="game.js"></script>
</body>
</html>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const flash = document.getElementById('flash');
const player = { x: 50, y: 50, width: 20, height: 20, speed: 5, dx: 0, dy: 0, health: 100 };
let score = 0;
let kills = 0;
let projectiles = [];
const enemies = [];
const generators = [];
const maxInitialEnemies = 30;
const tileSize = 10;
let walls = [];
let treasures = [];
let level = 1;
let treasuresCollected = 0;
let totalTreasures = 0;
// Function to initialize a new level
function initLevel() {
// Reset treasures collected for the new level
treasuresCollected = 0;
walls = generateWalls();
treasures = generateTreasures();
totalTreasures = treasures.length;
generateGenerators();
// Increment the level number
level++;
}
function initGame() {
walls = generateWalls();
treasures = generateTreasures();
totalTreasures = treasures.length;
generateGenerators();
score = 0;
kills = 0;
projectiles = [];
player.health = 100;
}
function generateWalls() {
const walls = [];
const rooms = 5;
const roomWidth = 100;
const roomHeight = 100;
for (let i = 0; i < rooms; i++) {
const x = Math.random() * (canvas.width - roomWidth);
const y = Math.random() * (canvas.height - roomHeight);
walls.push({ x, y, width: roomWidth, height: 20 }); // Top wall
walls.push({ x, y, width: 20, height: roomHeight }); // Left wall
walls.push({ x: x + roomWidth - 20, y, width: 20, height: roomHeight }); // Right wall
walls.push({ x, y: y + roomHeight - 20, width: roomWidth, height: 20 }); // Bottom wall
const entranceWall = Math.floor(Math.random() * 4);
const entrancePos = Math.random() * (roomWidth - 40) + 20;
switch (entranceWall) {
case 0: // Top wall
walls.pop();
break;
case 1: // Left wall
walls.pop();
break;
case 2: // Right wall
walls.pop();
break;
case 3: // Bottom wall
walls.pop();
break;
}
}
// Adding random walls to the dungeon
const extraWalls = 10;
for (let i = 0; i < extraWalls; i++) {
const x = Math.random() * (canvas.width - 50);
const y = Math.random() * (canvas.height - 50);
const width = Math.random() * 50 + 20;
const height = Math.random() * 50 + 20;
walls.push({ x, y, width, height });
}
return walls;
}
function generateTreasures() {
const treasures = [];
for (let i = 0; i < 10; i++) {
const x = Math.random() * (canvas.width - 15);
const y = Math.random() * (canvas.height - 15);
treasures.push({ x, y, width: 15, height: 15 });
}
return treasures;
}
function generateGenerators() {
const generatorCount = Math.floor(Math.random() * 5) + 3;
for (let i = 0; i < generatorCount; i++) {
const x = Math.random() * (canvas.width - 40) + 20;
const y = Math.random() * (canvas.height - 40) + 20;
const generator = { x, y, width: 20, height: 20, health: 5 };
generators.push(generator);
spawnEnemiesFromGenerator(generator);
}
}
function spawnEnemiesFromGenerator(generator) {
if (generator.health > 0 && enemies.length < maxInitialEnemies) {
const enemy = { x: generator.x, y: generator.y, width: 20, height: 20, speed: 2, dx: 0, dy: 0 };
enemies.push(enemy);
setTimeout(() => spawnEnemiesFromGenerator(generator), 3000);
}
}
function drawPlayer() {
ctx.fillStyle = 'blue';
ctx.fillRect(player.x, player.y, player.width, player.height);
}
function drawEnemies() {
ctx.fillStyle = 'red';
enemies.forEach(enemy => {
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
});
}
function drawWalls() {
ctx.fillStyle = 'gray';
walls.forEach(wall => {
ctx.fillRect(wall.x, wall.y, wall.width, wall.height);
});
}
function drawTreasures() {
ctx.fillStyle = 'yellow';
treasures.forEach(treasure => {
ctx.fillRect(treasure.x, treasure.y, treasure.width, treasure.height);
});
}
function drawProjectiles() {
ctx.fillStyle = 'white';
projectiles.forEach(projectile => {
ctx.fillRect(projectile.x, projectile.y, projectile.width, projectile.height);
});
}
function drawGenerators() {
generators.forEach(generator => {
ctx.fillStyle = `rgb(${255 - generator.health * 50}, 0, 0)`;
ctx.fillRect(generator.x, generator.y, generator.width, generator.height);
});
}
function drawScore() {
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText(`Score: ${score}`, 10, 30);
ctx.fillText(`Kills: ${kills}`, 150, 30);
ctx.fillText(`Health: ${player.health}`, 300, 30);
}
function updatePlayer() {
player.x += player.dx;
player.y += player.dy;
walls.forEach(wall => {
if (isColliding(player, wall)) {
player.x -= player.dx;
player.y -= player.dy;
}
});
if (player.x < 0) player.x = 0;
if (player.y < 0) player.y = 0;
if (player.x + player.width > canvas.width) player.x = canvas.width - player.width;
if (player.y + player.height > canvas.height) player.y = canvas.height - player.height;
}
// Define a Node class for A* pathfinding
class Node {
constructor(x, y) {
this.x = x;
this.y = y;
this.parent = null;
this.f = 0;
this.g = 0;
this.h = 0;
}
}
function findPath(start, end) {
// Check if start and end nodes are the same
if (start.x === end.x && start.y === end.y) {
return [];
}
const openList = [];
const closedList = [];
const grid = [];
const path = [];
for (let y = 0; y < canvas.height / tileSize; y++) {
grid[y] = [];
for (let x = 0; x < canvas.width / tileSize; x++) {
grid[y][x] = { x, y, walkable: !walls.some(wall => isColliding({ x: x * tileSize, y: y * tileSize, width: tileSize, height: tileSize }, wall)) };
}
}
const startNode = new Node(Math.floor(start.x / tileSize), Math.floor(start.y / tileSize));
const endNode = new Node(Math.floor(end.x / tileSize), Math.floor(end.y / tileSize));
openList.push(startNode);
while (openList.length > 0) {
let currentNode = openList[0];
for (let i = 1; i < openList.length; i++) {
if (openList[i].f < currentNode.f || (openList[i].f === currentNode.f && openList[i].h < currentNode.h)) {
currentNode = openList[i];
}
}
openList.splice(openList.indexOf(currentNode), 1);
closedList.push(currentNode);
if (currentNode.x === endNode.x && currentNode.y === endNode.y) {
let current = currentNode;
while (current.parent) {
path.push({ x: current.x, y: current.y });
current = current.parent;
}
return path.reverse();
}
const neighbors = [];
for (let x = -1; x <= 1; x++) {
for (let y = -1; y <= 1; y++) {
if (x === 0 && y === 0) continue;
const checkX = currentNode.x + x;
const checkY = currentNode.y + y;
if (checkX >= 0 && checkX < grid[0].length && checkY >= 0 && checkY < grid.length && grid[checkY][checkX].walkable) {
neighbors.push(grid[checkY][checkX]);
}
}
}
neighbors.forEach(neighbor => {
if (!closedList.some(node => node.x === neighbor.x && node.y === neighbor.y)) {
const gScore = currentNode.g + 1;
const hScore = Math.abs(neighbor.x - endNode.x) + Math.abs(neighbor.y - endNode.y);
const fScore = gScore + hScore;
if (!openList.some(node => node.x === neighbor.x && node.y === neighbor.y) || gScore < neighbor.g) {
neighbor.parent = currentNode;
neighbor.g = gScore;
neighbor.h = hScore;
neighbor.f = fScore;
if (!openList.some(node => node.x === neighbor.x && node.y === neighbor.y)) {
openList.push(neighbor);
}
}
}
});
}
// No path found
return [];
}
function updateEnemies() {
enemies.forEach((enemy, enemyIndex) => {
const path = findPath(enemy, player);
if (path.length > 1) {
const nextTile = path[1];
const targetX = nextTile.x * tileSize + tileSize / 2;
const targetY = nextTile.y * tileSize + tileSize / 2;
const dx = targetX - enemy.x;
const dy = targetY - enemy.y;
const distance = Math.sqrt(dx * dx + dy * dy);
enemy.dx = (dx / distance) * enemy.speed;
enemy.dy = (dy / distance) * enemy.speed;
enemy.x += enemy.dx;
enemy.y += enemy.dy;
}
if (isColliding(player, enemy)) {
enemies.splice(enemyIndex, 1);
player.health -= 20;
flashScreen();
if (player.health <= 0) {
console.log("Game Over");
initGame();
}
}
});
}
function flashScreen() {
flash.style.backgroundColor = 'rgba(255, 0, 0, 0.5)';
setTimeout(() => {
flash.style.backgroundColor = 'rgba(255, 0, 0, 0)';
}, 100);
}
function updateProjectiles() {
projectiles.forEach((projectile, projectileIndex) => {
projectile.x += projectile.dx;
projectile.y += projectile.dy;
enemies.forEach((enemy, enemyIndex) => {
if (isColliding(projectile, enemy)) {
enemies.splice(enemyIndex, 1);
projectiles.splice(projectileIndex, 1);
kills += 1;
}
});
generators.forEach((generator, generatorIndex) => {
if (isColliding(projectile, generator)) {
generator.health -= 1;
projectiles.splice(projectileIndex, 1);
if (generator.health <= 0) {
generators.splice(generatorIndex, 1);
}
}
});
if (projectile.x < 0 || projectile.y < 0 || projectile.x > canvas.width || projectile.y > canvas.height) {
projectiles.splice(projectileIndex, 1);
}
// Check for collision with walls
if (isProjectileCollidingWithWalls(projectile)) {
projectiles.splice(projectileIndex, 1);
}
});
}
function isProjectileCollidingWithWalls(projectile) {
return walls.some(wall => isColliding(projectile, wall));
}
function isColliding(rect1, rect2) {
return (
rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y
);
}
function shootProjectile() {
let target = null;
// Find the closest enemy
if (enemies.length > 0) {
target = enemies.reduce((closest, enemy) => {
const distToClosest = Math.hypot(closest.x - player.x, closest.y - player.y);
const distToEnemy = Math.hypot(enemy.x - player.x, enemy.y - player.y);
return distToEnemy < distToClosest ? enemy : closest;
}, enemies[0]);
}
// Find the closest generator
if (generators.length > 0) {
const generatorTarget = generators.reduce((closest, generator) => {
const distToClosest = Math.hypot(closest.x - player.x, closest.y - player.y);
const distToGenerator = Math.hypot(generator.x - player.x, generator.y - player.y);
return distToGenerator < distToClosest ? generator : closest;
}, generators[0]);
// If there are no enemies or generator is closer, target the generator
if (!target || Math.hypot(generatorTarget.x - player.x, generatorTarget.y - player.y) < Math.hypot(target.x - player.x, target.y - player.y)) {
target = generatorTarget;
}
}
if (target) {
const dx = target.x - player.x;
const dy = target.y - player.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const projectile = {
x: player.x + player.width / 2,
y: player.y + player.height / 2,
width: 5,
height: 5,
dx: (dx / distance) * 10,
dy: (dy / distance) * 10
};
projectiles.push(projectile);
}
}
// Function to draw the level number on the screen
function drawLevelNumber() {
ctx.fillStyle = "white";
ctx.font = "20px Arial";
ctx.fillText("Level: " + level, 500, 30);
}
function update() {
clear();
drawWalls();
drawPlayer();
drawEnemies();
drawTreasures();
drawProjectiles();
drawGenerators();
drawScore();
drawLevelNumber();
updatePlayer();
updateEnemies();
updateProjectiles();
checkTreasureCollection();
requestAnimationFrame(update);
}
function checkTreasureCollection() {
treasures.forEach((treasure, index) => {
if (isColliding(player, treasure)) {
treasures.splice(index, 1);
score += 10;
treasuresCollected++;
console.log(`${treasuresCollected} === ${totalTreasures}`)
if (treasuresCollected === totalTreasures) {
// Trigger cool animation effect
triggerAnimationEffect(() => {
// After animation, initialize the next level
initLevel();
});
}
}
});
}
// Function to trigger a cool animation effect
function triggerAnimationEffect(callback) {
// Define animation parameters
const animationDuration = 1000; // in milliseconds
const rotationSpeed = Math.PI / 180; // 1 degree rotation per frame
let elapsedTime = 0;
// Start animation loop
const animationLoop = () => {
// Clear the canvas
clear();
// Draw the rotating and fading effect
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(elapsedTime * rotationSpeed);
ctx.globalAlpha = 1 - (elapsedTime / animationDuration);
ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
ctx.fillRect(-canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);
ctx.restore();
// Update elapsed time
elapsedTime += 16; // Assuming 60 frames per second
if (elapsedTime < animationDuration) {
// Continue animation loop
requestAnimationFrame(animationLoop);
} else {
// Animation complete, call the callback function
callback();
}
};
// Start the animation loop
animationLoop();
}
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function movePlayer(e) {
switch (e.key) {
case 'ArrowUp':
player.dy = -player.speed;
break;
case 'ArrowDown':
player.dy = player.speed;
break;
case 'ArrowLeft':
player.dx = -player.speed;
break;
case 'ArrowRight':
player.dx = player.speed;
break;
case ' ':
shootProjectile();
break;
}
}
function stopPlayer(e) {
switch (e.key) {
case 'ArrowUp':
case 'ArrowDown':
player.dy = 0;
break;
case 'ArrowLeft':
case 'ArrowRight':
player.dx = 0;
break;
}
}
document.addEventListener('keydown', movePlayer);
document.addEventListener('keyup', stopPlayer);
initGame();
update();
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #000;
}
canvas {
background-color: #111;
border: 1px solid #fff;
}
.flash {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 0, 0, 0);
transition: background-color 0.5s ease-out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment