/**** * 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