1 <!DOCTYPE html>2 <html lang="es">3 <head>4 <meta charset="UTF-8" />5 <title>Elastic Ball Platformer</title>6 <style>7 body {8 margin: 0;9 background: #111;10 overflow: hidden;11 font-family: sans-serif;12 }13 canvas {14 display: block;15 margin: auto;16 background: linear-gradient(#87ceeb, #d0f4f7);17 }18 </style>19 </head>20 <body>21 22 <canvas id="game" width="900" height="500"></canvas>23 24 <script>25 const canvas = document.getElementById("game");26 const ctx = canvas.getContext("2d");27 28 const GRAVITY = 0.6;29 const FRICTION = 0.8;30 const JUMP_FORCE = -13;31 32 let keys = {};33 let lives = 3;34 let dead = false;35 36 document.addEventListener("keydown", e => keys[e.code] = true);37 document.addEventListener("keyup", e => keys[e.code] = false);38 39 const player = {40 x: 100,41 y: 100,42 r: 18,43 vx: 0,44 vy: 0,45 onGround: false,46 squashX: 1,47 squashY: 1,48 49 reset() {50 this.x = 100;51 this.y = 100;52 this.vx = 0;53 this.vy = 0;54 }55 };56 57 const platforms = [58 { x: 0, y: 460, w: 900, h: 40 },59 { x: 200, y: 360, w: 120, h: 20 },60 { x: 400, y: 300, w: 120, h: 20, move: true, dir: 1 },61 { x: 600, y: 260, w: 120, h: 20 }62 ];63 64 const holes = [65 { x: 150, y: 460, w: 80, h: 40 },66 { x: 500, y: 460, w: 100, h: 40 }67 ];68 69 function updatePlatforms() {70 for (let p of platforms) {71 if (p.move) {72 p.x += p.dir * 1.2;73 if (p.x < 350 || p.x > 500) p.dir *= -1;74 }75 }76 }77 78 function updatePlayer() {79 // Input80 if (keys["ArrowLeft"]) player.vx -= 0.6;81 if (keys["ArrowRight"]) player.vx += 0.6;82 if (keys["Space"] && player.onGround) {83 player.vy = JUMP_FORCE;84 player.onGround = false;85 }86 87 // Physics88 player.vy += GRAVITY;89 player.x += player.vx;90 player.y += player.vy;91 player.vx *= FRICTION;92 93 // Deformación elástica94 if (!player.onGround) {95 player.squashX = 0.9;96 player.squashY = 1.1;97 } else {98 player.squashX = 1.15;99 player.squashY = 0.85;100 }101 102 // Colisiones plataformas (solo desde arriba)103 player.onGround = false;104 for (let p of platforms) {105 if (106 player.x + player.r > p.x &&107 player.x - player.r < p.x + p.w &&108 player.y + player.r > p.y &&109 player.y + player.r < p.y + p.h &&110 player.vy >= 0111 ) {112 player.y = p.y - player.r;113 player.vy = 0;114 player.onGround = true;115 }116 }117 118 // Agujeros = muerte119 for (let h of holes) {120 if (121 player.x > h.x &&122 player.x < h.x + h.w &&123 player.y + player.r > h.y124 ) {125 killPlayer();126 }127 }128 129 // Caer fuera del mundo130 if (player.y > canvas.height + 100) {131 killPlayer();132 }133 134 // Suavizado deformación135 player.squashX += (1 - player.squashX) * 0.2;136 player.squashY += (1 - player.squashY) * 0.2;137 }138 139 function killPlayer() {140 if (dead) return;141 dead = true;142 lives--;143 setTimeout(() => {144 dead = false;145 if (lives <= 0) {146 lives = 3;147 }148 player.reset();149 }, 700);150 }151 152 function drawPlayer() {153 ctx.save();154 ctx.translate(player.x, player.y);155 ctx.scale(player.squashX, player.squashY);156 ctx.beginPath();157 ctx.arc(0, 0, player.r, 0, Math.PI * 2);158 ctx.fillStyle = "#ff4d4d";159 ctx.fill();160 ctx.restore();161 }162 163 function draw() {164 ctx.clearRect(0, 0, canvas.width, canvas.height);165 166 // Plataformas167 ctx.fillStyle = "#444";168 for (let p of platforms) {169 ctx.fillRect(p.x, p.y, p.w, p.h);170 }171 172 // Agujeros173 ctx.fillStyle = "#000";174 for (let h of holes) {175 ctx.fillRect(h.x, h.y, h.w, h.h);176 }177 178 drawPlayer();179 180 // HUD181 ctx.fillStyle = "#000";182 ctx.font = "18px sans-serif";183 ctx.fillText(`Vidas: ${lives}`, 20, 30);184 }185 186 function loop() {187 updatePlatforms();188 updatePlayer();189 draw();190 requestAnimationFrame(loop);191 }192 193 loop();194 </script>195 </body>196 </html>197 Enlace
El enlace para compartir es:

