User prompt
al principio apareceran 2 enemigos y poco a poco comenzaran a parecer mas.
User prompt
los enemigos aparecen de poco a poco. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mayor separación entre las flechas de movimiento. El ataque fuerte se llamara patada. El ataque rápido se llamara golpe. Cuando el jugador realice un ataque rápido, el personaje realizará una animación de tirar un golpe. Cuando el jugador realice un ataque fuerte, el personaje realizará una animación de tirar una patada. Cuando el jugador realice el ataque especial, el personaje realizará una animación de atacar con la espada. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
los botenes de las flechas deben ser el doble de grandes.
User prompt
añadir movimiento tactil al juego, cuando el jugador toque el personaje se podra mover en cualquier direccion.
User prompt
Corrige el error obj.parent indefinido en el método Player down
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var localPos = self.parent.toLocal(obj.parent.toGlobal({' Line Number: 267
User prompt
eliminar las flechas para mover al personaje. el personaje se movera cuando el jugador lo toque hacia cualquier direccion.
User prompt
eliminar obstaculos del juego.
User prompt
la pantalla solo tendra un fondo, el fondo inferior.
User prompt
el fondo de la pantalla de divide entre un tercio de la pantalla hacia arriba y el resto hacia abajo.
User prompt
la imagen de la espada se vera dependiendo del lado del que salga el ataque especial.
User prompt
los enemigos rodean los obstáculos. cuando el jugador este cerca de perder aparecerán objetos de color verde que le pueden rellenar la barra de vida a la mitad o completa, dependiendo de si el objeto verde es pequeño o grande, el pequeño le dará la mitad de la barra y el grande la llena completamente. si el jugador o los enemigos se topan con un obstáculo tendrán que rodearlo. si el enemigo esta a la izquierda del jugador el personaje atacara a la izquierda, si esta a la derecha atacara a la derecha respectivamente. basta con presionar cualquier flecha una vez para que el jugador se mueva.
User prompt
los obstaculos son estaticos. el puntaje solo se obtiene al derrotar enemigos. aleatoriamente pueden aparecer pocos enemigos del lado izquierdo de la pantalla.
User prompt
solo se necesita mantener presionada cualquier flecha para que el jugador empiece a moverse. el jugador perdera cuando la barra de salud de la esquina superior izquierda llegue a vaciarse. el puntaje estara en la esquina superior derecha.
User prompt
el jugador solo se movera con las flechas hacia arriba, abajo, izquierda y derecha que estaran en la esquina inferior izquierda. los 3 ataques estaran en la esquina inferior derecha.
User prompt
el personaje que controla el jugador y los enemigos apareceran de igual forma pero en el centro de la pantalla. los ataques rapido, fuerte y el especial estaran en la esquina inferior izquierda de la pantalla. y el ataque especial se llamara espada.
Code edit (1 edits merged)
Please save this source code
User prompt
Blade Runner Quest
Initial prompt
un videojuego en 2d del tipo hack and slash donde el personaje comienza en el lado izquierdo de la pantalla y se tiene que mover hacia la derecha avanzando y evitando obstaculos y enemigos. al presionar 2 botones de ataque rapido y fuerte se defendera de los enemigos, y con un tercer boton usara una espada que funcionaria como ataque especial.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Boss = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 1.0, tint: 0xFFD700, // Gold tint for boss scaleX: 2.0, // Much larger size scaleY: 2.0 }); self.health = 300; // Very high health self.maxHealth = 300; self.damage = 50; // High damage self.moveSpeed = -1.5; // Moderate speed self.lastDamageTime = 0; self.attackTimer = 0; self.specialAttackTimer = 0; self.phase = 1; // Boss phase (1 or 2) self.phaseChanged = false; // Track if phase has changed self.isDying = false; // Track if boss is in death animation self.takeDamage = function (damage) { if (self.isDying) return; // Don't take damage during death animation self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 200); // Phase 2 transition when health drops to 50% if (self.health <= self.maxHealth / 2 && self.phase === 1) { self.phase = 2; self.phaseChanged = true; // Flash red to indicate phase change LK.effects.flashObject(self, 0xFF0000, 1000); // Increase speed and aggression self.moveSpeed = -2.5; self.damage = 70; // Scale up for phase 2 tween(self, { scaleX: 2.3, scaleY: 2.3, tint: 0xFF4500 }, { duration: 800, easing: tween.easeOut }); LK.getSound('special').play(); // Phase change sound } if (self.health <= 0) { self.isDying = true; self.health = 0; // Death animation tween(self, { alpha: 0, rotation: Math.PI * 2, scaleX: 0.5, scaleY: 0.5 }, { duration: 2000, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } LK.setScore(LK.getScore() + 500); // Huge points for boss scoreTxt.setText(LK.getScore()); levelComplete = true; LK.showYouWin(); // Player wins when boss is defeated } }); LK.getSound('hit').play(); // Death sound } }; self.update = function () { if (self.isDying) return; // Don't update during death animation if (player) { // More intelligent movement var moveX = player.x - self.x; var moveY = player.y - self.y; var distance = Math.sqrt(moveX * moveX + moveY * moveY); if (distance > 0) { moveX = moveX / distance * Math.abs(self.moveSpeed); moveY = moveY / distance * Math.abs(self.moveSpeed); } self.x += moveX; self.y += moveY; // Boss attacks based on phase self.attackTimer++; self.specialAttackTimer++; // Phase 1: Only punch attacks when close if (self.phase === 1) { if (distance <= 150 && self.attackTimer >= 120) { self.attackTimer = 0; player.takeDamage(self.damage); // Flash boss to show punch attack LK.effects.flashObject(self, 0xFFD700, 300); // Punch animation tween(enemyGraphics, { x: 20 }, { duration: 100, easing: tween.easeOut }); tween(enemyGraphics, { x: 0 }, { duration: 100, easing: tween.easeIn }); LK.getSound('hit').play(); // Punch sound } } // Phase 2: Punch attacks + kick attacks else if (self.phase === 2) { if (distance <= 150 && self.attackTimer >= 90) { self.attackTimer = 0; player.takeDamage(self.damage); // Alternating punch and kick attacks if (Math.random() < 0.5) { // Punch attack LK.effects.flashObject(self, 0xFF4500, 300); tween(enemyGraphics, { x: 25 }, { duration: 80, easing: tween.easeOut }); tween(enemyGraphics, { x: 0 }, { duration: 80, easing: tween.easeIn }); LK.getSound('hit').play(); // Punch sound } else { // Kick attack LK.effects.flashObject(self, 0xFF0000, 400); tween(enemyGraphics, { rotation: 0.3, y: enemyGraphics.y - 30 }, { duration: 120, easing: tween.easeOut }); tween(enemyGraphics, { rotation: 0, y: enemyGraphics.y }, { duration: 120, easing: tween.easeIn }); LK.getSound('slash').play(); // Kick sound } } } } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 1.0 }); self.health = 50; self.damage = 20; self.moveSpeed = -2; self.lastDamageTime = 0; self.attackCooldown = 0; self.attackRange = 100; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 100); if (self.health <= 0) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); // Spawn a new enemy when this one is defeated spawnEnemy(); } }; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } if (player) { // Simple movement towards player var moveX = player.x - self.x; var moveY = player.y - self.y; // Normalize movement speed var distance = Math.sqrt(moveX * moveX + moveY * moveY); // Attack if close enough and cooldown is ready if (distance <= 150 && self.attackTimer <= 0) { self.attackTimer = 120; // 2 second cooldown for close attacks player.takeDamage(self.damage); // Flash boss to show attack LK.effects.flashObject(self, 0xFF0000, 300); LK.getSound('hit').play(); // Enemy attack sound } if (distance > 0) { moveX = moveX / distance * Math.abs(self.moveSpeed); moveY = moveY / distance * Math.abs(self.moveSpeed); } self.x += moveX; self.y += moveY; } else { self.x += self.moveSpeed; } if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } } }; return self; }); var FastEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 1.0, tint: 0x00FF00 // Green tint to distinguish from regular enemy }); self.health = 25; // Lower health self.damage = 15; // Lower damage self.moveSpeed = -4; // Faster movement self.lastDamageTime = 0; self.attackCooldown = 0; self.attackRange = 80; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 100); if (self.health <= 0) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } LK.setScore(LK.getScore() + 15); // More points for faster enemy scoreTxt.setText(LK.getScore()); // Spawn a new enemy when this one is defeated spawnEnemy(); } }; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } if (player) { // Simple movement towards player var moveX = player.x - self.x; var moveY = player.y - self.y; // Normalize movement speed var distance = Math.sqrt(moveX * moveX + moveY * moveY); // Attack if close enough and cooldown is ready if (distance <= self.attackRange && self.attackCooldown <= 0) { self.attackCooldown = 60; // 1 second cooldown (faster than regular enemy) player.takeDamage(self.damage); // Flash enemy to show attack LK.effects.flashObject(self, 0x00FF00, 200); LK.getSound('slash').play(); // FastEnemy attack sound } if (distance > 0) { moveX = moveX / distance * Math.abs(self.moveSpeed); moveY = moveY / distance * Math.abs(self.moveSpeed); } self.x += moveX; self.y += moveY; } else { self.x += self.moveSpeed; } if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } } }; return self; }); var HealthPickup = Container.expand(function () { var self = Container.call(this); self.isLarge = false; self.healAmount = 0; self.init = function (isLarge) { self.isLarge = isLarge; if (isLarge) { var graphics = self.attachAsset('largeHealthPickup', { anchorX: 0.5, anchorY: 0.5 }); self.healAmount = 100; // Full heal } else { var graphics = self.attachAsset('smallHealthPickup', { anchorX: 0.5, anchorY: 0.5 }); self.healAmount = 50; // Half heal } }; self.update = function () { // Simple floating animation self.y += Math.sin(LK.ticks * 0.1) * 0.5; }; return self; }); var HeavyAttack = Container.expand(function () { var self = Container.call(this); var attackGraphics = self.attachAsset('heavyAttack', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 50; self.lifetime = 25; // Slightly longer than quick attack self.hasHit = false; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.destroy(); for (var i = attacks.length - 1; i >= 0; i--) { if (attacks[i] === self) { attacks.splice(i, 1); break; } } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); self.health = 100; self.maxHealth = 100; self.moveSpeed = 3; self.isAttacking = false; self.attackCooldown = 0; self.specialCooldown = 0; self.maxSpecialCooldown = 180; // 3 seconds at 60fps // Energy system for sword attacks self.maxEnergy = 100; self.energy = 100; self.energyCostPerAttack = 25; // Cost 25 energy per sword attack self.energyRechargeDelay = 180; // 3 seconds before recharge starts self.energyRechargeTimer = 0; // Timer for recharge delay self.energyRechargeRate = 2; // Energy points per frame when recharging // Combo system properties self.punchCombo = 0; // 0, 1, 2 for combo stages self.kickCombo = 0; // 0, 1, 2 for combo stages self.punchComboTimer = 0; // Reset timer for punch combo self.kickComboTimer = 0; // Reset timer for kick combo self.comboResetTime = 60; // 1 second at 60fps // Jump and gravity properties self.velocityY = 0; self.gravity = 0.8; self.jumpPower = -18; self.groundY = 1800; // Lower ground level self.isOnGround = true; // Smooth movement properties self.velocityX = 0; self.acceleration = 0.5; self.deceleration = 0.8; self.maxSpeed = 5; self.runMultiplier = 1.8; self.isRunning = false; self.takeDamage = function (damage) { self.health -= damage; if (self.health <= 0) { self.health = 0; LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } else { LK.effects.flashObject(self, 0xFF0000, 300); } }; self.quickAttack = function () { if (self.attackCooldown > 0 || self.isAttacking) return; self.isAttacking = true; // Reset combo timer self.punchComboTimer = self.comboResetTime; var attack; var animationDuration; var cooldownTime; // Execute combo based on current stage if (self.punchCombo === 0) { // First hit - quick punch self.attackCooldown = 15; // Quick cooldown animationDuration = 150; // Quick punch animation tween(playerGraphics, { x: 10 }, { duration: 75, easing: tween.easeOut }); tween(playerGraphics, { x: 0 }, { duration: 75, easing: tween.easeIn }); attack = new QuickAttack(); LK.getSound('hit').play(); } else if (self.punchCombo === 1) { // Second hit - spinning punch self.attackCooldown = 25; // Medium cooldown animationDuration = 300; // Spinning animation tween(playerGraphics, { rotation: Math.PI * 2, scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut }); tween(playerGraphics, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); attack = new SpinAttack(); LK.getSound('hit').play(); } else { // Third hit - heavy punch self.attackCooldown = 40; // Long cooldown animationDuration = 500; // Heavy punch animation tween(playerGraphics, { x: 25, scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut }); tween(playerGraphics, { x: 0, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeIn }); attack = new HeavyAttack(); LK.getSound('hit').play(); } // Find closest enemy to determine attack direction var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } if (closestEnemy) { if (closestEnemy.x < self.x) { // Enemy is to the left, attack left attack.x = self.x - 60; } else { // Enemy is to the right, attack right attack.x = self.x + 60; } } else { attack.x = self.x + 60; } attack.y = self.y - 40; attacks.push(attack); game.addChild(attack); // Advance combo self.punchCombo = (self.punchCombo + 1) % 3; LK.setTimeout(function () { self.isAttacking = false; }, animationDuration); }; self.heavyAttack = function () { if (self.attackCooldown > 0 || self.isAttacking) return; self.isAttacking = true; // Reset combo timer self.kickComboTimer = self.comboResetTime; var attack; var animationDuration; var cooldownTime; // Execute combo based on current stage if (self.kickCombo === 0) { // First hit - quick kick self.attackCooldown = 20; // Quick cooldown animationDuration = 200; // Quick kick animation tween(playerGraphics, { rotation: 0.1 }, { duration: 100, easing: tween.easeOut }); tween(playerGraphics, { rotation: 0 }, { duration: 100, easing: tween.easeIn }); attack = new QuickAttack(); LK.getSound('hit').play(); } else if (self.kickCombo === 1) { // Second hit - spinning kick self.attackCooldown = 35; // Medium cooldown animationDuration = 400; // Spinning kick animation tween(playerGraphics, { rotation: Math.PI * 2, y: playerGraphics.y - 20 }, { duration: 250, easing: tween.easeOut }); tween(playerGraphics, { rotation: 0, y: playerGraphics.y }, { duration: 150, easing: tween.easeIn }); attack = new SpinAttack(); LK.getSound('hit').play(); } else { // Third hit - heavy kick self.attackCooldown = 50; // Long cooldown animationDuration = 600; // Heavy kick animation tween(playerGraphics, { rotation: 0.3, scaleX: 1.2, scaleY: 1.2 }, { duration: 250, easing: tween.easeOut }); tween(playerGraphics, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 350, easing: tween.easeIn }); attack = new HeavyAttack(); LK.getSound('hit').play(); } // Find closest enemy to determine attack direction var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } if (closestEnemy) { if (closestEnemy.x < self.x) { // Enemy is to the left, attack left attack.x = self.x - 75; } else { // Enemy is to the right, attack right attack.x = self.x + 75; } } else { attack.x = self.x + 75; } attack.y = self.y - 50; attacks.push(attack); game.addChild(attack); // Advance combo self.kickCombo = (self.kickCombo + 1) % 3; LK.setTimeout(function () { self.isAttacking = false; }, animationDuration); }; self.specialAttack = function () { if (self.specialCooldown > 0 || self.isAttacking || self.energy < self.energyCostPerAttack) return; self.isAttacking = true; self.specialCooldown = self.maxSpecialCooldown; // Consume energy for sword attack self.energy -= self.energyCostPerAttack; self.energyRechargeTimer = self.energyRechargeDelay; // Reset recharge timer // Sword swing animation - dramatic sweep tween(playerGraphics, { rotation: -0.5, scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut }); tween(playerGraphics, { rotation: 0.5 }, { duration: 200, easing: tween.easeInOut }); tween(playerGraphics, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); var attack = new SpecialAttack(); // Find closest enemy to determine attack direction var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2)); if (distance < closestDistance) { closestDistance = distance; closestEnemy = enemy; } } if (closestEnemy) { if (closestEnemy.x < self.x) { // Enemy is to the left, attack left attack.x = self.x - 100; attack.flipLeft = true; } else { // Enemy is to the right, attack right attack.x = self.x + 100; attack.flipLeft = false; } } else { attack.x = self.x + 100; attack.flipLeft = false; } attack.y = self.y - 60; attacks.push(attack); game.addChild(attack); LK.getSound('slash').play(); LK.setTimeout(function () { self.isAttacking = false; }, 600); }; self.moveUp = function () { self.y -= self.moveSpeed * 3; if (self.y < 120) self.y = 120; }; self.moveDown = function () { self.y += self.moveSpeed * 3; if (self.y > 2612) self.y = 2612; }; self.moveLeft = function () { self.x -= self.moveSpeed * 3; if (self.x < 40) self.x = 40; }; self.moveRight = function () { self.x += self.moveSpeed * 3; if (self.x > 2008) self.x = 2008; }; self.jump = function () { if (self.isOnGround) { self.velocityY = self.jumpPower; self.isOnGround = false; } }; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } if (self.specialCooldown > 0) { self.specialCooldown--; } // Update energy system if (self.energyRechargeTimer > 0) { self.energyRechargeTimer--; } else if (self.energy < self.maxEnergy) { // Recharge energy after delay self.energy += self.energyRechargeRate; if (self.energy > self.maxEnergy) { self.energy = self.maxEnergy; } } // Update combo timers if (self.punchComboTimer > 0) { self.punchComboTimer--; if (self.punchComboTimer === 0) { self.punchCombo = 0; // Reset punch combo } } if (self.kickComboTimer > 0) { self.kickComboTimer--; if (self.kickComboTimer === 0) { self.kickCombo = 0; // Reset kick combo } } // Apply gravity with more realistic physics self.velocityY += self.gravity; self.y += self.velocityY; // Check ground collision if (self.y >= self.groundY) { self.y = self.groundY; self.velocityY = 0; self.isOnGround = true; } // Horizontal movement with acceleration/deceleration var targetSpeed = 0; self.isRunning = false; if (isLeftPressed) { targetSpeed = -self.maxSpeed; if (leftPressTime > 30) { // Running after half second self.isRunning = true; targetSpeed *= self.runMultiplier; } } if (isRightPressed) { targetSpeed = self.maxSpeed; if (rightPressTime > 30) { // Running after half second self.isRunning = true; targetSpeed *= self.runMultiplier; } } // Apply acceleration or deceleration if (targetSpeed !== 0) { // Accelerate towards target speed if (self.velocityX < targetSpeed) { self.velocityX += self.acceleration; if (self.velocityX > targetSpeed) self.velocityX = targetSpeed; } else if (self.velocityX > targetSpeed) { self.velocityX -= self.acceleration; if (self.velocityX < targetSpeed) self.velocityX = targetSpeed; } } else { // Decelerate to stop if (self.velocityX > 0) { self.velocityX -= self.deceleration; if (self.velocityX < 0) self.velocityX = 0; } else if (self.velocityX < 0) { self.velocityX += self.deceleration; if (self.velocityX > 0) self.velocityX = 0; } } // Apply horizontal movement self.x += self.velocityX; // Boundary checks if (self.x < 40) { self.x = 40; self.velocityX = 0; } if (self.x > 2008) { self.x = 2008; self.velocityX = 0; } // Jump when up is pressed if (isUpPressed) { self.jump(); } }; return self; }); var QuickAttack = Container.expand(function () { var self = Container.call(this); var attackGraphics = self.attachAsset('quickAttack', { anchorX: 0.5, anchorY: 0.5 }); self.damage = 25; self.lifetime = 15; // Quarter second at 60fps self.hasHit = false; self.update = function () { self.lifetime--; if (self.lifetime <= 0) { self.destroy(); for (var i = attacks.length - 1; i >= 0; i--) { if (attacks[i] === self) { attacks.splice(i, 1); break; } } } }; return self; }); var SpecialAttack = Container.expand(function () { var self = Container.call(this); self.attackGraphics = null; self.flipLeft = false; self.damage = 100; self.lifetime = 35; // Longest lasting attack self.hasHit = false; self.setDirection = function (flipLeft) { if (self.attackGraphics) { self.removeChild(self.attackGraphics); } if (flipLeft) { self.attackGraphics = self.attachAsset('specialAttack', { anchorX: 0.5, anchorY: 0.5, flipX: 0 }); } else { self.attackGraphics = self.attachAsset('specialAttack', { anchorX: 0.5, anchorY: 0.5, flipX: 1 }); } }; // Initialize with default direction (right) self.setDirection(false); self.update = function () { // Update direction if flipLeft property changes if (self.flipLeft !== undefined && self.attackGraphics) { self.setDirection(self.flipLeft); self.flipLeft = undefined; // Reset to avoid repeated updates } self.lifetime--; if (self.lifetime <= 0) { self.destroy(); for (var i = attacks.length - 1; i >= 0; i--) { if (attacks[i] === self) { attacks.splice(i, 1); break; } } } }; return self; }); var SpinAttack = Container.expand(function () { var self = Container.call(this); var attackGraphics = self.attachAsset('specialAttack', { anchorX: 0.5, anchorY: 0.5, tint: 0x00FFFF // Cyan tint for spin attack }); self.damage = 35; // Medium damage self.lifetime = 20; // Medium duration self.hasHit = false; self.update = function () { self.lifetime--; // Spinning animation attackGraphics.rotation += 0.3; if (self.lifetime <= 0) { self.destroy(); for (var i = attacks.length - 1; i >= 0; i--) { if (attacks[i] === self) { attacks.splice(i, 1); break; } } } }; return self; }); var TankEnemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 1.0, tint: 0xFF0000, // Red tint to distinguish from regular enemy scaleX: 1.3, // Larger size scaleY: 1.3 }); self.health = 100; // Higher health self.damage = 35; // Higher damage self.moveSpeed = -1; // Slower movement self.lastDamageTime = 0; self.attackCooldown = 0; self.attackRange = 120; self.takeDamage = function (damage) { self.health -= damage; LK.effects.flashObject(self, 0xFFFFFF, 100); if (self.health <= 0) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } LK.setScore(LK.getScore() + 25); // More points for tough enemy scoreTxt.setText(LK.getScore()); // Spawn a new enemy when this one is defeated spawnEnemy(); } }; self.update = function () { if (self.attackCooldown > 0) { self.attackCooldown--; } if (player) { // Simple movement towards player var moveX = player.x - self.x; var moveY = player.y - self.y; // Normalize movement speed var distance = Math.sqrt(moveX * moveX + moveY * moveY); // Attack if close enough and cooldown is ready if (distance <= self.attackRange && self.attackCooldown <= 0) { self.attackCooldown = 120; // 2 second cooldown (slower but more powerful) player.takeDamage(self.damage); // Flash enemy to show attack LK.effects.flashObject(self, 0xFF0000, 300); LK.getSound('special').play(); // TankEnemy heavy attack sound } if (distance > 0) { moveX = moveX / distance * Math.abs(self.moveSpeed); moveY = moveY / distance * Math.abs(self.moveSpeed); } self.x += moveX; self.y += moveY; } else { self.x += self.moveSpeed; } if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { self.destroy(); for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i] === self) { enemies.splice(i, 1); break; } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F4F }); /**** * Game Code ****/ // Create background - only bottom background covering full screen var bottomBackground = LK.getAsset('backgroundBottom', { width: 2048, height: 2732, // Full screen height color: 0x228B22, shape: 'box', x: 0, y: 0 }); game.addChild(bottomBackground); var player; var enemies = []; var attacks = []; var spawnTimer = 0; var gameSpeed = 1; var isUpPressed = false; var isDownPressed = false; var isLeftPressed = false; var isRightPressed = false; var leftPressTime = 0; var rightPressTime = 0; var healthPickups = []; // UI Elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(1, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -50; scoreTxt.y = 50; var healthBarBg = LK.getAsset('healthBarBg', { width: 300, height: 30, color: 0xFF0000, shape: 'box', x: 150, y: 80 }); LK.gui.topLeft.addChild(healthBarBg); var healthBar = LK.getAsset('healthBar', { width: 300, height: 30, color: 0x00FF00, shape: 'box', x: 150, y: 80 }); LK.gui.topLeft.addChild(healthBar); var healthTxt = new Text2('Health', { size: 40, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); healthTxt.x = 150; healthTxt.y = 50; LK.gui.topLeft.addChild(healthTxt); var specialCooldownTxt = new Text2('Special Ready', { size: 40, fill: 0x9932CC }); specialCooldownTxt.anchor.set(0, 0); specialCooldownTxt.x = 50; specialCooldownTxt.y = 170; LK.gui.topLeft.addChild(specialCooldownTxt); // Energy bar for sword attacks var energyBarBg = LK.getAsset('healthBarBg', { width: 300, height: 25, color: 0x4B0082, shape: 'box', x: 150, y: 130 }); LK.gui.topLeft.addChild(energyBarBg); var energyBar = LK.getAsset('healthBar', { width: 300, height: 25, color: 0x9932CC, shape: 'box', x: 150, y: 130 }); LK.gui.topLeft.addChild(energyBar); var energyTxt = new Text2('Energy', { size: 35, fill: 0x9932CC }); energyTxt.anchor.set(0, 0); energyTxt.x = 150; energyTxt.y = 100; LK.gui.topLeft.addChild(energyTxt); // Boss health bar (initially hidden) var bossHealthBarBg = LK.getAsset('healthBarBg', { width: 600, height: 40, color: 0xFF0000, shape: 'box', x: 1024, y: 150 }); bossHealthBarBg.anchor.set(0.5, 0); bossHealthBarBg.visible = false; game.addChild(bossHealthBarBg); var bossHealthBar = LK.getAsset('healthBar', { width: 600, height: 40, color: 0xFFD700, shape: 'box', x: 1024, y: 150 }); bossHealthBar.anchor.set(0.5, 0); bossHealthBar.visible = false; game.addChild(bossHealthBar); var bossHealthTxt = new Text2('BOSS', { size: 60, fill: 0xFFD700 }); bossHealthTxt.anchor.set(0.5, 1); bossHealthTxt.x = 1024; bossHealthTxt.y = 140; bossHealthTxt.visible = false; game.addChild(bossHealthTxt); // Movement arrow buttons (bottom left) var upBtn = new Text2('↑', { size: 200, fill: 0xFFFFFF }); upBtn.anchor.set(0.5, 1); LK.gui.bottomLeft.addChild(upBtn); upBtn.x = 120; upBtn.y = -180; var downBtn = new Text2('↓', { size: 200, fill: 0xFFFFFF }); downBtn.anchor.set(0.5, 1); LK.gui.bottomLeft.addChild(downBtn); downBtn.x = 120; downBtn.y = -50; var leftBtn = new Text2('←', { size: 200, fill: 0xFFFFFF }); leftBtn.anchor.set(0.5, 1); LK.gui.bottomLeft.addChild(leftBtn); leftBtn.x = 50; leftBtn.y = -115; var rightBtn = new Text2('→', { size: 200, fill: 0xFFFFFF }); rightBtn.anchor.set(0.5, 1); LK.gui.bottomLeft.addChild(rightBtn); rightBtn.x = 190; rightBtn.y = -115; // Attack buttons (bottom right) var quickBtn = new Text2('Golpe', { size: 80, fill: 0xFFD700 }); quickBtn.anchor.set(1, 1); LK.gui.bottomRight.addChild(quickBtn); quickBtn.x = -50; quickBtn.y = -50; var heavyBtn = new Text2('Patada', { size: 80, fill: 0xFF6347 }); heavyBtn.anchor.set(1, 1); LK.gui.bottomRight.addChild(heavyBtn); heavyBtn.x = -50; heavyBtn.y = -150; var specialBtn = new Text2('Espada', { size: 80, fill: 0x9932CC }); specialBtn.anchor.set(1, 1); LK.gui.bottomRight.addChild(specialBtn); specialBtn.x = -50; specialBtn.y = -250; // Level progression variables var levelDistance = 0; var maxLevelDistance = 1000; // Distance to complete level var bossSpawned = false; var levelComplete = false; // Initialize player player = game.addChild(new Player()); player.x = 1024; // Center horizontally (2048/2) player.y = 1800; // Lower position // Level progress UI var progressTxt = new Text2('Progress: 0%', { size: 50, fill: 0xFFFFFF }); progressTxt.anchor.set(0.5, 0); progressTxt.x = 0; progressTxt.y = 50; LK.gui.top.addChild(progressTxt); // Button event handlers quickBtn.down = function (x, y, obj) { if (player) { player.quickAttack(); } }; heavyBtn.down = function (x, y, obj) { if (player) { player.heavyAttack(); } }; specialBtn.down = function (x, y, obj) { if (player) { player.specialAttack(); } }; // Movement button event handlers - single press movement upBtn.down = function (x, y, obj) { isUpPressed = true; }; downBtn.down = function (x, y, obj) { if (player) { var newY = player.y + player.moveSpeed * 10; if (newY > 2612) newY = 2612; player.y = newY; } }; leftBtn.down = function (x, y, obj) { isLeftPressed = true; leftPressTime = 0; }; rightBtn.down = function (x, y, obj) { isRightPressed = true; rightPressTime = 0; }; // Spawn enemies only function spawnEnemy() { // Don't spawn regular enemies if boss is spawned or level is complete if (bossSpawned || levelComplete) return; // Randomly choose enemy type var enemyType = Math.random(); var enemy; if (enemyType < 0.5) { enemy = new Enemy(); // Regular enemy - 50% chance } else if (enemyType < 0.8) { enemy = new FastEnemy(); // Fast enemy - 30% chance } else { enemy = new TankEnemy(); // Tank enemy - 20% chance } // Spawn enemy from right side if (Math.random() < 0.8) { enemy.x = 2048 + 100; enemy.y = 1800 - Math.random() * 600 + 300; // Lower area spawn // Start enemy invisible and fade in gradually enemy.alpha = 0; tween(enemy, { alpha: 1 }, { duration: 1000, easing: tween.easeIn }); enemies.push(enemy); game.addChild(enemy); } else { // Spawn enemy from left side enemy.x = -100; enemy.y = 1800 - Math.random() * 600 + 300; // Lower area spawn enemy.moveSpeed = Math.abs(enemy.moveSpeed); // Make moveSpeed positive for left-to-right movement // Start enemy invisible and fade in gradually enemy.alpha = 0; tween(enemy, { alpha: 1 }, { duration: 1000, easing: tween.easeIn }); enemies.push(enemy); game.addChild(enemy); } } // Spawn initial enemies at game start function spawnInitialEnemies() { for (var i = 0; i < 2; i++) { spawnEnemy(); } } // Call initial enemy spawn spawnInitialEnemies(); // Start background music LK.playMusic('Sonidofondo'); function spawnBoss() { if (bossSpawned) return; bossSpawned = true; var boss = new Boss(); boss.x = 2048 + 200; // Spawn from right side boss.y = 1800; // Lower position boss.alpha = 0; // Dramatic boss entrance tween(boss, { alpha: 1, x: 1800 }, { duration: 2000, easing: tween.easeOut }); // Show boss health bar bossHealthBarBg.visible = true; bossHealthBar.visible = true; bossHealthTxt.visible = true; enemies.push(boss); game.addChild(boss); } game.update = function () { // Update press time tracking for running if (isLeftPressed) leftPressTime++; if (isRightPressed) rightPressTime++; // Update game speed over time gameSpeed += 0.001; // Update level progression if (!levelComplete) { levelDistance += gameSpeed; var progressPercent = Math.min(100, levelDistance / maxLevelDistance * 100); progressTxt.setText('Progress: ' + Math.floor(progressPercent) + '%'); // Spawn boss after 2 minutes (7200 ticks at 60fps) if (LK.ticks >= 7200 && !bossSpawned) { spawnBoss(); } } // Enemy spawning is now handled when enemies are defeated (see Enemy class takeDamage method) // Update UI if (player) { // Update health bar var healthPercent = player.health / player.maxHealth; healthBar.width = 300 * healthPercent; healthBar.tint = healthPercent > 0.5 ? 0x00FF00 : healthPercent > 0.25 ? 0xFFFF00 : 0xFF0000; // Update energy bar var energyPercent = player.energy / player.maxEnergy; energyBar.width = 300 * energyPercent; energyBar.tint = energyPercent > 0.6 ? 0x9932CC : energyPercent > 0.3 ? 0xFFFF00 : 0xFF0000; if (player.specialCooldown > 0) { specialCooldownTxt.setText('Special: ' + Math.ceil(player.specialCooldown / 60) + 's'); } else if (player.energy < player.energyCostPerAttack) { specialCooldownTxt.setText('Low Energy'); } else { specialCooldownTxt.setText('Special Ready'); } // Check if health is zero for game over if (player.health <= 0) { LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } } // Update boss health bar if (bossSpawned && enemies.length > 0) { for (var i = 0; i < enemies.length; i++) { if (enemies[i].maxHealth && enemies[i].maxHealth === 300) { // Boss detection var boss = enemies[i]; var bossHealthPercent = boss.health / boss.maxHealth; bossHealthBar.width = 600 * bossHealthPercent; bossHealthBar.tint = bossHealthPercent > 0.5 ? 0xFFD700 : bossHealthPercent > 0.25 ? 0xFFFF00 : 0xFF0000; break; } } } // Enemy attacks are now handled in their individual update methods // Spawn health pickups when player health is low if (player && player.health < 30 && Math.random() < 0.002) { var isLarge = Math.random() < 0.3; // 30% chance for large pickup var pickup = new HealthPickup(); pickup.init(isLarge); pickup.x = 200 + Math.random() * 1600; pickup.y = 200 + Math.random() * 2200; healthPickups.push(pickup); game.addChild(pickup); } // Check collisions between player and health pickups for (var i = healthPickups.length - 1; i >= 0; i--) { var pickup = healthPickups[i]; if (player && player.intersects(pickup)) { if (pickup.isLarge) { player.health = player.maxHealth; // Full heal } else { player.health = Math.min(player.maxHealth, player.health + 50); // Half heal } pickup.destroy(); healthPickups.splice(i, 1); } } // Check collisions between attacks and enemies for (var i = attacks.length - 1; i >= 0; i--) { var attack = attacks[i]; if (attack.hasHit) continue; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (attack.intersects(enemy)) { enemy.takeDamage(attack.damage); attack.hasHit = true; // Special visual effect for sword attacks if (attack.damage >= 100) { LK.effects.flashObject(enemy, 0x9932CC, 500); tween(enemy, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut }); tween(enemy, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeIn }); } break; } } } // Score is only updated when enemies are defeated }; leftBtn.up = function (x, y, obj) { isLeftPressed = false; leftPressTime = 0; }; rightBtn.up = function (x, y, obj) { isRightPressed = false; rightPressTime = 0; }; upBtn.up = function (x, y, obj) { isUpPressed = false; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0,
tint: 0xFFD700,
// Gold tint for boss
scaleX: 2.0,
// Much larger size
scaleY: 2.0
});
self.health = 300; // Very high health
self.maxHealth = 300;
self.damage = 50; // High damage
self.moveSpeed = -1.5; // Moderate speed
self.lastDamageTime = 0;
self.attackTimer = 0;
self.specialAttackTimer = 0;
self.phase = 1; // Boss phase (1 or 2)
self.phaseChanged = false; // Track if phase has changed
self.isDying = false; // Track if boss is in death animation
self.takeDamage = function (damage) {
if (self.isDying) return; // Don't take damage during death animation
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 200);
// Phase 2 transition when health drops to 50%
if (self.health <= self.maxHealth / 2 && self.phase === 1) {
self.phase = 2;
self.phaseChanged = true;
// Flash red to indicate phase change
LK.effects.flashObject(self, 0xFF0000, 1000);
// Increase speed and aggression
self.moveSpeed = -2.5;
self.damage = 70;
// Scale up for phase 2
tween(self, {
scaleX: 2.3,
scaleY: 2.3,
tint: 0xFF4500
}, {
duration: 800,
easing: tween.easeOut
});
LK.getSound('special').play(); // Phase change sound
}
if (self.health <= 0) {
self.isDying = true;
self.health = 0;
// Death animation
tween(self, {
alpha: 0,
rotation: Math.PI * 2,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
LK.setScore(LK.getScore() + 500); // Huge points for boss
scoreTxt.setText(LK.getScore());
levelComplete = true;
LK.showYouWin(); // Player wins when boss is defeated
}
});
LK.getSound('hit').play(); // Death sound
}
};
self.update = function () {
if (self.isDying) return; // Don't update during death animation
if (player) {
// More intelligent movement
var moveX = player.x - self.x;
var moveY = player.y - self.y;
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
if (distance > 0) {
moveX = moveX / distance * Math.abs(self.moveSpeed);
moveY = moveY / distance * Math.abs(self.moveSpeed);
}
self.x += moveX;
self.y += moveY;
// Boss attacks based on phase
self.attackTimer++;
self.specialAttackTimer++;
// Phase 1: Only punch attacks when close
if (self.phase === 1) {
if (distance <= 150 && self.attackTimer >= 120) {
self.attackTimer = 0;
player.takeDamage(self.damage);
// Flash boss to show punch attack
LK.effects.flashObject(self, 0xFFD700, 300);
// Punch animation
tween(enemyGraphics, {
x: 20
}, {
duration: 100,
easing: tween.easeOut
});
tween(enemyGraphics, {
x: 0
}, {
duration: 100,
easing: tween.easeIn
});
LK.getSound('hit').play(); // Punch sound
}
}
// Phase 2: Punch attacks + kick attacks
else if (self.phase === 2) {
if (distance <= 150 && self.attackTimer >= 90) {
self.attackTimer = 0;
player.takeDamage(self.damage);
// Alternating punch and kick attacks
if (Math.random() < 0.5) {
// Punch attack
LK.effects.flashObject(self, 0xFF4500, 300);
tween(enemyGraphics, {
x: 25
}, {
duration: 80,
easing: tween.easeOut
});
tween(enemyGraphics, {
x: 0
}, {
duration: 80,
easing: tween.easeIn
});
LK.getSound('hit').play(); // Punch sound
} else {
// Kick attack
LK.effects.flashObject(self, 0xFF0000, 400);
tween(enemyGraphics, {
rotation: 0.3,
y: enemyGraphics.y - 30
}, {
duration: 120,
easing: tween.easeOut
});
tween(enemyGraphics, {
rotation: 0,
y: enemyGraphics.y
}, {
duration: 120,
easing: tween.easeIn
});
LK.getSound('slash').play(); // Kick sound
}
}
}
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0
});
self.health = 50;
self.damage = 20;
self.moveSpeed = -2;
self.lastDamageTime = 0;
self.attackCooldown = 0;
self.attackRange = 100;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Spawn a new enemy when this one is defeated
spawnEnemy();
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (player) {
// Simple movement towards player
var moveX = player.x - self.x;
var moveY = player.y - self.y;
// Normalize movement speed
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
// Attack if close enough and cooldown is ready
if (distance <= 150 && self.attackTimer <= 0) {
self.attackTimer = 120; // 2 second cooldown for close attacks
player.takeDamage(self.damage);
// Flash boss to show attack
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('hit').play(); // Enemy attack sound
}
if (distance > 0) {
moveX = moveX / distance * Math.abs(self.moveSpeed);
moveY = moveY / distance * Math.abs(self.moveSpeed);
}
self.x += moveX;
self.y += moveY;
} else {
self.x += self.moveSpeed;
}
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
return self;
});
var FastEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0,
tint: 0x00FF00 // Green tint to distinguish from regular enemy
});
self.health = 25; // Lower health
self.damage = 15; // Lower damage
self.moveSpeed = -4; // Faster movement
self.lastDamageTime = 0;
self.attackCooldown = 0;
self.attackRange = 80;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
LK.setScore(LK.getScore() + 15); // More points for faster enemy
scoreTxt.setText(LK.getScore());
// Spawn a new enemy when this one is defeated
spawnEnemy();
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (player) {
// Simple movement towards player
var moveX = player.x - self.x;
var moveY = player.y - self.y;
// Normalize movement speed
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
// Attack if close enough and cooldown is ready
if (distance <= self.attackRange && self.attackCooldown <= 0) {
self.attackCooldown = 60; // 1 second cooldown (faster than regular enemy)
player.takeDamage(self.damage);
// Flash enemy to show attack
LK.effects.flashObject(self, 0x00FF00, 200);
LK.getSound('slash').play(); // FastEnemy attack sound
}
if (distance > 0) {
moveX = moveX / distance * Math.abs(self.moveSpeed);
moveY = moveY / distance * Math.abs(self.moveSpeed);
}
self.x += moveX;
self.y += moveY;
} else {
self.x += self.moveSpeed;
}
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
return self;
});
var HealthPickup = Container.expand(function () {
var self = Container.call(this);
self.isLarge = false;
self.healAmount = 0;
self.init = function (isLarge) {
self.isLarge = isLarge;
if (isLarge) {
var graphics = self.attachAsset('largeHealthPickup', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 100; // Full heal
} else {
var graphics = self.attachAsset('smallHealthPickup', {
anchorX: 0.5,
anchorY: 0.5
});
self.healAmount = 50; // Half heal
}
};
self.update = function () {
// Simple floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
};
return self;
});
var HeavyAttack = Container.expand(function () {
var self = Container.call(this);
var attackGraphics = self.attachAsset('heavyAttack', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 50;
self.lifetime = 25; // Slightly longer than quick attack
self.hasHit = false;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
for (var i = attacks.length - 1; i >= 0; i--) {
if (attacks[i] === self) {
attacks.splice(i, 1);
break;
}
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.health = 100;
self.maxHealth = 100;
self.moveSpeed = 3;
self.isAttacking = false;
self.attackCooldown = 0;
self.specialCooldown = 0;
self.maxSpecialCooldown = 180; // 3 seconds at 60fps
// Energy system for sword attacks
self.maxEnergy = 100;
self.energy = 100;
self.energyCostPerAttack = 25; // Cost 25 energy per sword attack
self.energyRechargeDelay = 180; // 3 seconds before recharge starts
self.energyRechargeTimer = 0; // Timer for recharge delay
self.energyRechargeRate = 2; // Energy points per frame when recharging
// Combo system properties
self.punchCombo = 0; // 0, 1, 2 for combo stages
self.kickCombo = 0; // 0, 1, 2 for combo stages
self.punchComboTimer = 0; // Reset timer for punch combo
self.kickComboTimer = 0; // Reset timer for kick combo
self.comboResetTime = 60; // 1 second at 60fps
// Jump and gravity properties
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -18;
self.groundY = 1800; // Lower ground level
self.isOnGround = true;
// Smooth movement properties
self.velocityX = 0;
self.acceleration = 0.5;
self.deceleration = 0.8;
self.maxSpeed = 5;
self.runMultiplier = 1.8;
self.isRunning = false;
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
} else {
LK.effects.flashObject(self, 0xFF0000, 300);
}
};
self.quickAttack = function () {
if (self.attackCooldown > 0 || self.isAttacking) return;
self.isAttacking = true;
// Reset combo timer
self.punchComboTimer = self.comboResetTime;
var attack;
var animationDuration;
var cooldownTime;
// Execute combo based on current stage
if (self.punchCombo === 0) {
// First hit - quick punch
self.attackCooldown = 15; // Quick cooldown
animationDuration = 150;
// Quick punch animation
tween(playerGraphics, {
x: 10
}, {
duration: 75,
easing: tween.easeOut
});
tween(playerGraphics, {
x: 0
}, {
duration: 75,
easing: tween.easeIn
});
attack = new QuickAttack();
LK.getSound('hit').play();
} else if (self.punchCombo === 1) {
// Second hit - spinning punch
self.attackCooldown = 25; // Medium cooldown
animationDuration = 300;
// Spinning animation
tween(playerGraphics, {
rotation: Math.PI * 2,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut
});
tween(playerGraphics, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
attack = new SpinAttack();
LK.getSound('hit').play();
} else {
// Third hit - heavy punch
self.attackCooldown = 40; // Long cooldown
animationDuration = 500;
// Heavy punch animation
tween(playerGraphics, {
x: 25,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut
});
tween(playerGraphics, {
x: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
attack = new HeavyAttack();
LK.getSound('hit').play();
}
// Find closest enemy to determine attack direction
var closestEnemy = null;
var closestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < closestDistance) {
closestDistance = distance;
closestEnemy = enemy;
}
}
if (closestEnemy) {
if (closestEnemy.x < self.x) {
// Enemy is to the left, attack left
attack.x = self.x - 60;
} else {
// Enemy is to the right, attack right
attack.x = self.x + 60;
}
} else {
attack.x = self.x + 60;
}
attack.y = self.y - 40;
attacks.push(attack);
game.addChild(attack);
// Advance combo
self.punchCombo = (self.punchCombo + 1) % 3;
LK.setTimeout(function () {
self.isAttacking = false;
}, animationDuration);
};
self.heavyAttack = function () {
if (self.attackCooldown > 0 || self.isAttacking) return;
self.isAttacking = true;
// Reset combo timer
self.kickComboTimer = self.comboResetTime;
var attack;
var animationDuration;
var cooldownTime;
// Execute combo based on current stage
if (self.kickCombo === 0) {
// First hit - quick kick
self.attackCooldown = 20; // Quick cooldown
animationDuration = 200;
// Quick kick animation
tween(playerGraphics, {
rotation: 0.1
}, {
duration: 100,
easing: tween.easeOut
});
tween(playerGraphics, {
rotation: 0
}, {
duration: 100,
easing: tween.easeIn
});
attack = new QuickAttack();
LK.getSound('hit').play();
} else if (self.kickCombo === 1) {
// Second hit - spinning kick
self.attackCooldown = 35; // Medium cooldown
animationDuration = 400;
// Spinning kick animation
tween(playerGraphics, {
rotation: Math.PI * 2,
y: playerGraphics.y - 20
}, {
duration: 250,
easing: tween.easeOut
});
tween(playerGraphics, {
rotation: 0,
y: playerGraphics.y
}, {
duration: 150,
easing: tween.easeIn
});
attack = new SpinAttack();
LK.getSound('hit').play();
} else {
// Third hit - heavy kick
self.attackCooldown = 50; // Long cooldown
animationDuration = 600;
// Heavy kick animation
tween(playerGraphics, {
rotation: 0.3,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 250,
easing: tween.easeOut
});
tween(playerGraphics, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 350,
easing: tween.easeIn
});
attack = new HeavyAttack();
LK.getSound('hit').play();
}
// Find closest enemy to determine attack direction
var closestEnemy = null;
var closestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < closestDistance) {
closestDistance = distance;
closestEnemy = enemy;
}
}
if (closestEnemy) {
if (closestEnemy.x < self.x) {
// Enemy is to the left, attack left
attack.x = self.x - 75;
} else {
// Enemy is to the right, attack right
attack.x = self.x + 75;
}
} else {
attack.x = self.x + 75;
}
attack.y = self.y - 50;
attacks.push(attack);
game.addChild(attack);
// Advance combo
self.kickCombo = (self.kickCombo + 1) % 3;
LK.setTimeout(function () {
self.isAttacking = false;
}, animationDuration);
};
self.specialAttack = function () {
if (self.specialCooldown > 0 || self.isAttacking || self.energy < self.energyCostPerAttack) return;
self.isAttacking = true;
self.specialCooldown = self.maxSpecialCooldown;
// Consume energy for sword attack
self.energy -= self.energyCostPerAttack;
self.energyRechargeTimer = self.energyRechargeDelay; // Reset recharge timer
// Sword swing animation - dramatic sweep
tween(playerGraphics, {
rotation: -0.5,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
tween(playerGraphics, {
rotation: 0.5
}, {
duration: 200,
easing: tween.easeInOut
});
tween(playerGraphics, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
var attack = new SpecialAttack();
// Find closest enemy to determine attack direction
var closestEnemy = null;
var closestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - self.x, 2) + Math.pow(enemy.y - self.y, 2));
if (distance < closestDistance) {
closestDistance = distance;
closestEnemy = enemy;
}
}
if (closestEnemy) {
if (closestEnemy.x < self.x) {
// Enemy is to the left, attack left
attack.x = self.x - 100;
attack.flipLeft = true;
} else {
// Enemy is to the right, attack right
attack.x = self.x + 100;
attack.flipLeft = false;
}
} else {
attack.x = self.x + 100;
attack.flipLeft = false;
}
attack.y = self.y - 60;
attacks.push(attack);
game.addChild(attack);
LK.getSound('slash').play();
LK.setTimeout(function () {
self.isAttacking = false;
}, 600);
};
self.moveUp = function () {
self.y -= self.moveSpeed * 3;
if (self.y < 120) self.y = 120;
};
self.moveDown = function () {
self.y += self.moveSpeed * 3;
if (self.y > 2612) self.y = 2612;
};
self.moveLeft = function () {
self.x -= self.moveSpeed * 3;
if (self.x < 40) self.x = 40;
};
self.moveRight = function () {
self.x += self.moveSpeed * 3;
if (self.x > 2008) self.x = 2008;
};
self.jump = function () {
if (self.isOnGround) {
self.velocityY = self.jumpPower;
self.isOnGround = false;
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (self.specialCooldown > 0) {
self.specialCooldown--;
}
// Update energy system
if (self.energyRechargeTimer > 0) {
self.energyRechargeTimer--;
} else if (self.energy < self.maxEnergy) {
// Recharge energy after delay
self.energy += self.energyRechargeRate;
if (self.energy > self.maxEnergy) {
self.energy = self.maxEnergy;
}
}
// Update combo timers
if (self.punchComboTimer > 0) {
self.punchComboTimer--;
if (self.punchComboTimer === 0) {
self.punchCombo = 0; // Reset punch combo
}
}
if (self.kickComboTimer > 0) {
self.kickComboTimer--;
if (self.kickComboTimer === 0) {
self.kickCombo = 0; // Reset kick combo
}
}
// Apply gravity with more realistic physics
self.velocityY += self.gravity;
self.y += self.velocityY;
// Check ground collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocityY = 0;
self.isOnGround = true;
}
// Horizontal movement with acceleration/deceleration
var targetSpeed = 0;
self.isRunning = false;
if (isLeftPressed) {
targetSpeed = -self.maxSpeed;
if (leftPressTime > 30) {
// Running after half second
self.isRunning = true;
targetSpeed *= self.runMultiplier;
}
}
if (isRightPressed) {
targetSpeed = self.maxSpeed;
if (rightPressTime > 30) {
// Running after half second
self.isRunning = true;
targetSpeed *= self.runMultiplier;
}
}
// Apply acceleration or deceleration
if (targetSpeed !== 0) {
// Accelerate towards target speed
if (self.velocityX < targetSpeed) {
self.velocityX += self.acceleration;
if (self.velocityX > targetSpeed) self.velocityX = targetSpeed;
} else if (self.velocityX > targetSpeed) {
self.velocityX -= self.acceleration;
if (self.velocityX < targetSpeed) self.velocityX = targetSpeed;
}
} else {
// Decelerate to stop
if (self.velocityX > 0) {
self.velocityX -= self.deceleration;
if (self.velocityX < 0) self.velocityX = 0;
} else if (self.velocityX < 0) {
self.velocityX += self.deceleration;
if (self.velocityX > 0) self.velocityX = 0;
}
}
// Apply horizontal movement
self.x += self.velocityX;
// Boundary checks
if (self.x < 40) {
self.x = 40;
self.velocityX = 0;
}
if (self.x > 2008) {
self.x = 2008;
self.velocityX = 0;
}
// Jump when up is pressed
if (isUpPressed) {
self.jump();
}
};
return self;
});
var QuickAttack = Container.expand(function () {
var self = Container.call(this);
var attackGraphics = self.attachAsset('quickAttack', {
anchorX: 0.5,
anchorY: 0.5
});
self.damage = 25;
self.lifetime = 15; // Quarter second at 60fps
self.hasHit = false;
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
for (var i = attacks.length - 1; i >= 0; i--) {
if (attacks[i] === self) {
attacks.splice(i, 1);
break;
}
}
}
};
return self;
});
var SpecialAttack = Container.expand(function () {
var self = Container.call(this);
self.attackGraphics = null;
self.flipLeft = false;
self.damage = 100;
self.lifetime = 35; // Longest lasting attack
self.hasHit = false;
self.setDirection = function (flipLeft) {
if (self.attackGraphics) {
self.removeChild(self.attackGraphics);
}
if (flipLeft) {
self.attackGraphics = self.attachAsset('specialAttack', {
anchorX: 0.5,
anchorY: 0.5,
flipX: 0
});
} else {
self.attackGraphics = self.attachAsset('specialAttack', {
anchorX: 0.5,
anchorY: 0.5,
flipX: 1
});
}
};
// Initialize with default direction (right)
self.setDirection(false);
self.update = function () {
// Update direction if flipLeft property changes
if (self.flipLeft !== undefined && self.attackGraphics) {
self.setDirection(self.flipLeft);
self.flipLeft = undefined; // Reset to avoid repeated updates
}
self.lifetime--;
if (self.lifetime <= 0) {
self.destroy();
for (var i = attacks.length - 1; i >= 0; i--) {
if (attacks[i] === self) {
attacks.splice(i, 1);
break;
}
}
}
};
return self;
});
var SpinAttack = Container.expand(function () {
var self = Container.call(this);
var attackGraphics = self.attachAsset('specialAttack', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00FFFF // Cyan tint for spin attack
});
self.damage = 35; // Medium damage
self.lifetime = 20; // Medium duration
self.hasHit = false;
self.update = function () {
self.lifetime--;
// Spinning animation
attackGraphics.rotation += 0.3;
if (self.lifetime <= 0) {
self.destroy();
for (var i = attacks.length - 1; i >= 0; i--) {
if (attacks[i] === self) {
attacks.splice(i, 1);
break;
}
}
}
};
return self;
});
var TankEnemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0,
tint: 0xFF0000,
// Red tint to distinguish from regular enemy
scaleX: 1.3,
// Larger size
scaleY: 1.3
});
self.health = 100; // Higher health
self.damage = 35; // Higher damage
self.moveSpeed = -1; // Slower movement
self.lastDamageTime = 0;
self.attackCooldown = 0;
self.attackRange = 120;
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFFFFFF, 100);
if (self.health <= 0) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
LK.setScore(LK.getScore() + 25); // More points for tough enemy
scoreTxt.setText(LK.getScore());
// Spawn a new enemy when this one is defeated
spawnEnemy();
}
};
self.update = function () {
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
if (player) {
// Simple movement towards player
var moveX = player.x - self.x;
var moveY = player.y - self.y;
// Normalize movement speed
var distance = Math.sqrt(moveX * moveX + moveY * moveY);
// Attack if close enough and cooldown is ready
if (distance <= self.attackRange && self.attackCooldown <= 0) {
self.attackCooldown = 120; // 2 second cooldown (slower but more powerful)
player.takeDamage(self.damage);
// Flash enemy to show attack
LK.effects.flashObject(self, 0xFF0000, 300);
LK.getSound('special').play(); // TankEnemy heavy attack sound
}
if (distance > 0) {
moveX = moveX / distance * Math.abs(self.moveSpeed);
moveY = moveY / distance * Math.abs(self.moveSpeed);
}
self.x += moveX;
self.y += moveY;
} else {
self.x += self.moveSpeed;
}
if (self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
self.destroy();
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F4F
});
/****
* Game Code
****/
// Create background - only bottom background covering full screen
var bottomBackground = LK.getAsset('backgroundBottom', {
width: 2048,
height: 2732,
// Full screen height
color: 0x228B22,
shape: 'box',
x: 0,
y: 0
});
game.addChild(bottomBackground);
var player;
var enemies = [];
var attacks = [];
var spawnTimer = 0;
var gameSpeed = 1;
var isUpPressed = false;
var isDownPressed = false;
var isLeftPressed = false;
var isRightPressed = false;
var leftPressTime = 0;
var rightPressTime = 0;
var healthPickups = [];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -50;
scoreTxt.y = 50;
var healthBarBg = LK.getAsset('healthBarBg', {
width: 300,
height: 30,
color: 0xFF0000,
shape: 'box',
x: 150,
y: 80
});
LK.gui.topLeft.addChild(healthBarBg);
var healthBar = LK.getAsset('healthBar', {
width: 300,
height: 30,
color: 0x00FF00,
shape: 'box',
x: 150,
y: 80
});
LK.gui.topLeft.addChild(healthBar);
var healthTxt = new Text2('Health', {
size: 40,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 150;
healthTxt.y = 50;
LK.gui.topLeft.addChild(healthTxt);
var specialCooldownTxt = new Text2('Special Ready', {
size: 40,
fill: 0x9932CC
});
specialCooldownTxt.anchor.set(0, 0);
specialCooldownTxt.x = 50;
specialCooldownTxt.y = 170;
LK.gui.topLeft.addChild(specialCooldownTxt);
// Energy bar for sword attacks
var energyBarBg = LK.getAsset('healthBarBg', {
width: 300,
height: 25,
color: 0x4B0082,
shape: 'box',
x: 150,
y: 130
});
LK.gui.topLeft.addChild(energyBarBg);
var energyBar = LK.getAsset('healthBar', {
width: 300,
height: 25,
color: 0x9932CC,
shape: 'box',
x: 150,
y: 130
});
LK.gui.topLeft.addChild(energyBar);
var energyTxt = new Text2('Energy', {
size: 35,
fill: 0x9932CC
});
energyTxt.anchor.set(0, 0);
energyTxt.x = 150;
energyTxt.y = 100;
LK.gui.topLeft.addChild(energyTxt);
// Boss health bar (initially hidden)
var bossHealthBarBg = LK.getAsset('healthBarBg', {
width: 600,
height: 40,
color: 0xFF0000,
shape: 'box',
x: 1024,
y: 150
});
bossHealthBarBg.anchor.set(0.5, 0);
bossHealthBarBg.visible = false;
game.addChild(bossHealthBarBg);
var bossHealthBar = LK.getAsset('healthBar', {
width: 600,
height: 40,
color: 0xFFD700,
shape: 'box',
x: 1024,
y: 150
});
bossHealthBar.anchor.set(0.5, 0);
bossHealthBar.visible = false;
game.addChild(bossHealthBar);
var bossHealthTxt = new Text2('BOSS', {
size: 60,
fill: 0xFFD700
});
bossHealthTxt.anchor.set(0.5, 1);
bossHealthTxt.x = 1024;
bossHealthTxt.y = 140;
bossHealthTxt.visible = false;
game.addChild(bossHealthTxt);
// Movement arrow buttons (bottom left)
var upBtn = new Text2('↑', {
size: 200,
fill: 0xFFFFFF
});
upBtn.anchor.set(0.5, 1);
LK.gui.bottomLeft.addChild(upBtn);
upBtn.x = 120;
upBtn.y = -180;
var downBtn = new Text2('↓', {
size: 200,
fill: 0xFFFFFF
});
downBtn.anchor.set(0.5, 1);
LK.gui.bottomLeft.addChild(downBtn);
downBtn.x = 120;
downBtn.y = -50;
var leftBtn = new Text2('←', {
size: 200,
fill: 0xFFFFFF
});
leftBtn.anchor.set(0.5, 1);
LK.gui.bottomLeft.addChild(leftBtn);
leftBtn.x = 50;
leftBtn.y = -115;
var rightBtn = new Text2('→', {
size: 200,
fill: 0xFFFFFF
});
rightBtn.anchor.set(0.5, 1);
LK.gui.bottomLeft.addChild(rightBtn);
rightBtn.x = 190;
rightBtn.y = -115;
// Attack buttons (bottom right)
var quickBtn = new Text2('Golpe', {
size: 80,
fill: 0xFFD700
});
quickBtn.anchor.set(1, 1);
LK.gui.bottomRight.addChild(quickBtn);
quickBtn.x = -50;
quickBtn.y = -50;
var heavyBtn = new Text2('Patada', {
size: 80,
fill: 0xFF6347
});
heavyBtn.anchor.set(1, 1);
LK.gui.bottomRight.addChild(heavyBtn);
heavyBtn.x = -50;
heavyBtn.y = -150;
var specialBtn = new Text2('Espada', {
size: 80,
fill: 0x9932CC
});
specialBtn.anchor.set(1, 1);
LK.gui.bottomRight.addChild(specialBtn);
specialBtn.x = -50;
specialBtn.y = -250;
// Level progression variables
var levelDistance = 0;
var maxLevelDistance = 1000; // Distance to complete level
var bossSpawned = false;
var levelComplete = false;
// Initialize player
player = game.addChild(new Player());
player.x = 1024; // Center horizontally (2048/2)
player.y = 1800; // Lower position
// Level progress UI
var progressTxt = new Text2('Progress: 0%', {
size: 50,
fill: 0xFFFFFF
});
progressTxt.anchor.set(0.5, 0);
progressTxt.x = 0;
progressTxt.y = 50;
LK.gui.top.addChild(progressTxt);
// Button event handlers
quickBtn.down = function (x, y, obj) {
if (player) {
player.quickAttack();
}
};
heavyBtn.down = function (x, y, obj) {
if (player) {
player.heavyAttack();
}
};
specialBtn.down = function (x, y, obj) {
if (player) {
player.specialAttack();
}
};
// Movement button event handlers - single press movement
upBtn.down = function (x, y, obj) {
isUpPressed = true;
};
downBtn.down = function (x, y, obj) {
if (player) {
var newY = player.y + player.moveSpeed * 10;
if (newY > 2612) newY = 2612;
player.y = newY;
}
};
leftBtn.down = function (x, y, obj) {
isLeftPressed = true;
leftPressTime = 0;
};
rightBtn.down = function (x, y, obj) {
isRightPressed = true;
rightPressTime = 0;
};
// Spawn enemies only
function spawnEnemy() {
// Don't spawn regular enemies if boss is spawned or level is complete
if (bossSpawned || levelComplete) return;
// Randomly choose enemy type
var enemyType = Math.random();
var enemy;
if (enemyType < 0.5) {
enemy = new Enemy(); // Regular enemy - 50% chance
} else if (enemyType < 0.8) {
enemy = new FastEnemy(); // Fast enemy - 30% chance
} else {
enemy = new TankEnemy(); // Tank enemy - 20% chance
}
// Spawn enemy from right side
if (Math.random() < 0.8) {
enemy.x = 2048 + 100;
enemy.y = 1800 - Math.random() * 600 + 300; // Lower area spawn
// Start enemy invisible and fade in gradually
enemy.alpha = 0;
tween(enemy, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
enemies.push(enemy);
game.addChild(enemy);
} else {
// Spawn enemy from left side
enemy.x = -100;
enemy.y = 1800 - Math.random() * 600 + 300; // Lower area spawn
enemy.moveSpeed = Math.abs(enemy.moveSpeed); // Make moveSpeed positive for left-to-right movement
// Start enemy invisible and fade in gradually
enemy.alpha = 0;
tween(enemy, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
enemies.push(enemy);
game.addChild(enemy);
}
}
// Spawn initial enemies at game start
function spawnInitialEnemies() {
for (var i = 0; i < 2; i++) {
spawnEnemy();
}
}
// Call initial enemy spawn
spawnInitialEnemies();
// Start background music
LK.playMusic('Sonidofondo');
function spawnBoss() {
if (bossSpawned) return;
bossSpawned = true;
var boss = new Boss();
boss.x = 2048 + 200; // Spawn from right side
boss.y = 1800; // Lower position
boss.alpha = 0;
// Dramatic boss entrance
tween(boss, {
alpha: 1,
x: 1800
}, {
duration: 2000,
easing: tween.easeOut
});
// Show boss health bar
bossHealthBarBg.visible = true;
bossHealthBar.visible = true;
bossHealthTxt.visible = true;
enemies.push(boss);
game.addChild(boss);
}
game.update = function () {
// Update press time tracking for running
if (isLeftPressed) leftPressTime++;
if (isRightPressed) rightPressTime++;
// Update game speed over time
gameSpeed += 0.001;
// Update level progression
if (!levelComplete) {
levelDistance += gameSpeed;
var progressPercent = Math.min(100, levelDistance / maxLevelDistance * 100);
progressTxt.setText('Progress: ' + Math.floor(progressPercent) + '%');
// Spawn boss after 2 minutes (7200 ticks at 60fps)
if (LK.ticks >= 7200 && !bossSpawned) {
spawnBoss();
}
}
// Enemy spawning is now handled when enemies are defeated (see Enemy class takeDamage method)
// Update UI
if (player) {
// Update health bar
var healthPercent = player.health / player.maxHealth;
healthBar.width = 300 * healthPercent;
healthBar.tint = healthPercent > 0.5 ? 0x00FF00 : healthPercent > 0.25 ? 0xFFFF00 : 0xFF0000;
// Update energy bar
var energyPercent = player.energy / player.maxEnergy;
energyBar.width = 300 * energyPercent;
energyBar.tint = energyPercent > 0.6 ? 0x9932CC : energyPercent > 0.3 ? 0xFFFF00 : 0xFF0000;
if (player.specialCooldown > 0) {
specialCooldownTxt.setText('Special: ' + Math.ceil(player.specialCooldown / 60) + 's');
} else if (player.energy < player.energyCostPerAttack) {
specialCooldownTxt.setText('Low Energy');
} else {
specialCooldownTxt.setText('Special Ready');
}
// Check if health is zero for game over
if (player.health <= 0) {
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
}
// Update boss health bar
if (bossSpawned && enemies.length > 0) {
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].maxHealth && enemies[i].maxHealth === 300) {
// Boss detection
var boss = enemies[i];
var bossHealthPercent = boss.health / boss.maxHealth;
bossHealthBar.width = 600 * bossHealthPercent;
bossHealthBar.tint = bossHealthPercent > 0.5 ? 0xFFD700 : bossHealthPercent > 0.25 ? 0xFFFF00 : 0xFF0000;
break;
}
}
}
// Enemy attacks are now handled in their individual update methods
// Spawn health pickups when player health is low
if (player && player.health < 30 && Math.random() < 0.002) {
var isLarge = Math.random() < 0.3; // 30% chance for large pickup
var pickup = new HealthPickup();
pickup.init(isLarge);
pickup.x = 200 + Math.random() * 1600;
pickup.y = 200 + Math.random() * 2200;
healthPickups.push(pickup);
game.addChild(pickup);
}
// Check collisions between player and health pickups
for (var i = healthPickups.length - 1; i >= 0; i--) {
var pickup = healthPickups[i];
if (player && player.intersects(pickup)) {
if (pickup.isLarge) {
player.health = player.maxHealth; // Full heal
} else {
player.health = Math.min(player.maxHealth, player.health + 50); // Half heal
}
pickup.destroy();
healthPickups.splice(i, 1);
}
}
// Check collisions between attacks and enemies
for (var i = attacks.length - 1; i >= 0; i--) {
var attack = attacks[i];
if (attack.hasHit) continue;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (attack.intersects(enemy)) {
enemy.takeDamage(attack.damage);
attack.hasHit = true;
// Special visual effect for sword attacks
if (attack.damage >= 100) {
LK.effects.flashObject(enemy, 0x9932CC, 500);
tween(enemy, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
tween(enemy, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
break;
}
}
}
// Score is only updated when enemies are defeated
};
leftBtn.up = function (x, y, obj) {
isLeftPressed = false;
leftPressTime = 0;
};
rightBtn.up = function (x, y, obj) {
isRightPressed = false;
rightPressTime = 0;
};
upBtn.up = function (x, y, obj) {
isUpPressed = false;
};
pandillero que quiere pelear a puño limpio. In-Game asset. 2d. High contrast. No shadows
cristal verde de tamaño grande. In-Game asset. 2d. High contrast. No shadows
una calle de una ciudad peligrosa con edificios viejos en la parte de arriba. In-Game asset. 2d. High contrast. No shadows
barra de salud de color verde. In-Game asset. 2d. High contrast. No shadows
hombre con camisa negra de manga larga, pantalones negros, botas negras y guantes negros y un pasamontañas negro dando un puñetazo.. In-Game asset. 2d. High contrast. No shadows
hombre con camisa negra de manga larga, pantalones negros, botas negras y guantes negros y un pasamontañas negro dando una patada de artes marciales In-Game asset. 2d. High contrast. No shadows
hombre con camisa negra de manga larga, pantalones negros, botas negras y guantes negros y un pasamontañas negro atacando con una katana con un mango negro. In-Game asset. 2d. High contrast. No shadows
hombre con camisa negra de manga larga, pantalones negros, botas negras y guantes negros y un pasamontañas negro en posicion de combate. In-Game asset. 2d. High contrast. No shadows