User prompt
ahora de 1s
User prompt
deben tener un tiempo de espera entre enemigos de 0.25s
User prompt
ahora pueden salir aleatoriamente a partir del 5
User prompt
ahora del 5 al 10 pueden salir de manera aleatoria del centro y las diagonales
User prompt
ahora has que los primeros 5 salgan del centro
User prompt
continua fallando
User prompt
fix it
User prompt
cuando dejo de disparar siguen apareciendo todos del mismo lado
User prompt
implementalo
User prompt
ahora no saldran mas de dos enemigos consecutivos de un solo camino
User prompt
no esta sonando
User prompt
produce un sonido cada vez que se impacte un enemigo
User prompt
ahora no pueden salir mas de 2 enemigos seguidos de un solo camino
User prompt
que los enemigos mueran de un solo proyectil
User prompt
que el proyectil sea casi instantaneo
User prompt
ahora el proyectil sea morado y casi intantaneo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cada vez que tocas un enemigo el mago tira un proyectil ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ahora los proyectiles seran morados y mucho mas rapidos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cada vez que se toca un enemigo el mago tira un proyectil ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
el proyectil sale en direccion al enemigo a eliminar ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cada vez que el mago ataca sale un hechizo que golpea al enemigo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ahora el jugador es un brujo y ataca con un hechizo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
ahora que los caminos del nivel 1 sean de piedras
User prompt
todo el fondo celste
User prompt
ahora hazlo celeste
/**** * Plugins ****/ var tween = LK.import("@upit/tween.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); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 1.0 }); self.health = 100; self.maxHealth = 100; self.speed = 3; self.lastX = 0; self.update = function () { // 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; } 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; } } else { // Fallback: move down if knight doesn't exist self.y += self.speed; } }; self.takeDamage = function (damage) { self.health -= damage; // Flash red when hit LK.effects.flashObject(self, 0xFF0000, 200); // 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 () { // 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 }); 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 }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 2048 / 2; instructionsText.y = 1200; self.addChild(instructionsText); // Start button var startButton = self.attachAsset('wizard', { 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 }); 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 castle.visible = true; wizard.visible = true; for (var i = 0; i < paths.length; i++) { paths[i].visible = true; } 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 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; } }; 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 Wizard = Container.expand(function () { var self = Container.call(this); var wizardGraphics = self.attachAsset('wizard', { anchorX: 0.5, anchorY: 1.0 }); self.attackCooldown = 0; self.level = 1; self.experience = 0; self.health = 100; self.maxHealth = 100; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } }; 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(); // 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(50); } } } 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: 0x87CEEB // Celeste (sky blue) background }); /**** * Game Code ****/ // Game state variables var gameStarted = false; var gameMenu; // Game arrays to track objects var enemies = []; var coins = []; var projectiles = []; // Create and show game menu gameMenu = game.addChild(new GameMenu()); // Create castle background var castle = game.addChild(LK.getAsset('castle', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: 2732 - 200 })); castle.visible = false; // Create 5 dirt paths leading toward the knight 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 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 // Calculate path center position to extend from screen edge to knight var centerX = knightX + Math.cos(angle) * (pathLength / 2); var centerY = knightY + Math.sin(angle) * (pathLength / 2); // Create stone path with extended length var path = game.addChild(LK.getAsset('stonePath', { anchorX: 0.5, anchorY: 0.5, x: centerX, y: centerY, scaleY: pathLength / 800, // Scale to desired length rotation: angle + Math.PI / 2 // Rotate path to point toward knight })); // Make paths slightly transparent so they don't overwhelm the game path.alpha = 0.7; path.visible = false; // Store path index for identification path.pathIndex = p; // Add touch handler for directional attacks (enemy elimination is now handled by attacks) path.down = function (x, y, obj) { // Attack in this path's direction wizard.attack(obj.pathIndex); // Visual feedback - flash the path briefly LK.effects.flashObject(obj, 0xFFFFFF, 300); }; paths.push(path); } // Create wizard var wizard = game.addChild(new Wizard()); wizard.x = knightX; wizard.y = knightY; 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 }); 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 }); 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 }); 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 }); 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 enemySpawnRate = 60; // 1 second at 60fps 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 () { // Only update game logic if game has started if (!gameStarted) { return; } // Spawn enemies enemySpawnTimer++; if (enemySpawnTimer >= enemySpawnRate) { enemySpawnTimer = 0; var enemy = game.addChild(new Enemy()); // Spawn enemy at a random path entrance var randomPathIndex; if (enemyKillCounter < 10) { // First 10 enemies spawn from center path only randomPathIndex = 0; // Center path } else if (enemyKillCounter < 30) { // Next 20 enemies (11-30) alternate between center and diagonal paths var alternatingPaths = [0, 1, 2]; // Center, diagonal right, diagonal left randomPathIndex = alternatingPaths[enemyKillCounter % 3]; } else { // After 30 enemies, spawn from any path but limit consecutive spawns with cooldown system var availablePaths = []; 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; } // If path has spawned less than 2 consecutive times, it's available if (pathConsecutiveSpawns[pathIdx] < 2) { availablePaths.push(pathIdx); } } // If no paths available (shouldn't happen), reset all paths if (availablePaths.length === 0) { availablePaths = [0, 1, 2, 3, 4]; for (var resetIdx = 0; resetIdx < 5; resetIdx++) { pathConsecutiveSpawns[resetIdx] = 0; pathLastSpawnTime[resetIdx] = -1; } } randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)]; } // Update path-specific spawn tracking if (pathLastSpawnTime[randomPathIndex] === -1 || randomPathIndex !== lastSpawnedPath) { // First spawn from this path or different from last path pathConsecutiveSpawns[randomPathIndex] = 1; } else { // Consecutive spawn from same 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); // Increase difficulty over time if (enemySpawnRate > 30) { enemySpawnRate -= 2; } } // 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; } // 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
@@ -532,8 +532,12 @@
var enemySpawnTimer = 0;
var enemySpawnRate = 60; // 1 second at 60fps
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;
@@ -574,32 +578,43 @@
// Next 20 enemies (11-30) alternate between center and diagonal paths
var alternatingPaths = [0, 1, 2]; // Center, diagonal right, diagonal left
randomPathIndex = alternatingPaths[enemyKillCounter % 3];
} else {
- // After 30 enemies, spawn from any path but limit consecutive spawns
+ // After 30 enemies, spawn from any path but limit consecutive spawns with cooldown system
var availablePaths = [];
for (var pathIdx = 0; pathIdx < 5; pathIdx++) {
- // If we've had 2 consecutive spawns from the same path, exclude it
- if (lastSpawnedPath === pathIdx && consecutiveSpawns >= 2) {
- continue; // Skip this path
+ // 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;
}
- availablePaths.push(pathIdx);
+ // If path has spawned less than 2 consecutive times, it's available
+ if (pathConsecutiveSpawns[pathIdx] < 2) {
+ availablePaths.push(pathIdx);
+ }
}
- // If no paths available (shouldn't happen), reset and use all paths
+ // If no paths available (shouldn't happen), reset all paths
if (availablePaths.length === 0) {
availablePaths = [0, 1, 2, 3, 4];
- consecutiveSpawns = 0;
- lastSpawnedPath = -1;
+ for (var resetIdx = 0; resetIdx < 5; resetIdx++) {
+ pathConsecutiveSpawns[resetIdx] = 0;
+ pathLastSpawnTime[resetIdx] = -1;
+ }
}
randomPathIndex = availablePaths[Math.floor(Math.random() * availablePaths.length)];
}
- // Update consecutive spawn tracking
- if (randomPathIndex === lastSpawnedPath) {
- consecutiveSpawns++;
+ // Update path-specific spawn tracking
+ if (pathLastSpawnTime[randomPathIndex] === -1 || randomPathIndex !== lastSpawnedPath) {
+ // First spawn from this path or different from last path
+ pathConsecutiveSpawns[randomPathIndex] = 1;
} else {
- consecutiveSpawns = 1;
- lastSpawnedPath = randomPathIndex;
+ // Consecutive spawn from same 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;