Enlace Cyber Grid: Prompt de Juego de Serpiente en HTML5 Canvas
De Wikiprompt, la enciclopedia libre de prompts
Enlace Cyber Grid: Prompt de Juego de Serpiente en HTML5 Canvas Un prompt detallado para generar un juego completo de canvas HTML5 en un solo archivo con mecánica de serpiente cyberpunk, incluyendo especificaciones de renderizado, controles y estilo visual.
Contenido del PromptGuardar
🌐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cyber Grid Link</title>
<style>
body {
margin: 0;
padding: 0;
background: #0a0a12;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Courier New', monospace;
overflow: hidden;
}
canvas {
border: 2px solid #00ffcc;
box-shadow: 0 0 30px rgba(0, 255, 204, 0.3);
background: #0d0d1a;
}
#ui {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
color: #00ffcc;
font-size: 18px;
text-shadow: 0 0 10px #00ffcc;
z-index: 10;
letter-spacing: 2px;
}
#gameOver {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #ff0044;
font-size: 32px;
text-shadow: 0 0 20px #ff0044;
display: none;
z-index: 20;
text-align: center;
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border: 1px solid #ff0044;
}
#gameOver button {
margin-top: 15px;
padding: 10px 20px;
background: #ff0044;
color: white;
border: none;
font-size: 16px;
cursor: pointer;
font-family: 'Courier New', monospace;
}
</style>
</head>
<body>
<div id="ui">SCORE: 0 | LENGTH: 5</div>
<div id="gameOver">
<div>GAME OVER</div>
<button onclick="restartGame()">RESTART</button>
</div>
<canvas id="gameCanvas"></canvas>
<script>
(function() {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const ui = document.getElementById('ui');
const gameOverDiv = document.getElementById('gameOver');
// Grid settings
const GRID_SIZE = 20;
const CELL_SIZE = 30;
const COLS = 30;
const ROWS = 20;
canvas.width = COLS * CELL_SIZE;
canvas.height = ROWS * CELL_SIZE;
// Game state
let snake = [];
let direction = { x: 1, y: 0 };
let nextDirection = { x: 1, y: 0 };
let crystals = [];
let firewalls = [];
let score = 0;
let gameRunning = true;
let lastTime = 0;
let moveTimer = 0;
const MOVE_INTERVAL = 150; // ms per grid step
// Particle system for snake segments
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.targetX = x;
this.targetY = y;
this.prevX = x;
this.prevY = y;
}
update(deltaTime) {
// LERP interpolation for smooth movement
const lerpSpeed = 0.15;
this.x += (this.targetX - this.x) * lerpSpeed;
this.y += (this.targetY - this.y) * lerpSpeed;
}
setTarget(x, y) {
this.prevX = this.targetX;
this.prevY = this.targetY;
this.targetX = x;
this.targetY = y;
}
}
// Initialize snake
function initSnake() {
snake = [];
const startX = Math.floor(COLS / 2);
const startY = Math.floor(ROWS / 2);
for (let i = 0; i < 5; i++) {
const particle = new Particle(
(startX - i) * CELL_SIZE + CELL_SIZE / 2,
startY * CELL_SIZE + CELL_SIZE / 2
);
particle.setTarget(
(startX - i) * CELL_SIZE + CELL_SIZE / 2,
startY * CELL_SIZE + CELL_SIZE / 2
);
snake.push(particle);
}
}
// Spawn crystal
function spawnCrystal() {
let x, y;
do {
x = Math.floor(Math.random() * COLS);
y = Math.floor(Math.random() * ROWS);
} while (isSnakeCell(x, y) || isFirewallCell(x, y));
crystals.push({ x, y });
}
// Spawn firewall
function spawnFirewall() {
let x, y;
do {
x = Math.floor(Math.random() * COLS);
y = Math.floor(Math.random() * ROWS);
} while (isSnakeCell(x, y) || isCrystalCell(x, y));
firewalls.push({ x, y, dx: Math.random() > 0.5 ? 1 : -1, dy: Math.random() > 0.5 ? 1 : -1 });
}
function isSnakeCell(x, y) {
return snake.some(seg => {
const segX = Math.floor(seg.targetX / CELL_SIZE);
const segY = Math.floor(seg.targetY / CELL_SIZE);
return segX === x && segY === y;
});
}
function isCrystalCell(x, y) {
return crystals.some(c => c.x === x && c.y === y);
}
function isFirewallCell(x, y) {
return firewalls.some(f => f.x === x && f.y === y);
}
// Grid warping effect near snake head
function warpGrid(x, y) {
const head = snake[0];
if (!head) return { x, y };
const headX = head.x;
const headY = head.y;
const dx = x - headX;
const dy = y - headY;
const dist = Math.sqrt(dx * dx + dy * dy);
const warpRadius = 100;
if (dist < warpRadius) {
const warpFactor = (1 - dist / warpRadius) * 0.3;
return {
x: x + dx * warpFactor,
y: y + dy * warpFactor
};
}
return { x, y };
}
// Move snake
function moveSnake() {
// Update direction
direction = { ...nextDirection };
// Get head position
const head = snake[0];
const headGridX = Math.floor(head.targetX / CELL_SIZE);
const headGridY = Math.floor(head.targetY / CELL_SIZE);
// New head position
const newHeadX = headGridX + direction.x;
const newHeadY = headGridY + direction.y;
// Check wall collision
if (newHeadX < 0 || newHeadX >= COLS || newHeadY < 0 || newHeadY >= ROWS) {
gameOver();
return;
}
// Check self collision
if (isSnakeCell(newHeadX, newHeadY)) {
gameOver();
return;
}
// Check firewall collision
if (isFirewallCell(newHeadX, newHeadY)) {
gameOver();
return;
}
// Create new head particle
const newHead = new Particle(
newHeadX * CELL_SIZE + CELL_SIZE / 2,
newHeadY * CELL_SIZE + CELL_SIZE / 2
);
newHead.setTarget(
newHeadX * CELL_SIZE + CELL_SIZE / 2,
newHeadY * CELL_SIZE + CELL_SIZE / 2
);
// Shift snake
snake.unshift(newHead);
// Check crystal collection
const crystalIndex = crystals.findIndex(c => c.x === newHeadX && c.y === newHeadY);
if (crystalIndex !== -1) {
crystals.splice(crystalIndex, 1);
score += 10;
spawnCrystal();
// Don't remove tail (grow)
} else {
snake.pop();
}
// Update targets for smooth movement
for (let i = 1; i < snake.length; i++) {
snake[i].setTarget(snake[i - 1].prevX, snake[i - 1].prevY);
}
updateUI();
}
// Update firewalls
function updateFirewalls() {
firewalls.forEach(fw => {
fw.x += fw.dx;
fw.y += fw.dy;
// Bounce off walls
if (fw.x < 0 || fw.x >= COLS) fw.dx *= -1;
if (fw.y < 0 || fw.y >= ROWS) fw.dy *= -1;
// Clamp
fw.x = Math.max(0, Math.min(COLS - 1, fw.x));
fw.y = Math.max(0, Math.min(ROWS - 1, fw.y));
});
}
function gameOver() {
gameRunning = false;
gameOverDiv.style.display = 'block';
}
function restartGame() {
gameOverDiv.style.display = 'none';
score = 0;
direction = { x: 1, y: 0 };
nextDirection = { x: 1, y: 0 };
crystals = [];
firewalls = [];
initSnake();
spawnCrystal();
for (let i = 0; i < 3; i++) spawnFirewall();
gameRunning = true;
updateUI();
}
function updateUI() {
ui.textContent = `SCORE: ${score} | LENGTH: ${snake.length}`;
}
// Drawing functions
function drawGrid() {
ctx.strokeStyle = 'rgba(0, 255, 204, 0.2)';
ctx.lineWidth = 1;
for (let i = 0; i <= COLS; i++) {
const x = i * CELL_SIZE;
ctx.beginPath();
for (let j = 0; j <= ROWS; j++) {
const y = j * CELL_SIZE;
const warped = warpGrid(x, y);
if (j === 0) ctx.moveTo(warped.x, warped.y);
else ctx.lineTo(warped.x, warped.y);
}
ctx.stroke();
}
for (let j = 0; j <= ROWS; j++) {
const y = j * CELL_SIZE;
ctx.beginPath();
for (let i = 0; i <= COLS; i++) {
const x = i * CELL_SIZE;
const warped = warpGrid(x, y);
if (i === 0) ctx.moveTo(warped.x, warped.y);
else ctx.lineTo(warped.x, warped.y);
}
ctx.stroke();
}
}
function drawSnake() {
// Draw glow effect
ctx.shadowBlur = 20;
ctx.shadowColor = '#00ffcc';
// Draw snake segments with gradient
for (let i = snake.length - 1; i >= 0; i--) {
const seg = snake[i];
const hue = 160 + (i / snake.length) * 40;
const lightness = 50 + (i / snake.length) * 20;
ctx.fillStyle = `hsl(${hue}, 100%, ${lightness}%)`;
ctx.beginPath();
ctx.arc(seg.x, seg.y, CELL_SIZE * 0.35, 0, Math.PI * 2);
ctx.fill();
}
// Draw head with special effect
if (snake.length > 0) {
const head = snake[0];
ctx.fillStyle = '#00ffcc';
ctx.beginPath();
ctx.arc(head.x, head.y, CELL_SIZE * 0.45, 0, Math.PI * 2);
ctx.fill();
// Eyes
ctx.fillStyle = '#ffffff';
const eyeOffset = CELL_SIZE * 0.15;
ctx.beginPath();
ctx.arc(head.x + direction.x * eyeOffset, head.y + direction.y * eyeOffset, 4, 0, Math.PI * 2);
ctx.fill();
}
ctx.shadowBlur = 0;
}
function drawCrystals() {
crystals.forEach(crystal => {
const x = crystal.x * CELL_SIZE + CELL_SIZE / 2;
const y = crystal.y * CELL_SIZE + CELL_SIZE / 2;
ctx.shadowBlur = 15;
ctx.shadowColor = '#ff00ff';
ctx.fillStyle = '#ff00ff';
ctx.beginPath();
ctx.moveTo(x, y - 10);
ctx.lineTo(x + 8, y);
ctx.lineTo(x, y + 10);
ctx.lineTo(x - 8, y);
ctx.closePath();
ctx.fill();
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2);
ctx.fill();
});
ctx.shadowBlur = 0;
}
function drawFirewalls() {
firewalls.forEach(fw => {
const x = fw.x * CELL_SIZE + CELL_SIZE / 2;
const y = fw.y * CELL_SIZE + CELL_SIZE / 2;
ctx.shadowBlur = 10;
ctx.shadowColor = '#ff4400';
ctx.fillStyle = 'rgba(255, 68, 0, 0.8)';
ctx.fillRect(x - CELL_SIZE * 0.4, y - CELL_SIZE * 0.4, CELL_SIZE * 0.8, CELL_SIZE * 0.8);
ctx.strokeStyle = '#ff4400';
ctx.lineWidth = 2;
ctx.strokeRect(x - CELL_SIZE * 0.4, y - CELL_SIZE * 0.4, CELL_SIZE * 0.8, CELL_SIZE * 0.8);
});
ctx.shadowBlur = 0;
}
// Main game loop
function gameLoop(timestamp) {
const deltaTime = timestamp - lastTime;
lastTime = timestamp;
if (gameRunning) {
// Move timer
moveTimer += deltaTime;
if (moveTimer >= MOVE_INTERVAL) {
moveTimer -= MOVE_INTERVAL;
moveSnake();
updateFirewalls();
}
// Update particle positions
snake.forEach(seg => seg.update(deltaTime));
// Clear canvas
ctx.fillStyle = '#0d0d1a';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw everything
drawGrid();
drawCrystals();
drawFirewalls();
drawSnake();
}
requestAnimationFrame(gameLoop);
}
// Input handling
document.addEventListener('keydown', (e) => {
if (!gameRunning) return;
switch(e.key) {
case 'ArrowUp':
case 'w':
if (direction.y !== 1) nextDirection = { x: 0, y: -1 };
break;
case 'ArrowDown':
case 's':
if (direction.y !== -1) nextDirection = { x: 0, y: 1 };
break;
case 'ArrowLeft':
case 'a':
if (direction.x !== 1) nextDirection = { x: -1, y: 0 };
break;
case 'ArrowRight':
case 'd':
if (direction.x !== -1) nextDirection = { x: 1, y: 0 };
break;
}
e.preventDefault();
});
// Initialize game
initSnake();
spawnCrystal();
for (let i = 0; i < 3; i++) spawnFirewall();
updateUI();
// Start game loop
requestAnimationFrame(gameLoop);
})();
</script>
</body>
</html>
Iniciá sesión para ver el prompt completo
Continuar con:
Al iniciar sesión, aceptás nuestros Términos de uso y Política de privacidad
Uso
Este prompt está diseñado para usarse con coding. Copiá el contenido de arriba y pegalo en tu herramienta de IA preferida.
Para mejores resultados, personalizá los marcadores (indicados con corchetes o mayúsculas) con tus requisitos específicos.
Discusión
0 comentarios