inital commit with game file and Readme
This commit is contained in:
12
Readme.md
Normal file
12
Readme.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# ZIP!
|
||||
|
||||
This is a very small javascrpt game made using the Claude AI tool (using Claude-sonnet4)
|
||||
|
||||
## Instructions
|
||||
|
||||
Use the arrow keys ( <- and ->) or the 'a' and 'd' keys to guide the green player to collect as much loot as possible. The enemy player (red) will be trying to do the same.
|
||||
|
||||
The loot spawns randomly and is worth less points the longer it is un-collected.
|
||||
|
||||
First to 1000 points wins!
|
||||
|
||||
673
index.html
Normal file
673
index.html
Normal file
@@ -0,0 +1,673 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Loot Collector</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
font-family: 'Courier New', monospace;
|
||||
color: white;
|
||||
}
|
||||
|
||||
canvas {
|
||||
border: 3px solid #00ff88;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 30px rgba(0, 255, 136, 0.3);
|
||||
}
|
||||
|
||||
.ui {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.score {
|
||||
font-size: 24px;
|
||||
color: #00ff88;
|
||||
text-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
|
||||
}
|
||||
|
||||
.instructions {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.countdown {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 72px;
|
||||
color: #00ff88;
|
||||
text-shadow: 0 0 30px rgba(0, 255, 136, 0.8);
|
||||
z-index: 20;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.winner-screen {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.winner-text {
|
||||
font-size: 64px;
|
||||
color: #00ff88;
|
||||
text-shadow: 0 0 40px rgba(0, 255, 136, 1);
|
||||
margin-bottom: 20px;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.winner-score {
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.restart-button {
|
||||
padding: 15px 30px;
|
||||
font-size: 24px;
|
||||
background: linear-gradient(45deg, #00ff88, #00cc6a);
|
||||
color: #000;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.restart-button:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.space-hint {
|
||||
color: #aaa;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="ui">
|
||||
<div class="score">Player: <span id="playerScore">0</span> | Enemy: <span id="enemyScore">0</span></div>
|
||||
</div>
|
||||
|
||||
<div id="countdownDisplay" class="countdown">5</div>
|
||||
|
||||
<div id="winnerScreen" class="winner-screen">
|
||||
<div id="winnerText" class="winner-text">PLAYER WINS!</div>
|
||||
<div id="finalScore" class="winner-score">Final Score: Player 1000 - Enemy 850</div>
|
||||
<button id="restartButton" class="restart-button">PLAY AGAIN</button>
|
||||
<div class="space-hint">or press SPACE to restart</div>
|
||||
</div>
|
||||
|
||||
<canvas id="gameCanvas" width="800" height="600"></canvas>
|
||||
|
||||
<div class="instructions">
|
||||
Use A/D or Left/Right arrows to steer • Collect the glowing loot!
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('gameCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const playerScoreElement = document.getElementById('playerScore');
|
||||
const enemyScoreElement = document.getElementById('enemyScore');
|
||||
const countdownElement = document.getElementById('countdownDisplay');
|
||||
const winnerScreen = document.getElementById('winnerScreen');
|
||||
const winnerText = document.getElementById('winnerText');
|
||||
const finalScore = document.getElementById('finalScore');
|
||||
const restartButton = document.getElementById('restartButton');
|
||||
|
||||
// Game state
|
||||
let playerScore = 0;
|
||||
let enemyScore = 0;
|
||||
let gameRunning = false; // Start paused for countdown
|
||||
let gameEnded = false;
|
||||
let countdown = 5; // 5 second countdown
|
||||
let countdownTimer = 0;
|
||||
|
||||
// Player object
|
||||
const player = {
|
||||
x: 0, // Will be set randomly
|
||||
y: 0, // Will be set randomly
|
||||
size: 20,
|
||||
speed: 4,
|
||||
color: '#00ff88',
|
||||
direction: 0, // angle in radians
|
||||
velocity: { x: 0, y: 0 }
|
||||
};
|
||||
|
||||
// Trail system
|
||||
let playerTrail = [];
|
||||
|
||||
// Enemy object
|
||||
const enemy = {
|
||||
x: 0, // Will be set randomly
|
||||
y: 0, // Will be set randomly
|
||||
size: 20,
|
||||
speed: 3.5,
|
||||
color: '#ff4444',
|
||||
direction: 0, // Will be set randomly
|
||||
velocity: { x: 0, y: 0 },
|
||||
turnCooldown: 0,
|
||||
targetLoot: null
|
||||
};
|
||||
|
||||
// Enemy trail system
|
||||
let enemyTrail = [];
|
||||
|
||||
// Loot array
|
||||
let loot = [];
|
||||
let lootSpawnTimer = 0;
|
||||
const lootSpawnInterval = 120; // frames between spawns (2 seconds at 60fps)
|
||||
|
||||
// Input handling
|
||||
const keys = {};
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
keys[e.key.toLowerCase()] = true;
|
||||
|
||||
// Restart with spacebar
|
||||
if (e.key === ' ' && gameEnded) {
|
||||
restartGame();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
keys[e.key.toLowerCase()] = false;
|
||||
});
|
||||
|
||||
// Create loot
|
||||
function createLoot() {
|
||||
const lootItem = {
|
||||
x: Math.random() * (canvas.width - 20) + 10,
|
||||
y: Math.random() * (canvas.height - 20) + 10,
|
||||
size: 12,
|
||||
color: `hsl(0, 100%, 60%)`, // Start red
|
||||
glow: Math.random() * 10 + 5,
|
||||
pulse: Math.random() * 0.1 + 0.05,
|
||||
alpha: 0, // Start invisible
|
||||
fadeSpeed: 0.02,
|
||||
age: 1 // Start at age 1
|
||||
};
|
||||
loot.push(lootItem);
|
||||
}
|
||||
|
||||
// Restart button event
|
||||
restartButton.addEventListener('click', restartGame);
|
||||
|
||||
// Randomize starting positions
|
||||
function randomizeStartingPositions() {
|
||||
// Keep players away from edges and each other
|
||||
const margin = 50;
|
||||
let validPosition = false;
|
||||
let attempts = 0;
|
||||
|
||||
// Set player position
|
||||
player.x = Math.random() * (canvas.width - 2 * margin) + margin;
|
||||
player.y = Math.random() * (canvas.height - 2 * margin) + margin;
|
||||
player.direction = Math.random() * 2 * Math.PI;
|
||||
|
||||
// Set enemy position (make sure it's not too close to player)
|
||||
while (!validPosition && attempts < 20) {
|
||||
enemy.x = Math.random() * (canvas.width - 2 * margin) + margin;
|
||||
enemy.y = Math.random() * (canvas.height - 2 * margin) + margin;
|
||||
|
||||
const distance = Math.sqrt(
|
||||
Math.pow(player.x - enemy.x, 2) +
|
||||
Math.pow(player.y - enemy.y, 2)
|
||||
);
|
||||
|
||||
if (distance > 100) { // Minimum distance between players
|
||||
validPosition = true;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
enemy.direction = Math.random() * 2 * Math.PI;
|
||||
}
|
||||
|
||||
// Restart game function
|
||||
function restartGame() {
|
||||
// Reset game state
|
||||
playerScore = 0;
|
||||
enemyScore = 0;
|
||||
gameRunning = false;
|
||||
gameEnded = false;
|
||||
countdown = 5;
|
||||
countdownTimer = 0;
|
||||
|
||||
// Reset UI
|
||||
playerScoreElement.textContent = '0';
|
||||
enemyScoreElement.textContent = '0';
|
||||
countdownElement.textContent = '5';
|
||||
countdownElement.style.display = 'block';
|
||||
winnerScreen.style.display = 'none';
|
||||
|
||||
// Randomize starting positions
|
||||
randomizeStartingPositions();
|
||||
|
||||
// Reset velocities
|
||||
player.velocity.x = 0;
|
||||
player.velocity.y = 0;
|
||||
enemy.velocity.x = 0;
|
||||
enemy.velocity.y = 0;
|
||||
enemy.turnCooldown = 0;
|
||||
|
||||
// Clear trails and loot
|
||||
playerTrail = [];
|
||||
enemyTrail = [];
|
||||
loot = [];
|
||||
lootSpawnTimer = 0;
|
||||
}
|
||||
|
||||
// Check for winner
|
||||
function checkWinner() {
|
||||
if (gameEnded) return;
|
||||
|
||||
if (playerScore >= 1000) {
|
||||
gameEnded = true;
|
||||
gameRunning = false;
|
||||
winnerText.textContent = "PLAYER WINS!";
|
||||
winnerText.style.color = "#00ff88";
|
||||
finalScore.textContent = `Final Score: Player ${playerScore} - Enemy ${enemyScore}`;
|
||||
winnerScreen.style.display = 'flex';
|
||||
} else if (enemyScore >= 1000) {
|
||||
gameEnded = true;
|
||||
gameRunning = false;
|
||||
winnerText.textContent = "ENEMY WINS!";
|
||||
winnerText.style.color = "#ff4444";
|
||||
finalScore.textContent = `Final Score: Player ${playerScore} - Enemy ${enemyScore}`;
|
||||
winnerScreen.style.display = 'flex';
|
||||
}
|
||||
}
|
||||
|
||||
// Update countdown
|
||||
function updateCountdown() {
|
||||
if (countdown > 0) {
|
||||
countdownTimer++;
|
||||
if (countdownTimer >= 60) { // 1 second at 60fps
|
||||
countdown--;
|
||||
countdownTimer = 0;
|
||||
|
||||
if (countdown > 0) {
|
||||
countdownElement.textContent = countdown;
|
||||
} else {
|
||||
countdownElement.textContent = "GO!";
|
||||
// Start the game after a brief "GO!" display
|
||||
setTimeout(() => {
|
||||
gameRunning = true;
|
||||
countdownElement.style.display = 'none';
|
||||
|
||||
// Spawn initial loot
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const lootItem = {
|
||||
x: Math.random() * (canvas.width - 20) + 10,
|
||||
y: Math.random() * (canvas.height - 20) + 10,
|
||||
size: 12,
|
||||
color: `hsl(0, 100%, 60%)`,
|
||||
glow: Math.random() * 10 + 5,
|
||||
pulse: Math.random() * 0.1 + 0.05,
|
||||
alpha: 1,
|
||||
fadeSpeed: 0.02,
|
||||
age: 1
|
||||
};
|
||||
loot.push(lootItem);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update player position
|
||||
function updatePlayer() {
|
||||
if (!gameRunning || gameEnded) return; // Don't move during countdown or when game ended
|
||||
|
||||
// Handle steering input
|
||||
let turning = 0;
|
||||
if (keys['a'] || keys['arrowleft']) turning -= 0.06;
|
||||
if (keys['d'] || keys['arrowright']) turning += 0.06;
|
||||
|
||||
// Apply turning
|
||||
player.direction += turning;
|
||||
|
||||
// Always move forward in current direction
|
||||
player.velocity.x = Math.cos(player.direction) * player.speed;
|
||||
player.velocity.y = Math.sin(player.direction) * player.speed;
|
||||
|
||||
// Update position
|
||||
player.x += player.velocity.x;
|
||||
player.y += player.velocity.y;
|
||||
|
||||
// Bounce off walls
|
||||
if (player.x - player.size < 0) {
|
||||
player.x = player.size;
|
||||
player.direction = Math.PI - player.direction; // Reflect horizontally
|
||||
}
|
||||
if (player.x + player.size > canvas.width) {
|
||||
player.x = canvas.width - player.size;
|
||||
player.direction = Math.PI - player.direction; // Reflect horizontally
|
||||
}
|
||||
if (player.y - player.size < 0) {
|
||||
player.y = player.size;
|
||||
player.direction = -player.direction; // Reflect vertically
|
||||
}
|
||||
if (player.y + player.size > canvas.height) {
|
||||
player.y = canvas.height - player.size;
|
||||
player.direction = -player.direction; // Reflect vertically
|
||||
}
|
||||
|
||||
// Add current position to trail
|
||||
playerTrail.push({
|
||||
x: player.x,
|
||||
y: player.y,
|
||||
alpha: 1.0,
|
||||
size: player.size
|
||||
});
|
||||
|
||||
// Limit trail length and fade out
|
||||
if (playerTrail.length > 15) {
|
||||
playerTrail.shift();
|
||||
}
|
||||
|
||||
// Fade trail segments
|
||||
playerTrail.forEach((segment, index) => {
|
||||
segment.alpha = (index + 1) / playerTrail.length * 0.7;
|
||||
segment.size = player.size * (segment.alpha * 0.8 + 0.2);
|
||||
});
|
||||
}
|
||||
|
||||
// Update enemy AI
|
||||
function updateEnemy() {
|
||||
if (!gameRunning || gameEnded) return; // Don't move during countdown or when game ended
|
||||
|
||||
// Find closest loot
|
||||
let closestLoot = null;
|
||||
let closestDistance = Infinity;
|
||||
|
||||
loot.forEach(item => {
|
||||
if (item.alpha > 0.5) { // Only target visible loot
|
||||
const dx = enemy.x - item.x;
|
||||
const dy = enemy.y - item.y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
closestLoot = item;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// AI steering towards loot
|
||||
if (closestLoot && enemy.turnCooldown <= 0) {
|
||||
const dx = closestLoot.x - enemy.x;
|
||||
const dy = closestLoot.y - enemy.y;
|
||||
const targetAngle = Math.atan2(dy, dx);
|
||||
|
||||
// Calculate angle difference
|
||||
let angleDiff = targetAngle - enemy.direction;
|
||||
|
||||
// Normalize angle difference to -PI to PI
|
||||
while (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
|
||||
while (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;
|
||||
|
||||
// Turn towards target (similar turning speed to player)
|
||||
if (Math.abs(angleDiff) > 0.1) {
|
||||
if (angleDiff > 0) {
|
||||
enemy.direction += 0.05;
|
||||
} else {
|
||||
enemy.direction -= 0.05;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce turn cooldown
|
||||
if (enemy.turnCooldown > 0) enemy.turnCooldown--;
|
||||
|
||||
// Always move forward in current direction
|
||||
enemy.velocity.x = Math.cos(enemy.direction) * enemy.speed;
|
||||
enemy.velocity.y = Math.sin(enemy.direction) * enemy.speed;
|
||||
|
||||
// Update position
|
||||
enemy.x += enemy.velocity.x;
|
||||
enemy.y += enemy.velocity.y;
|
||||
|
||||
// Bounce off walls (same as player)
|
||||
if (enemy.x - enemy.size < 0) {
|
||||
enemy.x = enemy.size;
|
||||
enemy.direction = Math.PI - enemy.direction;
|
||||
enemy.turnCooldown = 30; // Brief cooldown after bouncing
|
||||
}
|
||||
if (enemy.x + enemy.size > canvas.width) {
|
||||
enemy.x = canvas.width - enemy.size;
|
||||
enemy.direction = Math.PI - enemy.direction;
|
||||
enemy.turnCooldown = 30;
|
||||
}
|
||||
if (enemy.y - enemy.size < 0) {
|
||||
enemy.y = enemy.size;
|
||||
enemy.direction = -enemy.direction;
|
||||
enemy.turnCooldown = 30;
|
||||
}
|
||||
if (enemy.y + enemy.size > canvas.height) {
|
||||
enemy.y = canvas.height - enemy.size;
|
||||
enemy.direction = -enemy.direction;
|
||||
enemy.turnCooldown = 30;
|
||||
}
|
||||
|
||||
// Add current position to enemy trail
|
||||
enemyTrail.push({
|
||||
x: enemy.x,
|
||||
y: enemy.y,
|
||||
alpha: 1.0,
|
||||
size: enemy.size
|
||||
});
|
||||
|
||||
// Limit trail length and fade out
|
||||
if (enemyTrail.length > 15) {
|
||||
enemyTrail.shift();
|
||||
}
|
||||
|
||||
// Fade trail segments
|
||||
enemyTrail.forEach((segment, index) => {
|
||||
segment.alpha = (index + 1) / enemyTrail.length * 0.7;
|
||||
segment.size = enemy.size * (segment.alpha * 0.8 + 0.2);
|
||||
});
|
||||
}
|
||||
|
||||
// Update loot spawning
|
||||
function updateLoot() {
|
||||
if (!gameRunning || gameEnded) return; // Don't spawn during countdown or when game ended
|
||||
|
||||
lootSpawnTimer++;
|
||||
|
||||
// Spawn new loot periodically
|
||||
if (lootSpawnTimer >= lootSpawnInterval) {
|
||||
createLoot();
|
||||
lootSpawnTimer = 0;
|
||||
}
|
||||
|
||||
// Update existing loot
|
||||
loot.forEach(item => {
|
||||
// Fade in effect
|
||||
if (item.alpha < 1) {
|
||||
item.alpha += item.fadeSpeed;
|
||||
if (item.alpha > 1) item.alpha = 1;
|
||||
}
|
||||
|
||||
// Age the loot
|
||||
item.age += 0.008; // Slow aging rate
|
||||
|
||||
// Update color based on age (red -> orange -> yellow -> green -> blue -> purple)
|
||||
const hue = Math.min((item.age - 1) * 60, 300); // 0 to 300 degrees over time
|
||||
item.color = `hsl(${hue}, 100%, 60%)`;
|
||||
|
||||
// Update glow animation
|
||||
item.glow += item.pulse;
|
||||
if (item.glow > 15 || item.glow < 5) {
|
||||
item.pulse = -item.pulse;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check collisions
|
||||
function checkCollisions() {
|
||||
loot = loot.filter(item => {
|
||||
const playerDx = player.x - item.x;
|
||||
const playerDy = player.y - item.y;
|
||||
const playerDistance = Math.sqrt(playerDx * playerDx + playerDy * playerDy);
|
||||
|
||||
const enemyDx = enemy.x - item.x;
|
||||
const enemyDy = enemy.y - item.y;
|
||||
const enemyDistance = Math.sqrt(enemyDx * enemyDx + enemyDy * enemyDy);
|
||||
|
||||
// Check player collision
|
||||
if (playerDistance < player.size + item.size && item.alpha > 0.5) {
|
||||
// Calculate points based on age (younger = more points)
|
||||
const points = Math.max(50 - Math.floor(item.age * 10), 5);
|
||||
playerScore += points;
|
||||
playerScoreElement.textContent = playerScore;
|
||||
checkWinner();
|
||||
return false; // Remove this loot
|
||||
}
|
||||
|
||||
// Check enemy collision
|
||||
if (enemyDistance < enemy.size + item.size && item.alpha > 0.5) {
|
||||
// Calculate points based on age (younger = more points)
|
||||
const points = Math.max(50 - Math.floor(item.age * 10), 5);
|
||||
enemyScore += points;
|
||||
enemyScoreElement.textContent = enemyScore;
|
||||
checkWinner();
|
||||
return false; // Remove this loot
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Draw everything
|
||||
function draw() {
|
||||
// Clear canvas completely
|
||||
ctx.fillStyle = 'rgb(26, 26, 46)';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Draw player trail
|
||||
playerTrail.forEach(segment => {
|
||||
if (segment.alpha > 0) {
|
||||
ctx.shadowColor = player.color;
|
||||
ctx.shadowBlur = 10 * segment.alpha;
|
||||
ctx.fillStyle = `rgba(0, 255, 136, ${segment.alpha * 0.6})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(segment.x, segment.y, segment.size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
// Draw enemy trail
|
||||
enemyTrail.forEach(segment => {
|
||||
if (segment.alpha > 0) {
|
||||
ctx.shadowColor = enemy.color;
|
||||
ctx.shadowBlur = 10 * segment.alpha;
|
||||
ctx.fillStyle = `rgba(255, 68, 68, ${segment.alpha * 0.6})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(segment.x, segment.y, segment.size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
// Draw loot with glow effect
|
||||
loot.forEach(item => {
|
||||
if (item.alpha > 0) {
|
||||
// Draw glow
|
||||
ctx.shadowColor = item.color;
|
||||
ctx.shadowBlur = item.glow * item.alpha;
|
||||
ctx.fillStyle = item.color.replace('60%)', `${60 * item.alpha}%)`);
|
||||
ctx.beginPath();
|
||||
ctx.arc(item.x, item.y, item.size * item.alpha, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Draw inner bright core
|
||||
ctx.shadowBlur = 0;
|
||||
ctx.fillStyle = `rgba(255, 255, 255, ${item.alpha})`;
|
||||
ctx.beginPath();
|
||||
ctx.arc(item.x, item.y, item.size * 0.3 * item.alpha, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
// Draw player (main body)
|
||||
ctx.shadowColor = player.color;
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.fillStyle = player.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(player.x, player.y, player.size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Player inner glow
|
||||
ctx.shadowBlur = 0;
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.beginPath();
|
||||
ctx.arc(player.x, player.y, player.size * 0.4, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Draw enemy (main body)
|
||||
ctx.shadowColor = enemy.color;
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.fillStyle = enemy.color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(enemy.x, enemy.y, enemy.size, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
|
||||
// Enemy inner glow
|
||||
ctx.shadowBlur = 0;
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.beginPath();
|
||||
ctx.arc(enemy.x, enemy.y, enemy.size * 0.4, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Game loop
|
||||
function gameLoop() {
|
||||
updateCountdown();
|
||||
updatePlayer();
|
||||
updateEnemy();
|
||||
updateLoot();
|
||||
checkCollisions();
|
||||
draw();
|
||||
requestAnimationFrame(gameLoop);
|
||||
}
|
||||
|
||||
// Start the game with random positions
|
||||
randomizeStartingPositions();
|
||||
gameLoop();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user