wormate-io-clone / wormate.js
dannyboy84's picture
in the beginig there is no ball to eat to start the game
02d94d9 verified
// Wormate.io clone game logic
const socket = io('https://wormate.io'); // Connect to wormate.io server
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('score-display');
const leaderboard = document.getElementById('leaderboard');
const playBtn = document.getElementById('play-btn');
// Set canvas to full window size
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Game state
let gameStarted = false;
let playerId = null;
let players = {};
let foods = [
{
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: 10,
color: getRandomColor()
}
];
let powerUps = [];
let score = 0;
// Player controls
const keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false
};
// Handle keyboard input
window.addEventListener('keydown', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = true;
e.preventDefault();
}
});
window.addEventListener('keyup', (e) => {
if (keys.hasOwnProperty(e.key)) {
keys[e.key] = false;
e.preventDefault();
}
});
// Socket event handlers
socket.on('connect', () => {
playerId = socket.id;
console.log('Connected to server with ID:', playerId);
});
socket.on('gameState', (gameState) => {
players = gameState.players;
foods = gameState.foods;
powerUps = gameState.powerUps;
if (players[playerId]) {
score = players[playerId].score;
scoreDisplay.textContent = `Score: ${score}`;
}
updateLeaderboard();
renderGame();
});
socket.on('playerDied', (data) => {
if (data.playerId === playerId) {
gameStarted = false;
playBtn.style.display = 'block';
alert(`Game Over! Your score: ${score}`);
}
});
// Game loop
function gameLoop() {
if (gameStarted) {
const direction = getDirection();
socket.emit('playerInput', direction);
}
requestAnimationFrame(gameLoop);
}
gameLoop();
// Helper functions
function getDirection() {
if (keys.ArrowUp) return 'up';
if (keys.ArrowDown) return 'down';
if (keys.ArrowLeft) return 'left';
if (keys.ArrowRight) return 'right';
return null;
}
function updateLeaderboard() {
const sortedPlayers = Object.values(players).sort((a, b) => b.score - a.score);
leaderboard.innerHTML = '<h3>Leaderboard</h3>' +
sortedPlayers.map(p =>
`<div class="player-row ${p.id === playerId ? 'you' : ''}">
<span class="player-name">${p.name}</span>
<span class="player-score">${p.score}</span>
</div>`
).join('');
}
function renderGame() {
// Clear canvas
ctx.fillStyle = '#1a1a2e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw foods
foods.forEach(food => {
ctx.fillStyle = food.color;
ctx.beginPath();
ctx.arc(food.x, food.y, food.radius, 0, Math.PI * 2);
ctx.fill();
});
// Draw power-ups
powerUps.forEach(powerUp => {
ctx.save();
ctx.translate(powerUp.x, powerUp.y);
ctx.rotate(Date.now() / 200);
ctx.fillStyle = powerUp.color;
ctx.fillRect(-powerUp.size/2, -powerUp.size/2, powerUp.size, powerUp.size);
ctx.restore();
});
// Draw players
Object.values(players).forEach(player => {
// Draw worm segments
player.segments.forEach((segment, i) => {
const gradient = ctx.createRadialGradient(
segment.x, segment.y, 0,
segment.x, segment.y, segment.radius
);
gradient.addColorStop(0, player.color);
gradient.addColorStop(1, darkenColor(player.color, 0.3));
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(segment.x, segment.y, segment.radius, 0, Math.PI * 2);
ctx.fill();
// Draw eyes on head
if (i === 0) {
const angle = Math.atan2(
player.segments[1].y - segment.y,
player.segments[1].x - segment.x
);
const eyeRadius = segment.radius * 0.3;
const eyeOffset = segment.radius * 0.6;
// Left eye
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(
segment.x + Math.cos(angle + Math.PI/2) * eyeOffset,
segment.y + Math.sin(angle + Math.PI/2) * eyeOffset,
eyeRadius, 0, Math.PI * 2
);
ctx.fill();
// Right eye
ctx.beginPath();
ctx.arc(
segment.x + Math.cos(angle - Math.PI/2) * eyeOffset,
segment.y + Math.sin(angle - Math.PI/2) * eyeOffset,
eyeRadius, 0, Math.PI * 2
);
ctx.fill();
// Pupils
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(
segment.x + Math.cos(angle + Math.PI/2) * eyeOffset + Math.cos(angle) * eyeRadius/2,
segment.y + Math.sin(angle + Math.PI/2) * eyeOffset + Math.sin(angle) * eyeRadius/2,
eyeRadius/2, 0, Math.PI * 2
);
ctx.fill();
ctx.beginPath();
ctx.arc(
segment.x + Math.cos(angle - Math.PI/2) * eyeOffset + Math.cos(angle) * eyeRadius/2,
segment.y + Math.sin(angle - Math.PI/2) * eyeOffset + Math.sin(angle) * eyeRadius/2,
eyeRadius/2, 0, Math.PI * 2
);
ctx.fill();
}
});
// Draw player name
if (player.segments.length > 0) {
const head = player.segments[0];
ctx.fillStyle = 'white';
ctx.font = '12px "Press Start 2P", cursive';
ctx.textAlign = 'center';
ctx.fillText(player.name, head.x, head.y - head.radius - 10);
}
});
}
function darkenColor(color, amount) {
// Convert hex to RGB
let r = parseInt(color.substr(1, 2), 16);
let g = parseInt(color.substr(3, 2), 16);
let b = parseInt(color.substr(5, 2), 16);
// Darken each component
r = Math.max(0, Math.floor(r * (1 - amount)));
g = Math.max(0, Math.floor(g * (1 - amount)));
b = Math.max(0, Math.floor(b * (1 - amount)));
// Convert back to hex
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
}
// Start game
playBtn.addEventListener('click', () => {
const playerName = prompt('Enter your name:', 'Player' + Math.floor(Math.random() * 1000));
if (playerName) {
socket.emit('joinGame', {
name: playerName,
color: getRandomColor()
});
gameStarted = true;
playBtn.style.display = 'none';
}
});
function getRandomColor() {
const colors = [
'#FF5252', '#FF4081', '#E040FB', '#7C4DFF',
'#536DFE', '#448AFF', '#40C4FF', '#18FFFF',
'#64FFDA', '#69F0AE', '#B2FF59', '#EEFF41',
'#FFFF00', '#FFD740', '#FFAB40', '#FF6E40'
];
return colors[Math.floor(Math.random() * colors.length)];
}