No al cierre de webs
ShareCode
Permalink: http://www.treeweb.es/u/974/ 01/02/2011

ShareCode

1 <!doctype html>2 <html lang="es" class="h-full">3  <head>4  <meta charset="UTF-8">5  <meta name="viewport" content="width=device-width, initial-scale=1.0">6  <title>Bouncy Ball Platformer</title>7  <script src="https://cdn.tailwindcss.com"></script>8  <script src="/_sdk/element_sdk.js"></script>9  <style>10  body {11  box-sizing: border-box;12  }13  14  @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600;700&display=swap');15  16  * {17  font-family: 'Fredoka', sans-serif;18  }19  20  .game-canvas {21  image-rendering: pixelated;22  }23  24  @keyframes float {25  0%, 100% { transform: translateY(0); }26  50% { transform: translateY(-10px); }27  }28  29  .floating {30  animation: float 2s ease-in-out infinite;31  }32  33  @keyframes pulse {34  0%, 100% { transform: scale(1); }35  50% { transform: scale(1.1); }36  }37  38  .pulse {39  animation: pulse 1s ease-in-out infinite;40  }41  42  @keyframes shake {43  0%, 100% { transform: translateX(0); }44  25% { transform: translateX(-5px); }45  75% { transform: translateX(5px); }46  }47  48  .shake {49  animation: shake 0.3s ease-in-out;50  }51  </style>52  <style>@view-transition { navigation: auto; }</style>53  <script src="/_sdk/data_sdk.js" type="text/javascript"></script>54  </head>55  <body class="h-full overflow-hidden bg-gradient-to-b from-indigo-900 via-purple-900 to-slate-900">56  <div id="app" class="h-full w-full flex flex-col"><!-- Header -->57  <div class="flex justify-between items-center p-4 bg-black/30 backdrop-blur-sm">58  <h1 id="game-title" class="text-2xl font-bold text-white drop-shadow-lg">🎮 Bouncy Ball Platformer</h1>59  <div class="flex items-center gap-6">60  <div class="flex items-center gap-2"><span class="text-yellow-400 text-xl">⭐</span> <span id="score-display" class="text-white font-bold text-xl">0</span>61  </div>62  <div id="lives-display" class="flex gap-1"><span class="text-2xl">❤️</span> <span class="text-2xl">❤️</span> <span class="text-2xl">❤️</span>63  </div>64  </div>65  </div><!-- Game Container -->66  <div id="game-container" class="flex-1 relative overflow-hidden">67  <canvas id="game-canvas" class="game-canvas w-full h-full"></canvas><!-- Start Screen -->68  <div id="start-screen" class="absolute inset-0 flex flex-col items-center justify-center bg-black/60 backdrop-blur-sm">69  <div class="text-center">70  <div class="text-8xl mb-4 floating">71  🔴72  </div>73  <h2 class="text-4xl font-bold text-white mb-4 drop-shadow-lg">¡Bouncy Ball!</h2>74  <p class="text-xl text-purple-200 mb-8">Salta entre plataformas y recoge estrellas</p>75  <div class="bg-white/10 rounded-xl p-6 mb-8 text-left">76  <p class="text-white mb-2">🎮 <span class="text-purple-200">Controles:</span></p>77  <p class="text-purple-300 text-sm mb-1">← → o A/D: Mover</p>78  <p class="text-purple-300 text-sm mb-1">↑ o W o Espacio: Saltar</p>79  <p class="text-purple-300 text-sm">⚠️ ¡Cuidado con los agujeros!</p>80  </div><button id="start-btn" class="px-8 py-4 bg-gradient-to-r from-pink-500 to-purple-600 text-white font-bold text-xl rounded-full hover:from-pink-600 hover:to-purple-700 transition-all transform hover:scale-105 shadow-lg"> ¡Jugar! </button>81  </div>82  </div><!-- Game Over Screen -->83  <div id="gameover-screen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black/70 backdrop-blur-sm">84  <div class="text-center">85  <div class="text-6xl mb-4">86  💀87  </div>88  <h2 class="text-4xl font-bold text-red-400 mb-4">¡Game Over!</h2>89  <p class="text-xl text-white mb-2">Puntuación final:</p>90  <p id="final-score" class="text-5xl font-bold text-yellow-400 mb-8">0</p><button id="restart-btn" class="px-8 py-4 bg-gradient-to-r from-green-500 to-emerald-600 text-white font-bold text-xl rounded-full hover:from-green-600 hover:to-emerald-700 transition-all transform hover:scale-105 shadow-lg"> Reintentar </button>91  </div>92  </div><!-- Win Screen -->93  <div id="win-screen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black/60 backdrop-blur-sm">94  <div class="text-center">95  <div class="text-6xl mb-4 pulse">96  🏆97  </div>98  <h2 class="text-4xl font-bold text-yellow-400 mb-4">¡Nivel Completado!</h2>99  <p class="text-xl text-white mb-2">Puntuación:</p>100  <p id="win-score" class="text-5xl font-bold text-yellow-400 mb-8">0</p><button id="next-btn" class="px-8 py-4 bg-gradient-to-r from-yellow-500 to-orange-600 text-white font-bold text-xl rounded-full hover:from-yellow-600 hover:to-orange-700 transition-all transform hover:scale-105 shadow-lg"> Siguiente Nivel </button>101  </div>102  </div>103  </div><!-- Mobile Controls -->104  <div id="mobile-controls" class="md:hidden flex justify-between items-center p-4 bg-black/30">105  <div class="flex gap-2"><button id="left-btn" class="w-16 h-16 bg-white/20 rounded-full text-3xl active:bg-white/40 transition-colors">←</button> <button id="right-btn" class="w-16 h-16 bg-white/20 rounded-full text-3xl active:bg-white/40 transition-colors">→</button>106  </div><button id="jump-btn" class="w-20 h-20 bg-gradient-to-r from-pink-500 to-purple-600 rounded-full text-3xl active:from-pink-600 active:to-purple-700 transition-colors shadow-lg">↑</button>107  </div>108  </div>109  <script>110  const defaultConfig = {111  game_title: "🎮 Bouncy Ball Platformer"112  };113 114  let config = { ...defaultConfig };115 116  // Game State117  const game = {118  canvas: null,119  ctx: null,120  width: 0,121  height: 0,122  running: false,123  score: 0,124  lives: 3,125  level: 1,126  cameraX: 0,127  levelWidth: 3000128  };129 130  // Player (Elastic Ball)131  const player = {132  x: 100,133  y: 0,134  width: 40,135  height: 40,136  baseWidth: 40,137  baseHeight: 40,138  vx: 0,139  vy: 0,140  speed: 5,141  jumpForce: -15,142  gravity: 0.6,143  grounded: false,144  scaleX: 1,145  scaleY: 1,146  targetScaleX: 1,147  targetScaleY: 1,148  color: '#ff4757',149  eyeOffset: 0150  };151 152  // Input153  const keys = {154  left: false,155  right: false,156  jump: false157  };158 159  // Level elements160  let platforms = [];161  let movingPlatforms = [];162  let stars = [];163  let particles = [];164  let goal = null;165 166  // Initialize game167  function init() {168  game.canvas = document.getElementById('game-canvas');169  game.ctx = game.canvas.getContext('2d');170  resizeCanvas();171  window.addEventListener('resize', resizeCanvas);172  setupControls();173  generateLevel();174  }175 176  function resizeCanvas() {177  const container = document.getElementById('game-container');178  game.canvas.width = container.clientWidth;179  game.canvas.height = container.clientHeight;180  game.width = game.canvas.width;181  game.height = game.canvas.height;182  }183 184  function setupControls() {185  // Keyboard186  document.addEventListener('keydown', (e) => {187  if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') keys.left = true;188  if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') keys.right = true;189  if ((e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W' || e.key === ' ') && player.grounded) {190  keys.jump = true;191  }192  });193 194  document.addEventListener('keyup', (e) => {195  if (e.key === 'ArrowLeft' || e.key === 'a' || e.key === 'A') keys.left = false;196  if (e.key === 'ArrowRight' || e.key === 'd' || e.key === 'D') keys.right = false;197  if (e.key === 'ArrowUp' || e.key === 'w' || e.key === 'W' || e.key === ' ') keys.jump = false;198  });199 200  // Mobile201  const leftBtn = document.getElementById('left-btn');202  const rightBtn = document.getElementById('right-btn');203  const jumpBtn = document.getElementById('jump-btn');204 205  leftBtn.addEventListener('touchstart', (e) => { e.preventDefault(); keys.left = true; });206  leftBtn.addEventListener('touchend', () => keys.left = false);207  rightBtn.addEventListener('touchstart', (e) => { e.preventDefault(); keys.right = true; });208  rightBtn.addEventListener('touchend', () => keys.right = false);209  jumpBtn.addEventListener('touchstart', (e) => { e.preventDefault(); if (player.grounded) keys.jump = true; });210  jumpBtn.addEventListener('touchend', () => keys.jump = false);211 212  // Buttons213  document.getElementById('start-btn').addEventListener('click', startGame);214  document.getElementById('restart-btn').addEventListener('click', restartGame);215  document.getElementById('next-btn').addEventListener('click', nextLevel);216  }217 218  function generateLevel() {219  platforms = [];220  movingPlatforms = [];221  stars = [];222  223  const groundY = game.height - 60;224  game.levelWidth = 2500 + game.level * 500;225  226  // Generate ground with gaps227  let x = 0;228  while (x < game.levelWidth) {229  const isGap = x > 400 && Math.random() < 0.15 + game.level * 0.02;230  231  if (isGap) {232  const gapWidth = 100 + Math.random() * 80;233  x += gapWidth;234  } else {235  const platformWidth = 150 + Math.random() * 200;236  platforms.push({237  x: x,238  y: groundY,239  width: platformWidth,240  height: 40,241  type: 'ground',242  color: '#4a5568'243  });244  x += platformWidth;245  }246  }247  248  // Floating platforms249  const numPlatforms = 15 + game.level * 5;250  for (let i = 0; i < numPlatforms; i++) {251  const px = 300 + Math.random() * (game.levelWidth - 500);252  const py = groundY - 100 - Math.random() * 250;253  254  // Some platforms are moving255  if (Math.random() < 0.2 + game.level * 0.05) {256  movingPlatforms.push({257  x: px,258  y: py,259  width: 100 + Math.random() * 60,260  height: 25,261  startX: px,262  startY: py,263  moveX: Math.random() > 0.5 ? 100 + Math.random() * 100 : 0,264  moveY: Math.random() > 0.5 ? 50 + Math.random() * 50 : 0,265  speed: 0.5 + Math.random() * 1,266  phase: Math.random() * Math.PI * 2,267  color: '#f59e0b'268  });269  } else {270  platforms.push({271  x: px,272  y: py,273  width: 80 + Math.random() * 80,274  height: 25,275  type: 'floating',276  color: '#6366f1'277  });278  }279  }280  281  // Stars282  const numStars = 20 + game.level * 5;283  for (let i = 0; i < numStars; i++) {284  stars.push({285  x: 200 + Math.random() * (game.levelWidth - 400),286  y: 100 + Math.random() * (groundY - 200),287  collected: false,288  angle: 0289  });290  }291  292  // Goal293  goal = {294  x: game.levelWidth - 150,295  y: groundY - 100,296  width: 60,297  height: 80298  };299  300  // End platform for goal301  platforms.push({302  x: game.levelWidth - 200,303  y: groundY,304  width: 200,305  height: 40,306  type: 'ground',307  color: '#10b981'308  });309  }310 311  function startGame() {312  document.getElementById('start-screen').classList.add('hidden');313  game.running = true;314  game.score = 0;315  game.lives = 3;316  game.level = 1;317  resetPlayer();318  generateLevel();319  updateUI();320  requestAnimationFrame(gameLoop);321  }322 323  function restartGame() {324  document.getElementById('gameover-screen').classList.add('hidden');325  document.getElementById('gameover-screen').style.display = 'none';326  game.running = true;327  game.score = 0;328  game.lives = 3;329  game.level = 1;330  resetPlayer();331  generateLevel();332  updateUI();333  requestAnimationFrame(gameLoop);334  }335 336  function nextLevel() {337  document.getElementById('win-screen').classList.add('hidden');338  document.getElementById('win-screen').style.display = 'none';339  game.level++;340  game.running = true;341  resetPlayer();342  generateLevel();343  requestAnimationFrame(gameLoop);344  }345 346  function resetPlayer() {347  player.x = 100;348  player.y = game.height - 200;349  player.vx = 0;350  player.vy = 0;351  player.grounded = false;352  player.scaleX = 1;353  player.scaleY = 1;354  game.cameraX = 0;355  }356 357  function updateUI() {358  document.getElementById('score-display').textContent = game.score;359  360  const livesDisplay = document.getElementById('lives-display');361  livesDisplay.innerHTML = '';362  for (let i = 0; i < 3; i++) {363  const heart = document.createElement('span');364  heart.className = 'text-2xl';365  heart.textContent = i < game.lives ? '❤️' : '🖤';366  livesDisplay.appendChild(heart);367  }368  }369 370  function loseLife() {371  game.lives--;372  updateUI();373  374  if (game.lives <= 0) {375  gameOver();376  } else {377  // Respawn with brief invincibility visual378  resetPlayer();379  createParticles(player.x, player.y, '#ff4757', 10);380  }381  }382 383  function gameOver() {384  game.running = false;385  document.getElementById('final-score').textContent = game.score;386  document.getElementById('gameover-screen').style.display = 'flex';387  document.getElementById('gameover-screen').classList.remove('hidden');388  }389 390  function winLevel() {391  game.running = false;392  document.getElementById('win-score').textContent = game.score;393  document.getElementById('win-screen').style.display = 'flex';394  document.getElementById('win-screen').classList.remove('hidden');395  }396 397  function createParticles(x, y, color, count) {398  for (let i = 0; i < count; i++) {399  particles.push({400  x: x,401  y: y,402  vx: (Math.random() - 0.5) * 8,403  vy: (Math.random() - 0.5) * 8 - 3,404  life: 1,405  color: color,406  size: 3 + Math.random() * 5407  });408  }409  }410 411  function update() {412  // Input413  if (keys.left) {414  player.vx = -player.speed;415  player.eyeOffset = -3;416  } else if (keys.right) {417  player.vx = player.speed;418  player.eyeOffset = 3;419  } else {420  player.vx *= 0.8;421  player.eyeOffset *= 0.9;422  }423 424  if (keys.jump && player.grounded) {425  player.vy = player.jumpForce;426  player.grounded = false;427  keys.jump = false;428  createParticles(player.x + player.width/2, player.y + player.height, '#ffffff', 5);429  }430 431  // Gravity432  player.vy += player.gravity;433  434  // Elastic deformation based on velocity435  if (player.vy < -5) {436  // Jumping up - stretch vertically437  player.targetScaleX = 0.85;438  player.targetScaleY = 1.2;439  } else if (player.vy > 5) {440  // Falling - stretch vertically slightly441  player.targetScaleX = 0.9;442  player.targetScaleY = 1.15;443  } else if (Math.abs(player.vx) > 3) {444  // Moving horizontally - squish slightly445  player.targetScaleX = 1.1;446  player.targetScaleY = 0.9;447  } else {448  // Idle - return to normal449  player.targetScaleX = 1;450  player.targetScaleY = 1;451  }452  453  // Smooth scale transition454  player.scaleX += (player.targetScaleX - player.scaleX) * 0.2;455  player.scaleY += (player.targetScaleY - player.scaleY) * 0.2;456 457  // Update moving platforms458  movingPlatforms.forEach(p => {459  p.phase += p.speed * 0.02;460  if (p.moveX > 0) {461  p.x = p.startX + Math.sin(p.phase) * p.moveX;462  }463  if (p.moveY > 0) {464  p.y = p.startY + Math.sin(p.phase) * p.moveY;465  }466  });467 468  // Move player469  player.x += player.vx;470  player.y += player.vy;471 472  // Keep player in bounds (left side)473  if (player.x < 0) player.x = 0;474  if (player.x > game.levelWidth - player.width) player.x = game.levelWidth - player.width;475 476  // Platform collision477  player.grounded = false;478  const allPlatforms = [...platforms, ...movingPlatforms];479  480  for (const plat of allPlatforms) {481  if (rectCollision(482  player.x, player.y, player.width, player.height,483  plat.x, plat.y, plat.width, plat.height484  )) {485  // Landing on top486  if (player.vy > 0 && player.y + player.height - player.vy <= plat.y + 10) {487  player.y = plat.y - player.height;488  player.vy = 0;489  player.grounded = true;490  491  // Landing squish effect492  if (player.targetScaleY > 1) {493  player.scaleX = 1.3;494  player.scaleY = 0.7;495  createParticles(player.x + player.width/2, player.y + player.height, '#ffffff', 3);496  }497  }498  // Side collision499  else if (player.vx > 0 && player.x + player.width - player.vx <= plat.x) {500  player.x = plat.x - player.width;501  player.vx = 0;502  player.scaleX = 0.8;503  player.scaleY = 1.1;504  }505  else if (player.vx < 0 && player.x - player.vx >= plat.x + plat.width) {506  player.x = plat.x + plat.width;507  player.vx = 0;508  player.scaleX = 0.8;509  player.scaleY = 1.1;510  }511  // Bottom collision512  else if (player.vy < 0 && player.y - player.vy >= plat.y + plat.height) {513  player.y = plat.y + plat.height;514  player.vy = 0;515  }516  }517  }518 519  // Fall into pit520  if (player.y > game.height + 100) {521  loseLife();522  }523 524  // Collect stars525  stars.forEach(star => {526  if (!star.collected) {527  star.angle += 0.05;528  const dist = Math.hypot(529  (player.x + player.width/2) - star.x,530  (player.y + player.height/2) - star.y531  );532  if (dist < 35) {533  star.collected = true;534  game.score += 100;535  updateUI();536  createParticles(star.x, star.y, '#ffd700', 8);537  }538  }539  });540 541  // Check goal542  if (goal && rectCollision(543  player.x, player.y, player.width, player.height,544  goal.x, goal.y, goal.width, goal.height545  )) {546  winLevel();547  }548 549  // Update particles550  particles = particles.filter(p => {551  p.x += p.vx;552  p.y += p.vy;553  p.vy += 0.2;554  p.life -= 0.02;555  return p.life > 0;556  });557 558  // Camera follow559  const targetCameraX = player.x - game.width / 3;560  game.cameraX += (targetCameraX - game.cameraX) * 0.1;561  game.cameraX = Math.max(0, Math.min(game.cameraX, game.levelWidth - game.width));562  }563 564  function rectCollision(x1, y1, w1, h1, x2, y2, w2, h2) {565  return x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2;566  }567 568  function draw() {569  const ctx = game.ctx;570  ctx.clearRect(0, 0, game.width, game.height);571 572  ctx.save();573  ctx.translate(-game.cameraX, 0);574 575  // Background elements (parallax)576  drawBackground();577 578  // Draw platforms579  platforms.forEach(plat => {580  // Platform shadow581  ctx.fillStyle = 'rgba(0,0,0,0.3)';582  roundRect(ctx, plat.x + 5, plat.y + 5, plat.width, plat.height, 8);583  ctx.fill();584  585  // Platform body586  const gradient = ctx.createLinearGradient(plat.x, plat.y, plat.x, plat.y + plat.height);587  if (plat.type === 'ground') {588  gradient.addColorStop(0, '#64748b');589  gradient.addColorStop(1, '#334155');590  } else {591  gradient.addColorStop(0, '#818cf8');592  gradient.addColorStop(1, '#4f46e5');593  }594  ctx.fillStyle = gradient;595  roundRect(ctx, plat.x, plat.y, plat.width, plat.height, 8);596  ctx.fill();597  598  // Platform highlight599  ctx.fillStyle = 'rgba(255,255,255,0.2)';600  roundRect(ctx, plat.x + 4, plat.y + 4, plat.width - 8, plat.height / 3, 4);601  ctx.fill();602  });603 604  // Draw moving platforms605  movingPlatforms.forEach(plat => {606  ctx.fillStyle = 'rgba(0,0,0,0.3)';607  roundRect(ctx, plat.x + 5, plat.y + 5, plat.width, plat.height, 8);608  ctx.fill();609  610  const gradient = ctx.createLinearGradient(plat.x, plat.y, plat.x, plat.y + plat.height);611  gradient.addColorStop(0, '#fbbf24');612  gradient.addColorStop(1, '#d97706');613  ctx.fillStyle = gradient;614  roundRect(ctx, plat.x, plat.y, plat.width, plat.height, 8);615  ctx.fill();616  617  // Arrow indicators618  ctx.fillStyle = 'rgba(255,255,255,0.5)';619  ctx.font = '16px Arial';620  ctx.textAlign = 'center';621  if (plat.moveX > 0) ctx.fillText('↔', plat.x + plat.width/2, plat.y + plat.height/2 + 5);622  if (plat.moveY > 0) ctx.fillText('↕', plat.x + plat.width/2, plat.y + plat.height/2 + 5);623  });624 625  // Draw stars626  stars.forEach(star => {627  if (!star.collected) {628  ctx.save();629  ctx.translate(star.x, star.y);630  ctx.rotate(star.angle);631  632  // Glow633  ctx.shadowColor = '#ffd700';634  ctx.shadowBlur = 15;635  636  ctx.font = '28px Arial';637  ctx.textAlign = 'center';638  ctx.textBaseline = 'middle';639  ctx.fillText('⭐', 0, 0);640  ctx.restore();641  }642  });643 644  // Draw goal645  if (goal) {646  ctx.save();647  ctx.translate(goal.x + goal.width/2, goal.y + goal.height/2);648  649  // Glow effect650  ctx.shadowColor = '#10b981';651  ctx.shadowBlur = 20;652  653  ctx.font = '50px Arial';654  ctx.textAlign = 'center';655  ctx.textBaseline = 'middle';656  ctx.fillText('🚩', 0, 0);657  ctx.restore();658  }659 660  // Draw player (elastic ball)661  drawPlayer();662 663  // Draw particles664  particles.forEach(p => {665  ctx.globalAlpha = p.life;666  ctx.fillStyle = p.color;667  ctx.beginPath();668  ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);669  ctx.fill();670  });671  ctx.globalAlpha = 1;672 673  ctx.restore();674 675  // UI overlay676  drawUI();677  }678 679  function drawBackground() {680  const ctx = game.ctx;681  682  // Distant mountains (parallax)683  for (let i = 0; i < game.levelWidth / 200; i++) {684  const x = i * 200 + game.cameraX * 0.3;685  ctx.fillStyle = 'rgba(99, 102, 241, 0.2)';686  ctx.beginPath();687  ctx.moveTo(x, game.height);688  ctx.lineTo(x + 100, game.height - 150 - Math.sin(i) * 50);689  ctx.lineTo(x + 200, game.height);690  ctx.closePath();691  ctx.fill();692  }693  694  // Stars in sky695  ctx.fillStyle = 'rgba(255,255,255,0.3)';696  for (let i = 0; i < 50; i++) {697  const x = (i * 137) % game.levelWidth;698  const y = (i * 89) % (game.height * 0.5);699  ctx.beginPath();700  ctx.arc(x, y, 1 + (i % 2), 0, Math.PI * 2);701  ctx.fill();702  }703  }704 705  function drawPlayer() {706  const ctx = game.ctx;707  const centerX = player.x + player.width / 2;708  const centerY = player.y + player.height / 2;709  710  ctx.save();711  ctx.translate(centerX, centerY);712  ctx.scale(player.scaleX, player.scaleY);713  714  // Shadow715  ctx.fillStyle = 'rgba(0,0,0,0.3)';716  ctx.beginPath();717  ctx.ellipse(3, player.baseHeight/2 - 5, player.baseWidth/2, 8, 0, 0, Math.PI * 2);718  ctx.fill();719  720  // Main body gradient721  const gradient = ctx.createRadialGradient(-5, -5, 0, 0, 0, player.baseWidth/2);722  gradient.addColorStop(0, '#ff6b7a');723  gradient.addColorStop(0.7, '#ff4757');724  gradient.addColorStop(1, '#c0392b');725  726  ctx.fillStyle = gradient;727  ctx.beginPath();728  ctx.ellipse(0, 0, player.baseWidth/2, player.baseHeight/2, 0, 0, Math.PI * 2);729  ctx.fill();730  731  // Highlight732  ctx.fillStyle = 'rgba(255,255,255,0.4)';733  ctx.beginPath();734  ctx.ellipse(-8, -8, 8, 6, -0.5, 0, Math.PI * 2);735  ctx.fill();736  737  // Eyes738  const eyeY = -3;739  const eyeSpacing = 8;740  741  // Eye whites742  ctx.fillStyle = 'white';743  ctx.beginPath();744  ctx.ellipse(-eyeSpacing + player.eyeOffset, eyeY, 7, 8, 0, 0, Math.PI * 2);745  ctx.fill();746  ctx.beginPath();747  ctx.ellipse(eyeSpacing + player.eyeOffset, eyeY, 7, 8, 0, 0, Math.PI * 2);748  ctx.fill();749  750  // Pupils751  ctx.fillStyle = '#1a1a2e';752  const pupilOffset = player.vx * 0.3;753  ctx.beginPath();754  ctx.arc(-eyeSpacing + player.eyeOffset + pupilOffset, eyeY + 1, 4, 0, Math.PI * 2);755  ctx.fill();756  ctx.beginPath();757  ctx.arc(eyeSpacing + player.eyeOffset + pupilOffset, eyeY + 1, 4, 0, Math.PI * 2);758  ctx.fill();759  760  // Pupil highlights761  ctx.fillStyle = 'white';762  ctx.beginPath();763  ctx.arc(-eyeSpacing + player.eyeOffset + pupilOffset - 1, eyeY - 1, 1.5, 0, Math.PI * 2);764  ctx.fill();765  ctx.beginPath();766  ctx.arc(eyeSpacing + player.eyeOffset + pupilOffset - 1, eyeY - 1, 1.5, 0, Math.PI * 2);767  ctx.fill();768  769  // Smile770  ctx.strokeStyle = '#8b0000';771  ctx.lineWidth = 2;772  ctx.lineCap = 'round';773  ctx.beginPath();774  ctx.arc(0, 5, 8, 0.2, Math.PI - 0.2);775  ctx.stroke();776  777  ctx.restore();778  }779 780  function drawUI() {781  const ctx = game.ctx;782  783  // Level indicator784  ctx.fillStyle = 'rgba(255,255,255,0.8)';785  ctx.font = 'bold 16px Fredoka';786  ctx.textAlign = 'right';787  ctx.fillText(`Nivel ${game.level}`, game.width - 20, 30);788  789  // Progress bar790  const progress = Math.min(1, (player.x) / (game.levelWidth - 200));791  ctx.fillStyle = 'rgba(0,0,0,0.3)';792  roundRect(ctx, game.width/2 - 100, 10, 200, 10, 5);793  ctx.fill();794  795  ctx.fillStyle = '#10b981';796  roundRect(ctx, game.width/2 - 100, 10, 200 * progress, 10, 5);797  ctx.fill();798  799  // Player indicator on progress bar800  ctx.fillStyle = '#ff4757';801  ctx.beginPath();802  ctx.arc(game.width/2 - 100 + 200 * progress, 15, 6, 0, Math.PI * 2);803  ctx.fill();804  }805 806  function roundRect(ctx, x, y, width, height, radius) {807  ctx.beginPath();808  ctx.moveTo(x + radius, y);809  ctx.lineTo(x + width - radius, y);810  ctx.quadraticCurveTo(x + width, y, x + width, y + radius);811  ctx.lineTo(x + width, y + height - radius);812  ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);813  ctx.lineTo(x + radius, y + height);814  ctx.quadraticCurveTo(x, y + height, x, y + height - radius);815  ctx.lineTo(x, y + radius);816  ctx.quadraticCurveTo(x, y, x + radius, y);817  ctx.closePath();818  }819 820  function gameLoop() {821  if (!game.running) return;822  823  update();824  draw();825  requestAnimationFrame(gameLoop);826  }827 828  // Element SDK Integration829  async function onConfigChange(newConfig) {830  config = { ...defaultConfig, ...newConfig };831  document.getElementById('game-title').textContent = config.game_title || defaultConfig.game_title;832  }833 834  function mapToCapabilities(config) {835  return {836  recolorables: [],837  borderables: [],838  fontEditable: undefined,839  fontSizeable: undefined840  };841  }842 843  function mapToEditPanelValues(config) {844  return new Map([845  ["game_title", config.game_title || defaultConfig.game_title]846  ]);847  }848 849  // Initialize850  window.elementSdk.init({851  defaultConfig,852  onConfigChange,853  mapToCapabilities,854  mapToEditPanelValues855  });856 857  init();858  </script>859  <script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9c687284f3bda431',t:'MTc2OTg1NDUyMS4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>860 </html>
Enlace
El enlace para compartir es: