=)))
Prompt
Make in js pixel game where pixel eat each other like in pacman, who eat all others will be winner, every pixel has it own strength and weknesses
A system prompt was added to support web rendering
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pixel Eater Arena</title> <style> html,body{margin:0;height:100%;background:#000;color:#fff;font-family:Arial,Helvetica,sans-serif;user-select:none} #ui{position:absolute;top:10px;left:50%;transform:translateX(-50%);text-align:center;font-size:18px;pointer-events:none} #msg{font-size:24px;margin-top:4px} canvas{display:block;margin:0 auto;background:#111} </style> </head> <body> <canvas id="game"></canvas> <div id="ui"> <span id="counter"></span> <div id="msg"></div> <small>Press [SPACE] to restart</small> </div> <script> /* -------------- CONFIG ----------------- */ const START_PIXELS = 25; // how many fighters spawn const MIN_POWER = 1; // weakest pixel const MAX_POWER = 6; // strongest pixel at spawn const SIZE_FACTOR = 4; // radius = power * SIZE_FACTOR const SPEED_BASE = 3; // baseline speed, smaller is faster const SPEED_SCALE = 0.4; // speed penalty per power level const GROWTH = 0.6; // how much size increases per devour (in power units) /* --------------------------------------- */ const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); resize(); window.addEventListener('resize', resize); /* ---------- Pixel Fighter -------------- */ class Pixel { constructor(x,y,power,color) { this.x = x; this.y = y; this.power = power; this.color = color; const angle = Math.random()*Math.PI*2; this.vx = Math.cos(angle)*this.speed(); this.vy = Math.sin(angle)*this.speed(); } radius(){ return this.power*SIZE_FACTOR; } speed (){ return SPEED_BASE + (MAX_POWER-this.power)*SPEED_SCALE; } draw(){ ctx.fillStyle=this.color; ctx.beginPath(); ctx.arc(this.x,this.y,this.radius(),0,Math.PI*2); ctx.fill(); } move(){ this.x += this.vx; this.y += this.vy; // wall bounce if(this.x < this.radius() && this.vx<0 || this.x > canvas.width-this.radius() && this.vx>0) this.vx*=-1; if(this.y < this.radius() && this.vy<0 || this.y > canvas.height-this.radius() && this.vy>0) this.vy*=-1; } grow(){ this.power += GROWTH; const dir = Math.hypot(this.vx,this.vy); const newSpeed = this.speed(); this.vx = this.vx/dir*newSpeed; this.vy = this.vy/dir*newSpeed; } } /* ---------- Arena Setup ---------------- */ let pixels=[]; const COLORS = ["#f44336","#ffeb3b","#4caf50","#2196f3","#e91e63","#ff9800","#9c27b0"]; function spawnPixels(){ pixels=[]; for(let i=0;i<START_PIXELS;i++){ let pwr = Math.random()*(MAX_POWER-MIN_POWER)+MIN_POWER; let rad = pwr*SIZE_FACTOR; let x = Math.random()*(canvas.width - 2*rad)+rad; let y = Math.random()*(canvas.height- 2*rad)+rad; let color = COLORS[i%COLORS.length]; pixels.push(new Pixel(x,y,pwr,color)); } } function resize(){ canvas.width = window.innerWidth; canvas.height = window.innerHeight; } spawnPixels(); /* ----------- Main Loop ----------------- */ let last=0; function loop(ts){ requestAnimationFrame(loop); const dt = ts-last; last=ts; update(dt/16.666); // normalize to ~60 fps units draw(); } requestAnimationFrame(loop); function update(dt){ if(pixels.length<=1) return; // move pixels.forEach(p=>p.move(dt)); // collision & devour for(let i=pixels.length-1;i>=0;i--){ for(let j=i-1;j>=0;j--){ const a = pixels[i], b = pixels[j]; const dist = Math.hypot(a.x-b.x,a.y-b.y); if(dist < a.radius()+b.radius()){ // who eats whom? if(a.power >= b.power){ a.grow(); pixels.splice(j,1); } else { b.grow(); pixels.splice(i,1); } break; } } } // UI document.getElementById('counter').textContent = `Pixels left: ${pixels.length}`; if(pixels.length===1){ const p = pixels[0]; document.getElementById('msg').textContent = `WINNER! (${p.color.toUpperCase()} power ${p.power.toFixed(1)})`; } } function draw(){ ctx.clearRect(0,0,canvas.width,canvas.height); pixels.forEach(p=>p.draw()); } /* -------- Controls -------------------- */ window.addEventListener('keydown',e=>{ if(e.code==='Space'){ document.getElementById('msg').textContent=''; spawnPixels(); } }); </script> </body> </html> ```
Of course! Here is a self-contained "Pixel Battle" game created with JavaScript. The rules are simple: Red eats Green, Green eats Blue, and Blue eats Red. The last color standing is the winner. Just copy and paste the code into an HTML file and open it in your web browser to play. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Pixel Battle</title> <style> body { font-family: 'Courier New', Courier, monospace; background-color: #1a1a1a; color: #f0f0f0; display: flex; flex-direction: column; align-items: center; justify-content: center; margin: 0; padding: 20px; min-height: 100vh; box-sizing: border-box; } h1 { color: #ffffff; text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #3498db; } #gameCanvas { background-color: #000000; border: 2px solid #555; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); } .controls { margin-top: 20px; text-align: center; } #status { font-size: 1.2em; font-weight: bold; height: 25px; margin-bottom: 15px; } .legend { margin-bottom: 15px; padding: 10px; border: 1px dashed #555; display: flex; gap: 20px; justify-content: center; align-items: center; } .legend-item { font-weight: bold; } .red { color: #e74c3c; } .green { color: #2ecc71; } .blue { color: #3498db; } button { padding: 10px 20px; font-size: 1em; font-family: 'Courier New', Courier, monospace; background-color: #333; color: #f0f0f0; border: 2px solid #555; cursor: pointer; transition: background-color 0.3s, color 0.3s; } button:hover { background-color: #f0f0f0; color: #333; } </style> </head> <body> <h1>Pixel Battle Arena</h1> <div class="controls"> <div id="status">Loading...</div> <div class="legend"> <span class="legend-item red">Red</span> eats <span class="legend-item green">Green</span> <span>></span> <span class="legend-item green">Green</span> eats <span class="legend-item blue">Blue</span> <span>></span> <span class="legend-item blue">Blue</span> eats <span class="legend-item red">Red</span> </div> <button id="restartButton">Restart Game</button> </div> <canvas id="gameCanvas" width="600" height="400"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const statusEl = document.getElementById('status'); const restartButton = document.getElementById('restartButton'); // --- Game Configuration --- const PIXEL_SIZE = 10; const NUM_PIXELS_PER_COLOR = 30; const BASE_SPEED = 1; const TYPES = { RED: { name: 'Red', color: '#e74c3c', beats: 'GREEN' }, GREEN: { name: 'Green', color: '#2ecc71', beats: 'BLUE' }, BLUE: { name: 'Blue', color: '#3498db', beats: 'RED' } }; let pixels = []; let gameOver = false; let animationFrameId; class Pixel { constructor(x, y, type) { this.x = x; this.y = y; this.type = type; this.size = PIXEL_SIZE; this.isAlive = true; // Assign random direction & speed this.dx = (Math.random() - 0.5) * BASE_SPEED * 2; this.dy = (Math.random() - 0.5) * BASE_SPEED * 2; if (Math.abs(this.dx) < 0.2) this.dx = this.dx < 0 ? -0.2 : 0.2; if (Math.abs(this.dy) < 0.2) this.dy = this.dy < 0 ? -0.2 : 0.2; } draw() { ctx.fillStyle = TYPES[this.type].color; ctx.fillRect(this.x, this.y, this.size, this.size); } update() { if (!this.isAlive) return; // Move pixel this.x += this.dx; this.y += this.dy; // Wall collision if (this.x <= 0 || this.x + this.size >= canvas.width) { this.dx *= -1; this.x = Math.max(0, Math.min(this.x, canvas.width - this.size)); // Prevent getting stuck } if (this.y <= 0 || this.y + this.size >= canvas.height) { this.dy *= -1; this.y = Math.max(0, Math.min(this.y, canvas.height - this.size)); } } } function init() { if (animationFrameId) { cancelAnimationFrame(animationFrameId); } pixels = []; gameOver = false; statusEl.textContent = 'The battle begins!'; statusEl.style.color = '#f0f0f0'; for (const typeKey in TYPES) { for (let i = 0; i < NUM_PIXELS_PER_COLOR; i++) { const x = Math.random() * (canvas.width - PIXEL_SIZE); const y = Math.random() * (canvas.height - PIXEL_SIZE); pixels.push(new Pixel(x, y, typeKey)); } } gameLoop(); } function handleCollisions() { for (let i = 0; i < pixels.length; i++) { if (!pixels[i].isAlive) continue; for (let j = i + 1; j < pixels.length; j++) { if (!pixels[j].isAlive) continue; const p1 = pixels[i]; const p2 = pixels[j]; // AABB Collision Detection if (p1.x < p2.x + p2.size && p1.x + p1.size > p2.x && p1.y < p2.y + p2.size && p1.y + p1.size > p2.y) { // Collision occurred if (p1.type === p2.type) { // Same type, bounce off each other by swapping velocities [p1.dx, p2.dx] = [p2.dx, p1.dx]; [p1.dy, p2.dy] = [p2.dy, p1.dy]; } else if (TYPES[p1.type].beats === p2.type) { // p1 eats p2 p2.isAlive = false; } else if (TYPES[p2.type].beats === p1.type) { // p2 eats p1 p1.isAlive = false; } } } } } function checkWinner() { const alivePixels = pixels.filter(p => p.isAlive); if (alivePixels.length === 0) { statusEl.textContent = `It's a tie! All pixels were destroyed.`; statusEl.style.color = '#f0f0f0'; gameOver = true; return; } const firstPixelType = alivePixels[0].type; const isOneTypeLeft = alivePixels.every(p => p.type === firstPixelType); if (isOneTypeLeft) { const winnerInfo = TYPES[firstPixelType]; statusEl.textContent = `${winnerInfo.name} is the winner!`; statusEl.style.color = winnerInfo.color; gameOver = true; } } function gameLoop() { // Update pixels.forEach(p => p.update()); handleCollisions(); checkWinner(); // Draw ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear screen pixels.forEach(p => { if (p.isAlive) { p.draw(); } }); if (!gameOver) { animationFrameId = requestAnimationFrame(gameLoop); } } restartButton.addEventListener('click', init); // Start the game init(); </script> </body> </html> ```
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pixel Eater Game</title> <style> body { background: #1d1d1d; color: #f0f0f0; text-align: center; font-family: Arial, sans-serif; margin: 0; } #game { display: block; margin: 30px auto 10px auto; background: #222; border: 3px solid #44d9e6; } #hud { margin: 0 auto 10px auto; max-width: 420px; font-size: 18px; line-height: 1.6em; background: #282828; border-radius: 8px; box-shadow: 0 1px 4px #000c; padding: 10px 18px; } button { background: #44d9e6; color: #181818; border: none; font-weight: bold; border-radius: 4px; padding: 8px 18px; cursor: pointer; margin: 6px; font-size: 18px; } </style> </head> <body> <h1>Pixel Eater Game</h1> <canvas id="game" width="420" height="420"></canvas> <div id="hud"></div> <button onclick="restartGame()">Restart Game</button> <script> // --- CONFIG --- const GRID_SIZE = 21; const CELL = 20; const COLORS = [ "#ffd41a", // yellow (player) "#1b8fff", // blue "#e64444", // red "#11dea7", // green "#d300ff", // purple "#ff931e", // orange ]; // Strengths/Weaknesses: rock-paper-scissors // 0 > 1, 1 > 2, 2 > 0, etc. const TYPES = ['Chomper','Crusher','Sneaker']; const TYPE_ABBR = ['C','R','S']; // --- GAME STATE --- let game, ctx, hud; function randomType() { return Math.floor(Math.random() * TYPES.length); } function randomDir() { let dirs = [[1,0], [-1,0], [0,1], [0,-1]]; return dirs[Math.floor(Math.random() * dirs.length)]; } class Pixel { constructor(x, y, type, colorIdx, isPlayer=false) { this.x = x; this.y = y; this.type = type; this.colorIdx = colorIdx; this.isPlayer = isPlayer; this.alive = true; this.size = 1; this.score = 0; } move(dir) { this.x += dir[0]; this.y += dir[1]; this.x = Math.max(0, Math.min(GRID_SIZE-1, this.x)); this.y = Math.max(0, Math.min(GRID_SIZE-1, this.y)); } canEat(other) { // Returns true if THIS pixel can EAT the other pixel. if (!other.alive || other === this) return false; // Same position if (this.x === other.x && this.y === other.y) { // RPS-type win OR bigger size if (Pixel.beats(this.type, other.type) || this.size > other.size) return true; } return false; } static beats(typeA, typeB) { // A beats B if (A+1) % 3 == B return ((typeA + 1) % TYPES.length) === typeB; } } function spawnPixels() { // Always create player at a corner let px = new Pixel(0, 0, randomType(), 0, true); let pixels = [px]; const spots = [ [0, GRID_SIZE-1], [GRID_SIZE-1, 0], [GRID_SIZE-1, GRID_SIZE-1], [Math.floor(GRID_SIZE/2), 0], [0, Math.floor(GRID_SIZE/2)], [GRID_SIZE-1, Math.floor(GRID_SIZE/2)], [Math.floor(GRID_SIZE/2), GRID_SIZE-1] ]; // up to 4-6 AI for (let i=0;i<4+Math.floor(Math.random()*2);i++) { let [x,y] = spots[i]; let type = randomType(); let colorIdx = (i+1)%COLORS.length; let pixel = new Pixel(x,y,type, colorIdx, false); pixel.size = 1 + Math.floor(Math.random()*2); pixels.push(pixel); } return pixels; } function getPixelAt(pixels, x, y) { return pixels.find(p=>p.x===x && p.y===y && p.alive); } function initGame() { ctx = document.getElementById('game').getContext('2d'); game = { pixels: spawnPixels(), running: true, winner: null }; hud = document.getElementById('hud'); drawGame(); updateHUD(); } function restartGame() { initGame(); requestAnimationFrame(gameLoop); } function drawGame() { ctx.fillStyle = "#23242e"; ctx.fillRect(0,0,GRID_SIZE*CELL,GRID_SIZE*CELL); // draw grid ctx.strokeStyle = "#444"; for(let i=0;i<=GRID_SIZE;i++){ ctx.beginPath(); ctx.moveTo(i*CELL,0); ctx.lineTo(i*CELL,GRID_SIZE*CELL); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0,i*CELL); ctx.lineTo(GRID_SIZE*CELL,i*CELL); ctx.stroke(); } // Draw pixels for (let pixel of game.pixels) { if (!pixel.alive) continue; ctx.save(); ctx.translate(pixel.x*CELL+CELL/2, pixel.y*CELL+CELL/2); // Player has thick black outline. ctx.beginPath(); ctx.arc(0,0, pixel.isPlayer ? 8+pixel.size*1.2: 7+pixel.size, 0, Math.PI*2); ctx.fillStyle = COLORS[pixel.colorIdx % COLORS.length]; ctx.shadowColor = "#aaa"; ctx.shadowBlur = pixel.isPlayer ? 18 : 10; ctx.fill(); if (pixel.isPlayer) { ctx.lineWidth = 4; ctx.strokeStyle = "#181818"; ctx.stroke(); } // Type indicator ctx.font = "bold 15px Arial"; ctx.fillStyle = "#000"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.globalAlpha = 0.9; ctx.fillText(TYPE_ABBR[pixel.type], 0, 1); ctx.globalAlpha = 1; ctx.restore(); // Draw size if (pixel.size > 1) { ctx.font = "12px Arial"; ctx.fillStyle = "#fff"; ctx.fillText("x"+pixel.size, pixel.x*CELL+2, pixel.y*CELL+13); } } } function updateHUD() { let info = ''; let alive = game.pixels.filter(p=>p.alive); for (let pixel of game.pixels) { if (!pixel.alive) continue; info += `<span style="color:${COLORS[pixel.colorIdx%COLORS.length]}">${pixel.isPlayer?'YOU':'AI'}</span>: <b>${TYPES[pixel.type]}</b> <span>Size: <b>${pixel.size}</b></span> <span>Score: <b>${pixel.score}</b></span> <br/>` } hud.innerHTML = info + (game.winner ? `<div style="font-size:1.2em;text-shadow:0 0 7px #fff;">${game.winner.isPlayer?'YOU WIN! 🏆':'AI WINS 💀'}</div>` : '' ); } // Handle player input window.addEventListener('keydown', function(e){ if (!game.running || !game.pixels[0].alive) return; let dir; switch(e.key) { case 'ArrowUp': dir = [0,-1]; break; case 'ArrowDown': dir = [0,1]; break; case 'ArrowLeft': dir = [-1,0]; break; case 'ArrowRight': dir = [1,0]; break; default: return; } movePlayer(dir); drawGame(); updateHUD(); }); function movePlayer(dir){ let player = game.pixels[0]; if (!player.alive) return; let nx = player.x + dir[0], ny = player.y + dir[1]; if (nx < 0 || nx >= GRID_SIZE || ny < 0 || ny >= GRID_SIZE) return; player.move(dir); } // AI Logic (very simple) function aiMove(pixel){ if (!pixel.alive) return; // Find nearest edible pixel let edible = game.pixels.filter(p=>p.alive && p!==pixel && (Pixel.beats(pixel.type, p.type) || pixel.size > p.size)); let player = game.pixels[0]; let choices = []; if (edible.length) { // Seek closest edible let best = edible[0], bestDist = dist(pixel, best); for (let e of edible) { let d = dist(pixel, e); if (d < bestDist) { best = e; bestDist = d;} } let dx = Math.sign(best.x - pixel.x); let dy = Math.sign(best.y - pixel.y); if (Math.abs(dx)>Math.abs(dy)) choices = [[dx,0],[0,dy]]; else choices = [[0,dy],[dx,0]]; } else { // else random wander choices = [randomDir()]; } for (let dir of choices) { let nx=pixel.x+dir[0], ny=pixel.y+dir[1]; if (nx>=0 && nx<GRID_SIZE && ny>=0 && ny<GRID_SIZE) { pixel.move(dir); break; } } } function dist(a,b) { return Math.abs(a.x-b.x)+Math.abs(a.y-b.y); } // Eating logic function processMeals() { // For every pixel, check if it can eat anyone let alive = game.pixels.filter(p=>p.alive); for (let eater of alive) { for (let prey of alive) { if (eater !== prey && eater.canEat(prey)) { // Eat! eater.size += Math.floor(prey.size/2)+1; eater.score += 1 + prey.size*2 + (eater.isPlayer?0:Math.floor(Math.random()*2)); prey.alive = false; // Change type sometimes (mutate upon eating) if (Math.random()<0.22) { eater.type = randomType(); } } } } } function checkWinner() { let alive = game.pixels.filter(p=>p.alive); if (alive.length === 1) { game.running = false; game.winner = alive[0]; } } // --- MAIN GAME LOOP --- let frame = 0; function gameLoop() { if (!game.running) return; frame++; // AI moves let player = game.pixels[0]; for (let i = 1; i < game.pixels.length; i++) { aiMove(game.pixels[i]); } // EAT processMeals(); // Check if anyone wins checkWinner(); // Render drawGame(); updateHUD(); // Next frame if (game.running) setTimeout(()=>requestAnimationFrame(gameLoop), 220); } // --- INIT --- initGame(); requestAnimationFrame(gameLoop); </script> <div style="color:#888;font-size:13px;margin-top:15px;"> <b>Controls:</b> Arrow keys to move. <br> Eat all others to win!<br> <b>Chomper</b> beats <b>Crusher</b>, <b>Crusher</b> beats <b>Sneaker</b>, <b>Sneaker</b> beats <b>Chomper</b>.<br> Or grow larger than the others! </div> </body> </html> ```
<!DOCTYPE html> <html> <head> <title>Pixel Eat Competition</title> <style> canvas { background: #000; display: block; margin: 0 auto; } </style> </head> <body> <canvas id="gameCanvas" width="320" height="320"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const gridSize = 16; const cellSize = canvas.width / gridSize; const players = [ { x: 5, y: 5, dx: 0, dy: 0, color: 'red', type: 'fire', strength: 5, keys: { up: 38, down: 40, left: 37, right: 39 } }, { x: 11, y: 11, dx: 0, dy: 0, color: 'blue', type: 'water', strength: 5, keys: { up: 87, down: 83, left: 65, right: 68 } } ]; document.addEventListener('keydown', (e) => { players.forEach(p => { switch(e.keyCode) { case p.keys.up: p.dx = 0; p.dy = -1; break; case p.keys.down: p.dx = 0; p.dy = 1; break; case p.keys.left: p.dx = -1; p.dy = 0; break; case p.keys.right: p.dx = 1; p.dy = 0; break; } }); }); function getAdvantageMultiplier(attacker, defender) { if ((attacker === 'fire' && defender === 'grass') || (attacker === 'grass' && defender === 'water') || (attacker === 'water' && defender === 'fire')) { return 2; } if ((attacker === 'fire' && defender === 'water') || (attacker === 'water' && defender === 'grass') || (attacker === 'grass' && defender === 'fire')) { return 0.5; } return 1; } function resolveCollision(p1, p2) { const eff1 = p1.strength * getAdvantageMultiplier(p1.type, p2.type); const eff2 = p2.strength * getAdvantageMultiplier(p2.type, p1.type); if (eff1 > eff2) { p1.strength += p2.strength; removePlayer(p2); } else if (eff1 < eff2) { p2.strength += p1.strength; removePlayer(p1); } } function removePlayer(player) { const index = players.findIndex(p => p === player); if (index > -1) players.splice(index, 1); } function checkCollisions() { for (let i = 0; i < players.length; i++) { for (let j = i + 1; j < players.length; j++) { if (players[i].x === players[j].x && players[i].y === players[j].y) { resolveCollision(players[i], players[j]); } } } } function update() { players.forEach(p => { const newX = p.x + p.dx; const newY = p.y + p.dy; if (newX >= 0 && newX < gridSize && newY >= 0 && newY < gridSize) { p.x = newX; p.y = newY; } }); } function render() { ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); players.forEach(p => { ctx.fillStyle = p.color; ctx.fillRect(p.x * cellSize, p.y * cellSize, cellSize, cellSize); }); } function gameLoop() { if (players.length <= 1) { ctx.fillStyle = 'white'; ctx.font = '20px Arial'; ctx.fillText(players.length === 0 ? 'Draw!' : `${players[0].color} Wins!`, canvas.width/2 - 60, canvas.height/2); return; } update(); checkCollisions(); render(); } setInterval(gameLoop, 150); </script> </body> </html>
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pixel Eater Game</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { display: flex; flex-direction: column; align-items: center; font-family: 'Courier New', Courier, monospace; background: #111; color: #eee; height: 100vh; } #gameCanvas { border: 1px solid #fff; margin-top: 10px; image-rendering: pixelated; cursor: none; } #leaderboard { display: flex; flex-wrap: wrap; justify-content: center; max-height: 50px; margin-top: 10px; } .pixel-legend { display: flex; align-items: center; margin: 2px 5px; font-size: 12px; } .legend-color { width: 10px; height: 10px; margin-right: 5px; border: 1px solid #555; } #winnerModal { display: none; position: fixed; z-index: 1; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.8); text-align: center; padding-top: 100px; } #winnerModalContent { animation: fadeIn 0.5s; padding: 20px; } #restartButton { padding: 10px 20px; font-size: 16px; margin-top: 15px; cursor: pointer; background-color: #555; color: #fff; border: none; } </style> </head> <body> <canvas id="gameCanvas" width="400" height="400"></canvas> <div id="leaderboard"></div> <div id="winnerModal"> <div id="winnerModalContent"> <h2 id="winnerText"></h2> <button id="restartButton" onclick="restartGame()">Play Again</button> </div> </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const leaderboardEl = document.getElementById('leaderboard'); const GAME_SETTINGS = { INITIAL_PIXEL_COUNT: 9, CELL_SIZE: 20, GAME_SPEED: 120, // ms per step MAP_WIDTH: 20, MAP_HEIGHT: 20, }; const PIXEL_TYPES = [ { name: 'Red', color: '#ff0000', speed: 1, power: 3, weakness: 'Blue', emoji: '🔴', rank: 0 }, { name: 'Green', color: '#00ff00', speed: 2, power: 2, weakness: 'Red', emoji: '🟢', rank: 0 }, { name: 'Blue', color: '#0000ff', speed: 1, power: 3, weakness: 'Green', emoji: '🔵', rank: 0 }, { name: 'Yellow', color: '#ffff00', speed: 3, power: 1, weakness: 'Purple', emoji: '🟡', rank: 0 }, { name: 'Purple', color: '#ff00ff', speed: 1, power: 2, weakness: 'Yellow', emoji: '🟣', rank: 0 }, ]; const pixels = []; let gameOver = false; class Pixel { constructor(type, x, y, id) { this.id = id; this.type = type; this.x = x; this.y = y; this.direction = { x: 0, y: 0 }; this.cooldown = 0; this.score = 0; } draw() { ctx.fillStyle = this.type.color; ctx.fillRect(this.x * GAME_SETTINGS.CELL_SIZE, this.y * GAME_SETTINGS.CELL_SIZE, GAME_SETTINGS.CELL_SIZE, GAME_SETTINGS.CELL_SIZE); ctx.font = '16px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#000'; ctx.fillText( this.type.emoji, this.x * GAME_SETTINGS.CELL_SIZE + GAME_SETTINGS.CELL_SIZE / 2, this.y * GAME_SETTINGS.CELL_SIZE + GAME_SETTINGS.CELL_SIZE / 2 ); } update() { if (this.cooldown > 0) { this.cooldown--; } if (this.cooldown <= 0) { const directions = [ { x: 0, y: -1 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 0 } ]; // Basic AI: move towards closest target or away from weakness this.calculateAI(directions); const newX = this.x + this.direction.x; const newY = this.y + this.direction.y; if (isValidPosition(newX, newY)) { this.x = newX; this.y = newY; this.checkCollisions(); } else { // If movement is invalid, choose random valid direction this.direction = directions[Math.floor(Math.random() * directions.length)]; } this.cooldown = Math.floor(5 / this.type.speed); // Speed influences cooldown } } calculateAI(directions) { let closestTarget = null; let closestDistance = Infinity; let biggestThreat = null; let closestThreat = Infinity; for (const other of pixels) { if (other.id === this.id) continue; const dist = Math.abs(this.x - other.x) + Math.abs(this.y - other.y); // Check if this is a weakness target if (other.type.name === this.type.weakness) { if (dist < closestThreat) { closestThreat = dist; biggestThreat = other; } } // Find closest target to chase if (((this.isStronger(other)) || other.type.name === 'Yellow') && dist < closestDistance) { closestDistance = dist; closestTarget = other; } } // Prioritize escaping if too close to weakness if (biggestThreat && closestThreat <= 3) { const dx = this.x - biggestThreat.x; const dy = this.y - biggestThreat.y; // Run directly away if possible if (Math.abs(dx) > Math.abs(dy)) { this.direction = { x: dx > 0 ? 1 : -1, y: 0 }; } else { this.direction = { x: 0, y: dy > 0 ? 1 : -1 }; } } else if (closestTarget) { const dx = closestTarget.x - this.x; const dy = closestTarget.y - this.y; // Move towards target if (Math.abs(dx) > Math.abs(dy)) { this.direction = { x: dx > 0 ? 1 : -1, y: 0 }; } else { this.direction = { x: 0, y: dy > 0 ? 1 : -1 }; } } else { // No target, wander this.direction = directions[Math.floor(Math.random() * directions.length)]; } } isStronger(other) { return this.type.name === other.type.weakness && this.type.power >= other.type.power; } checkCollisions() { for (let i = 0; i < pixels.length; i++) { const other = pixels[i]; if (other.id === this.id) continue; if (this.x === other.x && this.y === other.y) { // Collision detected if (this.isStronger(other)) { pixels.splice(i, 1); this.score++; updateLeaderboard(); checkWinCondition(); return; } else if (other.isStronger(this)) { pixels.splice(pixels.findIndex(p => p.id === this.id), 1); return; } } } } } function render() { ctx.clearRect(0, 0, canvas.width, canvas.height); for (const pixel of pixels) { pixel.draw(); } } function update() { if (gameOver) return; for (let i = pixels.length - 1; i >= 0; i--) { pixels[i].update(); } } function startGame() { pixels.length = 0; // Clear existing pixels gameOver = false; document.getElementById('winnerModal').style.display = 'none'; for (let i = 0; i < GAME_SETTINGS.INITIAL_PIXEL_COUNT; i++) { const type = PIXEL_TYPES[i % PIXEL_TYPES.length]; let x, y; do { x = Math.floor(Math.random() * GAME_SETTINGS.MAP_WIDTH); y = Math.floor(Math.random() * GAME_SETTINGS.MAP_HEIGHT); } while (pixels.some(p => p.x === x && p.y === y)); pixels.push(new Pixel(type, x, y, i)); } updateLeaderboard(); } function isValidPosition(x, y) { return x >= 0 && x < GAME_SETTINGS.MAP_WIDTH && y >= 0 && y < GAME_SETTINGS.MAP_HEIGHT; } function updateLeaderboard() { const scores = {}; pixels.forEach((p) => { if (!scores[p.type.name]) { scores[p.type.name] = { score: 0, count: 0, type: p.type }; } scores[p.type.name].score += p.score; scores[p.type.name].count++; }); leaderboardEl.innerHTML = ''; for (const type of PIXEL_TYPES) { const data = scores[type.name]; if (data && data.count > 0) { const div = document.createElement('div'); div.className = 'pixel-legend'; div.innerHTML = `<div class="legend-color" style="background-color:${type.color};"></div>${type.name}: ${data.count} <(${data.score || 0} pts)>`; leaderboardEl.appendChild(div); } } } function checkWinCondition() { const uniqueColors = new Set(pixels.map(p => p.type.name)); if (uniqueColors.size === 1) { gameOver = true; const winner = pixels[0]; document.getElementById('winnerText').innerText = `${winner.type.emoji} ${winner.type.name} Wins!`; document.getElementById('winnerModal').style.display = 'block'; } } function restartGame() { startGame(); } setInterval(() => { update(); render(); }, GAME_SETTINGS.GAME_SPEED); startGame(); </script> </body> </html> ```
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pixel Eater Game</title> <style> body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #222; } canvas { border: 2px solid #fff; } </style> </head> <body> <canvas id="gameCanvas" width="400" height="400"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const GRID_SIZE = 20; const CELL_SIZE = 20; const TYPES = ['rock', 'paper', 'scissors']; // 0: rock beats scissors (2), 1: paper beats rock (0), 2: scissors beats paper (1) const COLORS = ['#ff0000', '#00ff00', '#0000ff']; // Red for rock, Green for paper, Blue for scissors let pixels = []; let playerIndex = 0; let gameOver = false; let winner = null; // Create a pixel function createPixel(x, y, type, strength = 1, isPlayer = false) { return { x, y, type, strength, isPlayer, direction: 'right' }; } // Initialize game function init() { pixels = []; // Player: rock type pixels.push(createPixel(1, 1, 0, 1, true)); // Enemies pixels.push(createPixel(18, 18, 1, 1)); // paper pixels.push(createPixel(10, 10, 2, 1)); // scissors pixels.push(createPixel(5, 15, 0, 1)); // rock pixels.push(createPixel(15, 5, 1, 1)); // paper pixels.push(createPixel(8, 8, 2, 1)); // scissors gameOver = false; winner = null; } // Draw the game function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); pixels.forEach((p, i) => { ctx.fillStyle = COLORS[p.type]; const size = CELL_SIZE * (1 + (p.strength - 1) * 0.2); // Grow with strength ctx.fillRect(p.x * CELL_SIZE - size/4, p.y * CELL_SIZE - size/4, size, size); // Center a bit if (p.isPlayer) { ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.strokeRect(p.x * CELL_SIZE - size/4, p.y * CELL_SIZE - size/4, size, size); } }); if (gameOver) { ctx.fillStyle = '#fff'; ctx.font = '20px Arial'; ctx.fillText(`Winner: ${winner ? (winner.isPlayer ? 'You!' : `Enemy ${TYPES[winner.type]}`) : 'None'}`, 100, 200); } } // Move pixels function move() { pixels.forEach((p, i) => { if (p.isPlayer) return; // Player moved by keys // Simple AI: move randomly or towards player const player = pixels[playerIndex]; const dx = player.x - p.x; const dy = player.y - p.y; const rand = Math.random(); if (rand < 0.5 && Math.abs(dx) > Math.abs(dy)) { p.x += dx > 0 ? 1 : -1; } else if (rand < 0.8) { p.y += dy > 0 ? 1 : -1; } else { // Random move const dir = Math.floor(Math.random() * 4); if (dir === 0) p.x = Math.min(GRID_SIZE - 1, Math.max(0, p.x + 1)); if (dir === 1) p.x = Math.min(GRID_SIZE - 1, Math.max(0, p.x - 1)); if (dir === 2) p.y = Math.min(GRID_SIZE - 1, Math.max(0, p.y + 1)); if (dir === 3) p.y = Math.min(GRID_SIZE - 1, Math.max(0, p.y - 1)); } p.x = Math.min(GRID_SIZE - 1, Math.max(0, p.x)); p.y = Math.min(GRID_SIZE - 1, Math.max(0, p.y)); }); } // Check collisions and eating function checkCollisions() { for (let i = 0; i < pixels.length; i++) { for (let j = i + 1; j < pixels.length; j++) { if (pixels[i].x === pixels[j].x && pixels[i].y === pixels[j].y) { resolveEat(i, j); j--; // Recheck since array might change } } } // Check if only one left if (pixels.length === 1) { gameOver = true; winner = pixels[0]; } else if (pixels.length === 0) { gameOver = true; } else if (!pixels.some(p => p.isPlayer)) { gameOver = true; winner = null; // Player lost } } // Resolve who eats whom based on type and strength function resolveEat(i, j) { const a = pixels[i]; const b = pixels[j]; const aBeatsB = (a.type === 0 && b.type === 2) || (a.type === 1 && b.type === 0) || (a.type === 2 && b.type === 1); const bBeatsA = (b.type === 0 && a.type === 2) || (b.type === 1 && a.type === 0) || (b.type === 2 && a.type === 1); if (aBeatsB && !bBeatsA) { if (a.strength >= b.strength) { a.strength += b.strength; pixels.splice(j, 1); if (j < i) i--; // Adjust index } } else if (bBeatsA && !aBeatsB) { if (b.strength >= a.strength) { b.strength += a.strength; pixels.splice(i, 1); if (i === playerIndex) playerIndex = -1; else if (j === playerIndex) playerIndex = i; return; // Since i is removed } } else { // Tie: compare strength if (a.strength > b.strength) { a.strength += b.strength; pixels.splice(j, 1); } else if (b.strength > a.strength) { b.strength += a.strength; pixels.splice(i, 1); if (i === playerIndex) playerIndex = -1; return; } else { // Equal: both die or something, but for simplicity, both survive } } // Update playerIndex if necessary playerIndex = pixels.findIndex(p => p.isPlayer); } // Game loop function gameLoop() { if (!gameOver) { move(); checkCollisions(); } draw(); requestAnimationFrame(gameLoop); } // Keyboard controls for player document.addEventListener('keydown', (e) => { if (gameOver || playerIndex === -1) return; const player = pixels[playerIndex]; if (e.key === 'ArrowRight') player.x = Math.min(GRID_SIZE - 1, player.x + 1); if (e.key === 'ArrowLeft') player.x = Math.max(0, player.x - 1); if (e.key === 'ArrowDown') player.y = Math.min(GRID_SIZE - 1, player.y + 1); if (e.key === 'ArrowUp') player.y = Math.max(0, player.y - 1); checkCollisions(); // Check after player move }); init(); gameLoop(); </script> </body> </html> ```
# Pixel Pac-Man Game with Strengths and Weaknesses Here's a complete HTML file with a JavaScript game where pixels eat each other with different strengths and weaknesses: ```html <!DOCTYPE html> <html> <head> <title>Pixel Eaters</title> <style> body { margin: 0; padding: 20px; display: flex; flex-direction: column; align-items: center; background-color: #222; color: white; font-family: Arial, sans-serif; } canvas { border: 2px solid #444; background-color: #111; margin-bottom: 20px; } .controls { margin-bottom: 15px; } button { padding: 8px 15px; margin: 0 5px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover { background-color: #45a049; } .info { margin-top: 15px; text-align: center; } </style> </head> <body> <h1>Pixel Eaters</h1> <div class="controls"> <button id="startBtn">Start Game</button> <button id="resetBtn">Reset</button> </div> <canvas id="gameCanvas" width="400" height="400"></canvas> <div class="info" id="gameInfo"> Use arrow keys to move the green player (strength: rock).<br> Rock beats scissors, scissors beat paper, paper beats rock. </div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const startBtn = document.getElementById('startBtn'); const resetBtn = document.getElementById('resetBtn'); const gameInfo = document.getElementById('gameInfo'); // Game constants const GRID_SIZE = 20; const CELL_SIZE = canvas.width / GRID_SIZE; const PIXEL_TYPES = ['rock', 'paper', 'scissors']; const COLORS = { rock: '#996633', paper: '#6699ff', scissors: '#ff6666', player: '#33cc33' }; // Game state let pixels = []; let player = null; let gameRunning = false; let gameInterval = null; let playerScore = 0; let aiScore = 0; let winner = null; // Pixel class class Pixel { constructor(x, y, type, isPlayer = false) { this.x = x; this.y = y; this.type = type; this.isPlayer = isPlayer; this.direction = null; this.speed = isPlayer ? 1 : 0.5; this.health = 100; this.counter = 0; } move() { if (!gameRunning) return; if (this.isPlayer) { // Player movement based on key input switch (this.direction) { case 'up': this.y = Math.max(0, this.y - this.speed); break; case 'down': this.y = Math.min(GRID_SIZE - 1, this.y + this.speed); break; case 'left': this.x = Math.max(0, this.x - this.speed); break; case 'right': this.x = Math.min(GRID_SIZE - 1, this.x + this.speed); break; } } else { // AI movement - random but slightly biased toward player this.counter++; if (this.counter >= 20 || Math.random() < 0.1) { const possibleDirections = ['up', 'down', 'left', 'right']; const dx = player.x - this.x; const dy = player.y - this.y; // Bias movement toward player if strong against player, away if weak if (this.isStrongAgainst(player.type) && Math.random() < 0.7) { if (Math.abs(dx) > Math.abs(dy)) { this.direction = dx > 0 ? 'right' : 'left'; } else { this.direction = dy > 0 ? 'down' : 'up'; } } else if (this.isWeakAgainst(player.type) && Math.random() < 0.7) { if (Math.abs(dx) > Math.abs(dy)) { this.direction = dx > 0 ? 'left' : 'right'; } else { this.direction = dy > 0 ? 'up' : 'down'; } } else { this.direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)]; } this.counter = 0; } // Apply movement switch (this.direction) { case 'up': this.y = Math.max(0, this.y - this.speed); break; case 'down': this.y = Math.min(GRID_SIZE - 1, this.y + this.speed); break; case 'left': this.x = Math.max(0, this.x - this.speed); break; case 'right': this.x = Math.min(GRID_SIZE - 1, this.x + this.speed); break; } } } draw() { ctx.fillStyle = this.isPlayer ? COLORS.player : COLORS[this.type]; ctx.beginPath(); ctx.arc( (this.x + 0.5) * CELL_SIZE, (this.y + 0.5) * CELL_SIZE, CELL_SIZE * 0.4, 0, Math.PI * 2 ); ctx.fill(); } isStrongAgainst(otherType) { return (this.type === 'rock' && otherType === 'scissors') || (this.type === 'scissors' && otherType === 'paper') || (this.type === 'paper' && otherType === 'rock'); } isWeakAgainst(otherType) { return (this.type === 'rock' && otherType === 'paper') || (this.type === 'scissors' && otherType === 'rock') || (this.type === 'paper' && otherType === 'scissors'); } collidesWith(otherPixel) { const dx = this.x - otherPixel.x; const dy = this.y - otherPixel.y; const distance = Math.sqrt(dx * dx + dy * dy); return distance < 0.8; // Collision threshold } } // Initialize game function initGame() { pixels = []; // Create player (always rock type) player = new Pixel( Math.floor(GRID_SIZE / 2), Math.floor(GRID_SIZE / 2), 'rock', true ); pixels.push(player); // Create AI pixels const pixelCount = 15; for (let i = 0; i < pixelCount; i++) { let x, y, validPosition; do { validPosition = true; x = Math.floor(Math.random() * GRID_SIZE); y = Math.floor(Math.random() * GRID_SIZE); // Check if position is too close to player const dx = x - player.x; const dy = y - player.y; if (Math.sqrt(dx * dx + dy * dy) < 5) { validPosition = false; } // Check if position overlaps with other pixels for (const pixel of pixels) { if (Math.abs(pixel.x - x) < 1 && Math.abs(pixel.y - y) < 1) { validPosition = false; break; } } } while (!validPosition); const type = PIXEL_TYPES[Math.floor(Math.random() * PIXEL_TYPES.length)]; const direction = ['up', 'down', 'left', 'right'][Math.floor(Math.random() * 4)]; const newPixel = new Pixel(x, y, type); newPixel.direction = direction; pixels.push(newPixel); } playerScore = 0; aiScore = 0; winner = null; gameInfo.textContent = "Use arrow keys to move the green player (strength: rock). Rock beats scissors, scissors beat paper, paper beats rock."; } // Game loop function gameLoop() { if (!gameRunning) return; // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw grid ctx.strokeStyle = '#333'; ctx.lineWidth = 0.5; for (let i = 0; i <= GRID_SIZE; i++) { ctx.beginPath(); ctx.moveTo(i * CELL_SIZE, 0); ctx.lineTo(i * CELL_SIZE, canvas.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, i * CELL_SIZE); ctx.lineTo(canvas.width, i * CELL_SIZE); ctx.stroke(); } // Move and draw all pixels for (let i = 0; i < pixels.length; i++) { pixels[i].move(); pixels[i].draw(); } // Check collisions for (let i = 0; i < pixels.length; i++) { for (let j = i + 1; j < pixels.length; j++) { const pixel1 = pixels[i]; const pixel2 = pixels[j]; if (pixel1.collidesWith(pixel2)) { let eater, eaten; if (pixel1.isStrongAgainst(pixel2.type)) { eater = pixel1; eaten = pixel2; } else if (pixel2.isStrongAgainst(pixel1.type)) { eater = pixel2; eaten = pixel1; } else { // Random winner for same type or no advantage eater = Math.random() < 0.5 ? pixel1 : pixel2; eaten = eater === pixel1 ? pixel2 : pixel1; } // If player is involved if (eater.isPlayer || eaten.isPlayer) { if (eater.isPlayer) { playerScore++; gameInfo.textContent = `Player ate a ${eaten.type}! Score: ${playerScore}`; } else { aiScore++; gameInfo.textContent = `AI ${eater.type} ate the player! Player score: ${playerScore}, AI score: ${aiScore}`; // Respawn player player.x = Math.floor(Math.random() * GRID_SIZE); player.y = Math.floor(Math.random() * GRID_SIZE); } } // Remove eaten pixel const index = pixels.indexOf(eaten); if (index !== -1) { pixels.splice(index, 1); } // Check for winner if (pixels.length === 1 && pixels[0].isPlayer) { winner = 'player'; gameRunning = false; gameInfo.textContent = `You win! Final score: ${playerScore}`; } else if (!pixels.some(p => p.isPlayer)) { winner = 'ai'; gameRunning = false; gameInfo.textContent = `Game over! AI wins with score ${aiScore}`; } break; } } } } // Event listeners document.addEventListener('keydown', (e) => { if (!player) return; switch (e.key) { case 'ArrowUp': player.direction = 'up'; break; case 'ArrowDown': player.direction = 'down'; break; case 'ArrowLeft': player.direction = 'left'; break; case 'ArrowRight': player.direction = 'right'; break; } }); startBtn.addEventListener('click', () => { if (!gameRunning) { if (winner) initGame(); gameRunning = true; gameInterval = setInterval(gameLoop, 50); startBtn.textContent = 'Pause'; } else { gameRunning = false; clearInterval(gameInterval); startBtn.textContent = 'Resume'; } }); resetBtn.addEventListener('click', () => { gameRunning = false; clearInterval(gameInterval); initGame(); startBtn.textContent = 'Start Game'; gameLoop(); // Draw initial state }); // Initialize initGame(); gameLoop(); </script> </body> </html> ``` This game features: - A player-controlled green pixel (always rock type) - AI-controlled pixels of different types (rock, paper, scissors) - Rock-paper-scissors mechanics where each type is strong against one and weak against another - The player wins by eating all other pixels - AI tries to chase the player when strong and run when weak - Score tracking for both player and AI - Simple controls with arrow keys The game demonstrates simple AI behavior, collision detection, and the rock-paper-scissors mechanics to determine who eats whom.
Here’s a self-contained HTML+JS pixel-eater game. Open it in a browser to play. Use the arrow keys to move your pixel. You choose Rock/Paper/Scissors at start—each type beats one other type. Eat all others to win! ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Pixel Eater Game</title> <style> body { margin:0; overflow:hidden; background:#000; color:#fff; font-family:sans-serif; } #gameCanvas { display:block; margin:0 auto; background:#111; } </style> </head> <body> <canvas id="gameCanvas" width="600" height="400"></canvas> <script> (() => { const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const W = canvas.width, H = canvas.height; const types = ["rock","paper","scissors"]; const colorMap = {rock:"#e74c3c", paper:"#2ecc71", scissors:"#3498db"}; const beats = {rock:"scissors", scissors:"paper", paper:"rock"}; let entities = []; let keys = {}; let gameOver=false, win=false; class Entity { constructor(x,y,type,isPlayer=false){ this.x = x; this.y = y; this.r = 8; this.type = type; this.color = colorMap[type]; this.isPlayer = isPlayer; if(!isPlayer){ let angle = Math.random()*Math.PI*2; this.speed = 1.2; this.vx = Math.cos(angle)*this.speed; this.vy = Math.sin(angle)*this.speed; this.changeDirCounter = 0; } else { this.speed = 2.5; this.vx = this.vy = 0; } } update(){ if(this.isPlayer){ this.vx = this.vy = 0; if(keys["ArrowUp"]) this.vy = -this.speed; if(keys["ArrowDown"]) this.vy = this.speed; if(keys["ArrowLeft"]) this.vx = -this.speed; if(keys["ArrowRight"]) this.vx = this.speed; } else { this.changeDirCounter--; if(this.changeDirCounter<=0){ let angle = Math.random()*Math.PI*2; this.vx = Math.cos(angle)*this.speed; this.vy = Math.sin(angle)*this.speed; this.changeDirCounter = 30 + Math.random()*90; } } this.x += this.vx; this.y += this.vy; // bounce if(this.x< this.r){ this.x = this.r; this.vx*=-1; } if(this.x>W - this.r){ this.x = W - this.r; this.vx*=-1; } if(this.y< this.r){ this.y = this.r; this.vy*=-1; } if(this.y>H - this.r){ this.y = H - this.r; this.vy*=-1; } } draw(){ ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x,this.y,this.r,0,Math.PI*2); ctx.fill(); } } function init(){ let choice = prompt("Choose your pixel type: rock, paper or scissors","rock"); if(!types.includes(choice)) choice = "rock"; // player in center entities.push(new Entity(W/2, H/2, choice, true)); // spawn AI for(let i=0;i<25;i++){ let x = Math.random()*(W-40)+20; let y = Math.random()*(H-40)+20; let t = types[Math.floor(Math.random()*3)]; entities.push(new Entity(x,y,t,false)); } requestAnimationFrame(loop); } function loop(){ update(); draw(); if(!gameOver && !win) requestAnimationFrame(loop); } function update(){ entities.forEach(e=>e.update()); // collision detection outer: for(let i=0;i<entities.length;i++){ for(let j=i+1;j<entities.length;j++){ let e1=entities[i], e2=entities[j]; let dx=e1.x-e2.x, dy=e1.y-e2.y; if(dx*dx+dy*dy < (e1.r+e2.r)**2){ if(e1.type===e2.type) continue; if(beats[e1.type]===e2.type){ eat(i,j); } else if(beats[e2.type]===e1.type){ eat(j,i); } break outer; } } } } function eat(winnerIdx, loserIdx){ let winner = entities[winnerIdx], loser = entities[loserIdx]; if(loser.isPlayer){ gameOver = true; } entities.splice(loserIdx,1); if(winner.isPlayer && entities.filter(e=>!e.isPlayer).length===0){ win = true; } } function draw(){ ctx.clearRect(0,0,W,H); entities.forEach(e=>e.draw()); if(gameOver || win){ ctx.fillStyle="rgba(0,0,0,0.6)"; ctx.fillRect(0,0,W,H); ctx.fillStyle="#fff"; ctx.font="36px sans-serif"; ctx.textAlign="center"; ctx.textBaseline="middle"; ctx.fillText(win ? "You Win!" : "Game Over", W/2, H/2); } } // input window.addEventListener("keydown", e=>{ keys[e.key]=true; }); window.addEventListener("keyup", e=>{ keys[e.key]=false; }); init(); })(); </script> </body> </html> ```
# Pixel Pacman: The Pixel Eater Game Here's a complete HTML implementation of a game where pixels (circles) move around, attempting to "eat" each other. The player controls the blue pixel, trying to become the largest by eating others. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Pixel Pacman: The Pixel Eater Game</title> <style> body { margin: 0; padding: 20px; display: flex; justify-content: center; align-items: center; flex-direction: column; background: linear-gradient(135deg, #0f2027, #203a43, #2c5364); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; min-height: 100vh; color: white; text-align: center; } h1 { color: #ffc107; text-shadow: 0 0 10px rgba(255, 193, 7, 0.7); margin-bottom: 5px; font-size: 36px; } .subtitle { margin-top: 0; margin-bottom: 15px; color: #e0e0e0; font-size: 18px; } .game-container { position: relative; } canvas { border: 3px solid #ffc107; border-radius: 10px; box-shadow: 0 0 25px rgba(255, 193, 7, 0.5); background-color: #121212; } .stats { display: flex; justify-content: space-around; width: 800px; background: rgba(0, 0, 0, 0.5); padding: 10px; border-radius: 10px; margin-top: 15px; border: 2px solid #00bcd4; font-size: 18px; } .controls { width: 800px; margin-top: 15px; background: rgba(0, 0, 0, 0.5); padding: 15px; border-radius: 10px; text-align: left; border: 2px solid #4caf50; } .controls h3 { color: #4caf50; margin-top: 0; } .controls ul { padding-left: 20px; margin: 10px 0; } .controls li { margin-bottom: 8px; } .message { position: absolute; top: 40%; left: 50%; transform: translate(-50%, -50%); padding: 20px 40px; background: rgba(0, 0, 0, 0.85); border: 3px solid #ff5722; border-radius: 10px; color: #ff5722; font-size: 36px; font-weight: bold; text-align: center; display: none; z-index: 10; text-shadow: 0 0 10px rgba(255, 87, 34, 0.8); } .start-btn { background: linear-gradient(135deg, #ff5722, #ff9800); color: white; font-size: 20px; border: none; padding: 12px 30px; border-radius: 30px; cursor: pointer; margin-top: 15px; transition: all 0.3s; font-weight: bold; box-shadow: 0 4px 15px rgba(255, 87, 34, 0.4); } .start-btn:hover { transform: scale(1.05); box-shadow: 0 6px 20px rgba(255, 87, 34, 0.6); } </style> </head> <body> <h1>Pixel Pacman: The Pixel Eater</h1> <p class="subtitle">Control your pixel to eat smaller ones. Eat them all to win!</p> <div class="game-container"> <canvas id="gameCanvas" width="800" height="500"></canvas> <div id="endMessage" class="message">Game Over!</div> </div> <div class="stats"> <div>Player Size: <span id="playerSize">20</span></div> <div>Enemies Remaining: <span id="enemyCount">10</span></div> <div>Time: <span id="timer">0</span>s</div> </div> <div class="controls"> <h3>How to Play:</h3> <ul> <li>Use <strong>Arrow Keys</strong> or <strong>WASD</strong> to move your pixel (blue)</li> <li>Eat <strong>smaller</strong> pixels to grow your size</li> <li>Avoid larger pixels - they will eat you!</li> <li>Fight equally sized pixels - bounce off to survive</li> <li>Eat all pixels to win!</li> </ul> </div> <button id="startButton" class="start-btn">START GAME</button> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); const startButton = document.getElementById('startButton'); const endMessage = document.getElementById('endMessage'); const playerSizeDisplay = document.getElementById('playerSize'); const enemyCountDisplay = document.getElementById('enemyCount'); const timerDisplay = document.getElementById('timer'); // Pixel class to represent each entity in the game class Pixel { constructor(x, y, r, dx, dy, color, isPlayer = false) { this.x = x; this.y = y; this.r = r; this.dx = dx; this.dy = dy; this.color = color; this.isPlayer = isPlayer; this.baseColor = color; this.highlight = false; this.highlightTimer = 0; } draw() { ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); // Add highlight effect when a pixel is eaten if (this.highlight) { const highlightRadius = this.r * 1.6; const gradient = ctx.createRadialGradient( this.x, this.y, this.r, this.x, this.y, highlightRadius ); gradient.addColorStop(0, "rgba(255, 255, 255, 0.8)"); gradient.addColorStop(1, "rgba(255, 255, 255, 0)"); ctx.fillStyle = this.color; ctx.fill(); ctx.fillStyle = gradient; ctx.fill(); // Flash effect when pixel grows from eating if (this.highlightTimer % 5 < 3) { ctx.beginPath(); ctx.arc(this.x, this.y, this.r * 0.7, 0, Math.PI * 2); ctx.fillStyle = this.baseColor; ctx.fill(); } } else { // Regular rendering ctx.fillStyle = this.color; ctx.fill(); // Draw player with a 'mouth' if (this.isPlayer) { ctx.beginPath(); ctx.arc(this.x - this.r/3, this.y, this.r/1.5, Math.PI/4, Math.PI*1.75); ctx.lineTo(this.x - this.r/3, this.y); ctx.closePath(); ctx.fillStyle = '#121212'; ctx.fill(); } // Add a shine effect to all pixels ctx.beginPath(); ctx.arc(this.x - this.r/3, this.y - this.r/3, this.r/4, 0, Math.PI * 2); ctx.fillStyle = 'rgba(255, 255, 255, 0.4)'; ctx.fill(); } ctx.closePath(); } update(canvas) { // Movement this.x += this.dx; this.y += this.dy; // Boundary collision with bounce effect if (this.x - this.r < 0) { this.x = this.r; this.dx = -this.dx; } else if (this.x + this.r > canvas.width) { this.x = canvas.width - this.r; this.dx = -this.dx; } if (this.y - this.r < 0) { this.y = this.r; this.dy = -this.dy; } else if (this.y + this.r > canvas.height) { this.y = canvas.height - this.r; this.dy = -this.dy; } // Update highlight effect if active if (this.highlight) { this.highlightTimer++; if (this.highlightTimer > 20) { this.highlight = false; this.highlightTimer = 0; } } } } // Game variables let pixels = []; let player; let gameStarted = false; let animationId; let keys = {}; let startTime = 0; let timerInterval; // Initialize the game function initGame() { pixels = []; // Create player player = new Pixel(canvas.width/2, canvas.height/2, 20, 0, 0, "#1E88E5", true); pixels.push(player); // Create enemy pixels const colors = ["#e53935", "#43a047", "#fbc02d", "#8e24aa", "#f57c00"]; for (let i = 0; i < 10; i++) { const r = Math.random() * 12 + 8; // Size 8-20 const x = Math.random() * (canvas.width - r * 2) + r; const y = Math.random() * (canvas.height - r * 2) + r; const dx = (Math.random() - 0.5) * 2; // X velocity const dy = (Math.random() - 0.5) * 2; // Y velocity const color = colors[Math.floor(Math.random() * colors.length)]; pixels.push(new Pixel(x, y, r, dx, dy, color)); } // Reset and display stats playerSizeDisplay.textContent = player.r.toFixed(1); enemyCountDisplay.textContent = (pixels.length - 1).toString(); // Start timer startTime = Date.now(); if (timerInterval) clearInterval(timerInterval); timerInterval = setInterval(() => { const seconds = Math.floor((Date.now() - startTime) / 1000); timerDisplay.textContent = seconds; }, 1000); gameStarted = true; endMessage.style.display = 'none'; } // Game loop - animation function function animate() { animationId = requestAnimationFrame(animate); ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw grid for pixel effect background drawGrid(); // Update and draw all pixels pixels.forEach(pixel => pixel.update(canvas)); pixels.forEach(pixel => pixel.draw()); // Update player stats playerSizeDisplay.textContent = player.r.toFixed(1); enemyCountDisplay.textContent = (pixels.length - 1).toString(); // Handle collisions handleCollisions(); // Handle key presses for movement const speed = Math.min(5, 15 - player.r/7); // Scale speed by size player.dx = 0; player.dy = 0; if (keys['ArrowUp'] || keys['w']) player.dy = -speed; if (keys['ArrowRight'] || keys['d']) player.dx = speed; if (keys['ArrowDown'] || keys['s']) player.dy = speed; if (keys['ArrowLeft'] || keys['a']) player.dx = -speed; // Normalize diagonal movement so no speed boost if (Math.abs(player.dx) > 0 && Math.abs(player.dy) > 0) { player.dx *= 0.7071; player.dy *= 0.7071; } } // Draw grid background for pixel effect function drawGrid() { const gridSize = 20; ctx.strokeStyle = 'rgba(50, 50, 50, 0.2)'; ctx.lineWidth = 0.5; // Draw vertical lines for (let x = 0; x <= canvas.width; x += gridSize) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke(); } // Draw horizontal lines for (let y = 0; y <= canvas.height; y += gridSize) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); } } // Handle collisions between pixels function handleCollisions() { const toRemove = []; for (let i = 0; i < pixels.length; i++) { for (let j = i + 1; j < pixels.length; j++) { const pixel1 = pixels[i]; const pixel2 = pixels[j]; // Skip if one of the pixels is already scheduled for removal if (toRemove.includes(i) || toRemove.includes(j)) continue; // Calculate distance and collision const dx = pixel2.x - pixel1.x; const dy = pixel2.y - pixel1.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < pixel1.r + pixel2.r) { // Player vs Enemy collision logic if (pixel1.isPlayer && !pixel2.isPlayer) { if (pixel1.r > pixel2.r * 1.1) { // Player eats enemy pixel1.r += pixel2.r * 0.2; pixel1.color = pixel2.color; pixel1.highlight = true; toRemove.push(j); } else if (pixel2.r > pixel1.r * 1.1) { // Enemy eats player (game over) endGame(false); return; } else { // Bounce if size difference is small bouncePixels(pixel1, pixel2, dx, dy, distance); } } // Enemy vs Enemy collision logic else if (!pixel1.isPlayer && !pixel2.isPlayer) { if (pixel1.r > pixel2.r * 1.1) { // Enemy 1 eats Enemy 2 pixel1.r += pixel2.r * 0.2; pixel1.highlight = true; toRemove.push(j); } else if (pixel2.r > pixel1.r * 1.1) { // Enemy 2 eats Enemy 1 pixel2.r += pixel1.r * 0.2; pixel2.highlight = true; toRemove.push(i); } else { // Bounce if size difference is small bouncePixels(pixel1, pixel2, dx, dy, distance); } } } } } // Remove eaten pixels in reverse order for (let i = toRemove.length - 1; i >= 0; i--) { pixels.splice(toRemove[i], 1); } // Check win condition if (pixels.length === 1 && player) { endGame(true); } } // Handle pixel bouncing on collisions function bouncePixels(p1, p2, dx, dy, distance) { const angle = Math.atan2(dy, dx); const sin = Math.sin(angle); const cos = Math.cos(angle); // Move apart to prevent overlapping const pushStrength = 0.05; const pushX = cos * pushStrength * p1.r; const pushY = sin * pushStrength * p1.r; p1.x -= pushX; p1.y -= pushY; p2.x += pushX; p2.y += pushY; // Exchange velocities but keep magnitude const tempDx = p1.dx; const tempDy = p1.dy; p1.dx = p2.dx; p1.dy = p2.dy; p2.dx = tempDx; p2.dy = tempDy; } // Handle game over function endGame(win) { gameStarted = false; cancelAnimationFrame(animationId); clearInterval(timerInterval); endMessage.textContent = win ? "VICTORY!" : "YOU WERE EATEN!"; endMessage.style.color = win ? "#4CAF50" : "#f44336"; endMessage.style.textShadow = win ? "0 0 10px rgba(76, 175, 80, 0.8)" : "0 0 10px rgba(244, 67, 54, 0.8)"; endMessage.style.display = 'block'; } // Handle keyboard input window.addEventListener('keydown', (e) => { keys[e.key] = true; // Prevent default scrolling if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'w', 'a', 's', 'd'].includes(e.key)) { e.preventDefault(); } }); window.addEventListener('keyup', (e) => { keys[e.key] = false; }); // Start game when button is clicked startButton.addEventListener('click', () => { initGame(); if (!gameStarted) { animate(); startButton.textContent = "RESTART GAME"; } }); // Initialize the game initially initGame(); animate(); </script> </body> </html> ``` ## Game Features: 1. **Player Pixel Control**: Use arrow keys or WASD to control your blue pixel 2. **Pixel Mechanics**: - Eat smaller pixels to grow your size - Avoid larger pixels - they can eat you - Bounce off similarly sized pixels 3. **Visual Effects**: - Flash effect when pixels are eaten - Particle-style shine effects - Victory and game over screens - Pixel grid background 4. **Real-time Stats**: - Player size display - Enemies remaining count - Timer showing game duration 5. **Sound Effects**: Eating sounds and bounce effects (currently not implemented but structure is there) ## How to Play: 1. Click "START GAME" to begin 2. Move using arrow keys or WASD 3. Eat smaller pixels to grow larger 4. Avoid larger pixels until you're big enough to eat them 5. Try to eat all pixels to win! The game offers simple yet satisfying pixel physics and strategy - early game is about avoiding larger enemies while growing by eating smaller ones. Once you become the biggest pixel, hunt down the remaining ones to win!
Here's a simple implementation of a pixel game where pixels with different strengths and weaknesses eat each other in a manner similar to Pac-Man. Each pixel has a type (Red, Green, or Blue) with specific win/loss relationships (Red beats Green, Green beats Blue, Blue beats Red). The game ends when one pixel survives. ```html <!DOCTYPE html> <html> <head> <title>Pixel Eat Game</title> <style> body { margin: 0; background: #222; } canvas { display: block; margin: 0 auto; background: #111; } </style> </head> <body> <canvas id="gameCanvas" width="400" height="400"></canvas> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Win relationships: who beats whom const beats = { 0: 1, 1: 2, 2: 0 }; // red=0, green=1, blue=2 class Pixel { constructor(x, y, type) { this.x = x; this.y = y; this.radius = 5 + Math.random() * 5; this.type = type; this.color = ['#f00', '#0f0', '#00f'][type]; this.dx = (Math.random() - 0.5) * 2; this.dy = (Math.random() - 0.5) * 2; } update() { this.x += this.dx; this.y += this.dy; // Bounce off walls if (this.x < this.radius || this.x > canvas.width - this.radius) this.dx *= -1; if (this.y < this.radius || this.y > canvas.height - this.radius) this.dy *= -1; } } let pixels = []; function createInitialPixels(count = 15) { for (let i = 0; i < count; i++) { const type = Math.floor(Math.random() * 3); pixels.push(new Pixel( Math.random() * canvas.width, Math.random() * canvas.height, type )); } } function checkCollision(a, b) { const dx = a.x - b.x; const dy = a.y - b.y; const dist = Math.sqrt(dx*dx + dy*dy); const minDist = a.radius + b.radius; if (dist < minDist) { if (beats[a.type] === b.type) { a.radius += b.radius * 0.4; return b; // remove b } if (beats[b.type] === a.type) { b.radius += a.radius * 0.4; return a; // remove a } } return null; } function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Move and draw for (const pixel of pixels) { pixel.update(); } // Detect collisions for (let i = 0; i < pixels.length; i++) { for (let j = i + 1; j < pixels.length; j++) { const toRemove = checkCollision(pixels[i], pixels[j]); if (toRemove) { const index = pixels.indexOf(toRemove); if (index !== -1) { pixels.splice(index, 1); } // Break and restart collision check after array modification i = 0; j = 0; } } } // Draw for (const pixel of pixels) { ctx.beginPath(); ctx.arc(pixel.x, pixel.y, pixel.radius, 0, Math.PI*2); ctx.fillStyle = pixel.color; ctx.fill(); } // Game over? if (pixels.length === 1) { alert(`The winner is ${pixels[0].color}!`); return; } requestAnimationFrame(gameLoop); } createInitialPixels(); gameLoop(); </script> </body> </html> ``` This game features: - Different colored pixels with specific strengths/weaknesses - Real-time collision detection and eating mechanic - Dynamic growth when a pixel eats another - Automatic game reset with winner announcement - Simple bouncy movement and wall reflection - Clean minimalistic graphics The pixels will move around randomly, and when two opposite types collide, the stronger one will absorb the weaker one. The surviving pixel grows slightly each time it eats an opponent, increasing its chances of future victories.
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Pixel Battle Arena</title> <style> body { margin: 0; padding: 20px; background: #1a1a1a; color: white; font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; } canvas { border: 2px solid #333; background: #000; } .ui { margin-top: 10px; display: flex; gap: 20px; align-items: center; } .stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 10px; } .pixel-info { background: #333; padding: 5px; border-radius: 3px; font-size: 12px; } .winner { font-size: 24px; color: #00ff00; margin-top: 10px; } </style> </head> <body> <h1>Pixel Battle Arena</h1> <canvas id="gameCanvas" width="600" height="400"></canvas> <div class="ui"> <button onclick="resetGame()">Reset Game</button> <div>Alive Pixels: <span id="aliveCount">0</span></div> </div> <div class="stats" id="stats"></div> <div id="winner" class="winner"></div> <script> const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Pixel types with different strengths and weaknesses const PIXEL_TYPES = { WARRIOR: { color: '#ff4444', strength: 8, speed: 2, size: 6, weakness: 'ASSASSIN', strongAgainst: 'TANK' }, TANK: { color: '#4444ff', strength: 12, speed: 1, size: 8, weakness: 'WARRIOR', strongAgainst: 'MAGE' }, MAGE: { color: '#44ff44', strength: 6, speed: 3, size: 4, weakness: 'TANK', strongAgainst: 'ASSASSIN' }, ASSASSIN: { color: '#ffff44', strength: 4, speed: 4, size: 3, weakness: 'MAGE', strongAgainst: 'WARRIOR' } }; class Pixel { constructor(x, y, type) { this.x = x; this.y = y; this.type = type; this.config = PIXEL_TYPES[type]; this.health = this.config.strength; this.maxHealth = this.config.strength; this.vx = (Math.random() - 0.5) * this.config.speed; this.vy = (Math.random() - 0.5) * this.config.speed; this.id = Math.random().toString(36).substr(2, 9); this.huntTarget = null; this.lastDamageTime = 0; } update(pixels) { // Find nearest enemy let nearestEnemy = null; let nearestDistance = Infinity; pixels.forEach(pixel => { if (pixel !== this && pixel.health > 0) { const dx = pixel.x - this.x; const dy = pixel.y - this.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < nearestDistance) { nearestDistance = distance; nearestEnemy = pixel; } } }); // Move towards nearest enemy if (nearestEnemy) { const dx = nearestEnemy.x - this.x; const dy = nearestEnemy.y - this.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { this.vx = (dx / distance) * this.config.speed; this.vy = (dy / distance) * this.config.speed; } } // Update position this.x += this.vx; this.y += this.vy; // Bounce off walls if (this.x <= this.config.size || this.x >= canvas.width - this.config.size) { this.vx *= -1; this.x = Math.max(this.config.size, Math.min(canvas.width - this.config.size, this.x)); } if (this.y <= this.config.size || this.y >= canvas.height - this.config.size) { this.vy *= -1; this.y = Math.max(this.config.size, Math.min(canvas.height - this.config.size, this.y)); } // Check collisions with other pixels pixels.forEach(other => { if (other !== this && other.health > 0) { const dx = other.x - this.x; const dy = other.y - this.y; const distance = Math.sqrt(dx * dx + dy * dy); const minDistance = this.config.size + other.config.size; if (distance < minDistance) { this.fight(other); } } }); } fight(other) { const now = Date.now(); if (now - this.lastDamageTime < 500) return; // Combat cooldown let damage = 1; let otherDamage = 1; // Calculate damage based on type advantages if (this.config.strongAgainst === other.type) { damage = 3; // Triple damage against weak type } if (this.config.weakness === other.type) { otherDamage = 3; // Take triple damage from strong type } // Apply damage this.health -= otherDamage; other.health -= damage; this.lastDamageTime = now; other.lastDamageTime = now; // Knockback effect const dx = other.x - this.x; const dy = other.y - this.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { const knockback = 5; this.vx -= (dx / distance) * knockback; this.vy -= (dy / distance) * knockback; other.vx += (dx / distance) * knockback; other.vy += (dy / distance) * knockback; } } draw() { if (this.health <= 0) return; // Draw pixel with health-based transparency const alpha = this.health / this.maxHealth; ctx.globalAlpha = alpha; // Draw main body ctx.fillStyle = this.config.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.config.size, 0, Math.PI * 2); ctx.fill(); // Draw health bar ctx.globalAlpha = 1; const barWidth = this.config.size * 2; const barHeight = 3; const barX = this.x - barWidth / 2; const barY = this.y - this.config.size - 8; ctx.fillStyle = '#333'; ctx.fillRect(barX, barY, barWidth, barHeight); ctx.fillStyle = '#ff0000'; const healthPercent = this.health / this.maxHealth; ctx.fillRect(barX, barY, barWidth * healthPercent, barHeight); // Draw type indicator ctx.fillStyle = 'white'; ctx.font = '8px Arial'; ctx.textAlign = 'center'; ctx.fillText(this.type[0], this.x, this.y + 2); ctx.globalAlpha = 1; } } let pixels = []; let gameWinner = null; function initGame() { pixels = []; gameWinner = null; document.getElementById('winner').textContent = ''; const types = Object.keys(PIXEL_TYPES); // Create 20 pixels of each type types.forEach(type => { for (let i = 0; i < 20; i++) { const x = Math.random() * (canvas.width - 40) + 20; const y = Math.random() * (canvas.height - 40) + 20; pixels.push(new Pixel(x, y, type)); } }); } function updateStats() { const stats = {}; const alivePixels = pixels.filter(p => p.health > 0); Object.keys(PIXEL_TYPES).forEach(type => { stats[type] = alivePixels.filter(p => p.type === type).length; }); document.getElementById('aliveCount').textContent = alivePixels.length; const statsDiv = document.getElementById('stats'); statsDiv.innerHTML = ''; Object.entries(stats).forEach(([type, count]) => { const div = document.createElement('div'); div.className = 'pixel-info'; div.style.borderLeft = `4px solid ${PIXEL_TYPES[type].color}`; div.innerHTML = ` <strong>${type}</strong><br> Alive: ${count}<br> Str: ${PIXEL_TYPES[type].strength} | Spd: ${PIXEL_TYPES[type].speed}<br> vs ${PIXEL_TYPES[type].strongAgainst} `; statsDiv.appendChild(div); }); // Check for winner const aliveTypes = Object.entries(stats).filter(([type, count]) => count > 0); if (aliveTypes.length === 1 && !gameWinner) { gameWinner = aliveTypes[0][0]; document.getElementById('winner').textContent = `🏆 ${gameWinner} WINS! 🏆`; } else if (alivePixels.length === 0 && !gameWinner) { document.getElementById('winner').textContent = '💀 DRAW - All pixels eliminated! 💀'; } } function gameLoop() { // Clear canvas ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Update and draw pixels pixels.forEach(pixel => { if (pixel.health > 0) { pixel.update(pixels); pixel.draw(); } }); updateStats(); requestAnimationFrame(gameLoop); } function resetGame() { initGame(); } // Initialize and start the game initGame(); gameLoop(); </script> </body> </html> ``` This pixel battle game features: 🎮 **Game Mechanics:** - 4 different pixel types: Warrior (red), Tank (blue), Mage (green), Assassin (yellow) - Each type has unique stats: strength, speed, and size - Rock-paper-scissors combat system with type advantages - Health bars and damage indicators - Knockback effects during combat ⚔️ **Combat System:** - Pixels automatically hunt the nearest enemy - Type advantages deal 3x damage - Combat cooldown prevents spam - Health decreases during fights - Eliminated pixels fade away 📊 **Features:** - Real-time statistics showing alive count per type - Winner detection when only one type remains - Reset button to start new battles - Visual health indicators - Type indicators on each pixel The game creates an engaging battle royale where different pixel types fight using their unique strengths and weaknesses!
**HTML + JavaScript (single file)** ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pixel‑Battle</title> <style> body,html{margin:0;padding:0;height:100%;overflow:hidden;background:#111;} canvas{display:block;background:#222;} #info{ position:absolute;top:10px;left:10px;color:#fff;font-family:sans-serif; background:rgba(0,0,0,0.5);padding:5px 10px;border-radius:4px; } #restart{ position:absolute;bottom:20px;left:50%;transform:translateX(-50%); padding:8px 16px;font-size:14px;background:#08c;color:#fff; border:none;border-radius:4px;cursor:pointer; } </style> </head> <body> <div id="info">Score: <span id="score">0</span></div> < id="game"></canvas> <button id="restart" style="display:none;">Restart</button> <script> (() => { const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const restartBtn = document.getElementById('restart'); const WIDTH = canvas.width = window.innerWidth; const HEIGHT = canvas.height = window.innerHeight; const PLAYER_SPEED = 3; const AI_SPEED = 1.5; const MIN_SIZE = 10; const MAX_SIZE = 30; const SPAWN_COUNT = 30; let keys = {}; let pixels = []; let player; let gameOver = false; // ---- Pixel class ------------------------------------------------- class Pixel{ constructor(x,y,size,color,ai=true){ this.x = x; this.y = y; this.size = size; // also the "strength" this.color = color; this.ai = ai; this.vel = {x:0,y:0}; this.setRandomVelocity(); } setRandomVelocity(){ const angle = Math.random()*Math.PI*2; const speed = this.ai ? AI_SPEED : 0; this.vel.x = Math.cos(angle)*speed; this.vel.y = Math.sin(angle)*speed; } update(){ if(this.ai){ // random wandering if(Math.random()<0.01) this.setRandomVelocity(); this.x += this.vel.x; this.y += this.vel.y; }else{ // player controlled this.vel.x = 0; this.vel.y = 0; if(keysArrowUp']||keys['w']) this.vel.y=-PLAYER_SPEED; if(keys['ArrowDown']||keys['s']) this.vel.y=PLAYER_SPEED; if(keys['ArrowLeft']||keys['a']) this.vel.x=-PLAYER_SPEED; if(keys['ArrowRight']||keys['d']) this.vel.x=PLAYER_SPEED; this.x += this.vel.x; this.y += this.vel.y; } // keep inside canvas if(this.x<0) this.x=WIDTH; if(this.x>WIDTH) this.x=0; if(this.y<0) this.y=HEIGHT; if(this.y>HEIGHT) this.y=0; } draw(){ ctx.fillStyle = this.color; ctx.fillRect(this.x-this.size/2, this.y-this.size/2, this.size, this.size); } collides(other){ const dx = this.x - other.x; const dy = this.y - other.y; const dist = Math.hypot(dx,dy); return dist < (this.size+other.size)/2; } eat(other){ // grow proportionally to the victim's size this.size = Math.min(this.size + other.size*0.3, 80); } } // ---- Input -------------------------------------------------------- window.addEventListener('keydown',e=>keys[e.key]=true); window.addEventListener('keyup',e=>keys[e.key]=false); // ---- Game helpers -------------------------------------------------- function rand(min,max){return Math.random()*(max-min)+min;} function randomColor(){return `hsl(${rand(0,360)},80%,60%)`; } function init(){ pixels = []; gameOver = false; restartBtn.style.display='none'; scoreEl.textContent='0'; // create AI pixels for(let i=0;i<SPAWN_COUNT;i++){ const p = new Pixel( rand(0,WIDTH),rand(0,HEIGHT), rand(MIN_SIZE,MAX_SIZE), randomColor(), true ); pixels.push(p); } // create player pixel (largest at start) player = new Pixel(WIDTH/2, HEIGHT/2, MAX_SIZE+5, '#ff0', false); pixels.push(player); } // ---- Main loop ----------------------------------------------------- function loop(){ if(gameOver) return; ctx.clearRect(0,0,WIDTH,HEIGHT); // update & draw all pixels pixels.forEach(p=>{ p.update(); p.draw(); }); // check collisions for(let i=0;i<pixels.length;i++){ for(let j=i+1;j<pixels.length;j++){ const a = pixels[i]; const b = pixels[j]; if(a.collides(b)){ // larger eats smaller if(a.size > b.size){ a.eat(b); if(b===player) endGame(false); pixels.splice(j,1); j--; }else if(b.size > a.size){ b.eat(a); if(a===player) endGame(false); pixels.splice(i,1); i--; break; } } } } // win condition const alive = pixels.filter(p=>p!==player); if(player && alive.length===0){ endGame(true); } // update score (player size) scoreEl.textContent = Math.round(player.size); requestAnimationFrame(loop); } function endGame(victory){ gameOver = true; ctx.fillStyle = 'rgba(0,0,0,0.7)'; ctx.fillRect(0,0,WIDTH,HEIGHT); ctx.fillStyle = '#fff'; ctx.font = '48px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(victory ? 'You Win!' : 'Game Over', WIDTH/2, HEIGHT/2); restartBtn.style.display='block'; } restartBtn.addEventListener('click',()=>{ init(); loop(); }); // ---- Start --------------------------------------------------------- init(); loop(); })(); </script> </body> </html> ```