|
|
@@ -124,14 +124,20 @@ class Game {
|
|
|
});
|
|
|
|
|
|
// Handle audio context (for browsers that require user interaction)
|
|
|
- this.canvas.addEventListener('click', () => {
|
|
|
+ const startMusic = () => {
|
|
|
if (this.backgroundMusic.paused && this.gameState === 'playing') {
|
|
|
this.backgroundMusic.play().catch(e => console.log('Audio play failed:', e));
|
|
|
}
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ this.canvas.addEventListener('click', startMusic);
|
|
|
+ this.canvas.addEventListener('touchstart', startMusic, { passive: true });
|
|
|
|
|
|
// Agregar controles de teclado
|
|
|
this.setupKeyboardControls();
|
|
|
+
|
|
|
+ // Inicializar controles táctiles para dispositivos móviles
|
|
|
+ this.touchControls = new TouchControls(this.canvas, input);
|
|
|
}
|
|
|
|
|
|
// Método para agregar elementos de forma dinámica
|
|
|
@@ -195,13 +201,13 @@ class Game {
|
|
|
}
|
|
|
|
|
|
startGame() {
|
|
|
- // Create player
|
|
|
- this.player = new Player(144, 176, this.processedSpriteSheet);
|
|
|
+ // Create player (scaled for 800x600 canvas)
|
|
|
+ this.player = new Player(360, 500, this.processedSpriteSheet);
|
|
|
|
|
|
// Crear elementos de fondo usando los nuevos métodos
|
|
|
- // Piso
|
|
|
- for (let i = 0; i < 10; i++) {
|
|
|
- this.addFloorTile(i * 32, 208);
|
|
|
+ // Piso (scaled and extended for wider canvas) - moved down to fill bottom space
|
|
|
+ for (let i = 0; i < 26; i++) {
|
|
|
+ this.addFloorTile(i * 32, 568); // Moved from 520 to 568 (600-32=568)
|
|
|
}
|
|
|
|
|
|
// Inicializar sistema de nubes
|
|
|
@@ -210,21 +216,21 @@ class Game {
|
|
|
// Inicializar sistema de objetos de fondo
|
|
|
this.backgroundObjectSystem.init(this.processedSpriteSheet, this.backgroundLayers.mid);
|
|
|
|
|
|
- // Macarons
|
|
|
- this.addSprite(10, 183, 35, 26, { x: 137, y: 104, w: 35, h: 26 });
|
|
|
- this.addSprite(42, 183, 35, 26, { x: 173, y: 104, w: 35, h: 26 });
|
|
|
- this.addSprite(74, 183, 35, 26, { x: 137, y: 131, w: 35, h: 26 });
|
|
|
- this.addSprite(106, 183, 35, 26, { x: 173, y: 131, w: 35, h: 26 });
|
|
|
+ // Macarons (scaled positions) - adjusted Y position
|
|
|
+ this.addSprite(25, 518, 70, 52, { x: 137, y: 104, w: 35, h: 26 });
|
|
|
+ this.addSprite(105, 518, 70, 52, { x: 173, y: 104, w: 35, h: 26 });
|
|
|
+ this.addSprite(185, 518, 70, 52, { x: 137, y: 131, w: 35, h: 26 });
|
|
|
+ this.addSprite(265, 518, 70, 52, { x: 173, y: 131, w: 35, h: 26 });
|
|
|
|
|
|
- // Candybar
|
|
|
- this.addSprite(200, 130, 48, 79, { x: 179, y: 438, w: 48, h: 79 });
|
|
|
+ // Candybar (scaled) - adjusted to ground level
|
|
|
+ this.addSprite(500, 410, 96, 158, { x: 179, y: 438, w: 48, h: 79 });
|
|
|
|
|
|
- // Cake
|
|
|
- this.addSprite(260, 134, 100, 75, { x: 461, y: 414, w: 100, h: 75 });
|
|
|
+ // Cake (scaled) - adjusted to ground level
|
|
|
+ this.addSprite(650, 418, 200, 150, { x: 461, y: 414, w: 100, h: 75 });
|
|
|
|
|
|
- // Cat
|
|
|
- this.addSprite(185, 187, 20, 23, { x: 235, y: 87, w: 20, h: 23 });
|
|
|
- this.addSprite(200, 187, 20, 23, { x: 389, y: 87, w: 16, h: 23 });
|
|
|
+ // Cat (scaled) - adjusted Y position
|
|
|
+ this.addSprite(463, 528, 40, 46, { x: 235, y: 87, w: 20, h: 23 });
|
|
|
+ this.addSprite(500, 528, 40, 46, { x: 389, y: 87, w: 16, h: 23 });
|
|
|
|
|
|
this.gameLoop();
|
|
|
}
|
|
|
@@ -363,12 +369,12 @@ class Game {
|
|
|
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
|
|
|
|
|
this.ctx.fillStyle = 'white';
|
|
|
- this.ctx.font = '8px Courier New';
|
|
|
+ this.ctx.font = '20px Courier New';
|
|
|
this.ctx.textAlign = 'center';
|
|
|
- this.ctx.fillText('Click para iniciar música', 160, 120);
|
|
|
- this.ctx.fillText('AD o ← → para moverte', 160, 130);
|
|
|
- this.ctx.fillText('L - Mostrar/Ocultar letras', 160, 140);
|
|
|
- this.ctx.fillText('R - Reiniciar juego', 160, 150);
|
|
|
+ this.ctx.fillText('Click to start music', 400, 300);
|
|
|
+ this.ctx.fillText('AD or ← → to move', 400, 325);
|
|
|
+ this.ctx.fillText('L - Show/Hide lyrics', 400, 350);
|
|
|
+ this.ctx.fillText('R - Restart game', 400, 375);
|
|
|
// this.ctx.fillText('Ctrl+G - Simular fin de canción', 160, 160);
|
|
|
}
|
|
|
|
|
|
@@ -410,16 +416,16 @@ class Game {
|
|
|
|
|
|
// Texto de fin de juego
|
|
|
this.ctx.fillStyle = 'white';
|
|
|
- this.ctx.font = '16px Courier New';
|
|
|
+ this.ctx.font = '40px Courier New';
|
|
|
this.ctx.textAlign = 'center';
|
|
|
|
|
|
- this.ctx.fillText('¡Canción terminada!', 160, 100);
|
|
|
- this.ctx.fillText('¿Quieres jugar otra vez?', 160, 120);
|
|
|
+ this.ctx.fillText('Song finished!', 400, 250);
|
|
|
+ this.ctx.fillText('Want to play again?', 400, 300);
|
|
|
|
|
|
// Botones
|
|
|
- this.ctx.font = '12px Courier New';
|
|
|
- this.ctx.fillText('Presiona R para reiniciar', 160, 150);
|
|
|
- this.ctx.fillText('o recarga la página', 160, 165);
|
|
|
+ this.ctx.font = '24px Courier New';
|
|
|
+ this.ctx.fillText('Press R to restart', 400, 375);
|
|
|
+ this.ctx.fillText('or reload the page', 400, 412);
|
|
|
}
|
|
|
|
|
|
restartGame() {
|
|
|
@@ -451,26 +457,26 @@ class Game {
|
|
|
}
|
|
|
|
|
|
recreateBackgroundElements() {
|
|
|
- // Piso
|
|
|
- for (let i = 0; i < 10; i++) {
|
|
|
- this.addFloorTile(i * 32, 208);
|
|
|
+ // Piso (scaled and extended for wider canvas) - moved down to fill bottom space
|
|
|
+ for (let i = 0; i < 26; i++) {
|
|
|
+ this.addFloorTile(i * 32, 568); // Moved from 520 to 568 (600-32=568)
|
|
|
}
|
|
|
|
|
|
- // Macarons
|
|
|
- this.addSprite(10, 183, 35, 26, { x: 137, y: 104, w: 35, h: 26 });
|
|
|
- this.addSprite(42, 183, 35, 26, { x: 173, y: 104, w: 35, h: 26 });
|
|
|
- this.addSprite(74, 183, 35, 26, { x: 137, y: 131, w: 35, h: 26 });
|
|
|
- this.addSprite(106, 183, 35, 26, { x: 173, y: 131, w: 35, h: 26 });
|
|
|
+ // Macarons (scaled positions) - adjusted Y position
|
|
|
+ this.addSprite(25, 518, 70, 52, { x: 137, y: 104, w: 35, h: 26 });
|
|
|
+ this.addSprite(105, 518, 70, 52, { x: 173, y: 104, w: 35, h: 26 });
|
|
|
+ this.addSprite(185, 518, 70, 52, { x: 137, y: 131, w: 35, h: 26 });
|
|
|
+ this.addSprite(265, 518, 70, 52, { x: 173, y: 131, w: 35, h: 26 });
|
|
|
|
|
|
- // Candybar
|
|
|
- this.addSprite(200, 130, 48, 79, { x: 179, y: 438, w: 48, h: 79 });
|
|
|
+ // Candybar (scaled) - adjusted to ground level
|
|
|
+ this.addSprite(500, 410, 96, 158, { x: 179, y: 438, w: 48, h: 79 });
|
|
|
|
|
|
- // Cake
|
|
|
- this.addSprite(260, 134, 100, 75, { x: 461, y: 414, w: 100, h: 75 });
|
|
|
+ // Cake (scaled) - adjusted to ground level
|
|
|
+ this.addSprite(650, 418, 200, 150, { x: 461, y: 414, w: 100, h: 75 });
|
|
|
|
|
|
- // Cat
|
|
|
- this.addSprite(185, 187, 20, 23, { x: 235, y: 87, w: 20, h: 23 });
|
|
|
- this.addSprite(200, 187, 20, 23, { x: 389, y: 87, w: 16, h: 23 });
|
|
|
+ // Cat (scaled) - adjusted Y position
|
|
|
+ this.addSprite(463, 528, 40, 46, { x: 235, y: 87, w: 20, h: 23 });
|
|
|
+ this.addSprite(500, 528, 40, 46, { x: 389, y: 87, w: 16, h: 23 });
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -482,15 +488,15 @@ class CloudSystem {
|
|
|
this.cloudLayer = null;
|
|
|
this.frameCount = 0;
|
|
|
|
|
|
- // Configuración simplificada
|
|
|
+ // Configuración simplificada (scaled for 800x600 canvas)
|
|
|
this.config = {
|
|
|
spawnRate: 0.1, // Probabilidad de spawn por frame (aumentada)
|
|
|
- maxClouds: 2, // Máximo número de nubes en pantalla (aumentado)
|
|
|
- speedRange: { min: 0.1, max: 0.15 }, // Velocidad de movimiento
|
|
|
- yRange: { min: 1, max: 120 }, // Rango de altura
|
|
|
+ maxClouds: 3, // Máximo número de nubes en pantalla (aumentado)
|
|
|
+ speedRange: { min: 0.25, max: 0.375 }, // Velocidad de movimiento (scaled)
|
|
|
+ yRange: { min: 2, max: 300 }, // Rango de altura (scaled)
|
|
|
spriteCoords: { x: 231, y: 112, w: 287, h: 148 },
|
|
|
- size: { w: 287, h: 148 },
|
|
|
- minSpacing: 100, // Espaciado mínimo entre nubes (reducido)
|
|
|
+ size: { w: 574, h: 296 }, // Scaled cloud size
|
|
|
+ minSpacing: 250, // Espaciado mínimo entre nubes (scaled)
|
|
|
minTimeBetweenSpawns: 60 // Frames mínimos entre apariciones (reducido)
|
|
|
};
|
|
|
|
|
|
@@ -647,16 +653,16 @@ class BackgroundObjectSystem {
|
|
|
this.objectLayer = null;
|
|
|
this.frameCount = 0;
|
|
|
|
|
|
- // Configuración para objetos de fondo
|
|
|
+ // Configuración para objetos de fondo (scaled for 800x600 canvas)
|
|
|
this.config = {
|
|
|
- spawnRate: 0.3, // Probabilidad de spawn por frame (aumentada)
|
|
|
- maxObjects: 300, // Máximo número de objetos en pantalla (aumentado)
|
|
|
- speedRange: { min: 0.05, max: 0.1 }, // Velocidad de movimiento
|
|
|
- yRange: { min: 10, max: 180 }, // Rango de altura (expandido)
|
|
|
- minSpacing: 80, // Espaciado mínimo entre grupos (reducido)
|
|
|
- minTimeBetweenSpawns: 60, // Frames mínimos entre apariciones (reducido)
|
|
|
- groupSize: { min: 15, max: 25 }, // Tamaño del grupo de objetos (reducido)
|
|
|
- groupSpacing: { min: 5, max: 40 } // Espaciado entre objetos en el grupo (ajustado)
|
|
|
+ spawnRate: 0.15, // Probabilidad de spawn por frame (reducida para mejor control)
|
|
|
+ maxObjects: 300, // Máximo número de objetos en pantalla
|
|
|
+ speedRange: { min: 0.125, max: 0.25 }, // Velocidad de movimiento (scaled)
|
|
|
+ yRange: { min: 25, max: 450 }, // Rango de altura (scaled)
|
|
|
+ minSpacing: 300, // Espaciado mínimo entre grupos (aumentado)
|
|
|
+ minTimeBetweenSpawns: 120, // Frames mínimos entre apariciones (aumentado)
|
|
|
+ groupSize: { min: 8, max: 15 }, // Tamaño del grupo de objetos (reducido)
|
|
|
+ groupSpacing: { min: 15, max: 80 } // Espaciado entre objetos en el grupo
|
|
|
};
|
|
|
|
|
|
this.lastSpawnTime = 0;
|
|
|
@@ -671,16 +677,25 @@ class BackgroundObjectSystem {
|
|
|
}
|
|
|
|
|
|
spawnInitialObjects() {
|
|
|
- // Generar 3-5 grupos iniciales para llenar la pantalla
|
|
|
- const initialGroups = Math.floor(Math.random() * 3) + 3;
|
|
|
-
|
|
|
- for (let i = 0; i < initialGroups; i++) {
|
|
|
- // Distribuir los grupos iniciales por toda la pantalla
|
|
|
- const x = (i * this.canvas.width / initialGroups) + (Math.random() * 100);
|
|
|
- const y = this.getRandomY();
|
|
|
- const speed = this.getRandomSpeed();
|
|
|
-
|
|
|
- this.createObjectGroup(x, y, speed);
|
|
|
+ // Generar objetos en múltiples filas para mejor distribución
|
|
|
+ const layers = 3; // Número de capas de profundidad
|
|
|
+ const groupsPerLayer = 4; // Grupos por capa
|
|
|
+
|
|
|
+ for (let layer = 0; layer < layers; layer++) {
|
|
|
+ for (let i = 0; i < groupsPerLayer; i++) {
|
|
|
+ // Distribuir horizontalmente
|
|
|
+ const x = (i * this.canvas.width / groupsPerLayer) + (Math.random() * 150);
|
|
|
+
|
|
|
+ // Crear diferentes niveles de altura
|
|
|
+ const baseY = 100 + (layer * 120); // Capas a diferentes alturas
|
|
|
+ const y = baseY + (Math.random() * 80 - 40); // Variación aleatoria
|
|
|
+
|
|
|
+ // Velocidad ligeramente diferente por capa para efecto parallax
|
|
|
+ const baseSpeed = this.getRandomSpeed();
|
|
|
+ const speed = baseSpeed * (1 + layer * 0.1);
|
|
|
+
|
|
|
+ this.createObjectGroup(x, y, speed);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -742,16 +757,26 @@ class BackgroundObjectSystem {
|
|
|
}
|
|
|
|
|
|
spawnObjectGroup() {
|
|
|
- const y = this.getRandomY();
|
|
|
- const speed = this.getRandomSpeed();
|
|
|
+ // Generar múltiples grupos a diferentes alturas simultáneamente
|
|
|
+ const numLayers = Math.floor(Math.random() * 2) + 2; // 2-3 capas
|
|
|
|
|
|
- // Generar desde la derecha de la pantalla
|
|
|
- const x = this.canvas.width;
|
|
|
+ for (let i = 0; i < numLayers; i++) {
|
|
|
+ // Diferentes alturas para cada capa
|
|
|
+ const baseY = 100 + (i * 150);
|
|
|
+ const y = baseY + (Math.random() * 100 - 50);
|
|
|
+
|
|
|
+ // Velocidad ligeramente diferente por capa
|
|
|
+ const baseSpeed = this.getRandomSpeed();
|
|
|
+ const speed = baseSpeed * (1 + i * 0.15);
|
|
|
+
|
|
|
+ // Generar desde la derecha de la pantalla con ligera variación
|
|
|
+ const x = this.canvas.width + (Math.random() * 100);
|
|
|
+
|
|
|
+ this.createObjectGroup(x, y, speed);
|
|
|
+ }
|
|
|
|
|
|
- this.createObjectGroup(x, y, speed);
|
|
|
this.lastSpawnTime = this.frameCount;
|
|
|
-
|
|
|
- console.log(`Nuevo grupo de objetos generado en (${x}, ${y}) con velocidad ${speed}`);
|
|
|
+ console.log(`Nuevos grupos de objetos generados en múltiples capas`);
|
|
|
}
|
|
|
|
|
|
createObjectGroup(x, y, speed) {
|
|
|
@@ -774,12 +799,14 @@ class BackgroundObjectSystem {
|
|
|
// Aplicar dispersión vertical aleatoria
|
|
|
const yOffset = (Math.random() - 0.5) * 40; // ±20 píxeles
|
|
|
|
|
|
+ // Scale the background objects (2x scale factor)
|
|
|
+ const scaleFactor = 2;
|
|
|
const object = {
|
|
|
type: 'backgroundObject',
|
|
|
x: currentX,
|
|
|
y: y + yOffset,
|
|
|
- w: spriteVariant.w,
|
|
|
- h: spriteVariant.h,
|
|
|
+ w: spriteVariant.w * scaleFactor,
|
|
|
+ h: spriteVariant.h * scaleFactor,
|
|
|
spriteCoords: spriteVariant,
|
|
|
moveSpeed: speed,
|
|
|
rotation: rotation,
|
|
|
@@ -788,11 +815,11 @@ class BackgroundObjectSystem {
|
|
|
|
|
|
this.objectLayer.push(object);
|
|
|
|
|
|
- // Calcular siguiente posición con espaciado aleatorio
|
|
|
+ // Calcular siguiente posición con espaciado aleatorio (adjusted for scaled objects)
|
|
|
const spacing = Math.random() *
|
|
|
(this.config.groupSpacing.max - this.config.groupSpacing.min) +
|
|
|
this.config.groupSpacing.min;
|
|
|
- currentX += spriteVariant.w + spacing;
|
|
|
+ currentX += (spriteVariant.w * scaleFactor) + spacing;
|
|
|
}
|
|
|
}
|
|
|
|