User prompt
cambia la opcion de attack speed por una que te de un escudo de un uso en contra de los enemigos
User prompt
crea una opcion diferente que sea igual pero te de un 10% despues de matar un enemigo
User prompt
crea una nueva mejora que te de un 10% de probabilidad de ganar 10 puntos de vida al matar un enemigo
User prompt
cra una mejora en el menu de mejora que te de un 20% de probabilidad de ganar 10 puntos de vida al matar un enemigo
User prompt
cra una mejora en el menu de mejora que te de un 10% de probabilidad de ganar 10 puntos de vida al matar un enemigo
User prompt
pon una mejora en el menu de mejoras que te de un 5% de probabilidad de ganar 10 puntos de vida al matar un enemigo
User prompt
no se escucha la musica
User prompt
ahora crea musica
User prompt
la parte arriba del proyectil siempre apunta hacia el enemigo a matar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ahora el proyectil apunta hacia el enemigo que va a atacar
User prompt
aumenta el tamano del proyectil
User prompt
aumenta el doble el tamano de los proyectiles
User prompt
quiero mantener la imagen de fondodelacueva de fondo del mapa pero cuando lo pongo queda la escala muy baja y cuando bajo la escala queda como una imagen aparte
User prompt
como puedo mantener la escala baja y que sea el fondo del mapa
User prompt
prueba esala 2
User prompt
no se ve el pixel art del fondo
User prompt
Please fix the bug: 'game.setBackgroundAsset is not a function' in or related to this line: 'game.setBackgroundAsset('fondodelacueva', {' Line Number: 1329
User prompt
has que fondodelacueva sea el fondo del juego
User prompt
acomoda el fondodelacueva
User prompt
aumentalo a 10
User prompt
aumenta la escala a 3
User prompt
`scaleX: 2.0, scaleY: 2.0`
User prompt
quita el escalado 2x
User prompt
aumenta el contraste del fondo
User prompt
voltea la animacion de los enemigos de la diagonal a la derecha para que miren al jugador
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.bobOffset = Math.random() * Math.PI * 2; self.initialY = 0; self.update = function () { if (self.initialY === 0) { self.initialY = self.y; } // Only do bobbing animation and collection if not animating to coin counter if (!self.isAnimating) { // Bobbing animation self.y = self.initialY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10; // Check collection by knight if (knight && self.intersects(knight)) { self.collect(); } } }; self.collect = function () { LK.getSound('coinCollect').play(); LK.setScore(LK.getScore() + 5); coinCounter++; coinText.setText('Coins: ' + coinCounter); // Remove from coins array for (var i = coins.length - 1; i >= 0; i--) { if (coins[i] === self) { coins.splice(i, 1); break; } } self.destroy(); }; return self; }); // Game arrays to track objects var Enemy = Container.expand(function () { var self = Container.call(this); // Animation system for skeleton self.currentFrame = 1; self.animationTimer = 0; self.animationSpeed = 15; // Change frame every 15 ticks (250ms at 60fps) self.animationState = 'walking'; // walking, attacking, dying, idle // Create all skeleton graphics frames and store them self.skeletonFrames = []; for (var i = 1; i <= 4; i++) { var frameGraphics = self.attachAsset('esqueleto' + i, { anchorX: 0.5, anchorY: 1.0, scaleX: 2.0, scaleY: 2.0 }); frameGraphics.visible = i === 1; // Only show first frame initially self.skeletonFrames.push(frameGraphics); } // Create invisible hitbox with double size var hitbox = self.attachAsset('esqueleto1', { anchorX: 0.5, anchorY: 1.0, scaleX: 4, scaleY: 4 }); hitbox.alpha = 0; // Make hitbox invisible self.health = 100; self.maxHealth = 100; self.speed = 7; // Note: health, maxHealth and speed will be overridden by difficulty system self.lastX = 0; self.update = function () { // Animation system - cycle through skeleton frames based on state self.animationTimer++; var frameSpeed = self.animationSpeed; if (self.animationState === 'attacking') { frameSpeed = 8; // Faster animation for attacking } else if (self.animationState === 'dying') { frameSpeed = 20; // Slower animation for dying } else if (self.animationState === 'idle') { frameSpeed = 25; // Very slow animation for idle } if (self.animationTimer >= frameSpeed) { self.animationTimer = 0; // Hide current frame self.skeletonFrames[self.currentFrame - 1].visible = false; // Move to next frame based on animation state if (self.animationState === 'walking') { self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 1; } } else if (self.animationState === 'attacking') { // Cycle through frames 2-4 for attacking self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 2; } } else if (self.animationState === 'dying') { // Play frames 3-4 once for dying if (self.currentFrame < 4) { self.currentFrame++; } } else if (self.animationState === 'idle') { // Cycle between frames 1-2 for idle self.currentFrame = self.currentFrame === 1 ? 2 : 1; } // Show new frame self.skeletonFrames[self.currentFrame - 1].visible = true; } // Progressive speed increase - increase speed by 50% over 10 seconds if (!self.speedTweenStarted) { self.speedTweenStarted = true; var targetSpeed = self.speed * 2.5; // Increase speed by 150% tween(self, { speed: targetSpeed }, { duration: 10000, // 10 seconds easing: tween.easeOut }); } // Move along the assigned path toward the wizard if (wizard && self.pathAngle !== undefined) { // Move along the path direction toward the wizard var moveX = -Math.cos(self.pathAngle) * self.speed; var moveY = -Math.sin(self.pathAngle) * self.speed; self.x += moveX; self.y += moveY; // Face toward the wizard - flip horizontally if enemy is coming from the right if (self.pathIndex === 3 || self.pathIndex === 1) { // Right side path (horizontal) or diagonal right path // Flip all skeleton frames to face left (toward wizard) for (var frameIdx = 0; frameIdx < self.skeletonFrames.length; frameIdx++) { self.skeletonFrames[frameIdx].scaleX = -2.0; // Negative scale flips horizontally } } else { // Ensure normal orientation for other paths for (var frameIdx = 0; frameIdx < self.skeletonFrames.length; frameIdx++) { self.skeletonFrames[frameIdx].scaleX = 2.0; // Positive scale for normal orientation } } } else if (wizard) { // Fallback: move directly toward the wizard if no path assigned var dx = wizard.x - self.x; var dy = wizard.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // Normalize direction and apply speed self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Face toward the wizard - flip horizontally if moving from right to left if (dx < 0) { // Moving toward left (wizard is to the left) for (var frameIdx = 0; frameIdx < self.skeletonFrames.length; frameIdx++) { self.skeletonFrames[frameIdx].scaleX = -2.0; // Flip to face left } } else { for (var frameIdx = 0; frameIdx < self.skeletonFrames.length; frameIdx++) { self.skeletonFrames[frameIdx].scaleX = 2.0; // Normal orientation to face right } } } } else { // Fallback: move down if knight doesn't exist self.y += self.speed; } }; self.takeDamage = function (damage) { self.health -= damage; // Change animation state to attacking when hit self.animationState = 'attacking'; // Flash red when hit LK.effects.flashObject(self, 0xFF0000, 200); // Return to walking animation after brief attacking animation tween({}, {}, { duration: 300, onFinish: function onFinish() { if (self.animationState === 'attacking') { self.animationState = 'walking'; } } }); // Enemies die from any projectile hit self.die(); }; self.down = function (x, y, obj) { // Create projectile from wizard to enemy when enemy is tapped if (wizard && projectiles.length < 10) { // Limit projectiles to prevent spam var projectile = game.addChild(new Projectile()); projectile.x = wizard.x; projectile.y = wizard.y; // Calculate direction from wizard to enemy var dx = self.x - wizard.x; var dy = self.y - wizard.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { projectile.direction.x = dx / distance; projectile.direction.y = dy / distance; } projectiles.push(projectile); LK.getSound('spellCast').play(); } }; self.die = function () { // Change animation state to dying self.animationState = 'dying'; self.currentFrame = 3; // Start dying animation from frame 3 // Play pain sound when enemy dies LK.getSound('painSound').play(); // Drop coin var coin = game.addChild(new Coin()); coin.x = self.x; coin.y = self.y - 50; coin.isAnimating = true; coins.push(coin); // Animate coin moving toward coin counter var coinTargetX = 120 + coinText.width / 2; var coinTargetY = 90 + coinText.height / 2; tween(coin, { x: coinTargetX, y: coinTargetY, scaleX: 0.5, scaleY: 0.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Increment coin counter after animation coinCounter++; coinText.setText('Coins: ' + coinCounter); // Remove coin from array and destroy for (var i = coins.length - 1; i >= 0; i--) { if (coins[i] === coin) { coins.splice(i, 1); break; } } coin.destroy(); } }); // Increment enemy kill counter enemyKillCounter++; killCountText.setText('Puntuacion: ' + enemyKillCounter); // Add experience to wizard wizard.gainExperience(25); // Remove from enemies array for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } self.destroy(); LK.setScore(LK.getScore() + 10); }; return self; }); var GameMenu = Container.expand(function () { var self = Container.call(this); // Semi-transparent background overlay var menuBg = self.attachAsset('pathSelector', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 35, scaleY: 45 }); menuBg.alpha = 0.9; menuBg.tint = 0x87CEEB; // Celeste (sky blue) color // Title text var titleText = new Text2('WIZARD DEFENDER', { size: 150, fill: 0xFFD700, font: "monospace" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 800; self.addChild(titleText); // Instructions text var instructionsText = new Text2('TAP PATHS TO CAST SPELLS\nDEFEND YOUR CASTLE!', { size: 80, fill: 0xFFFFFF, font: "monospace" }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 2048 / 2; instructionsText.y = 1200; self.addChild(instructionsText); // Start button var startButton = self.attachAsset('wizard1', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1600, scaleX: 2, scaleY: 2 }); var startButtonText = new Text2('START GAME', { size: 100, fill: 0x000000, font: "monospace" }); startButtonText.anchor.set(0.5, 0.5); startButtonText.x = 2048 / 2; startButtonText.y = 1700; self.addChild(startButtonText); // Button interaction self.down = function (x, y, obj) { // Start the game by hiding menu self.startGame(); }; self.startGame = function () { // Hide menu and start game self.visible = false; gameStarted = true; // Show all game elements wizard.visible = true; for (var i = 0; i < paths.length; i++) { paths[i].visible = true; } // Show all stone path segments but keep them invisible for (var i = 0; i < game.children.length; i++) { var child = game.children[i]; if (child.pathIndex !== undefined && child !== paths[child.pathIndex]) { child.visible = true; child.alpha = 0; // Keep paths invisible } } coinText.visible = true; killCountText.visible = true; tapText.visible = true; healthBarBg.visible = true; healthBar.visible = true; healthText.visible = true; // Start medieval music LK.playMusic('medievalTheme'); }; return self; }); var Knight = Container.expand(function () { var self = Container.call(this); // Animation system for knight self.currentFrame = 1; self.animationTimer = 0; self.animationSpeed = 22; // Change frame every 22 ticks (367ms at 60fps) self.animationState = 'walking'; // walking, attacking, dying, idle // Create all knight graphics frames and store them self.knightFrames = []; for (var i = 1; i <= 4; i++) { var frameGraphics = self.attachAsset('knight' + i, { anchorX: 0.5, anchorY: 1.0, scaleX: 2.0, scaleY: 2.0 }); frameGraphics.visible = i === 1; // Only show first frame initially self.knightFrames.push(frameGraphics); } // Create invisible hitbox with double size var hitbox = self.attachAsset('knight1', { anchorX: 0.5, anchorY: 1.0, scaleX: 4, scaleY: 4 }); hitbox.alpha = 0; // Make hitbox invisible self.health = 100; self.maxHealth = 100; self.speed = 7; self.hitsToKill = 3; // Knights need 3 hits to die self.hitsTaken = 0; // Note: health, maxHealth and speed will be overridden by difficulty system self.lastX = 0; self.update = function () { // Animation system - cycle through knight frames based on state self.animationTimer++; var frameSpeed = self.animationSpeed; if (self.animationState === 'attacking') { frameSpeed = 12; // Faster animation for attacking } else if (self.animationState === 'dying') { frameSpeed = 28; // Slower animation for dying } else if (self.animationState === 'idle') { frameSpeed = 35; // Very slow animation for idle } if (self.animationTimer >= frameSpeed) { self.animationTimer = 0; // Hide current frame self.knightFrames[self.currentFrame - 1].visible = false; // Move to next frame based on animation state if (self.animationState === 'walking') { self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 1; } } else if (self.animationState === 'attacking') { // Cycle through frames 2-4 for attacking self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 2; } } else if (self.animationState === 'dying') { // Play frames 3-4 once for dying if (self.currentFrame < 4) { self.currentFrame++; } } else if (self.animationState === 'idle') { // Cycle between frames 1-2 for idle self.currentFrame = self.currentFrame === 1 ? 2 : 1; } // Show new frame self.knightFrames[self.currentFrame - 1].visible = true; } // Progressive speed increase - increase speed by 150% over 10 seconds if (!self.speedTweenStarted) { self.speedTweenStarted = true; var targetSpeed = self.speed * 2.5; // Increase speed by 150% tween(self, { speed: targetSpeed }, { duration: 10000, // 10 seconds easing: tween.easeOut }); } // Move along the assigned path toward the wizard if (wizard && self.pathAngle !== undefined) { // Move along the path direction toward the wizard var moveX = -Math.cos(self.pathAngle) * self.speed; var moveY = -Math.sin(self.pathAngle) * self.speed; self.x += moveX; self.y += moveY; // Face toward the wizard - flip horizontally if knight is coming from the right if (self.pathIndex === 3 || self.pathIndex === 1) { // Right side path (horizontal) or diagonal right path // Flip all knight frames to face left (toward wizard) for (var frameIdx = 0; frameIdx < self.knightFrames.length; frameIdx++) { self.knightFrames[frameIdx].scaleX = -2.0; // Negative scale flips horizontally } } else { // Ensure normal orientation for other paths for (var frameIdx = 0; frameIdx < self.knightFrames.length; frameIdx++) { self.knightFrames[frameIdx].scaleX = 2.0; // Positive scale for normal orientation } } } else if (wizard) { // Fallback: move directly toward the wizard if no path assigned var dx = wizard.x - self.x; var dy = wizard.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // Normalize direction and apply speed self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Face toward the wizard - flip horizontally if moving from right to left if (dx < 0) { // Moving toward left (wizard is to the left) for (var frameIdx = 0; frameIdx < self.knightFrames.length; frameIdx++) { self.knightFrames[frameIdx].scaleX = -2.0; // Flip to face left } } else { for (var frameIdx = 0; frameIdx < self.knightFrames.length; frameIdx++) { self.knightFrames[frameIdx].scaleX = 2.0; // Normal orientation to face right } } } } else { // Fallback: move down if knight doesn't exist self.y += self.speed; } }; self.takeDamage = function (damage) { self.health -= damage; self.hitsTaken++; // Change animation state to attacking when hit self.animationState = 'attacking'; // Flash red when hit LK.effects.flashObject(self, 0xFF0000, 200); // Return to walking animation after brief attacking animation tween({}, {}, { duration: 500, onFinish: function onFinish() { if (self.animationState === 'attacking') { self.animationState = 'walking'; } } }); // Knights need 3 hits to die if (self.hitsTaken >= self.hitsToKill) { self.die(); } }; self.down = function (x, y, obj) { // Create projectile from wizard to knight when knight is tapped if (wizard && projectiles.length < 10) { // Limit projectiles to prevent spam var projectile = game.addChild(new Projectile()); projectile.x = wizard.x; projectile.y = wizard.y; // Calculate direction from wizard to knight var dx = self.x - wizard.x; var dy = self.y - wizard.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { projectile.direction.x = dx / distance; projectile.direction.y = dy / distance; } projectiles.push(projectile); LK.getSound('spellCast').play(); } }; self.die = function () { // Change animation state to dying self.animationState = 'dying'; self.currentFrame = 3; // Start dying animation from frame 3 // Play pain sound when knight dies LK.getSound('painSound').play(); // Drop coin var coin = game.addChild(new Coin()); coin.x = self.x; coin.y = self.y - 50; coin.isAnimating = true; coins.push(coin); // Animate coin moving toward coin counter var coinTargetX = 120 + coinText.width / 2; var coinTargetY = 90 + coinText.height / 2; tween(coin, { x: coinTargetX, y: coinTargetY, scaleX: 0.5, scaleY: 0.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Increment coin counter after animation coinCounter++; coinText.setText('Coins: ' + coinCounter); // Remove coin from array and destroy for (var i = coins.length - 1; i >= 0; i--) { if (coins[i] === coin) { coins.splice(i, 1); break; } } coin.destroy(); } }); // Increment enemy kill counter enemyKillCounter++; killCountText.setText('Puntuacion: ' + enemyKillCounter); // Add experience to wizard wizard.gainExperience(25); // Remove from knights array for (var i = knights.length - 1; i >= 0; i--) { if (knights[i] === self) { knights.splice(i, 1); break; } } self.destroy(); LK.setScore(LK.getScore() + 20); }; return self; }); var Ogre = Container.expand(function () { var self = Container.call(this); // Animation system for ogre self.currentFrame = 1; self.animationTimer = 0; self.animationSpeed = 20; // Change frame every 20 ticks (333ms at 60fps) self.animationState = 'walking'; // walking, attacking, dying, idle // Create all ogre graphics frames and store them self.ogreFrames = []; for (var i = 1; i <= 4; i++) { var frameGraphics = self.attachAsset('ogre' + i, { anchorX: 0.5, anchorY: 1.0, scaleX: 2.0, scaleY: 2.0 }); frameGraphics.visible = i === 1; // Only show first frame initially self.ogreFrames.push(frameGraphics); } // Create invisible hitbox with double size var hitbox = self.attachAsset('ogre1', { anchorX: 0.5, anchorY: 1.0, scaleX: 4, scaleY: 4 }); hitbox.alpha = 0; // Make hitbox invisible self.health = 100; self.maxHealth = 100; self.speed = 7; self.hitsToKill = 2; self.hitsTaken = 0; // Note: health, maxHealth and speed will be overridden by difficulty system self.lastX = 0; self.update = function () { // Animation system - cycle through ogre frames based on state self.animationTimer++; var frameSpeed = self.animationSpeed; if (self.animationState === 'attacking') { frameSpeed = 10; // Faster animation for attacking } else if (self.animationState === 'dying') { frameSpeed = 25; // Slower animation for dying } else if (self.animationState === 'idle') { frameSpeed = 30; // Very slow animation for idle } if (self.animationTimer >= frameSpeed) { self.animationTimer = 0; // Hide current frame self.ogreFrames[self.currentFrame - 1].visible = false; // Move to next frame based on animation state if (self.animationState === 'walking') { self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 1; } } else if (self.animationState === 'attacking') { // Cycle through frames 2-4 for attacking self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 2; } } else if (self.animationState === 'dying') { // Play frames 3-4 once for dying if (self.currentFrame < 4) { self.currentFrame++; } } else if (self.animationState === 'idle') { // Cycle between frames 1-2 for idle self.currentFrame = self.currentFrame === 1 ? 2 : 1; } // Show new frame self.ogreFrames[self.currentFrame - 1].visible = true; } // Progressive speed increase - increase speed by 150% over 10 seconds if (!self.speedTweenStarted) { self.speedTweenStarted = true; var targetSpeed = self.speed * 2.5; // Increase speed by 150% tween(self, { speed: targetSpeed }, { duration: 10000, // 10 seconds easing: tween.easeOut }); } // Move along the assigned path toward the wizard if (wizard && self.pathAngle !== undefined) { // Move along the path direction toward the wizard var moveX = -Math.cos(self.pathAngle) * self.speed; var moveY = -Math.sin(self.pathAngle) * self.speed; self.x += moveX; self.y += moveY; // Face toward the wizard - flip horizontally if ogre is coming from the right if (self.pathIndex === 3 || self.pathIndex === 1) { // Right side path (horizontal) or diagonal right path // Flip all ogre frames to face left (toward wizard) for (var frameIdx = 0; frameIdx < self.ogreFrames.length; frameIdx++) { self.ogreFrames[frameIdx].scaleX = -2.0; // Negative scale flips horizontally } } else { // Ensure normal orientation for other paths for (var frameIdx = 0; frameIdx < self.ogreFrames.length; frameIdx++) { self.ogreFrames[frameIdx].scaleX = 2.0; // Positive scale for normal orientation } } } else if (wizard) { // Fallback: move directly toward the wizard if no path assigned var dx = wizard.x - self.x; var dy = wizard.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // Normalize direction and apply speed self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; // Face toward the wizard - flip horizontally if moving from right to left if (dx < 0) { // Moving toward left (wizard is to the left) for (var frameIdx = 0; frameIdx < self.ogreFrames.length; frameIdx++) { self.ogreFrames[frameIdx].scaleX = -2.0; // Flip to face left } } else { for (var frameIdx = 0; frameIdx < self.ogreFrames.length; frameIdx++) { self.ogreFrames[frameIdx].scaleX = 2.0; // Normal orientation to face right } } } } else { // Fallback: move down if knight doesn't exist self.y += self.speed; } }; self.takeDamage = function (damage) { self.health -= damage; self.hitsTaken++; // Change animation state to attacking when hit self.animationState = 'attacking'; // Flash red when hit LK.effects.flashObject(self, 0xFF0000, 200); // Return to walking animation after brief attacking animation tween({}, {}, { duration: 400, onFinish: function onFinish() { if (self.animationState === 'attacking') { self.animationState = 'walking'; } } }); // Ogres need 2 hits to die if (self.hitsTaken >= self.hitsToKill) { self.die(); } }; self.down = function (x, y, obj) { // Create projectile from wizard to ogre when ogre is tapped if (wizard && projectiles.length < 10) { // Limit projectiles to prevent spam var projectile = game.addChild(new Projectile()); projectile.x = wizard.x; projectile.y = wizard.y; // Calculate direction from wizard to ogre var dx = self.x - wizard.x; var dy = self.y - wizard.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { projectile.direction.x = dx / distance; projectile.direction.y = dy / distance; } projectiles.push(projectile); LK.getSound('spellCast').play(); } }; self.die = function () { // Change animation state to dying self.animationState = 'dying'; self.currentFrame = 3; // Start dying animation from frame 3 // Play pain sound when ogre dies LK.getSound('painSound').play(); // Drop coin var coin = game.addChild(new Coin()); coin.x = self.x; coin.y = self.y - 50; coin.isAnimating = true; coins.push(coin); // Animate coin moving toward coin counter var coinTargetX = 120 + coinText.width / 2; var coinTargetY = 90 + coinText.height / 2; tween(coin, { x: coinTargetX, y: coinTargetY, scaleX: 0.5, scaleY: 0.5 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Increment coin counter after animation coinCounter++; coinText.setText('Coins: ' + coinCounter); // Remove coin from array and destroy for (var i = coins.length - 1; i >= 0; i--) { if (coins[i] === coin) { coins.splice(i, 1); break; } } coin.destroy(); } }); // Increment enemy kill counter enemyKillCounter++; killCountText.setText('Puntuacion: ' + enemyKillCounter); // Add experience to wizard wizard.gainExperience(25); // Remove from ogres array for (var i = ogres.length - 1; i >= 0; i--) { if (ogres[i] === self) { ogres.splice(i, 1); break; } } self.destroy(); LK.setScore(LK.getScore() + 15); }; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var projectileGraphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 50; self.direction = { x: 0, y: 0 }; self.lastIntersecting = {}; self.update = function () { // Move projectile self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Remove if off screen if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) { self.removeFromGame(); return; } // Check collision with enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (!self.lastIntersecting[i]) { self.lastIntersecting[i] = false; } var currentIntersecting = self.intersects(enemy); if (!self.lastIntersecting[i] && currentIntersecting) { // Hit enemy enemy.takeDamage(50); self.removeFromGame(); return; } self.lastIntersecting[i] = currentIntersecting; } // Check collision with ogres for (var i = ogres.length - 1; i >= 0; i--) { var ogre = ogres[i]; var ogreKey = 'ogre_' + i; if (!self.lastIntersecting[ogreKey]) { self.lastIntersecting[ogreKey] = false; } var currentOgreIntersecting = self.intersects(ogre); if (!self.lastIntersecting[ogreKey] && currentOgreIntersecting) { // Hit ogre ogre.takeDamage(50); self.removeFromGame(); return; } self.lastIntersecting[ogreKey] = currentOgreIntersecting; } // Check collision with knights for (var i = knights.length - 1; i >= 0; i--) { var knight = knights[i]; var knightKey = 'knight_' + i; if (!self.lastIntersecting[knightKey]) { self.lastIntersecting[knightKey] = false; } var currentKnightIntersecting = self.intersects(knight); if (!self.lastIntersecting[knightKey] && currentKnightIntersecting) { // Hit knight knight.takeDamage(50); self.removeFromGame(); return; } self.lastIntersecting[knightKey] = currentKnightIntersecting; } }; self.removeFromGame = function () { // Remove from projectiles array for (var i = projectiles.length - 1; i >= 0; i--) { if (projectiles[i] === self) { projectiles.splice(i, 1); break; } } self.destroy(); }; return self; }); var UpgradeMenu = Container.expand(function () { var self = Container.call(this); // Set high z-index to ensure menu appears above all game elements self.zIndex = 1000; // Cooldown system for upgrade menu self.cooldownDuration = 120; // 2 seconds at 60fps self.cooldownTimer = 0; // Background removed - no overlay needed // Title text var titleText = new Text2('UPGRADES', { size: 120, fill: 0xFFD700, font: "monospace" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 1050; self.addChild(titleText); // Upgrade options var upgradeOptions = [{ name: 'ATTACK SPEED', description: 'Faster spells' }, { name: 'SPELL POWER', description: 'More damage' }, { name: 'HEALTH BOOST', description: 'More health' }]; // Create upgrade buttons for (var i = 0; i < upgradeOptions.length; i++) { var upgrade = upgradeOptions[i]; var xPos = 2048 / 2 - 400 + i * 400; // Center the upgrades horizontally var yPos = 1300; // Same Y position for all // Upgrade button background var upgradeBtn = self.attachAsset('pathSelector', { anchorX: 0.5, anchorY: 0.5, x: xPos, y: yPos, scaleX: 6, scaleY: 4 }); upgradeBtn.upgradeIndex = i; upgradeBtn.tint = 0x8B008B; // Upgrade text var upgradeText = new Text2(upgrade.name + '\n' + upgrade.description + '\nCost: 10 coins', { size: 45, fill: 0xFFFFFF, font: "monospace" }); upgradeText.anchor.set(0.5, 0.5); upgradeText.x = xPos; upgradeText.y = yPos; self.addChild(upgradeText); } // Close button var closeBtn = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1600, scaleX: 2, scaleY: 2 }); closeBtn.tint = 0xFF0000; var closeText = new Text2('CLOSE', { size: 80, fill: 0xFFFFFF, font: "monospace" }); closeText.anchor.set(0.5, 0.5); closeText.x = 2048 / 2; closeText.y = 1600; self.addChild(closeText); // Update method for cooldown timer self.update = function () { if (self.cooldownTimer > 0) { self.cooldownTimer--; // Apply visual feedback during cooldown var cooldownAlpha = 0.3 + self.cooldownTimer / self.cooldownDuration * 0.7; self.alpha = cooldownAlpha; } else { self.alpha = 1.0; // Full opacity when cooldown is over } }; // Handle upgrade purchases self.down = function (x, y, obj) { // Check if cooldown is active if (self.cooldownTimer > 0) { // Flash red to indicate cooldown is active LK.effects.flashScreen(0xFF0000, 200); return; // Exit early if cooldown is active } // Determine which upgrade was clicked based on X position (horizontal layout) var upgradeIndex = -1; if (x >= 424 && x <= 724 && y >= 1150 && y <= 1450) { upgradeIndex = 0; // Attack Speed } else if (x >= 824 && x <= 1124 && y >= 1150 && y <= 1450) { upgradeIndex = 1; // Spell Power } else if (x >= 1224 && x <= 1524 && y >= 1150 && y <= 1450) { upgradeIndex = 2; // Health Boost } // Check if upgrade button was clicked if (upgradeIndex !== -1) { // Close menu immediately when any upgrade option is selected self.closeMenu(); if (coinCounter >= 10) { coinCounter -= 10; coinText.setText('Coins: ' + coinCounter); // Apply upgrade based on index switch (upgradeIndex) { case 0: // Attack Speed - reduce cooldown wizard.attackCooldown = Math.max(5, wizard.attackCooldown - 5); break; case 1: // Spell Power - increase damage multiplier if (!wizard.spellPowerLevel) wizard.spellPowerLevel = 0; wizard.spellPowerLevel++; break; case 2: // Health Boost wizard.maxHealth += 25; wizard.health = Math.min(wizard.health + 25, wizard.maxHealth); updateHealthBar(); break; } // Visual feedback - flash the upgrade area green LK.effects.flashScreen(0x00FF00, 300); } else { // Not enough coins - flash red LK.effects.flashScreen(0xFF0000, 300); } } else if (y >= 1450 && y <= 1750) { // Close button area clicked self.closeMenu(); } }; self.closeMenu = function () { self.visible = false; gameStarted = true; // Resume game time LK.playMusic('medievalTheme'); }; return self; }); var Wizard = Container.expand(function () { var self = Container.call(this); // Animation system for wizard self.currentFrame = 1; self.animationTimer = 0; self.animationSpeed = 18; // Change frame every 18 ticks (300ms at 60fps) // Create all wizard graphics frames and store them self.wizardFrames = []; for (var i = 1; i <= 4; i++) { var frameGraphics = self.attachAsset('wizard' + i, { anchorX: 0.5, anchorY: 1.0, scaleX: 2.5, scaleY: 2.5 }); frameGraphics.visible = i === 1; // Only show first frame initially self.wizardFrames.push(frameGraphics); } self.attackCooldown = 0; self.level = 1; self.experience = 0; self.health = 100; self.maxHealth = 100; self.spellPowerLevel = 0; // Track spell power upgrades self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } // Animation system - cycle through wizard frames self.animationTimer++; if (self.animationTimer >= self.animationSpeed) { self.animationTimer = 0; // Hide current frame self.wizardFrames[self.currentFrame - 1].visible = false; // Move to next frame self.currentFrame++; if (self.currentFrame > 4) { self.currentFrame = 1; } // Show new frame self.wizardFrames[self.currentFrame - 1].visible = true; } }; self.attack = function (direction) { if (self.attackCooldown <= 0) { // Default direction if none specified if (direction === undefined) { direction = 0; // Default to center path } // Get attack angle based on path direction var attackAngle = pathAngles[direction]; var attackDistance = 100; // Calculate spell position based on attack direction var spellX = self.x + Math.cos(attackAngle) * attackDistance; var spellY = self.y + Math.sin(attackAngle) * attackDistance; // Create spell effect var spell = game.addChild(LK.getAsset('spell', { anchorX: 0.5, anchorY: 0.5, x: spellX, y: spellY, scaleX: 0.5, scaleY: 0.5 })); // Animate spell with magical effects tween(spell, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { spell.destroy(); } }); // Add rotation animation to spell tween(spell, { rotation: Math.PI * 2 }, { duration: 500, easing: tween.linear }); self.attackCooldown = 30; // 0.5 seconds at 60fps LK.getSound('spellCast').play(); // Calculate damage based on spell power upgrades var baseDamage = 50; var spellPowerMultiplier = 1 + (self.spellPowerLevel || 0) * 0.5; // 50% more damage per upgrade var totalDamage = Math.floor(baseDamage * spellPowerMultiplier); // Attack enemies in the specified direction/path for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.pathIndex === direction) { // Check if enemy is within attack range along this path var dx = enemy.x - self.x; var dy = enemy.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Attack range enemy.takeDamage(totalDamage); } } } // Attack ogres in the specified direction/path for (var i = ogres.length - 1; i >= 0; i--) { var ogre = ogres[i]; if (ogre.pathIndex === direction) { // Check if ogre is within attack range along this path var dx = ogre.x - self.x; var dy = ogre.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Attack range ogre.takeDamage(totalDamage); } } } // Attack knights in the specified direction/path for (var i = knights.length - 1; i >= 0; i--) { var knight = knights[i]; if (knight.pathIndex === direction) { // Check if knight is within attack range along this path var dx = knight.x - self.x; var dy = knight.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Attack range knight.takeDamage(totalDamage); } } } return true; } return false; }; self.gainExperience = function (amount) { self.experience += amount; var expNeeded = self.level * 100; if (self.experience >= expNeeded) { self.levelUp(); } }; self.levelUp = function () { self.level++; self.experience = 0; // Visual level up effect LK.effects.flashObject(self, 0xFFD700, 500); }; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; // Game over when health reaches 0 LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } // Update health bar updateHealthBar(); // Flash red when hit LK.effects.flashObject(self, 0xFF0000, 200); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Black background for pixel art }); /**** * Game Code ****/ // Game state variables var gameStarted = false; var gameMenu; var upgradeMenu; var upgradeMenuShown = false; var secondUpgradeMenuShown = false; // Game arrays to track objects var enemies = []; var ogres = []; var knights = []; var coins = []; var projectiles = []; // Create and show game menu gameMenu = game.addChild(new GameMenu()); // Create upgrade menu (initially hidden) upgradeMenu = game.addChild(new UpgradeMenu()); upgradeMenu.visible = false; // Create 5 stone paths leading toward the wizard position var paths = []; var knightX = 2048 / 2; var knightY = 2732 - 250; // Create paths: center, two diagonal, and two side paths var pathAngles = [-Math.PI / 2, // Center (straight down) -Math.PI / 4, // Diagonal right -3 * Math.PI / 4, // Diagonal left 0, // Right side (horizontal) Math.PI // Left side (horizontal) ]; // 5 paths: center, two diagonal, two sides // Create multiple stone segments for each path to form visible stone roads for (var p = 0; p < 5; p++) { var angle = pathAngles[p]; // Calculate path length - make center path longer var pathLength = p === 0 ? 3000 : 1800; // Center path is longer var segmentSize = 120; // Size of each stone segment var numSegments = Math.floor(pathLength / segmentSize); // Create individual stone segments along the path for (var s = 0; s < numSegments; s++) { var segmentDistance = s * segmentSize + segmentSize / 2; var segmentX = knightX + Math.cos(angle) * segmentDistance; var segmentY = knightY + Math.sin(angle) * segmentDistance; // Create stone path segment var stoneSegment = game.addChild(LK.getAsset('stonePath', { anchorX: 0.5, anchorY: 0.5, x: segmentX, y: segmentY, scaleX: 2.0, scaleY: 2.0, rotation: angle + Math.PI / 2 // Rotate stone to align with path })); // Make stones completely invisible stoneSegment.alpha = 0; // Make completely invisible stoneSegment.visible = false; stoneSegment.pathIndex = p; } } // Create invisible path collision areas for touch detection for (var p = 0; p < 5; p++) { var angle = pathAngles[p]; var pathLength = p === 0 ? 3000 : 1800; var centerX = knightX + Math.cos(angle) * (pathLength / 2); var centerY = knightY + Math.sin(angle) * (pathLength / 2); // Create invisible collision path var path = game.addChild(LK.getAsset('pathSelector', { anchorX: 0.5, anchorY: 0.5, x: centerX, y: centerY, scaleX: 4, scaleY: pathLength / 60, rotation: angle + Math.PI / 2 })); // Make collision path completely invisible path.alpha = 0; path.visible = false; path.pathIndex = p; // Add touch handler for directional attacks path.down = function (x, y, obj) { // Attack in this path's direction wizard.attack(obj.pathIndex); // Visual feedback - no flash for invisible paths // Paths remain invisible when tapped }; paths.push(path); } // Set fondodelacueva as the actual game background with proper pixel art scaling var backgroundMap = game.addChild(LK.getAsset('fondodelacueva', { anchorX: 0, anchorY: 0, scaleX: 1.5, scaleY: 2.0, x: 0, y: 0 })); // Send background to the back but use a less extreme z-index backgroundMap.zIndex = -100; // Ensure background is visible backgroundMap.visible = true; backgroundMap.alpha = 1.0; // Create wizard var wizard = game.addChild(new Wizard()); wizard.x = knightX; wizard.y = knightY + 100; // Move wizard 100 pixels lower wizard.visible = false; // UI Elements // Removed scoreText and levelText to eliminate stray characters in top right var coinCounter = 0; var enemyKillCounter = 0; var coinText = new Text2('Coins: 0', { size: 60, fill: 0xFFD700, font: "monospace" }); coinText.anchor.set(0, 0); LK.gui.topLeft.addChild(coinText); coinText.x = 120; coinText.y = 90; coinText.visible = false; var killCountText = new Text2('Puntuacion: 0', { size: 60, fill: 0xFF6B6B, font: "monospace" }); killCountText.anchor.set(0, 0); LK.gui.topLeft.addChild(killCountText); killCountText.x = 120; killCountText.y = 150; killCountText.visible = false; var tapText = new Text2('TAP TO CAST SPELLS!', { size: 100, fill: 0xFF6B6B, font: "monospace" }); tapText.anchor.set(0.5, 0.5); LK.gui.center.addChild(tapText); tapText.y = -200; tapText.visible = false; // Health bar UI var healthBarBg = LK.getAsset('healthBarBg', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(healthBarBg); healthBarBg.x = 120; healthBarBg.y = 20; healthBarBg.visible = false; var healthBar = LK.getAsset('healthBar', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(healthBar); healthBar.x = 120; healthBar.y = 20; healthBar.visible = false; var healthText = new Text2('Health: 100/100', { size: 50, fill: 0xFFFFFF, font: "monospace" }); healthText.anchor.set(0, 0); LK.gui.topLeft.addChild(healthText); healthText.x = 120; healthText.y = 50; healthText.visible = false; function updateHealthBar() { var healthPercent = wizard.health / wizard.maxHealth; healthBar.scaleX = healthPercent; healthText.setText('Health: ' + wizard.health + '/' + wizard.maxHealth); // Change color based on health if (healthPercent > 0.6) { healthBar.tint = 0x00ff00; // Green } else if (healthPercent > 0.3) { healthBar.tint = 0xffff00; // Yellow } else { healthBar.tint = 0xff0000; // Red } } // Enemy spawning variables var enemySpawnTimer = 0; var lastSpawnedPath = -1; // Track the last spawned path var consecutiveSpawns = 0; // Track consecutive spawns from same path // Cooldown system variables var pathLastSpawnTime = [-1, -1, -1, -1, -1]; // Track last spawn time for each path var pathConsecutiveSpawns = [0, 0, 0, 0, 0]; // Track consecutive spawns per path var pathCooldownDuration = 300; // 5 seconds at 60fps // Game input handling game.down = function (x, y, obj) { // Check if a path was tapped for directional attack var pathTapped = false; for (var p = 0; p < paths.length; p++) { var path = paths[p]; // Convert tap position to path's local coordinates var localPos = path.toLocal({ x: x, y: y }); // Check if tap is within path bounds if (Math.abs(localPos.x) < path.width / 2 && Math.abs(localPos.y) < path.height / 2) { // Attack in this path's direction wizard.attack(path.pathIndex); pathTapped = true; break; } } // No default attack - player must tap a path to attack }; // Main game update loop game.update = function () { // Sort children by z-index to ensure proper rendering order game.children.sort(function (a, b) { return (a.zIndex || 0) - (b.zIndex || 0); }); // Only update game logic if game has started if (!gameStarted) { return; } // Show upgrade menu after 12 enemies are killed if (enemyKillCounter >= 12 && !upgradeMenuShown) { upgradeMenuShown = true; upgradeMenu.visible = true; upgradeMenu.cooldownTimer = upgradeMenu.cooldownDuration; // Start 2-second cooldown gameStarted = false; // Pause game while menu is open LK.stopMusic(); // Pause music // Clear all enemies on screen when upgrade menu is shown for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemies.splice(i, 1); enemy.destroy(); } // Clear all ogres on screen when upgrade menu is shown for (var i = ogres.length - 1; i >= 0; i--) { var ogre = ogres[i]; ogres.splice(i, 1); ogre.destroy(); } // Clear all knights on screen when upgrade menu is shown for (var i = knights.length - 1; i >= 0; i--) { var knight = knights[i]; knights.splice(i, 1); knight.destroy(); } } // Show upgrade menu again after 35 enemies are killed if (enemyKillCounter >= 35 && upgradeMenuShown && !secondUpgradeMenuShown) { secondUpgradeMenuShown = true; upgradeMenu.visible = true; upgradeMenu.cooldownTimer = upgradeMenu.cooldownDuration; // Start 2-second cooldown gameStarted = false; // Pause game while menu is open LK.stopMusic(); // Pause music // Clear all enemies on screen when upgrade menu is shown for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemies.splice(i, 1); enemy.destroy(); } // Clear all ogres on screen when upgrade menu is shown for (var i = ogres.length - 1; i >= 0; i--) { var ogre = ogres[i]; ogres.splice(i, 1); ogre.destroy(); } // Clear all knights on screen when upgrade menu is shown for (var i = knights.length - 1; i >= 0; i--) { var knight = knights[i]; knights.splice(i, 1); knight.destroy(); } } // Reset consecutive spawns for paths that have cooled down (runs every frame) for (var pathIdx = 0; pathIdx < 5; pathIdx++) { // Check if enough time has passed since last spawn (cooldown expired) if (pathLastSpawnTime[pathIdx] !== -1 && LK.ticks - pathLastSpawnTime[pathIdx] > pathCooldownDuration) { // Reset consecutive spawns for this path due to cooldown pathConsecutiveSpawns[pathIdx] = 0; } } // Progressive difficulty system based on kills var difficultyLevel = Math.floor(enemyKillCounter / 10); // Every 10 kills increases difficulty var currentSpawnRate = Math.max(30, 90 - difficultyLevel * 8); // Faster spawning over time var enemyHealthMultiplier = 1 + difficultyLevel * 0.3; // 30% more health per difficulty level var enemySpeedMultiplier = 1 + difficultyLevel * 0.35; // 35% faster per difficulty level // Spawn enemies enemySpawnTimer++; if (enemySpawnTimer >= currentSpawnRate) { enemySpawnTimer = 0; var enemy = game.addChild(new Enemy()); // Apply difficulty scaling to enemy stats enemy.health = Math.floor(100 * enemyHealthMultiplier); enemy.maxHealth = enemy.health; enemy.speed = 3 * enemySpeedMultiplier; // Spawn enemy at a random path entrance var randomPathIndex; if (enemyKillCounter < 5) { // First 5 enemies spawn from center path only randomPathIndex = 0; // Center path } else { // After 5 enemies, spawn from any path but limit consecutive spawns with cooldown system // Build available paths list var availablePaths = []; for (var pathIdx = 0; pathIdx < 5; pathIdx++) { // If path has spawned less than 2 consecutive times, it's available if (pathConsecutiveSpawns[pathIdx] < 2) { availablePaths.push(pathIdx); } } // If no paths available, reset ALL paths to ensure balanced distribution if (availablePaths.length === 0) { // Reset all paths' consecutive spawn counters for (var pathIdx = 0; pathIdx < 5; pathIdx++) { pathConsecutiveSpawns[pathIdx] = 0; availablePaths.push(pathIdx); } } randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)]; } // Update path-specific spawn tracking // Always increment consecutive spawns for the selected path pathConsecutiveSpawns[randomPathIndex]++; // Update path spawn time and global tracking pathLastSpawnTime[randomPathIndex] = LK.ticks; lastSpawnedPath = randomPathIndex; consecutiveSpawns = pathConsecutiveSpawns[randomPathIndex]; var pathAngle = pathAngles[randomPathIndex]; // Store the path information on the enemy enemy.pathIndex = randomPathIndex; enemy.pathAngle = pathAngle; // Calculate spawn position at the far end of the path (screen edge) var pathLength = randomPathIndex === 0 ? 3000 : 1800; // Match path lengths var spawnDistance = pathLength * 0.8; // Spawn farther away - 80% of path length enemy.x = knightX + Math.cos(pathAngle) * spawnDistance; enemy.y = knightY + Math.sin(pathAngle) * spawnDistance; // Make sure enemies spawn within screen bounds enemy.x = Math.max(50, Math.min(1998, enemy.x)); enemy.y = Math.max(-200, Math.min(2732 + 100, enemy.y)); enemy.lastX = enemy.x; enemies.push(enemy); } // Spawn ogres after 15 seconds (900 ticks at 60fps) if (LK.ticks >= 900 && LK.ticks % 180 === 0) { // Every 3 seconds after 15 seconds var ogre = game.addChild(new Ogre()); // Apply difficulty scaling to ogre stats ogre.health = Math.floor(150 * enemyHealthMultiplier); // Ogres have more base health ogre.maxHealth = ogre.health; ogre.speed = 2.5 * enemySpeedMultiplier; // Ogres are slightly slower // Spawn ogre at a random path entrance var ogrePathIndex = Math.floor(Math.random() * 5); var ogrePathAngle = pathAngles[ogrePathIndex]; // Store the path information on the ogre ogre.pathIndex = ogrePathIndex; ogre.pathAngle = ogrePathAngle; // Calculate spawn position at the far end of the path (screen edge) var ogrePathLength = ogrePathIndex === 0 ? 3000 : 1800; var ogreSpawnDistance = ogrePathLength * 0.8; ogre.x = knightX + Math.cos(ogrePathAngle) * ogreSpawnDistance; ogre.y = knightY + Math.sin(ogrePathAngle) * ogreSpawnDistance; // Make sure ogres spawn within screen bounds ogre.x = Math.max(50, Math.min(1998, ogre.x)); ogre.y = Math.max(-200, Math.min(2732 + 100, ogre.y)); ogre.lastX = ogre.x; ogres.push(ogre); } // Spawn knights after 30 enemies killed if (enemyKillCounter >= 30 && LK.ticks % 300 === 0) { // Every 5 seconds after 30th enemy var knight = game.addChild(new Knight()); // Apply difficulty scaling to knight stats knight.health = Math.floor(200 * enemyHealthMultiplier); // Knights have highest base health knight.maxHealth = knight.health; knight.speed = 2 * enemySpeedMultiplier; // Knights are slowest // Spawn knight at a random path entrance var knightPathIndex = Math.floor(Math.random() * 5); var knightPathAngle = pathAngles[knightPathIndex]; // Store the path information on the knight knight.pathIndex = knightPathIndex; knight.pathAngle = knightPathAngle; // Calculate spawn position at the far end of the path (screen edge) var knightPathLength = knightPathIndex === 0 ? 3000 : 1800; var knightSpawnDistance = knightPathLength * 0.8; knight.x = knightX + Math.cos(knightPathAngle) * knightSpawnDistance; knight.y = knightY + Math.sin(knightPathAngle) * knightSpawnDistance; // Make sure knights spawn within screen bounds knight.x = Math.max(50, Math.min(1998, knight.x)); knight.y = Math.max(-200, Math.min(2732 + 100, knight.y)); knight.lastX = knight.x; knights.push(knight); } // Check enemy-knight collisions and cleanup off-screen enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; // Remove enemies that went off-screen at bottom if (enemy.y > 2732 + 100) { enemies.splice(i, 1); enemy.destroy(); continue; } // Initialize lastIntersecting if not set if (enemy.lastIntersecting === undefined) { enemy.lastIntersecting = false; } // Check for collision transition var currentIntersecting = enemy.intersects(wizard); if (!enemy.lastIntersecting && currentIntersecting) { // Damage wizard when enemy touches for the first time wizard.takeDamage(20); // Remove enemy after dealing damage enemies.splice(i, 1); enemy.destroy(); continue; } // Update last intersecting state enemy.lastIntersecting = currentIntersecting; } // Check ogre-wizard collisions and cleanup off-screen ogres for (var i = ogres.length - 1; i >= 0; i--) { var ogre = ogres[i]; // Remove ogres that went off-screen at bottom if (ogre.y > 2732 + 100) { ogres.splice(i, 1); ogre.destroy(); continue; } // Initialize lastIntersecting if not set if (ogre.lastIntersecting === undefined) { ogre.lastIntersecting = false; } // Check for collision transition var currentOgreIntersecting = ogre.intersects(wizard); if (!ogre.lastIntersecting && currentOgreIntersecting) { // Damage wizard when ogre touches for the first time wizard.takeDamage(30); // Ogres deal 30 damage // Remove ogre after dealing damage ogres.splice(i, 1); ogre.destroy(); continue; } // Update last intersecting state ogre.lastIntersecting = currentOgreIntersecting; } // Check knight-wizard collisions and cleanup off-screen knights for (var i = knights.length - 1; i >= 0; i--) { var knight = knights[i]; // Remove knights that went off-screen at bottom if (knight.y > 2732 + 100) { knights.splice(i, 1); knight.destroy(); continue; } // Initialize lastIntersecting if not set if (knight.lastIntersecting === undefined) { knight.lastIntersecting = false; } // Check for collision transition var currentKnightIntersecting = knight.intersects(wizard); if (!knight.lastIntersecting && currentKnightIntersecting) { // Damage wizard when knight touches for the first time wizard.takeDamage(40); // Knights deal 40 damage // Remove knight after dealing damage knights.splice(i, 1); knight.destroy(); continue; } // Update last intersecting state knight.lastIntersecting = currentKnightIntersecting; } // Make tap text pulse var pulse = 1 + Math.sin(LK.ticks * 0.1) * 0.2; tapText.scale.set(pulse, pulse); }; // Remove tap text after 5 seconds tween({}, {}, { duration: 5000, onFinish: function onFinish() { if (tapText && tapText.parent) { tapText.destroy(); } } });
===================================================================
--- original.js
+++ change.js
@@ -1294,10 +1294,10 @@
// Set fondodelacueva as the actual game background with proper pixel art scaling
var backgroundMap = game.addChild(LK.getAsset('fondodelacueva', {
anchorX: 0,
anchorY: 0,
- scaleX: 2.0,
- scaleY: 3.0,
+ scaleX: 1.5,
+ scaleY: 2.0,
x: 0,
y: 0
}));
// Send background to the back but use a less extreme z-index