/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var HealthBar = Container.expand(function (maxHealth) { var self = Container.call(this); self.maxHealth = maxHealth || 100; self.currentHealth = self.maxHealth; var bgBar = self.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5 }); var healthBar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0.5, x: -50 }); self.updateHealth = function (health) { self.currentHealth = Math.max(0, health); var healthPercent = self.currentHealth / self.maxHealth; healthBar.width = 100 * healthPercent; if (healthPercent > 0.6) { healthBar.tint = 0x00FF00; // Green } else if (healthPercent > 0.3) { healthBar.tint = 0xFFFF00; // Yellow } else { healthBar.tint = 0xFF0000; // Red } }; return self; }); var Seal = Container.expand(function (isPlayer) { var self = Container.call(this); self.isPlayer = isPlayer || false; self.maxHealth = 100; self.currentHealth = self.maxHealth; self.attackDamage = 25; self.speed = 3; self.lastAttackTime = 0; self.attackCooldown = 1000; // 1 second self.isInvincible = false; self.invincibilityDuration = 3000; // 3 seconds var sealBody = self.attachAsset(isPlayer ? 'playerSeal' : 'enemySeal', { anchorX: 0.5, anchorY: 0.5 }); self.healthBar = self.addChild(new HealthBar(self.maxHealth)); self.healthBar.y = -80; self.takeDamage = function (damage) { // Check if invincible if (self.isInvincible) { return; // No damage during invincibility } // Check if player has shield active if (self.isPlayer && shieldActive) { return; // No damage during shield } self.currentHealth -= damage; self.healthBar.updateHealth(self.currentHealth); // Flash effect when taking damage LK.effects.flashObject(self, 0xFFFFFF, 200); if (self.currentHealth <= 0) { self.die(); } }; self.die = function () { LK.getSound('defeat').play(); self.isDead = true; // Death animation tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 500, onFinish: function onFinish() { if (self.parent) { self.destroy(); } } }); }; // Attack system properties self.currentAttack = 0; // 0-4 for different attacks self.isCharging = false; self.chargeStartTime = 0; self.chargingIndicator = null; // Define 5 different attacks with different charge times and effects self.attackTypes = [{ name: 'Quick Strike', chargeTime: 200, // 0.2 seconds damage: 15, color: 0xFFFF00, scale: 1.1 }, { name: 'Power Slam', chargeTime: 800, // 0.8 seconds damage: 35, color: 0xFF4500, scale: 1.3 }, { name: 'Spinning Attack', chargeTime: 1200, // 1.2 seconds damage: 45, color: 0x9932CC, scale: 1.4 }, { name: 'Devastating Blow', chargeTime: 2000, // 2 seconds damage: 60, color: 0xFF0000, scale: 1.6 }, { name: 'Ultimate Strike', chargeTime: 3000, // 3 seconds damage: 80, color: 0x00FFFF, scale: 1.8 }, { name: 'Stone Throw', chargeTime: 1000, // 1 second damage: 40, color: 0x8B4513, scale: 1.2, ranged: true }]; self.startCharging = function () { if (self.isCharging) return; self.isCharging = true; self.chargeStartTime = Date.now(); // Create charging indicator if (!self.chargingIndicator) { self.chargingIndicator = self.addChild(LK.getAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, y: -100, width: 0, height: 8 })); } var attack = self.attackTypes[self.currentAttack]; self.chargingIndicator.tint = attack.color; self.chargingIndicator.visible = true; // Animate charging indicator tween(self.chargingIndicator, { width: 120 }, { duration: attack.chargeTime, easing: tween.linear }); // Charging visual effect on seal tween(self, { tint: attack.color }, { duration: attack.chargeTime / 4, easing: tween.easeInOut }); }; self.releaseAttack = function (target) { if (!self.isCharging) return; var currentTime = Date.now(); var chargeTime = currentTime - self.chargeStartTime; var attack = self.attackTypes[self.currentAttack]; // Stop charging self.isCharging = false; if (self.chargingIndicator) { self.chargingIndicator.visible = false; tween.stop(self.chargingIndicator); } // Reset seal color tween.stop(self); tween(self, { tint: 0xFFFFFF }, { duration: 200 }); // Check if we have a valid target before attacking if (!target) return; // Check if charge time was sufficient if (chargeTime >= attack.chargeTime) { // Full power attack target.takeDamage(attack.damage); LK.getSound('hit').play(); // Attack animation based on attack type if (self.currentAttack === 0) { // Quick Strike - Fast dart forward var originalX = self.x; var originalY = self.y; var angle = Math.atan2(target.y - self.y, target.x - self.x); tween(self, { x: self.x + Math.cos(angle) * 30, y: self.y + Math.sin(angle) * 30, scaleX: attack.scale, scaleY: attack.scale }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { x: originalX, y: originalY, scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } }); } else if (self.currentAttack === 1) { // Power Slam - Bounce up and down tween(self, { y: self.y - 40, scaleX: attack.scale, scaleY: attack.scale * 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { y: self.y + 40, scaleX: 1, scaleY: 0.8 }, { duration: 150, easing: tween.bounceOut, onFinish: function onFinish() { tween(self, { scaleY: 1 }, { duration: 100 }); } }); } }); } else if (self.currentAttack === 2) { // Spinning Attack - Full rotation with scale tween(self, { rotation: Math.PI * 2, scaleX: attack.scale, scaleY: attack.scale }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } else if (self.currentAttack === 3) { var _doPulse = function doPulse() { tween(self, { scaleX: attack.scale, scaleY: attack.scale, tint: 0xFF4444 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.1, scaleY: 1.1, tint: 0xFFFFFF }, { duration: 80, easing: tween.easeIn, onFinish: function onFinish() { pulseCount++; if (pulseCount < maxPulses) { _doPulse(); } else { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } } }); } }); }; // Devastating Blow - Multiple quick pulses var pulseCount = 0; var maxPulses = 3; _doPulse(); } else if (self.currentAttack === 4) { var _doShake = function doShake() { var shakeAmount = 15; tween(self, { x: originalX + (Math.random() - 0.5) * shakeAmount, y: originalY + (Math.random() - 0.5) * shakeAmount, scaleX: 1 + shakeCount * 0.1, scaleY: 1 + shakeCount * 0.1 }, { duration: 50, onFinish: function onFinish() { shakeCount++; if (shakeCount < maxShakes) { _doShake(); } else { // Final explosive strike tween(self, { x: originalX, y: originalY, scaleX: attack.scale, scaleY: attack.scale, tint: 0x00FFFF }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); } }); } } }); }; // Ultimate Strike - Charge up with shake then explosive strike var originalX = self.x; var originalY = self.y; var shakeCount = 0; var maxShakes = 8; _doShake(); } // Flash effect with attack color LK.effects.flashObject(target, attack.color, 300); // Activate invincibility for 3 seconds self.isInvincible = true; // Visual feedback for invincibility - make seal semi-transparent and glow tween(self, { alpha: 0.6, tint: 0x00FFFF }, { duration: 200, onFinish: function onFinish() { // Pulsing effect during invincibility var _pulseEffect = function pulseEffect() { if (self.isInvincible) { tween(self, { alpha: 0.4 }, { duration: 300, onFinish: function onFinish() { if (self.isInvincible) { tween(self, { alpha: 0.6 }, { duration: 300, onFinish: _pulseEffect }); } } }); } }; _pulseEffect(); } }); // End invincibility after duration LK.setTimeout(function () { self.isInvincible = false; // Restore normal appearance tween(self, { alpha: 1, tint: 0xFFFFFF }, { duration: 300 }); }, self.invincibilityDuration); } else { // Partial charge - reduced damage var chargePercent = chargeTime / attack.chargeTime; var reducedDamage = Math.floor(attack.damage * chargePercent * 0.5); if (reducedDamage > 0 && target) { target.takeDamage(reducedDamage); LK.getSound('hit').play(); } // Weak attack animation tween(self, { scaleX: 1.05, scaleY: 1.05 }, { duration: 100, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; self.cycleAttack = function () { if (!self.isCharging) { self.currentAttack = (self.currentAttack + 1) % 6; } }; self.attack = function (target) { var currentTime = Date.now(); if (currentTime - self.lastAttackTime > self.attackCooldown) { target.takeDamage(self.attackDamage); LK.getSound('hit').play(); self.lastAttackTime = currentTime; // Attack animation tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); } }; return self; }); var EnemySeal = Seal.expand(function () { var self = Seal.call(this, false); self.moveDirection = Math.random() * Math.PI * 2; self.directionChangeTime = 0; self.lastPlayerDistance = 1000; self.update = function () { if (self.isDead) return; // Change direction occasionally if (LK.ticks % 120 === 0) { self.moveDirection = Math.random() * Math.PI * 2; } // Move towards player if close enough var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2)); if (distanceToPlayer < 300) { var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x); self.moveDirection = angleToPlayer; } // Move self.x += Math.cos(self.moveDirection) * self.speed; self.y += Math.sin(self.moveDirection) * self.speed; // Keep within arena bounds var centerX = 2048 / 2; var centerY = 2732 / 2; var arenaRadius = 700; var distFromCenter = Math.sqrt(Math.pow(self.x - centerX, 2) + Math.pow(self.y - centerY, 2)); if (distFromCenter > arenaRadius) { var angleToCenter = Math.atan2(centerY - self.y, centerX - self.x); self.moveDirection = angleToCenter; } // Attack player if touching if (self.intersects(player) && !player.isDead) { self.attack(player); } }; return self; }); var Stone = Container.expand(function (target) { var self = Container.call(this); var stoneGraphics = self.attachAsset('stone', { anchorX: 0.5, anchorY: 0.5 }); self.target = target; self.speed = 8; self.damage = 40; self.lifetime = 0; self.maxLifetime = 3000; // 3 seconds max self.update = function () { if (!self.target || self.target.isDead) { // Remove stone if target is dead if (self.parent) { self.destroy(); } return; } // Calculate direction to target var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Normalize direction and move towards target if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Check collision with target if (self.intersects(self.target)) { self.target.takeDamage(self.damage); LK.getSound('hit').play(); LK.effects.flashObject(self.target, 0x8B4513, 300); if (self.parent) { self.destroy(); } return; } // Remove stone after maximum lifetime self.lifetime += 16; // Approximate frame time at 60fps if (self.lifetime > self.maxLifetime) { if (self.parent) { self.destroy(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F4F }); /**** * Game Code ****/ // Menu variables var menuState = 'main'; // 'main', 'playing', 'credits', 'options' var menuButtons = []; var backgroundObjects = []; // Game options with defaults var gameOptions = { soundVolume: 100, musicVolume: 100, difficulty: 'Normal' }; // Load saved options var savedOptions = storage.gameOptions; if (savedOptions) { gameOptions = savedOptions; } // Game variables var player; var enemies = []; var stones = []; var currentWave = 1; var enemiesInWave = 3; var waveStartTime = 0; var dragNode = null; var gameState = 'playing'; // 'playing', 'waveComplete', 'gameOver' var healingFish = null; var shieldActive = false; var shieldDuration = 5000; // 5 seconds var lastScoreMilestone = 0; var damageMultiplier = 1; var damageBoostActive = false; var damageBoostDuration = 10000; // 10 seconds var waveTxt; var scoreTxt; // Create main menu function createBackgroundObjects() { // Clear existing background objects for (var i = 0; i < backgroundObjects.length; i++) { if (backgroundObjects[i].parent) { backgroundObjects[i].destroy(); } } backgroundObjects = []; // Create various rotating objects var objectTypes = ['helmet', 'shield', 'sword', 'stone', 'fish']; var objectColors = [0x8b7355, 0x654321, 0xc0c0c0, 0x8B4513, 0x00FFFF]; for (var i = 0; i < 15; i++) { var objectType = objectTypes[Math.floor(Math.random() * objectTypes.length)]; var obj = game.addChild(LK.getAsset(objectType, { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: Math.random() * 2732, scaleX: 0.5 + Math.random() * 0.5, scaleY: 0.5 + Math.random() * 0.5 })); // Random tint obj.tint = objectColors[Math.floor(Math.random() * objectColors.length)]; obj.alpha = 0.3 + Math.random() * 0.4; // Store movement properties obj.rotationSpeed = (Math.random() - 0.5) * 0.1; obj.moveSpeedX = (Math.random() - 0.5) * 2; obj.moveSpeedY = (Math.random() - 0.5) * 2; // Start rotating animation tween(obj, { rotation: Math.PI * 2 }, { duration: 3000 + Math.random() * 4000, easing: tween.linear, onFinish: function onFinish() { if (this.parent && menuState !== 'playing') { // Continue rotating tween(this, { rotation: this.rotation + Math.PI * 2 }, { duration: 3000 + Math.random() * 4000, easing: tween.linear, onFinish: arguments.callee }); } } }); // Start floating animation tween(obj, { x: obj.x + (Math.random() - 0.5) * 400, y: obj.y + (Math.random() - 0.5) * 400 }, { duration: 4000 + Math.random() * 6000, easing: tween.easeInOut, onFinish: function onFinish() { if (this.parent && menuState !== 'playing') { // Continue floating tween(this, { x: this.x + (Math.random() - 0.5) * 400, y: this.y + (Math.random() - 0.5) * 400 }, { duration: 4000 + Math.random() * 6000, easing: tween.easeInOut, onFinish: arguments.callee }); } } }); backgroundObjects.push(obj); } } function createMainMenu() { // Note: LK engine doesn't support global volume control // Volume settings are stored for future use with individual sound assets // Clear any existing menu elements for (var i = 0; i < menuButtons.length; i++) { if (menuButtons[i].parent) { menuButtons[i].destroy(); } } menuButtons = []; // Create rotating background objects createBackgroundObjects(); // Game title var titleTxt = new Text2('SEAL ARENA', { size: 120, fill: 0xFFFFFF }); titleTxt.anchor.set(0.5, 0.5); titleTxt.x = 0; titleTxt.y = -300; LK.gui.center.addChild(titleTxt); // Menu buttons var buttonTexts = ['JUGAR', 'CREDITOS', 'OPCIONES']; var buttonActions = [startGame, showCredits, showOptions]; for (var i = 0; i < 3; i++) { var menuButton = new Container(); var buttonBg = menuButton.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.tint = 0x8b4513; var buttonText = new Text2(buttonTexts[i], { size: 50, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); menuButton.addChild(buttonText); menuButton.y = -100 + i * 120; menuButton.actionIndex = i; menuButton.down = function (x, y, obj) { buttonActions[this.actionIndex](); }; menuButtons.push(menuButton); LK.gui.center.addChild(menuButton); } } function startGame() { menuState = 'playing'; clearMenu(); initializeGame(); } function showCredits() { menuState = 'credits'; clearMenu(); var creditsTxt = new Text2('CREDITOS\n\nDesarrollado por FRVR\nMotor: LK Game Engine\nGraficos: Assets personalizados\n\nGracias por jugar!', { size: 40, fill: 0xFFFFFF }); creditsTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(creditsTxt); var backButton = new Container(); var buttonBg = backButton.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 60 }); buttonBg.tint = 0x8b4513; var buttonText = new Text2('VOLVER', { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); backButton.addChild(buttonText); backButton.y = 300; backButton.down = function () { menuState = 'main'; clearMenu(); createMainMenu(); }; menuButtons.push(backButton); LK.gui.center.addChild(backButton); } function showOptions() { menuState = 'options'; clearMenu(); // Title var titleTxt = new Text2('OPCIONES', { size: 80, fill: 0xFFFFFF }); titleTxt.anchor.set(0.5, 0.5); titleTxt.y = -350; LK.gui.center.addChild(titleTxt); // Sound Volume Section var soundTxt = new Text2('Volumen de Sonido', { size: 50, fill: 0xFFFFFF }); soundTxt.anchor.set(0.5, 0.5); soundTxt.y = -200; LK.gui.center.addChild(soundTxt); // Sound volume buttons var soundDownBtn = new Container(); var soundDownBg = soundDownBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); soundDownBg.tint = 0x8b4513; var soundDownText = new Text2('-', { size: 40, fill: 0xFFFFFF }); soundDownText.anchor.set(0.5, 0.5); soundDownBtn.addChild(soundDownText); soundDownBtn.x = -150; soundDownBtn.y = -120; soundDownBtn.down = function () { if (gameOptions.soundVolume > 0) { gameOptions.soundVolume = Math.max(0, gameOptions.soundVolume - 10); updateOptionDisplay(); } }; LK.gui.center.addChild(soundDownBtn); menuButtons.push(soundDownBtn); var soundUpBtn = new Container(); var soundUpBg = soundUpBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); soundUpBg.tint = 0x8b4513; var soundUpText = new Text2('+', { size: 40, fill: 0xFFFFFF }); soundUpText.anchor.set(0.5, 0.5); soundUpBtn.addChild(soundUpText); soundUpBtn.x = 150; soundUpBtn.y = -120; soundUpBtn.down = function () { if (gameOptions.soundVolume < 100) { gameOptions.soundVolume = Math.min(100, gameOptions.soundVolume + 10); updateOptionDisplay(); } }; LK.gui.center.addChild(soundUpBtn); menuButtons.push(soundUpBtn); var soundValueTxt = new Text2(gameOptions.soundVolume + '%', { size: 40, fill: 0xFFFF00 }); soundValueTxt.anchor.set(0.5, 0.5); soundValueTxt.y = -120; LK.gui.center.addChild(soundValueTxt); // Music Volume Section var musicTxt = new Text2('Volumen de Musica', { size: 50, fill: 0xFFFFFF }); musicTxt.anchor.set(0.5, 0.5); musicTxt.y = -20; LK.gui.center.addChild(musicTxt); // Music volume buttons var musicDownBtn = new Container(); var musicDownBg = musicDownBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); musicDownBg.tint = 0x8b4513; var musicDownText = new Text2('-', { size: 40, fill: 0xFFFFFF }); musicDownText.anchor.set(0.5, 0.5); musicDownBtn.addChild(musicDownText); musicDownBtn.x = -150; musicDownBtn.y = 60; musicDownBtn.down = function () { if (gameOptions.musicVolume > 0) { gameOptions.musicVolume = Math.max(0, gameOptions.musicVolume - 10); updateOptionDisplay(); } }; LK.gui.center.addChild(musicDownBtn); menuButtons.push(musicDownBtn); var musicUpBtn = new Container(); var musicUpBg = musicUpBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); musicUpBg.tint = 0x8b4513; var musicUpText = new Text2('+', { size: 40, fill: 0xFFFFFF }); musicUpText.anchor.set(0.5, 0.5); musicUpBtn.addChild(musicUpText); musicUpBtn.x = 150; musicUpBtn.y = 60; musicUpBtn.down = function () { if (gameOptions.musicVolume < 100) { gameOptions.musicVolume = Math.min(100, gameOptions.musicVolume + 10); updateOptionDisplay(); } }; LK.gui.center.addChild(musicUpBtn); menuButtons.push(musicUpBtn); var musicValueTxt = new Text2(gameOptions.musicVolume + '%', { size: 40, fill: 0xFFFF00 }); musicValueTxt.anchor.set(0.5, 0.5); musicValueTxt.y = 60; LK.gui.center.addChild(musicValueTxt); // Difficulty Section var difficultyTxt = new Text2('Dificultad', { size: 50, fill: 0xFFFFFF }); difficultyTxt.anchor.set(0.5, 0.5); difficultyTxt.y = 160; LK.gui.center.addChild(difficultyTxt); // Difficulty buttons var difficultyDownBtn = new Container(); var difficultyDownBg = difficultyDownBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); difficultyDownBg.tint = 0x8b4513; var difficultyDownText = new Text2('<', { size: 40, fill: 0xFFFFFF }); difficultyDownText.anchor.set(0.5, 0.5); difficultyDownBtn.addChild(difficultyDownText); difficultyDownBtn.x = -150; difficultyDownBtn.y = 240; difficultyDownBtn.down = function () { var difficulties = ['Facil', 'Normal', 'Dificil']; var currentIndex = difficulties.indexOf(gameOptions.difficulty); if (currentIndex > 0) { gameOptions.difficulty = difficulties[currentIndex - 1]; updateOptionDisplay(); } }; LK.gui.center.addChild(difficultyDownBtn); menuButtons.push(difficultyDownBtn); var difficultyUpBtn = new Container(); var difficultyUpBg = difficultyUpBtn.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 60, height: 60 }); difficultyUpBg.tint = 0x8b4513; var difficultyUpText = new Text2('>', { size: 40, fill: 0xFFFFFF }); difficultyUpText.anchor.set(0.5, 0.5); difficultyUpBtn.addChild(difficultyUpText); difficultyUpBtn.x = 150; difficultyUpBtn.y = 240; difficultyUpBtn.down = function () { var difficulties = ['Facil', 'Normal', 'Dificil']; var currentIndex = difficulties.indexOf(gameOptions.difficulty); if (currentIndex < difficulties.length - 1) { gameOptions.difficulty = difficulties[currentIndex + 1]; updateOptionDisplay(); } }; LK.gui.center.addChild(difficultyUpBtn); menuButtons.push(difficultyUpBtn); var difficultyValueTxt = new Text2(gameOptions.difficulty, { size: 40, fill: 0xFFFF00 }); difficultyValueTxt.anchor.set(0.5, 0.5); difficultyValueTxt.y = 240; LK.gui.center.addChild(difficultyValueTxt); // Update function for option displays function updateOptionDisplay() { soundValueTxt.setText(gameOptions.soundVolume + '%'); musicValueTxt.setText(gameOptions.musicVolume + '%'); difficultyValueTxt.setText(gameOptions.difficulty); // Note: LK engine doesn't support global volume control // Volume settings are stored for future reference // Save options storage.gameOptions = gameOptions; } var backButton = new Container(); var buttonBg = backButton.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 60 }); buttonBg.tint = 0x8b4513; var buttonText = new Text2('VOLVER', { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); backButton.addChild(buttonText); backButton.y = 350; backButton.down = function () { menuState = 'main'; clearMenu(); createMainMenu(); }; menuButtons.push(backButton); LK.gui.center.addChild(backButton); } function clearMenu() { // Clear all GUI elements while (LK.gui.center.children.length > 0) { LK.gui.center.children[0].destroy(); } while (LK.gui.bottom.children.length > 0) { LK.gui.bottom.children[0].destroy(); } while (LK.gui.top.children.length > 0) { LK.gui.top.children[0].destroy(); } while (LK.gui.topLeft.children.length > 0) { LK.gui.topLeft.children[0].destroy(); } while (LK.gui.topRight.children.length > 0) { LK.gui.topRight.children[0].destroy(); } // Clear all game objects while (game.children.length > 0) { game.children[0].destroy(); } // Clear background objects for (var i = 0; i < backgroundObjects.length; i++) { if (backgroundObjects[i].parent) { backgroundObjects[i].destroy(); } } backgroundObjects = []; menuButtons = []; } function initializeGame() { // Create arena var arenaOuter = game.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); var arenaInner = game.addChild(LK.getAsset('arenaFloor', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); // Create player player = game.addChild(new Seal(true)); player.x = 2048 / 2; player.y = 2732 / 2 + 200; // UI Elements scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 120; scoreTxt.y = 50; LK.gui.topLeft.addChild(scoreTxt); waveTxt = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); waveTxt.anchor.set(1, 0); LK.gui.topRight.addChild(waveTxt); // Attack type display var attackTxt = new Text2('Attack: Quick Strike', { size: 40, fill: 0xFFFF00 }); attackTxt.anchor.set(0.5, 0); attackTxt.y = 50; LK.gui.top.addChild(attackTxt); // Create attack buttons var attackButtons = []; for (var i = 0; i < 6; i++) { var button = new Container(); var buttonBg = button.attachAsset('healthBarBg', { anchorX: 0.5, anchorY: 0.5, width: 160, height: 80 }); // Make button background red buttonBg.tint = 0xFF0000; var buttonText = new Text2(player.attackTypes[i].name, { size: 24, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); button.addChild(buttonText); // Position buttons horizontally across bottom of screen button.x = (i - 2.5) * 160; button.y = -120; // Store button index for reference button.attackIndex = i; // Button click handler button.down = function (x, y, obj) { if (gameState === 'playing' && !player.isDead) { player.currentAttack = this.attackIndex; attackTxt.setText('Attack: ' + player.attackTypes[player.currentAttack].name); attackTxt.tint = player.attackTypes[player.currentAttack].color; // Special handling for stone throw attack (infinite usage) if (player.currentAttack === 5) { // Find closest enemy for stone targeting var stoneTarget = null; var closestStoneDistance = Infinity; for (var m = 0; m < enemies.length; m++) { var enemy = enemies[m]; if (enemy && !enemy.isDead) { var distance = Math.sqrt(Math.pow(player.x - enemy.x, 2) + Math.pow(player.y - enemy.y, 2)); if (distance < closestStoneDistance) { closestStoneDistance = distance; stoneTarget = enemy; } } } if (stoneTarget) { var stone = new Stone(stoneTarget); stone.x = player.x; stone.y = player.y; stones.push(stone); game.addChild(stone); // Throwing animation var attack = player.attackTypes[player.currentAttack]; tween(player, { scaleX: attack.scale, scaleY: attack.scale, rotation: Math.PI / 4 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(player, { scaleX: 1, scaleY: 1, rotation: 0 }, { duration: 150, easing: tween.easeIn }); } }); } // Update button visual states for stone attack for (var j = 0; j < attackButtons.length; j++) { if (j === player.currentAttack) { attackButtons[j].children[0].tint = 0xFFAAAA; // Lighter red for selected attackButtons[j].children[1].tint = 0x000000; } else { attackButtons[j].children[0].tint = 0xFF0000; // Red for unselected attackButtons[j].children[1].tint = 0xFFFFFF; } } return; // Exit early for stone attacks to avoid melee logic } // Find closest enemy and attack instantly for melee attacks var closestEnemy = null; var closestDistance = Infinity; for (var k = 0; k < enemies.length; k++) { var enemy = enemies[k]; if (enemy && !enemy.isDead) { var distance = Math.sqrt(Math.pow(player.x - enemy.x, 2) + Math.pow(player.y - enemy.y, 2)); if (distance < closestDistance && distance < 200) { // Attack range closestDistance = distance; closestEnemy = enemy; } } } // Execute instant attack if enemy in range if (closestEnemy) { var attack = player.attackTypes[player.currentAttack]; var finalDamage = attack.damage * damageMultiplier; closestEnemy.takeDamage(finalDamage); LK.getSound('hit').play(); // Execute attack animation instantly if (player.currentAttack === 0) { // Quick Strike - Fast dart forward var originalX = player.x; var originalY = player.y; var angle = Math.atan2(closestEnemy.y - player.y, closestEnemy.x - player.x); tween(player, { x: player.x + Math.cos(angle) * 30, y: player.y + Math.sin(angle) * 30, scaleX: attack.scale, scaleY: attack.scale }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(player, { x: originalX, y: originalY, scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeIn }); } }); } else if (player.currentAttack === 1) { // Power Slam - Bounce up and down tween(player, { y: player.y - 40, scaleX: attack.scale, scaleY: attack.scale * 1.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(player, { y: player.y + 40, scaleX: 1, scaleY: 0.8 }, { duration: 150, easing: tween.bounceOut, onFinish: function onFinish() { tween(player, { scaleY: 1 }, { duration: 100 }); } }); } }); } else if (player.currentAttack === 2) { // Spinning Attack - Full rotation with scale tween(player, { rotation: Math.PI * 2, scaleX: attack.scale, scaleY: attack.scale }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(player, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } else if (player.currentAttack === 3) { // Devastating Blow - Multiple quick pulses var pulseCount = 0; var maxPulses = 3; var _doPulse2 = function doPulse() { tween(player, { scaleX: attack.scale, scaleY: attack.scale, tint: 0xFF4444 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(player, { scaleX: 1.1, scaleY: 1.1, tint: 0xFFFFFF }, { duration: 80, easing: tween.easeIn, onFinish: function onFinish() { pulseCount++; if (pulseCount < maxPulses) { _doPulse2(); } else { tween(player, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } } }); } }); }; _doPulse2(); } else if (player.currentAttack === 4) { // Ultimate Strike - Charge up with shake then explosive strike var originalX = player.x; var originalY = player.y; var shakeCount = 0; var maxShakes = 8; var _doShake2 = function doShake() { var shakeAmount = 15; tween(player, { x: originalX + (Math.random() - 0.5) * shakeAmount, y: originalY + (Math.random() - 0.5) * shakeAmount, scaleX: 1 + shakeCount * 0.1, scaleY: 1 + shakeCount * 0.1 }, { duration: 50, onFinish: function onFinish() { shakeCount++; if (shakeCount < maxShakes) { _doShake2(); } else { // Final explosive strike tween(player, { x: originalX, y: originalY, scaleX: attack.scale, scaleY: attack.scale, tint: 0x00FFFF }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { tween(player, { scaleX: 1, scaleY: 1, tint: 0xFFFFFF }, { duration: 300, easing: tween.easeOut }); } }); } } }); }; _doShake2(); } // Flash effect with attack color if (closestEnemy) { LK.effects.flashObject(closestEnemy, attack.color, 300); } // Activate invincibility for 3 seconds player.isInvincible = true; // Visual feedback for invincibility - make seal semi-transparent and glow tween(player, { alpha: 0.6, tint: 0x00FFFF }, { duration: 200, onFinish: function onFinish() { // Pulsing effect during invincibility var _pulseEffect2 = function pulseEffect() { if (player.isInvincible) { tween(player, { alpha: 0.4 }, { duration: 300, onFinish: function onFinish() { if (player.isInvincible) { tween(player, { alpha: 0.6 }, { duration: 300, onFinish: _pulseEffect2 }); } } }); } }; _pulseEffect2(); } }); // End invincibility after duration LK.setTimeout(function () { player.isInvincible = false; // Restore normal appearance tween(player, { alpha: 1, tint: 0xFFFFFF }, { duration: 300 }); }, player.invincibilityDuration); LK.setScore(LK.getScore() + 100); scoreTxt.setText('Score: ' + LK.getScore()); checkScoreMilestone(); } // Update button visual states for (var j = 0; j < attackButtons.length; j++) { if (j === player.currentAttack) { attackButtons[j].children[0].tint = 0xFFAAAA; // Lighter red for selected attackButtons[j].children[1].tint = 0x000000; } else { attackButtons[j].children[0].tint = 0xFF0000; // Red for unselected attackButtons[j].children[1].tint = 0xFFFFFF; } } } }; attackButtons.push(button); LK.gui.bottom.addChild(button); } // Set initial button states attackButtons[0].children[0].tint = 0xFFAAAA; // Lighter red for selected attackButtons[0].children[1].tint = 0x000000; for (var i = 1; i < attackButtons.length; i++) { attackButtons[i].children[0].tint = 0xFF0000; // Red for unselected attackButtons[i].children[1].tint = 0xFFFFFF; } // Instructions var instructionTxt = new Text2('Select attack with buttons | Touch buttons to attack nearby enemies', { size: 30, fill: 0xCCCCCC }); instructionTxt.anchor.set(0.5, 1); instructionTxt.y = -40; LK.gui.bottom.addChild(instructionTxt); // Start first wave spawnWave(); } // Functions function spawnWave() { enemies = []; waveStartTime = Date.now(); // Apply difficulty modifier var difficultyMultiplier = 1; if (gameOptions.difficulty === 'Facil') { difficultyMultiplier = 0.7; } else if (gameOptions.difficulty === 'Dificil') { difficultyMultiplier = 1.5; } var adjustedEnemiesInWave = Math.ceil(enemiesInWave * difficultyMultiplier); for (var i = 0; i < adjustedEnemiesInWave; i++) { var enemy = game.addChild(new EnemySeal()); // Apply difficulty to enemy stats enemy.maxHealth = Math.floor(enemy.maxHealth * difficultyMultiplier); enemy.currentHealth = enemy.maxHealth; enemy.healthBar.updateHealth(enemy.currentHealth); enemy.attackDamage = Math.floor(enemy.attackDamage * difficultyMultiplier); enemy.speed = enemy.speed * (0.8 + difficultyMultiplier * 0.4); // Spawn enemies around the arena edge var angle = i / adjustedEnemiesInWave * Math.PI * 2; var spawnRadius = 500; enemy.x = 2048 / 2 + Math.cos(angle) * spawnRadius; enemy.y = 2732 / 2 + Math.sin(angle) * spawnRadius; enemies.push(enemy); } waveTxt.setText('Wave: ' + currentWave); gameState = 'playing'; } function createConfetti() { // Create multiple confetti pieces for (var i = 0; i < 50; i++) { var confetti = game.addChild(LK.getAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, width: 10 + Math.random() * 10, height: 10 + Math.random() * 10, x: Math.random() * 2048, y: -50 })); // Random colors for confetti var colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF]; confetti.tint = colors[Math.floor(Math.random() * colors.length)]; // Animate confetti falling tween(confetti, { y: 2732 + 100, rotation: Math.PI * 4 * (Math.random() - 0.5), x: confetti.x + (Math.random() - 0.5) * 200 }, { duration: 3000 + Math.random() * 2000, easing: tween.easeOut, onFinish: function onFinish() { if (this.parent) { this.destroy(); } } }); } } function checkScoreMilestone() { var currentScore = LK.getScore(); var currentMilestone = Math.floor(currentScore / 100000); if (currentMilestone > lastScoreMilestone) { lastScoreMilestone = currentMilestone; // Launch confetti createConfetti(); // Activate triple damage for 10 seconds damageMultiplier = 3; damageBoostActive = true; // Visual feedback for damage boost tween(player, { tint: 0xFF4500 // Orange glow for damage boost }, { duration: 300, onFinish: function onFinish() { // Pulsing effect during damage boost var _pulseDamageBoost = function pulseDamageBoost() { if (damageBoostActive) { tween(player, { scaleX: 1.1, scaleY: 1.1 }, { duration: 500, onFinish: function onFinish() { if (damageBoostActive) { tween(player, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, onFinish: _pulseDamageBoost }); } } }); } }; _pulseDamageBoost(); } }); // End damage boost after duration LK.setTimeout(function () { damageMultiplier = 1; damageBoostActive = false; // Restore normal appearance tween(player, { tint: 0xFFFFFF, scaleX: 1, scaleY: 1 }, { duration: 500 }); }, damageBoostDuration); // Flash screen to indicate milestone LK.effects.flashScreen(0xFFD700, 1000); } } function spawnHealingFish() { if (healingFish) return; // Don't spawn if fish already exists healingFish = game.addChild(LK.getAsset('fish', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 150 })); // Animate fish floating and glowing tween(healingFish, { y: healingFish.y - 20, tint: 0x00FFFF }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(healingFish, { y: healingFish.y + 20, tint: 0xFFFFFF }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (healingFish && healingFish.parent) { spawnHealingFish(); // Continue animation loop } } }); } }); // Make fish clickable for healing healingFish.down = function (x, y, obj) { if (player && !player.isDead) { // Heal player to full health player.currentHealth = player.maxHealth; player.healthBar.updateHealth(player.currentHealth); // Activate shield for 5 seconds shieldActive = true; // Visual feedback for shield - golden glow tween(player, { alpha: 0.8, tint: 0xFFD700 // Golden color for shield }, { duration: 300, onFinish: function onFinish() { // Pulsing shield effect var _shieldPulse = function shieldPulse() { if (shieldActive) { tween(player, { alpha: 0.6 }, { duration: 400, onFinish: function onFinish() { if (shieldActive) { tween(player, { alpha: 0.8 }, { duration: 400, onFinish: _shieldPulse }); } } }); } }; _shieldPulse(); } }); // End shield after duration LK.setTimeout(function () { shieldActive = false; // Restore normal appearance tween(player, { alpha: 1, tint: 0xFFFFFF }, { duration: 500 }); }, shieldDuration); // Fish consumption animation tween(healingFish, { scaleX: 1.5, scaleY: 1.5, alpha: 0, tint: 0x00FF00 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { if (healingFish && healingFish.parent) { healingFish.destroy(); healingFish = null; } } }); // Flash player green to show healing LK.effects.flashObject(player, 0x00FF00, 500); } }; } function nextWave() { currentWave++; enemiesInWave += 2; // Increase difficulty // Spawn healing fish at the end of each wave spawnHealingFish(); LK.setTimeout(function () { spawnWave(); }, 2000); gameState = 'waveComplete'; } function checkWaveComplete() { var aliveEnemies = 0; for (var i = 0; i < enemies.length; i++) { if (enemies[i] && !enemies[i].isDead) { aliveEnemies++; } } if (aliveEnemies === 0 && gameState === 'playing') { // Wave complete bonus var timeBonus = Math.max(0, 10000 - (Date.now() - waveStartTime)) / 100; LK.setScore(LK.getScore() + 500 + Math.floor(timeBonus)); scoreTxt.setText('Score: ' + LK.getScore()); checkScoreMilestone(); if (currentWave >= 5) { // Victory condition LK.showYouWin(); } else { nextWave(); } } } // Input handling game.down = function (x, y, obj) { if (menuState === 'playing' && gameState === 'playing' && player && !player.isDead) { // Start dragging for positioning dragNode = player; } }; game.move = function (x, y, obj) { if (menuState === 'playing' && dragNode && gameState === 'playing' && player && !player.isDead) { dragNode.x = x; dragNode.y = y; // Keep player within arena bounds var centerX = 2048 / 2; var centerY = 2732 / 2; var arenaRadius = 700; var distFromCenter = Math.sqrt(Math.pow(dragNode.x - centerX, 2) + Math.pow(dragNode.y - centerY, 2)); if (distFromCenter > arenaRadius) { var angle = Math.atan2(dragNode.y - centerY, dragNode.x - centerX); dragNode.x = centerX + Math.cos(angle) * arenaRadius; dragNode.y = centerY + Math.sin(angle) * arenaRadius; } } }; game.up = function (x, y, obj) { dragNode = null; }; // Main game loop game.update = function () { // Update background objects when in menu if (menuState !== 'playing') { for (var i = 0; i < backgroundObjects.length; i++) { var obj = backgroundObjects[i]; if (obj && obj.parent) { // Apply continuous movement obj.x += obj.moveSpeedX; obj.y += obj.moveSpeedY; // Apply continuous rotation obj.rotation += obj.rotationSpeed; // Keep objects within screen bounds if (obj.x < -100) obj.x = 2148; if (obj.x > 2148) obj.x = -100; if (obj.y < -100) obj.y = 2832; if (obj.y > 2832) obj.y = -100; } } } if (menuState === 'playing' && gameState === 'playing') { // Update and clean up stone projectiles for (var i = stones.length - 1; i >= 0; i--) { var stone = stones[i]; if (stone && stone.parent) { // Stone is still active, update handled by stone.update() } else { // Stone was destroyed, remove from array stones.splice(i, 1); } } // Remove dead enemies from array and handle enemy updates for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy && enemy.isDead) { enemies.splice(i, 1); } } // Check if player is dead if (player && player.isDead) { gameState = 'gameOver'; LK.setTimeout(function () { menuState = 'main'; clearMenu(); createMainMenu(); }, 1000); } // Check wave completion checkWaveComplete(); } }; // Initialize main menu createMainMenu();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var HealthBar = Container.expand(function (maxHealth) {
var self = Container.call(this);
self.maxHealth = maxHealth || 100;
self.currentHealth = self.maxHealth;
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var healthBar = self.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0.5,
x: -50
});
self.updateHealth = function (health) {
self.currentHealth = Math.max(0, health);
var healthPercent = self.currentHealth / self.maxHealth;
healthBar.width = 100 * healthPercent;
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00; // Yellow
} else {
healthBar.tint = 0xFF0000; // Red
}
};
return self;
});
var Seal = Container.expand(function (isPlayer) {
var self = Container.call(this);
self.isPlayer = isPlayer || false;
self.maxHealth = 100;
self.currentHealth = self.maxHealth;
self.attackDamage = 25;
self.speed = 3;
self.lastAttackTime = 0;
self.attackCooldown = 1000; // 1 second
self.isInvincible = false;
self.invincibilityDuration = 3000; // 3 seconds
var sealBody = self.attachAsset(isPlayer ? 'playerSeal' : 'enemySeal', {
anchorX: 0.5,
anchorY: 0.5
});
self.healthBar = self.addChild(new HealthBar(self.maxHealth));
self.healthBar.y = -80;
self.takeDamage = function (damage) {
// Check if invincible
if (self.isInvincible) {
return; // No damage during invincibility
}
// Check if player has shield active
if (self.isPlayer && shieldActive) {
return; // No damage during shield
}
self.currentHealth -= damage;
self.healthBar.updateHealth(self.currentHealth);
// Flash effect when taking damage
LK.effects.flashObject(self, 0xFFFFFF, 200);
if (self.currentHealth <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('defeat').play();
self.isDead = true;
// Death animation
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 500,
onFinish: function onFinish() {
if (self.parent) {
self.destroy();
}
}
});
};
// Attack system properties
self.currentAttack = 0; // 0-4 for different attacks
self.isCharging = false;
self.chargeStartTime = 0;
self.chargingIndicator = null;
// Define 5 different attacks with different charge times and effects
self.attackTypes = [{
name: 'Quick Strike',
chargeTime: 200,
// 0.2 seconds
damage: 15,
color: 0xFFFF00,
scale: 1.1
}, {
name: 'Power Slam',
chargeTime: 800,
// 0.8 seconds
damage: 35,
color: 0xFF4500,
scale: 1.3
}, {
name: 'Spinning Attack',
chargeTime: 1200,
// 1.2 seconds
damage: 45,
color: 0x9932CC,
scale: 1.4
}, {
name: 'Devastating Blow',
chargeTime: 2000,
// 2 seconds
damage: 60,
color: 0xFF0000,
scale: 1.6
}, {
name: 'Ultimate Strike',
chargeTime: 3000,
// 3 seconds
damage: 80,
color: 0x00FFFF,
scale: 1.8
}, {
name: 'Stone Throw',
chargeTime: 1000,
// 1 second
damage: 40,
color: 0x8B4513,
scale: 1.2,
ranged: true
}];
self.startCharging = function () {
if (self.isCharging) return;
self.isCharging = true;
self.chargeStartTime = Date.now();
// Create charging indicator
if (!self.chargingIndicator) {
self.chargingIndicator = self.addChild(LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
y: -100,
width: 0,
height: 8
}));
}
var attack = self.attackTypes[self.currentAttack];
self.chargingIndicator.tint = attack.color;
self.chargingIndicator.visible = true;
// Animate charging indicator
tween(self.chargingIndicator, {
width: 120
}, {
duration: attack.chargeTime,
easing: tween.linear
});
// Charging visual effect on seal
tween(self, {
tint: attack.color
}, {
duration: attack.chargeTime / 4,
easing: tween.easeInOut
});
};
self.releaseAttack = function (target) {
if (!self.isCharging) return;
var currentTime = Date.now();
var chargeTime = currentTime - self.chargeStartTime;
var attack = self.attackTypes[self.currentAttack];
// Stop charging
self.isCharging = false;
if (self.chargingIndicator) {
self.chargingIndicator.visible = false;
tween.stop(self.chargingIndicator);
}
// Reset seal color
tween.stop(self);
tween(self, {
tint: 0xFFFFFF
}, {
duration: 200
});
// Check if we have a valid target before attacking
if (!target) return;
// Check if charge time was sufficient
if (chargeTime >= attack.chargeTime) {
// Full power attack
target.takeDamage(attack.damage);
LK.getSound('hit').play();
// Attack animation based on attack type
if (self.currentAttack === 0) {
// Quick Strike - Fast dart forward
var originalX = self.x;
var originalY = self.y;
var angle = Math.atan2(target.y - self.y, target.x - self.x);
tween(self, {
x: self.x + Math.cos(angle) * 30,
y: self.y + Math.sin(angle) * 30,
scaleX: attack.scale,
scaleY: attack.scale
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
x: originalX,
y: originalY,
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
} else if (self.currentAttack === 1) {
// Power Slam - Bounce up and down
tween(self, {
y: self.y - 40,
scaleX: attack.scale,
scaleY: attack.scale * 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 40,
scaleX: 1,
scaleY: 0.8
}, {
duration: 150,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleY: 1
}, {
duration: 100
});
}
});
}
});
} else if (self.currentAttack === 2) {
// Spinning Attack - Full rotation with scale
tween(self, {
rotation: Math.PI * 2,
scaleX: attack.scale,
scaleY: attack.scale
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
} else if (self.currentAttack === 3) {
var _doPulse = function doPulse() {
tween(self, {
scaleX: attack.scale,
scaleY: attack.scale,
tint: 0xFF4444
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xFFFFFF
}, {
duration: 80,
easing: tween.easeIn,
onFinish: function onFinish() {
pulseCount++;
if (pulseCount < maxPulses) {
_doPulse();
} else {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
}
});
}
});
};
// Devastating Blow - Multiple quick pulses
var pulseCount = 0;
var maxPulses = 3;
_doPulse();
} else if (self.currentAttack === 4) {
var _doShake = function doShake() {
var shakeAmount = 15;
tween(self, {
x: originalX + (Math.random() - 0.5) * shakeAmount,
y: originalY + (Math.random() - 0.5) * shakeAmount,
scaleX: 1 + shakeCount * 0.1,
scaleY: 1 + shakeCount * 0.1
}, {
duration: 50,
onFinish: function onFinish() {
shakeCount++;
if (shakeCount < maxShakes) {
_doShake();
} else {
// Final explosive strike
tween(self, {
x: originalX,
y: originalY,
scaleX: attack.scale,
scaleY: attack.scale,
tint: 0x00FFFF
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
}
});
};
// Ultimate Strike - Charge up with shake then explosive strike
var originalX = self.x;
var originalY = self.y;
var shakeCount = 0;
var maxShakes = 8;
_doShake();
}
// Flash effect with attack color
LK.effects.flashObject(target, attack.color, 300);
// Activate invincibility for 3 seconds
self.isInvincible = true;
// Visual feedback for invincibility - make seal semi-transparent and glow
tween(self, {
alpha: 0.6,
tint: 0x00FFFF
}, {
duration: 200,
onFinish: function onFinish() {
// Pulsing effect during invincibility
var _pulseEffect = function pulseEffect() {
if (self.isInvincible) {
tween(self, {
alpha: 0.4
}, {
duration: 300,
onFinish: function onFinish() {
if (self.isInvincible) {
tween(self, {
alpha: 0.6
}, {
duration: 300,
onFinish: _pulseEffect
});
}
}
});
}
};
_pulseEffect();
}
});
// End invincibility after duration
LK.setTimeout(function () {
self.isInvincible = false;
// Restore normal appearance
tween(self, {
alpha: 1,
tint: 0xFFFFFF
}, {
duration: 300
});
}, self.invincibilityDuration);
} else {
// Partial charge - reduced damage
var chargePercent = chargeTime / attack.chargeTime;
var reducedDamage = Math.floor(attack.damage * chargePercent * 0.5);
if (reducedDamage > 0 && target) {
target.takeDamage(reducedDamage);
LK.getSound('hit').play();
}
// Weak attack animation
tween(self, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
self.cycleAttack = function () {
if (!self.isCharging) {
self.currentAttack = (self.currentAttack + 1) % 6;
}
};
self.attack = function (target) {
var currentTime = Date.now();
if (currentTime - self.lastAttackTime > self.attackCooldown) {
target.takeDamage(self.attackDamage);
LK.getSound('hit').play();
self.lastAttackTime = currentTime;
// Attack animation
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
}
};
return self;
});
var EnemySeal = Seal.expand(function () {
var self = Seal.call(this, false);
self.moveDirection = Math.random() * Math.PI * 2;
self.directionChangeTime = 0;
self.lastPlayerDistance = 1000;
self.update = function () {
if (self.isDead) return;
// Change direction occasionally
if (LK.ticks % 120 === 0) {
self.moveDirection = Math.random() * Math.PI * 2;
}
// Move towards player if close enough
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
if (distanceToPlayer < 300) {
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
self.moveDirection = angleToPlayer;
}
// Move
self.x += Math.cos(self.moveDirection) * self.speed;
self.y += Math.sin(self.moveDirection) * self.speed;
// Keep within arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = 700;
var distFromCenter = Math.sqrt(Math.pow(self.x - centerX, 2) + Math.pow(self.y - centerY, 2));
if (distFromCenter > arenaRadius) {
var angleToCenter = Math.atan2(centerY - self.y, centerX - self.x);
self.moveDirection = angleToCenter;
}
// Attack player if touching
if (self.intersects(player) && !player.isDead) {
self.attack(player);
}
};
return self;
});
var Stone = Container.expand(function (target) {
var self = Container.call(this);
var stoneGraphics = self.attachAsset('stone', {
anchorX: 0.5,
anchorY: 0.5
});
self.target = target;
self.speed = 8;
self.damage = 40;
self.lifetime = 0;
self.maxLifetime = 3000; // 3 seconds max
self.update = function () {
if (!self.target || self.target.isDead) {
// Remove stone if target is dead
if (self.parent) {
self.destroy();
}
return;
}
// Calculate direction to target
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize direction and move towards target
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Check collision with target
if (self.intersects(self.target)) {
self.target.takeDamage(self.damage);
LK.getSound('hit').play();
LK.effects.flashObject(self.target, 0x8B4513, 300);
if (self.parent) {
self.destroy();
}
return;
}
// Remove stone after maximum lifetime
self.lifetime += 16; // Approximate frame time at 60fps
if (self.lifetime > self.maxLifetime) {
if (self.parent) {
self.destroy();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F4F
});
/****
* Game Code
****/
// Menu variables
var menuState = 'main'; // 'main', 'playing', 'credits', 'options'
var menuButtons = [];
var backgroundObjects = [];
// Game options with defaults
var gameOptions = {
soundVolume: 100,
musicVolume: 100,
difficulty: 'Normal'
};
// Load saved options
var savedOptions = storage.gameOptions;
if (savedOptions) {
gameOptions = savedOptions;
}
// Game variables
var player;
var enemies = [];
var stones = [];
var currentWave = 1;
var enemiesInWave = 3;
var waveStartTime = 0;
var dragNode = null;
var gameState = 'playing'; // 'playing', 'waveComplete', 'gameOver'
var healingFish = null;
var shieldActive = false;
var shieldDuration = 5000; // 5 seconds
var lastScoreMilestone = 0;
var damageMultiplier = 1;
var damageBoostActive = false;
var damageBoostDuration = 10000; // 10 seconds
var waveTxt;
var scoreTxt;
// Create main menu
function createBackgroundObjects() {
// Clear existing background objects
for (var i = 0; i < backgroundObjects.length; i++) {
if (backgroundObjects[i].parent) {
backgroundObjects[i].destroy();
}
}
backgroundObjects = [];
// Create various rotating objects
var objectTypes = ['helmet', 'shield', 'sword', 'stone', 'fish'];
var objectColors = [0x8b7355, 0x654321, 0xc0c0c0, 0x8B4513, 0x00FFFF];
for (var i = 0; i < 15; i++) {
var objectType = objectTypes[Math.floor(Math.random() * objectTypes.length)];
var obj = game.addChild(LK.getAsset(objectType, {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
scaleX: 0.5 + Math.random() * 0.5,
scaleY: 0.5 + Math.random() * 0.5
}));
// Random tint
obj.tint = objectColors[Math.floor(Math.random() * objectColors.length)];
obj.alpha = 0.3 + Math.random() * 0.4;
// Store movement properties
obj.rotationSpeed = (Math.random() - 0.5) * 0.1;
obj.moveSpeedX = (Math.random() - 0.5) * 2;
obj.moveSpeedY = (Math.random() - 0.5) * 2;
// Start rotating animation
tween(obj, {
rotation: Math.PI * 2
}, {
duration: 3000 + Math.random() * 4000,
easing: tween.linear,
onFinish: function onFinish() {
if (this.parent && menuState !== 'playing') {
// Continue rotating
tween(this, {
rotation: this.rotation + Math.PI * 2
}, {
duration: 3000 + Math.random() * 4000,
easing: tween.linear,
onFinish: arguments.callee
});
}
}
});
// Start floating animation
tween(obj, {
x: obj.x + (Math.random() - 0.5) * 400,
y: obj.y + (Math.random() - 0.5) * 400
}, {
duration: 4000 + Math.random() * 6000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (this.parent && menuState !== 'playing') {
// Continue floating
tween(this, {
x: this.x + (Math.random() - 0.5) * 400,
y: this.y + (Math.random() - 0.5) * 400
}, {
duration: 4000 + Math.random() * 6000,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
}
});
backgroundObjects.push(obj);
}
}
function createMainMenu() {
// Note: LK engine doesn't support global volume control
// Volume settings are stored for future use with individual sound assets
// Clear any existing menu elements
for (var i = 0; i < menuButtons.length; i++) {
if (menuButtons[i].parent) {
menuButtons[i].destroy();
}
}
menuButtons = [];
// Create rotating background objects
createBackgroundObjects();
// Game title
var titleTxt = new Text2('SEAL ARENA', {
size: 120,
fill: 0xFFFFFF
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 0;
titleTxt.y = -300;
LK.gui.center.addChild(titleTxt);
// Menu buttons
var buttonTexts = ['JUGAR', 'CREDITOS', 'OPCIONES'];
var buttonActions = [startGame, showCredits, showOptions];
for (var i = 0; i < 3; i++) {
var menuButton = new Container();
var buttonBg = menuButton.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = 0x8b4513;
var buttonText = new Text2(buttonTexts[i], {
size: 50,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
menuButton.addChild(buttonText);
menuButton.y = -100 + i * 120;
menuButton.actionIndex = i;
menuButton.down = function (x, y, obj) {
buttonActions[this.actionIndex]();
};
menuButtons.push(menuButton);
LK.gui.center.addChild(menuButton);
}
}
function startGame() {
menuState = 'playing';
clearMenu();
initializeGame();
}
function showCredits() {
menuState = 'credits';
clearMenu();
var creditsTxt = new Text2('CREDITOS\n\nDesarrollado por FRVR\nMotor: LK Game Engine\nGraficos: Assets personalizados\n\nGracias por jugar!', {
size: 40,
fill: 0xFFFFFF
});
creditsTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(creditsTxt);
var backButton = new Container();
var buttonBg = backButton.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 60
});
buttonBg.tint = 0x8b4513;
var buttonText = new Text2('VOLVER', {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
backButton.addChild(buttonText);
backButton.y = 300;
backButton.down = function () {
menuState = 'main';
clearMenu();
createMainMenu();
};
menuButtons.push(backButton);
LK.gui.center.addChild(backButton);
}
function showOptions() {
menuState = 'options';
clearMenu();
// Title
var titleTxt = new Text2('OPCIONES', {
size: 80,
fill: 0xFFFFFF
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.y = -350;
LK.gui.center.addChild(titleTxt);
// Sound Volume Section
var soundTxt = new Text2('Volumen de Sonido', {
size: 50,
fill: 0xFFFFFF
});
soundTxt.anchor.set(0.5, 0.5);
soundTxt.y = -200;
LK.gui.center.addChild(soundTxt);
// Sound volume buttons
var soundDownBtn = new Container();
var soundDownBg = soundDownBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
soundDownBg.tint = 0x8b4513;
var soundDownText = new Text2('-', {
size: 40,
fill: 0xFFFFFF
});
soundDownText.anchor.set(0.5, 0.5);
soundDownBtn.addChild(soundDownText);
soundDownBtn.x = -150;
soundDownBtn.y = -120;
soundDownBtn.down = function () {
if (gameOptions.soundVolume > 0) {
gameOptions.soundVolume = Math.max(0, gameOptions.soundVolume - 10);
updateOptionDisplay();
}
};
LK.gui.center.addChild(soundDownBtn);
menuButtons.push(soundDownBtn);
var soundUpBtn = new Container();
var soundUpBg = soundUpBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
soundUpBg.tint = 0x8b4513;
var soundUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
soundUpText.anchor.set(0.5, 0.5);
soundUpBtn.addChild(soundUpText);
soundUpBtn.x = 150;
soundUpBtn.y = -120;
soundUpBtn.down = function () {
if (gameOptions.soundVolume < 100) {
gameOptions.soundVolume = Math.min(100, gameOptions.soundVolume + 10);
updateOptionDisplay();
}
};
LK.gui.center.addChild(soundUpBtn);
menuButtons.push(soundUpBtn);
var soundValueTxt = new Text2(gameOptions.soundVolume + '%', {
size: 40,
fill: 0xFFFF00
});
soundValueTxt.anchor.set(0.5, 0.5);
soundValueTxt.y = -120;
LK.gui.center.addChild(soundValueTxt);
// Music Volume Section
var musicTxt = new Text2('Volumen de Musica', {
size: 50,
fill: 0xFFFFFF
});
musicTxt.anchor.set(0.5, 0.5);
musicTxt.y = -20;
LK.gui.center.addChild(musicTxt);
// Music volume buttons
var musicDownBtn = new Container();
var musicDownBg = musicDownBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
musicDownBg.tint = 0x8b4513;
var musicDownText = new Text2('-', {
size: 40,
fill: 0xFFFFFF
});
musicDownText.anchor.set(0.5, 0.5);
musicDownBtn.addChild(musicDownText);
musicDownBtn.x = -150;
musicDownBtn.y = 60;
musicDownBtn.down = function () {
if (gameOptions.musicVolume > 0) {
gameOptions.musicVolume = Math.max(0, gameOptions.musicVolume - 10);
updateOptionDisplay();
}
};
LK.gui.center.addChild(musicDownBtn);
menuButtons.push(musicDownBtn);
var musicUpBtn = new Container();
var musicUpBg = musicUpBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
musicUpBg.tint = 0x8b4513;
var musicUpText = new Text2('+', {
size: 40,
fill: 0xFFFFFF
});
musicUpText.anchor.set(0.5, 0.5);
musicUpBtn.addChild(musicUpText);
musicUpBtn.x = 150;
musicUpBtn.y = 60;
musicUpBtn.down = function () {
if (gameOptions.musicVolume < 100) {
gameOptions.musicVolume = Math.min(100, gameOptions.musicVolume + 10);
updateOptionDisplay();
}
};
LK.gui.center.addChild(musicUpBtn);
menuButtons.push(musicUpBtn);
var musicValueTxt = new Text2(gameOptions.musicVolume + '%', {
size: 40,
fill: 0xFFFF00
});
musicValueTxt.anchor.set(0.5, 0.5);
musicValueTxt.y = 60;
LK.gui.center.addChild(musicValueTxt);
// Difficulty Section
var difficultyTxt = new Text2('Dificultad', {
size: 50,
fill: 0xFFFFFF
});
difficultyTxt.anchor.set(0.5, 0.5);
difficultyTxt.y = 160;
LK.gui.center.addChild(difficultyTxt);
// Difficulty buttons
var difficultyDownBtn = new Container();
var difficultyDownBg = difficultyDownBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
difficultyDownBg.tint = 0x8b4513;
var difficultyDownText = new Text2('<', {
size: 40,
fill: 0xFFFFFF
});
difficultyDownText.anchor.set(0.5, 0.5);
difficultyDownBtn.addChild(difficultyDownText);
difficultyDownBtn.x = -150;
difficultyDownBtn.y = 240;
difficultyDownBtn.down = function () {
var difficulties = ['Facil', 'Normal', 'Dificil'];
var currentIndex = difficulties.indexOf(gameOptions.difficulty);
if (currentIndex > 0) {
gameOptions.difficulty = difficulties[currentIndex - 1];
updateOptionDisplay();
}
};
LK.gui.center.addChild(difficultyDownBtn);
menuButtons.push(difficultyDownBtn);
var difficultyUpBtn = new Container();
var difficultyUpBg = difficultyUpBtn.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 60
});
difficultyUpBg.tint = 0x8b4513;
var difficultyUpText = new Text2('>', {
size: 40,
fill: 0xFFFFFF
});
difficultyUpText.anchor.set(0.5, 0.5);
difficultyUpBtn.addChild(difficultyUpText);
difficultyUpBtn.x = 150;
difficultyUpBtn.y = 240;
difficultyUpBtn.down = function () {
var difficulties = ['Facil', 'Normal', 'Dificil'];
var currentIndex = difficulties.indexOf(gameOptions.difficulty);
if (currentIndex < difficulties.length - 1) {
gameOptions.difficulty = difficulties[currentIndex + 1];
updateOptionDisplay();
}
};
LK.gui.center.addChild(difficultyUpBtn);
menuButtons.push(difficultyUpBtn);
var difficultyValueTxt = new Text2(gameOptions.difficulty, {
size: 40,
fill: 0xFFFF00
});
difficultyValueTxt.anchor.set(0.5, 0.5);
difficultyValueTxt.y = 240;
LK.gui.center.addChild(difficultyValueTxt);
// Update function for option displays
function updateOptionDisplay() {
soundValueTxt.setText(gameOptions.soundVolume + '%');
musicValueTxt.setText(gameOptions.musicVolume + '%');
difficultyValueTxt.setText(gameOptions.difficulty);
// Note: LK engine doesn't support global volume control
// Volume settings are stored for future reference
// Save options
storage.gameOptions = gameOptions;
}
var backButton = new Container();
var buttonBg = backButton.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 60
});
buttonBg.tint = 0x8b4513;
var buttonText = new Text2('VOLVER', {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
backButton.addChild(buttonText);
backButton.y = 350;
backButton.down = function () {
menuState = 'main';
clearMenu();
createMainMenu();
};
menuButtons.push(backButton);
LK.gui.center.addChild(backButton);
}
function clearMenu() {
// Clear all GUI elements
while (LK.gui.center.children.length > 0) {
LK.gui.center.children[0].destroy();
}
while (LK.gui.bottom.children.length > 0) {
LK.gui.bottom.children[0].destroy();
}
while (LK.gui.top.children.length > 0) {
LK.gui.top.children[0].destroy();
}
while (LK.gui.topLeft.children.length > 0) {
LK.gui.topLeft.children[0].destroy();
}
while (LK.gui.topRight.children.length > 0) {
LK.gui.topRight.children[0].destroy();
}
// Clear all game objects
while (game.children.length > 0) {
game.children[0].destroy();
}
// Clear background objects
for (var i = 0; i < backgroundObjects.length; i++) {
if (backgroundObjects[i].parent) {
backgroundObjects[i].destroy();
}
}
backgroundObjects = [];
menuButtons = [];
}
function initializeGame() {
// Create arena
var arenaOuter = game.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
var arenaInner = game.addChild(LK.getAsset('arenaFloor', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create player
player = game.addChild(new Seal(true));
player.x = 2048 / 2;
player.y = 2732 / 2 + 200;
// UI Elements
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
waveTxt = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(waveTxt);
// Attack type display
var attackTxt = new Text2('Attack: Quick Strike', {
size: 40,
fill: 0xFFFF00
});
attackTxt.anchor.set(0.5, 0);
attackTxt.y = 50;
LK.gui.top.addChild(attackTxt);
// Create attack buttons
var attackButtons = [];
for (var i = 0; i < 6; i++) {
var button = new Container();
var buttonBg = button.attachAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0.5,
width: 160,
height: 80
});
// Make button background red
buttonBg.tint = 0xFF0000;
var buttonText = new Text2(player.attackTypes[i].name, {
size: 24,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonText);
// Position buttons horizontally across bottom of screen
button.x = (i - 2.5) * 160;
button.y = -120;
// Store button index for reference
button.attackIndex = i;
// Button click handler
button.down = function (x, y, obj) {
if (gameState === 'playing' && !player.isDead) {
player.currentAttack = this.attackIndex;
attackTxt.setText('Attack: ' + player.attackTypes[player.currentAttack].name);
attackTxt.tint = player.attackTypes[player.currentAttack].color;
// Special handling for stone throw attack (infinite usage)
if (player.currentAttack === 5) {
// Find closest enemy for stone targeting
var stoneTarget = null;
var closestStoneDistance = Infinity;
for (var m = 0; m < enemies.length; m++) {
var enemy = enemies[m];
if (enemy && !enemy.isDead) {
var distance = Math.sqrt(Math.pow(player.x - enemy.x, 2) + Math.pow(player.y - enemy.y, 2));
if (distance < closestStoneDistance) {
closestStoneDistance = distance;
stoneTarget = enemy;
}
}
}
if (stoneTarget) {
var stone = new Stone(stoneTarget);
stone.x = player.x;
stone.y = player.y;
stones.push(stone);
game.addChild(stone);
// Throwing animation
var attack = player.attackTypes[player.currentAttack];
tween(player, {
scaleX: attack.scale,
scaleY: attack.scale,
rotation: Math.PI / 4
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Update button visual states for stone attack
for (var j = 0; j < attackButtons.length; j++) {
if (j === player.currentAttack) {
attackButtons[j].children[0].tint = 0xFFAAAA; // Lighter red for selected
attackButtons[j].children[1].tint = 0x000000;
} else {
attackButtons[j].children[0].tint = 0xFF0000; // Red for unselected
attackButtons[j].children[1].tint = 0xFFFFFF;
}
}
return; // Exit early for stone attacks to avoid melee logic
}
// Find closest enemy and attack instantly for melee attacks
var closestEnemy = null;
var closestDistance = Infinity;
for (var k = 0; k < enemies.length; k++) {
var enemy = enemies[k];
if (enemy && !enemy.isDead) {
var distance = Math.sqrt(Math.pow(player.x - enemy.x, 2) + Math.pow(player.y - enemy.y, 2));
if (distance < closestDistance && distance < 200) {
// Attack range
closestDistance = distance;
closestEnemy = enemy;
}
}
}
// Execute instant attack if enemy in range
if (closestEnemy) {
var attack = player.attackTypes[player.currentAttack];
var finalDamage = attack.damage * damageMultiplier;
closestEnemy.takeDamage(finalDamage);
LK.getSound('hit').play();
// Execute attack animation instantly
if (player.currentAttack === 0) {
// Quick Strike - Fast dart forward
var originalX = player.x;
var originalY = player.y;
var angle = Math.atan2(closestEnemy.y - player.y, closestEnemy.x - player.x);
tween(player, {
x: player.x + Math.cos(angle) * 30,
y: player.y + Math.sin(angle) * 30,
scaleX: attack.scale,
scaleY: attack.scale
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
x: originalX,
y: originalY,
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
} else if (player.currentAttack === 1) {
// Power Slam - Bounce up and down
tween(player, {
y: player.y - 40,
scaleX: attack.scale,
scaleY: attack.scale * 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
y: player.y + 40,
scaleX: 1,
scaleY: 0.8
}, {
duration: 150,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(player, {
scaleY: 1
}, {
duration: 100
});
}
});
}
});
} else if (player.currentAttack === 2) {
// Spinning Attack - Full rotation with scale
tween(player, {
rotation: Math.PI * 2,
scaleX: attack.scale,
scaleY: attack.scale
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
} else if (player.currentAttack === 3) {
// Devastating Blow - Multiple quick pulses
var pulseCount = 0;
var maxPulses = 3;
var _doPulse2 = function doPulse() {
tween(player, {
scaleX: attack.scale,
scaleY: attack.scale,
tint: 0xFF4444
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.1,
scaleY: 1.1,
tint: 0xFFFFFF
}, {
duration: 80,
easing: tween.easeIn,
onFinish: function onFinish() {
pulseCount++;
if (pulseCount < maxPulses) {
_doPulse2();
} else {
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
}
});
}
});
};
_doPulse2();
} else if (player.currentAttack === 4) {
// Ultimate Strike - Charge up with shake then explosive strike
var originalX = player.x;
var originalY = player.y;
var shakeCount = 0;
var maxShakes = 8;
var _doShake2 = function doShake() {
var shakeAmount = 15;
tween(player, {
x: originalX + (Math.random() - 0.5) * shakeAmount,
y: originalY + (Math.random() - 0.5) * shakeAmount,
scaleX: 1 + shakeCount * 0.1,
scaleY: 1 + shakeCount * 0.1
}, {
duration: 50,
onFinish: function onFinish() {
shakeCount++;
if (shakeCount < maxShakes) {
_doShake2();
} else {
// Final explosive strike
tween(player, {
x: originalX,
y: originalY,
scaleX: attack.scale,
scaleY: attack.scale,
tint: 0x00FFFF
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
}
});
};
_doShake2();
}
// Flash effect with attack color
if (closestEnemy) {
LK.effects.flashObject(closestEnemy, attack.color, 300);
}
// Activate invincibility for 3 seconds
player.isInvincible = true;
// Visual feedback for invincibility - make seal semi-transparent and glow
tween(player, {
alpha: 0.6,
tint: 0x00FFFF
}, {
duration: 200,
onFinish: function onFinish() {
// Pulsing effect during invincibility
var _pulseEffect2 = function pulseEffect() {
if (player.isInvincible) {
tween(player, {
alpha: 0.4
}, {
duration: 300,
onFinish: function onFinish() {
if (player.isInvincible) {
tween(player, {
alpha: 0.6
}, {
duration: 300,
onFinish: _pulseEffect2
});
}
}
});
}
};
_pulseEffect2();
}
});
// End invincibility after duration
LK.setTimeout(function () {
player.isInvincible = false;
// Restore normal appearance
tween(player, {
alpha: 1,
tint: 0xFFFFFF
}, {
duration: 300
});
}, player.invincibilityDuration);
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
checkScoreMilestone();
}
// Update button visual states
for (var j = 0; j < attackButtons.length; j++) {
if (j === player.currentAttack) {
attackButtons[j].children[0].tint = 0xFFAAAA; // Lighter red for selected
attackButtons[j].children[1].tint = 0x000000;
} else {
attackButtons[j].children[0].tint = 0xFF0000; // Red for unselected
attackButtons[j].children[1].tint = 0xFFFFFF;
}
}
}
};
attackButtons.push(button);
LK.gui.bottom.addChild(button);
}
// Set initial button states
attackButtons[0].children[0].tint = 0xFFAAAA; // Lighter red for selected
attackButtons[0].children[1].tint = 0x000000;
for (var i = 1; i < attackButtons.length; i++) {
attackButtons[i].children[0].tint = 0xFF0000; // Red for unselected
attackButtons[i].children[1].tint = 0xFFFFFF;
}
// Instructions
var instructionTxt = new Text2('Select attack with buttons | Touch buttons to attack nearby enemies', {
size: 30,
fill: 0xCCCCCC
});
instructionTxt.anchor.set(0.5, 1);
instructionTxt.y = -40;
LK.gui.bottom.addChild(instructionTxt);
// Start first wave
spawnWave();
}
// Functions
function spawnWave() {
enemies = [];
waveStartTime = Date.now();
// Apply difficulty modifier
var difficultyMultiplier = 1;
if (gameOptions.difficulty === 'Facil') {
difficultyMultiplier = 0.7;
} else if (gameOptions.difficulty === 'Dificil') {
difficultyMultiplier = 1.5;
}
var adjustedEnemiesInWave = Math.ceil(enemiesInWave * difficultyMultiplier);
for (var i = 0; i < adjustedEnemiesInWave; i++) {
var enemy = game.addChild(new EnemySeal());
// Apply difficulty to enemy stats
enemy.maxHealth = Math.floor(enemy.maxHealth * difficultyMultiplier);
enemy.currentHealth = enemy.maxHealth;
enemy.healthBar.updateHealth(enemy.currentHealth);
enemy.attackDamage = Math.floor(enemy.attackDamage * difficultyMultiplier);
enemy.speed = enemy.speed * (0.8 + difficultyMultiplier * 0.4);
// Spawn enemies around the arena edge
var angle = i / adjustedEnemiesInWave * Math.PI * 2;
var spawnRadius = 500;
enemy.x = 2048 / 2 + Math.cos(angle) * spawnRadius;
enemy.y = 2732 / 2 + Math.sin(angle) * spawnRadius;
enemies.push(enemy);
}
waveTxt.setText('Wave: ' + currentWave);
gameState = 'playing';
}
function createConfetti() {
// Create multiple confetti pieces
for (var i = 0; i < 50; i++) {
var confetti = game.addChild(LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5,
width: 10 + Math.random() * 10,
height: 10 + Math.random() * 10,
x: Math.random() * 2048,
y: -50
}));
// Random colors for confetti
var colors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF];
confetti.tint = colors[Math.floor(Math.random() * colors.length)];
// Animate confetti falling
tween(confetti, {
y: 2732 + 100,
rotation: Math.PI * 4 * (Math.random() - 0.5),
x: confetti.x + (Math.random() - 0.5) * 200
}, {
duration: 3000 + Math.random() * 2000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (this.parent) {
this.destroy();
}
}
});
}
}
function checkScoreMilestone() {
var currentScore = LK.getScore();
var currentMilestone = Math.floor(currentScore / 100000);
if (currentMilestone > lastScoreMilestone) {
lastScoreMilestone = currentMilestone;
// Launch confetti
createConfetti();
// Activate triple damage for 10 seconds
damageMultiplier = 3;
damageBoostActive = true;
// Visual feedback for damage boost
tween(player, {
tint: 0xFF4500 // Orange glow for damage boost
}, {
duration: 300,
onFinish: function onFinish() {
// Pulsing effect during damage boost
var _pulseDamageBoost = function pulseDamageBoost() {
if (damageBoostActive) {
tween(player, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 500,
onFinish: function onFinish() {
if (damageBoostActive) {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
onFinish: _pulseDamageBoost
});
}
}
});
}
};
_pulseDamageBoost();
}
});
// End damage boost after duration
LK.setTimeout(function () {
damageMultiplier = 1;
damageBoostActive = false;
// Restore normal appearance
tween(player, {
tint: 0xFFFFFF,
scaleX: 1,
scaleY: 1
}, {
duration: 500
});
}, damageBoostDuration);
// Flash screen to indicate milestone
LK.effects.flashScreen(0xFFD700, 1000);
}
}
function spawnHealingFish() {
if (healingFish) return; // Don't spawn if fish already exists
healingFish = game.addChild(LK.getAsset('fish', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 150
}));
// Animate fish floating and glowing
tween(healingFish, {
y: healingFish.y - 20,
tint: 0x00FFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(healingFish, {
y: healingFish.y + 20,
tint: 0xFFFFFF
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (healingFish && healingFish.parent) {
spawnHealingFish(); // Continue animation loop
}
}
});
}
});
// Make fish clickable for healing
healingFish.down = function (x, y, obj) {
if (player && !player.isDead) {
// Heal player to full health
player.currentHealth = player.maxHealth;
player.healthBar.updateHealth(player.currentHealth);
// Activate shield for 5 seconds
shieldActive = true;
// Visual feedback for shield - golden glow
tween(player, {
alpha: 0.8,
tint: 0xFFD700 // Golden color for shield
}, {
duration: 300,
onFinish: function onFinish() {
// Pulsing shield effect
var _shieldPulse = function shieldPulse() {
if (shieldActive) {
tween(player, {
alpha: 0.6
}, {
duration: 400,
onFinish: function onFinish() {
if (shieldActive) {
tween(player, {
alpha: 0.8
}, {
duration: 400,
onFinish: _shieldPulse
});
}
}
});
}
};
_shieldPulse();
}
});
// End shield after duration
LK.setTimeout(function () {
shieldActive = false;
// Restore normal appearance
tween(player, {
alpha: 1,
tint: 0xFFFFFF
}, {
duration: 500
});
}, shieldDuration);
// Fish consumption animation
tween(healingFish, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
tint: 0x00FF00
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (healingFish && healingFish.parent) {
healingFish.destroy();
healingFish = null;
}
}
});
// Flash player green to show healing
LK.effects.flashObject(player, 0x00FF00, 500);
}
};
}
function nextWave() {
currentWave++;
enemiesInWave += 2; // Increase difficulty
// Spawn healing fish at the end of each wave
spawnHealingFish();
LK.setTimeout(function () {
spawnWave();
}, 2000);
gameState = 'waveComplete';
}
function checkWaveComplete() {
var aliveEnemies = 0;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] && !enemies[i].isDead) {
aliveEnemies++;
}
}
if (aliveEnemies === 0 && gameState === 'playing') {
// Wave complete bonus
var timeBonus = Math.max(0, 10000 - (Date.now() - waveStartTime)) / 100;
LK.setScore(LK.getScore() + 500 + Math.floor(timeBonus));
scoreTxt.setText('Score: ' + LK.getScore());
checkScoreMilestone();
if (currentWave >= 5) {
// Victory condition
LK.showYouWin();
} else {
nextWave();
}
}
}
// Input handling
game.down = function (x, y, obj) {
if (menuState === 'playing' && gameState === 'playing' && player && !player.isDead) {
// Start dragging for positioning
dragNode = player;
}
};
game.move = function (x, y, obj) {
if (menuState === 'playing' && dragNode && gameState === 'playing' && player && !player.isDead) {
dragNode.x = x;
dragNode.y = y;
// Keep player within arena bounds
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var arenaRadius = 700;
var distFromCenter = Math.sqrt(Math.pow(dragNode.x - centerX, 2) + Math.pow(dragNode.y - centerY, 2));
if (distFromCenter > arenaRadius) {
var angle = Math.atan2(dragNode.y - centerY, dragNode.x - centerX);
dragNode.x = centerX + Math.cos(angle) * arenaRadius;
dragNode.y = centerY + Math.sin(angle) * arenaRadius;
}
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game loop
game.update = function () {
// Update background objects when in menu
if (menuState !== 'playing') {
for (var i = 0; i < backgroundObjects.length; i++) {
var obj = backgroundObjects[i];
if (obj && obj.parent) {
// Apply continuous movement
obj.x += obj.moveSpeedX;
obj.y += obj.moveSpeedY;
// Apply continuous rotation
obj.rotation += obj.rotationSpeed;
// Keep objects within screen bounds
if (obj.x < -100) obj.x = 2148;
if (obj.x > 2148) obj.x = -100;
if (obj.y < -100) obj.y = 2832;
if (obj.y > 2832) obj.y = -100;
}
}
}
if (menuState === 'playing' && gameState === 'playing') {
// Update and clean up stone projectiles
for (var i = stones.length - 1; i >= 0; i--) {
var stone = stones[i];
if (stone && stone.parent) {
// Stone is still active, update handled by stone.update()
} else {
// Stone was destroyed, remove from array
stones.splice(i, 1);
}
}
// Remove dead enemies from array and handle enemy updates
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy && enemy.isDead) {
enemies.splice(i, 1);
}
}
// Check if player is dead
if (player && player.isDead) {
gameState = 'gameOver';
LK.setTimeout(function () {
menuState = 'main';
clearMenu();
createMainMenu();
}, 1000);
}
// Check wave completion
checkWaveComplete();
}
};
// Initialize main menu
createMainMenu();
arena de sumo de pixeles. In-Game asset. 2d. High contrast. No shadows
una foca de pixeles con armadura de gladiador. In-Game asset. 2d. High contrast. No shadows
pes de pixeles. In-Game asset. 2d. High contrast. No shadows
piedra de pixeles. In-Game asset. 2d. High contrast. No shadows
casco de gladiador de pixeles. In-Game asset. 2d. High contrast. No shadows
peto de pixeles. In-Game asset. 2d. High contrast. No shadows
espada de pixeles orizontal. In-Game asset. 2d. High contrast. No shadows
boton azul de pixeles. In-Game asset. 2d. High contrast. No shadows