User prompt
Muestra las barras de vida después de que inicie el combate, no en el menú, en el menú has un fondo en dónde los personajes aparezcan luchando en un vacío y que muestre el puntaje de la anterior partida ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Agrega partículas para cuando estés defendiendo, cuando ataques con el golpe o con patada
User prompt
Que la inteligencia del enemigo sea mayor dependiendo la dificultad pero que aún así pueda moverse y luchar de manera inteligente
User prompt
Que el enemigo se pueda acercar y atacarte, esquivar y defenderse
User prompt
Que puedas elegir entre el tiburón, el lobo y el lagarto y que no solo te ponga al tiburon
User prompt
Arregla que al seleccionar un personaje no te de otro totalmente diferente, que el menú se puedan editar sus assets y que se puedan poner más variedades de enemigos
User prompt
Cada que ganes que aparezca un letrero de k.o de que ganaste y que te dé la opción de seguir luchando con otros enemigos o parar ahí, que haya un total de 20 enemigos y que aparezcan de manera aleatoria pero con sus nombres
User prompt
Que la barra de esta mina disminuya de manera que si atacas mucho te canses y para recuperarla necesites no atacar, que la vida sea mucho mayor para que el combate dure una buena cantidad pero que no sea excesiva
User prompt
Que los botones estén el centro, más grandes y un poco más separados , que el botón de defender reduzca el daño que recibas y que las patadas sean algo lentas pero con un poco más de daño
User prompt
La línea gris que también se vaya con los personajes y que el fondo sea más grande y deja libre la parte de abajo para agregar los botones y que aparezcan en la pantalla
User prompt
Elimina los botones de saltar y morder que sean reemplazados por la cruceta y que tendrán las siguientes funciones, arriba saltar, izquierda ir para la izquierda, derecha para ir a la derecha y abajo para agacharse, necesito que dónde están los personajes se encuentre más centrado de la pantalla para que así puedas poner la cruceta en la parte inferior central izquierda y agregues los botones para golpear, patear y defenderse
Code edit (1 edits merged)
Please save this source code
User prompt
Necesito que implementos las diferentes habilidades y que sean únicas de cada personaje y que no se repitan, también necesito que hagas una cruceta para que te puedas mover de izquierda a derecha y que puedas saltar y agacharte sin necesidad de que la cruceta este hasta la esquina derecha, necesito que esté en el centro izquierdo
User prompt
Necesito que hagas una cruceta , para que puedas moverte de un lado al otro, saltar y agacharse, que el enemigo sea un poco más agresivo y que la cruceta no esté hasta la esquina
Code edit (1 edits merged)
Please save this source code
User prompt
Necesito que los botones de acciones para pelear aparezcan después de iniciar el juego ya que en el menú estorban, también que los botones no estén hasta la esquina derecha, pueden estar en la parte superior central y con separación y algo grandes
User prompt
Necesito que separes un poco los botones del menu y que los botones de movimiento se vean como una cruceta incluyendo un botón para saltar y agacharse y que cada personaje tenga habilidades diferentes por ejemplo el tiburón que lance aguas, que el lagarto se mueva más rápido y que el lobo pueda morder, también necesito que las barras de vida del enemigo sean más altas y que estén del lado del oponente
User prompt
Que los botones de pelear y defenderse aparezcan después del menu, junto a botones en dónde tú personaje se pueda mover y que el botón de atacar no sea el único que también haya botones de patada o agarres que salen al enemigo y que el enemigo también se pueda mover y atacar de manera inteligente dependiendo la dificultad que se podra elegir en el inicio
User prompt
Al momento de iniciar la batalla que inicie un contador y que haya botones en la parte superior para que en móvil se puedan seleccionar al igual Sprites para cada acción que selecciones, también que el oponente tenga una barra de vida y el contador para acabar la pelea se pueda seleccionar sin límite o con un límite de 90 segundos
User prompt
Faltan botones para las acciones y el menú general para iniciar un combate
Code edit (1 edits merged)
Please save this source code
User prompt
Furry Fighter Arena
User prompt
Se me ocurre que los jefes y combatientes tengan pinta de animales furros como tiburones fuertes, lagartos etc,
User prompt
Please continue polishing my design document.
Initial prompt
Se me ocurre un juego de peleas rítmicas en dónde se deban de usar botones al ritmo sonoro con jefes con soundtrack memorables y personajes icónicos
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Button = Container.expand(function (assetName, text) { var self = Container.call(this); var buttonGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); var buttonText = new Text2(text, { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); self.down = function (x, y, obj) { tween(buttonGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(buttonGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); }; return self; }); var CharacterCard = Container.expand(function (characterType, name) { var self = Container.call(this); self.characterType = characterType; self.isSelected = false; var cardBg = self.attachAsset('characterCard', { anchorX: 0.5, anchorY: 0.5 }); var character = self.attachAsset(characterType + 'Fighter', { anchorX: 0.5, anchorY: 0.8, y: -20 }); var nameText = new Text2(name, { size: 30, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = 100; self.addChild(nameText); self.setSelected = function (selected) { self.isSelected = selected; if (selected) { cardBg.tint = 0xf39c12; tween(cardBg, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200 }); } else { cardBg.tint = 0xFFFFFF; tween(cardBg, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }; self.down = function (x, y, obj) { if (gameState === 'characterSelect') { selectedCharacter = self.characterType; for (var i = 0; i < characterCards.length; i++) { characterCards[i].setSelected(characterCards[i] === self); } console.log('Selected character:', selectedCharacter); } }; return self; }); var Fighter = Container.expand(function (isPlayer) { var self = Container.call(this); self.isPlayer = isPlayer || false; self.maxHealth = 300; self.health = self.maxHealth; self.maxStamina = 100; self.stamina = self.maxStamina; self.attackPower = 20; self.isBlocking = false; self.isAttacking = false; self.canAttack = true; self.staminaRegenRate = 0.5; self.lastAttackTime = 0; var assetName = 'playerFighter'; if (isPlayer) { // Use the selected character for the player assetName = selectedCharacter + 'Fighter'; console.log('Using player asset:', assetName, 'selectedCharacter:', selectedCharacter); } else { // Randomly select enemy type for variety var enemyTypes = ['enemy', 'lizard', 'shark', 'wolf', 'bear', 'tiger', 'eagle']; var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)]; assetName = randomType + 'Fighter'; console.log('Using enemy asset:', assetName); } var fighterGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1 }); self.attack = function () { if (!self.canAttack || self.stamina < 25) { return false; } self.isAttacking = true; self.canAttack = false; self.stamina -= 25; self.lastAttackTime = Date.now(); tween(fighterGraphics, { scaleX: 1.2, scaleY: 0.9 }, { duration: 100, onFinish: function onFinish() { tween(fighterGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100 }); } }); LK.getSound('punch').play(); // Add punch particles if (self.isPlayer) { var punchParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', self.x + 50, self.y - 100, 8)); } LK.setTimeout(function () { self.isAttacking = false; self.canAttack = true; }, 300); return true; }; self.block = function () { if (self.stamina < 15) { return false; } self.isBlocking = true; self.stamina -= 15; self.lastAttackTime = Date.now(); tween(fighterGraphics, { tint: 0x3498db }, { duration: 200, onFinish: function onFinish() { tween(fighterGraphics, { tint: 0xffffff }, { duration: 200 }); } }); LK.getSound('block').play(); // Add block particles if (self.isPlayer) { var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', self.x, self.y - 100, 12)); } LK.setTimeout(function () { self.isBlocking = false; }, 400); return true; }; self.specialAttack = function () { if (self.stamina < 60) { return false; } self.stamina -= 60; self.lastAttackTime = Date.now(); tween(fighterGraphics, { scaleX: 1.5, scaleY: 1.5, tint: 0xffd700 }, { duration: 300, onFinish: function onFinish() { tween(fighterGraphics, { scaleX: 1, scaleY: 1, tint: 0xffffff }, { duration: 300 }); } }); LK.getSound('special').play(); return true; }; self.takeDamage = function (damage) { if (self.isBlocking) { damage = Math.floor(damage * 0.2); } self.health -= damage; if (self.health < 0) { self.health = 0; } LK.effects.flashObject(self, 0xff0000, 200); tween(fighterGraphics, { x: fighterGraphics.x + (self.isPlayer ? -20 : 20) }, { duration: 100, onFinish: function onFinish() { tween(fighterGraphics, { x: 0 }, { duration: 100 }); } }); }; self.update = function () { var currentTime = Date.now(); // Only regenerate stamina if not attacking recently (1 second cooldown) if (currentTime - self.lastAttackTime > 1000) { if (self.stamina < self.maxStamina) { self.stamina += self.staminaRegenRate; if (self.stamina > self.maxStamina) { self.stamina = self.maxStamina; } } } }; return self; }); var HealthBar = Container.expand(function (maxValue) { var self = Container.call(this); self.maxValue = maxValue; self.currentValue = maxValue; var background = self.attachAsset('healthBarBg', { anchorX: 0, anchorY: 0 }); var bar = self.attachAsset('healthBar', { anchorX: 0, anchorY: 0 }); self.setValue = function (value) { self.currentValue = value; var percentage = value / self.maxValue; bar.scaleX = percentage; if (percentage > 0.6) { bar.tint = 0x2ecc71; } else if (percentage > 0.3) { bar.tint = 0xf39c12; } else { bar.tint = 0xe74c3c; } }; return self; }); var ParticleSystem = Container.expand(function (particleType, x, y, count) { var self = Container.call(this); self.particles = []; self.particleType = particleType; self.x = x; self.y = y; // Create particles for (var i = 0; i < count; i++) { var particle = self.addChild(LK.getAsset(particleType, { anchorX: 0.5, anchorY: 0.5 })); // Set initial properties based on particle type if (particleType === 'sparkParticle') { particle.velocityX = (Math.random() - 0.5) * 200; particle.velocityY = (Math.random() - 0.5) * 200 - 100; particle.life = 1.0; particle.decay = 0.02; } else if (particleType === 'blockParticle') { particle.velocityX = (Math.random() - 0.5) * 150; particle.velocityY = (Math.random() - 0.5) * 150; particle.life = 1.0; particle.decay = 0.03; } else if (particleType === 'hitParticle') { particle.velocityX = (Math.random() - 0.5) * 300; particle.velocityY = (Math.random() - 0.5) * 300 - 50; particle.life = 1.0; particle.decay = 0.025; } self.particles.push(particle); } self.update = function () { for (var i = self.particles.length - 1; i >= 0; i--) { var particle = self.particles[i]; // Update position particle.x += particle.velocityX * 0.016; // 60fps particle.y += particle.velocityY * 0.016; // Apply gravity for spark and hit particles if (particleType === 'sparkParticle' || particleType === 'hitParticle') { particle.velocityY += 300 * 0.016; // Gravity } // Update life and alpha particle.life -= particle.decay; particle.alpha = particle.life; // Remove dead particles if (particle.life <= 0) { particle.destroy(); self.particles.splice(i, 1); } } // Remove system when all particles are gone if (self.particles.length === 0) { self.destroy(); } }; return self; }); var StaminaBar = Container.expand(function (maxValue) { var self = Container.call(this); self.maxValue = maxValue; self.currentValue = maxValue; var background = self.attachAsset('staminaBarBg', { anchorX: 0, anchorY: 0 }); var bar = self.attachAsset('staminaBar', { anchorX: 0, anchorY: 0 }); self.setValue = function (value) { self.currentValue = value; var percentage = value / self.maxValue; bar.scaleX = percentage; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c3e50 }); /**** * Game Code ****/ var gameState = 'menu'; var roundTimer = 60; var roundStartTime = 0; var battleCountdown = 3; var countdownActive = false; var timerMode = 'unlimited'; // 'unlimited' or 'limited' var selectedCharacter = 'shark'; var characterCards = []; var currentEnemyIndex = 0; var totalEnemies = 20; var enemyNames = ['Razor Claw', 'Iron Fang', 'Storm Fury', 'Shadow Beast', 'Thunder Paws', 'Venom Strike', 'Blade Runner', 'Fire Tooth', 'Ice Crusher', 'Wind Slasher', 'Stone Jaw', 'Lightning Bolt', 'Dark Hunter', 'Flame Warrior', 'Frost Bite', 'Night Stalker', 'Blood Fang', 'Steel Claw', 'Wild Storm', 'Bone Breaker', 'Crimson Fang', 'Golden Claw', 'Silver Strike', 'Midnight Howl', 'Dawn Breaker', 'Skull Crusher', 'Void Walker', 'Star Slayer', 'Moon Fang', 'Sun Warrior']; var menuContainer = game.addChild(new Container()); var characterSelectContainer = game.addChild(new Container()); var gameplayContainer = game.addChild(new Container()); // Create animated background for menu var menuBg = menuContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366, alpha: 0.3 })); // Create fighting characters in background var menuFighter1 = menuContainer.addChild(LK.getAsset('sharkFighter', { anchorX: 0.5, anchorY: 1, x: 2048 / 2 - 400, y: 1600, alpha: 0.4 })); var menuFighter2 = menuContainer.addChild(LK.getAsset('wolfFighter', { anchorX: 0.5, anchorY: 1, x: 2048 / 2 + 400, y: 1600, alpha: 0.4 })); // Animate background fighters tween(menuFighter1, { x: menuFighter1.x + 50, scaleX: 1.1, scaleY: 0.9 }, { duration: 1000, loop: true, yoyo: true }); tween(menuFighter2, { x: menuFighter2.x - 50, scaleX: 1.1, scaleY: 0.9 }, { duration: 1200, loop: true, yoyo: true }); var titleText = new Text2('FURRY FIGHTER ARENA', { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 600; menuContainer.addChild(titleText); // Display previous game score var previousScore = storage.lastScore || 0; var previousScoreText = new Text2('Previous Score: ' + previousScore, { size: 50, fill: 0xecf0f1 }); previousScoreText.anchor.set(0.5, 0.5); previousScoreText.x = 2048 / 2; previousScoreText.y = 1000; menuContainer.addChild(previousScoreText); var startButton = new Button('menuButton', 'START COMBAT'); startButton.x = 2048 / 2; startButton.y = 1200; menuContainer.addChild(startButton); startButton.down = function (x, y, obj) { if (gameState === 'menu') { gameState = 'characterSelect'; menuContainer.visible = false; characterSelectContainer.visible = true; } }; var characterSelectTitle = new Text2('SELECT YOUR FIGHTER', { size: 60, fill: 0xFFFFFF }); characterSelectTitle.anchor.set(0.5, 0.5); characterSelectTitle.x = 2048 / 2; characterSelectTitle.y = 400; characterSelectContainer.addChild(characterSelectTitle); var sharkCard = new CharacterCard('shark', 'SHARK'); sharkCard.x = 2048 / 2 - 300; sharkCard.y = 1000; characterSelectContainer.addChild(sharkCard); characterCards.push(sharkCard); var lizardCard = new CharacterCard('lizard', 'LIZARD'); lizardCard.x = 2048 / 2; lizardCard.y = 1000; characterSelectContainer.addChild(lizardCard); characterCards.push(lizardCard); var wolfCard = new CharacterCard('wolf', 'WOLF'); wolfCard.x = 2048 / 2 + 300; wolfCard.y = 1000; characterSelectContainer.addChild(wolfCard); characterCards.push(wolfCard); sharkCard.setSelected(true); selectedCharacter = 'shark'; console.log('Initial selected character:', selectedCharacter); var difficultyText = new Text2('DIFFICULTY: MEDIUM', { size: 50, fill: 0xFFFFFF }); difficultyText.anchor.set(0.5, 0.5); difficultyText.x = 2048 / 2; difficultyText.y = 1300; characterSelectContainer.addChild(difficultyText); var difficultyButton = new Button('menuButton', 'CHANGE DIFFICULTY'); difficultyButton.x = 2048 / 2; difficultyButton.y = 1400; characterSelectContainer.addChild(difficultyButton); var timerModeText = new Text2('TIMER MODE: UNLIMITED', { size: 50, fill: 0xFFFFFF }); timerModeText.anchor.set(0.5, 0.5); timerModeText.x = 2048 / 2; timerModeText.y = 1500; characterSelectContainer.addChild(timerModeText); difficultyButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { if (enemyAI.difficulty === 'easy') { enemyAI.difficulty = 'medium'; difficultyText.setText('DIFFICULTY: MEDIUM'); } else if (enemyAI.difficulty === 'medium') { enemyAI.difficulty = 'hard'; difficultyText.setText('DIFFICULTY: HARD'); } else { enemyAI.difficulty = 'easy'; difficultyText.setText('DIFFICULTY: EASY'); } } }; var timerModeButton = new Button('menuButton', 'TOGGLE TIMER'); timerModeButton.x = 2048 / 2; timerModeButton.y = 1550; characterSelectContainer.addChild(timerModeButton); timerModeButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { if (timerMode === 'unlimited') { timerMode = 'limited'; timerModeText.setText('TIMER MODE: 90 SECONDS'); } else { timerMode = 'unlimited'; timerModeText.setText('TIMER MODE: UNLIMITED'); } } }; var fightButton = new Button('menuButton', 'FIGHT!'); fightButton.x = 2048 / 2; fightButton.y = 1650; characterSelectContainer.addChild(fightButton); fightButton.down = function (x, y, obj) { if (gameState === 'characterSelect') { gameState = 'countdown'; characterSelectContainer.visible = false; gameplayContainer.visible = true; // Show health and stamina bars when combat starts playerHealthBar.visible = true; enemyHealthBar.visible = true; playerStaminaBar.visible = true; enemyStaminaBar.visible = true; // Recreate player fighter with selected character gameplayContainer.removeChild(playerFighter); playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; if (timerMode === 'limited') { roundTimer = 90; } else { roundTimer = -1; // Unlimited time } battleCountdown = 3; countdownActive = true; // Reset enemy progression currentEnemyIndex = 0; // Shuffle enemy names for random encounters for (var i = enemyNames.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = enemyNames[i]; enemyNames[i] = enemyNames[j]; enemyNames[j] = temp; } } }; characterSelectContainer.visible = false; gameplayContainer.visible = false; var arena = gameplayContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 1800 })); var arenaLine = gameplayContainer.addChild(LK.getAsset('arenaLine', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 1600 })); var playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; // Aligned with arena line var enemyFighter = gameplayContainer.addChild(new Fighter(false)); enemyFighter.x = 2048 / 2 + 300; enemyFighter.y = 1600; // Aligned with arena line var playerHealthBar = new HealthBar(300); playerHealthBar.x = 100; playerHealthBar.y = 100; playerHealthBar.visible = false; LK.gui.topLeft.addChild(playerHealthBar); var enemyHealthBar = new HealthBar(300); enemyHealthBar.x = -500; enemyHealthBar.y = 100; enemyHealthBar.visible = false; LK.gui.topRight.addChild(enemyHealthBar); var playerStaminaBar = new StaminaBar(100); playerStaminaBar.x = 100; playerStaminaBar.y = 150; playerStaminaBar.visible = false; LK.gui.topLeft.addChild(playerStaminaBar); var enemyStaminaBar = new StaminaBar(100); enemyStaminaBar.x = -500; enemyStaminaBar.y = 150; enemyStaminaBar.visible = false; LK.gui.topRight.addChild(enemyStaminaBar); var timerText = new Text2('60', { size: 80, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); var countdownText = new Text2('3', { size: 200, fill: 0xf39c12 }); countdownText.anchor.set(0.5, 0.5); countdownText.x = 2048 / 2; countdownText.y = 1366; gameplayContainer.addChild(countdownText); countdownText.visible = false; var scoreText = new Text2('Score: 0', { size: 50, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.y = 100; LK.gui.top.addChild(scoreText); var actionSprite = LK.getAsset('actionSprite', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1000 }); gameplayContainer.addChild(actionSprite); actionSprite.visible = false; // Victory screen elements var victoryContainer = game.addChild(new Container()); victoryContainer.visible = false; var victoryBg = victoryContainer.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366, scaleX: 1.2, scaleY: 1.5 })); victoryBg.tint = 0x2c3e50; victoryBg.alpha = 0.9; var koText = new Text2('K.O.!', { size: 150, fill: 0xf39c12 }); koText.anchor.set(0.5, 0.5); koText.x = 2048 / 2; koText.y = 800; victoryContainer.addChild(koText); var victoryText = new Text2('YOU WIN!', { size: 80, fill: 0x2ecc71 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 2048 / 2; victoryText.y = 950; victoryContainer.addChild(victoryText); var enemyDefeatedText = new Text2('', { size: 60, fill: 0xFFFFFF }); enemyDefeatedText.anchor.set(0.5, 0.5); enemyDefeatedText.x = 2048 / 2; enemyDefeatedText.y = 1100; victoryContainer.addChild(enemyDefeatedText); var progressText = new Text2('', { size: 50, fill: 0xecf0f1 }); progressText.anchor.set(0.5, 0.5); progressText.x = 2048 / 2; progressText.y = 1200; victoryContainer.addChild(progressText); var continueButton = new Button('menuButton', 'CONTINUE FIGHTING'); continueButton.x = 2048 / 2 - 250; continueButton.y = 1400; victoryContainer.addChild(continueButton); var stopButton = new Button('menuButton', 'STOP HERE'); stopButton.x = 2048 / 2 + 250; stopButton.y = 1400; victoryContainer.addChild(stopButton); function showActionSprite(actionType, color) { if (gameState !== 'playing') { return; } actionSprite.visible = true; actionSprite.tint = color; actionSprite.scaleX = 0.5; actionSprite.scaleY = 0.5; tween(actionSprite, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 500, onFinish: function onFinish() { actionSprite.visible = false; actionSprite.alpha = 1; actionSprite.scaleX = 1; actionSprite.scaleY = 1; } }); } // Movement controls in d-pad formation - bottom center-left positioning var moveUpButton = new Button('moveButton', '↑'); moveUpButton.x = -400; moveUpButton.y = -320; moveUpButton.scaleX = 1.5; moveUpButton.scaleY = 1.5; LK.gui.bottom.addChild(moveUpButton); var moveLeftButton = new Button('moveButton', '←'); moveLeftButton.x = -500; moveLeftButton.y = -220; moveLeftButton.scaleX = 1.5; moveLeftButton.scaleY = 1.5; LK.gui.bottom.addChild(moveLeftButton); var moveRightButton = new Button('moveButton', '→'); moveRightButton.x = -300; moveRightButton.y = -220; moveRightButton.scaleX = 1.5; moveRightButton.scaleY = 1.5; LK.gui.bottom.addChild(moveRightButton); var moveDownButton = new Button('moveButton', '↓'); moveDownButton.x = -400; moveDownButton.y = -120; moveDownButton.scaleX = 1.5; moveDownButton.scaleY = 1.5; LK.gui.bottom.addChild(moveDownButton); // Combat controls - bottom center positioning with better spacing var attackButton = new Button('attackButton', 'PUNCH'); attackButton.x = 0; attackButton.y = -320; attackButton.scaleX = 1.5; attackButton.scaleY = 1.5; LK.gui.bottom.addChild(attackButton); var kickButton = new Button('attackButton', 'KICK'); kickButton.x = 300; kickButton.y = -320; kickButton.scaleX = 1.5; kickButton.scaleY = 1.5; LK.gui.bottom.addChild(kickButton); var blockButton = new Button('blockButton', 'BLOCK'); blockButton.x = 150; blockButton.y = -180; blockButton.scaleX = 1.5; blockButton.scaleY = 1.5; LK.gui.bottom.addChild(blockButton); // Hide all action buttons initially moveUpButton.visible = false; moveLeftButton.visible = false; moveRightButton.visible = false; moveDownButton.visible = false; attackButton.visible = false; kickButton.visible = false; blockButton.visible = false; var playerSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; var playerProjectiles = []; moveUpButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } // Jump functionality tween(playerFighter, { y: playerFighter.y - 100 }, { duration: 300, onFinish: function onFinish() { tween(playerFighter, { y: playerFighter.y + 100 }, { duration: 300 }); } }); }; moveLeftButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; if (playerFighter.x > 200) { playerFighter.x -= currentSpeed; } }; moveRightButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50; if (playerFighter.x < 1848) { playerFighter.x += currentSpeed; } }; moveDownButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } // Crouch functionality tween(playerFighter, { scaleY: 0.5 }, { duration: 200, onFinish: function onFinish() { LK.setTimeout(function () { tween(playerFighter, { scaleY: 1 }, { duration: 200 }); }, 500); } }); }; attackButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } showActionSprite('attack', 0xe74c3c); if (playerFighter.attack()) { var distance = Math.abs(playerFighter.x - enemyFighter.x); if (distance < 350) { var damage = playerFighter.attackPower; enemyFighter.takeDamage(damage); // Add hit particles on enemy var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 10)); } } }; var kickCooldown = 0; kickButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } var currentTime = Date.now(); if (currentTime < kickCooldown) { return; // Kick is on cooldown } showActionSprite('kick', 0xff6b35); if (playerFighter.attack()) { // Add kick particles (more intense than punch) var kickParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', playerFighter.x + 60, playerFighter.y - 80, 15)); var distance = Math.abs(playerFighter.x - enemyFighter.x); if (distance < 400) { var damage = playerFighter.attackPower * 2.0; enemyFighter.takeDamage(damage); // Add more intense hit particles for kicks var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 15)); } kickCooldown = currentTime + 800; // 800ms cooldown for kicks } }; blockButton.down = function (x, y, obj) { if (gameState !== 'playing') { return; } showActionSprite('block', 0x3498db); playerFighter.block(); // Add additional block particles for visual feedback var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', playerFighter.x, playerFighter.y - 120, 15)); }; var enemyAI = { nextActionTime: 0, actionCooldown: 1000, nextMoveTime: 0, moveCooldown: 500, difficulty: 'medium', // easy, medium, hard playerHealthHistory: [], playerMovementHistory: [], consecutiveAttacks: 0, lastPlayerPosition: 0, adaptiveStrategy: 'balanced', // balanced, aggressive, defensive strategyTimer: 0, update: function update() { if (gameState !== 'playing') { return; } var currentTime = Date.now(); var distance = Math.abs(playerFighter.x - enemyFighter.x); // Track player behavior for adaptive AI this.trackPlayerBehavior(currentTime); // Update adaptive strategy based on difficulty this.updateAdaptiveStrategy(currentTime); // Get difficulty-based multipliers var difficultySettings = this.getDifficultySettings(); // Enhanced Movement AI with intelligent positioning if (currentTime >= this.nextMoveTime) { var moveAction = Math.random(); if (moveAction < difficultySettings.moveFrequency) { var optimalDistance = this.getOptimalDistance(); if (distance > optimalDistance + 50) { // Move closer with smart pathfinding var approachSpeed = difficultySettings.moveSpeed * this.getApproachMultiplier(); if (playerFighter.x > enemyFighter.x && enemyFighter.x < 1848) { enemyFighter.x += approachSpeed; } else if (playerFighter.x < enemyFighter.x && enemyFighter.x > 200) { enemyFighter.x -= approachSpeed; } } else if (distance < optimalDistance - 50) { // Maintain optimal distance with tactical retreats var retreatChance = difficultySettings.retreatChance; if (Math.random() < retreatChance) { var retreatSpeed = difficultySettings.moveSpeed * 0.8; if (playerFighter.x > enemyFighter.x && enemyFighter.x > 200) { enemyFighter.x -= retreatSpeed; } else if (playerFighter.x < enemyFighter.x && enemyFighter.x < 1848) { enemyFighter.x += retreatSpeed; } } } else { // Optimal distance - intelligent repositioning based on strategy var repositionChance = difficultySettings.repositionChance; if (Math.random() < repositionChance) { var tacticalMove = this.getTacticalMove(); if (enemyFighter.x + tacticalMove > 200 && enemyFighter.x + tacticalMove < 1848) { enemyFighter.x += tacticalMove; } } } } this.nextMoveTime = currentTime + difficultySettings.moveCooldown + Math.random() * 200; } // Advanced Dodge/Evasion AI with predictive movement if (playerFighter.isAttacking && distance < 400) { var dodgeChance = difficultySettings.dodgeChance; // Increase dodge chance if player is predictable if (this.consecutiveAttacks > 2) { dodgeChance *= 1.5; } if (Math.random() < dodgeChance && currentTime >= this.nextMoveTime) { var dodgeDirection = this.getPredictiveDodge(); if (enemyFighter.x + dodgeDirection > 200 && enemyFighter.x + dodgeDirection < 1848) { enemyFighter.x += dodgeDirection; this.nextMoveTime = currentTime + 150; // Quick cooldown after dodge } } } // Intelligent Combat AI with pattern recognition if (currentTime < this.nextActionTime) { return; } var combatDecision = this.makeCombatDecision(distance, currentTime); if (combatDecision.action === 'attack') { this.executeAttack(combatDecision.attackType, distance); } else if (combatDecision.action === 'block') { enemyFighter.block(); } else if (combatDecision.action === 'special') { if (enemyFighter.specialAttack()) { var specialDamage = enemyFighter.attackPower * (combatDecision.damageMultiplier || 2); playerFighter.takeDamage(specialDamage); } } // Dynamic cooldown based on AI intelligence and player behavior var finalCooldown = this.calculateAdaptiveCooldown(currentTime, difficultySettings); this.nextActionTime = currentTime + finalCooldown; }, getDifficultySettings: function getDifficultySettings() { var settings = { easy: { moveFrequency: 0.3, moveSpeed: 20, retreatChance: 0.2, repositionChance: 0.1, moveCooldown: 800, dodgeChance: 0.15, attackChance: 0.25, blockChance: 0.4, specialChance: 0.05, reactionTime: 1000, patternRecognition: 0.1 }, medium: { moveFrequency: 0.5, moveSpeed: 35, retreatChance: 0.35, repositionChance: 0.25, moveCooldown: 600, dodgeChance: 0.3, attackChance: 0.4, blockChance: 0.55, specialChance: 0.15, reactionTime: 700, patternRecognition: 0.3 }, hard: { moveFrequency: 0.7, moveSpeed: 50, retreatChance: 0.5, repositionChance: 0.4, moveCooldown: 400, dodgeChance: 0.45, attackChance: 0.55, blockChance: 0.7, specialChance: 0.25, reactionTime: 400, patternRecognition: 0.6 } }; return settings[this.difficulty]; }, trackPlayerBehavior: function trackPlayerBehavior(currentTime) { // Track player health changes this.playerHealthHistory.push({ time: currentTime, health: playerFighter.health, stamina: playerFighter.stamina }); if (this.playerHealthHistory.length > 10) { this.playerHealthHistory.shift(); } // Track player movement patterns if (this.lastPlayerPosition !== playerFighter.x) { this.playerMovementHistory.push({ time: currentTime, position: playerFighter.x, direction: playerFighter.x > this.lastPlayerPosition ? 'right' : 'left' }); this.lastPlayerPosition = playerFighter.x; } if (this.playerMovementHistory.length > 8) { this.playerMovementHistory.shift(); } // Track consecutive attacks if (playerFighter.isAttacking) { this.consecutiveAttacks++; } else if (currentTime - (playerFighter.lastAttackTime || 0) > 1000) { this.consecutiveAttacks = 0; } }, updateAdaptiveStrategy: function updateAdaptiveStrategy(currentTime) { if (currentTime < this.strategyTimer) return; var difficultySettings = this.getDifficultySettings(); var healthPercentage = enemyFighter.health / enemyFighter.maxHealth; var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina; // Switch strategies based on situation and difficulty intelligence if (difficultySettings.patternRecognition > Math.random()) { if (healthPercentage < 0.3) { this.adaptiveStrategy = 'defensive'; } else if (playerFighter.health < enemyFighter.health && staminaPercentage > 0.6) { this.adaptiveStrategy = 'aggressive'; } else { this.adaptiveStrategy = 'balanced'; } } this.strategyTimer = currentTime + 3000; // Re-evaluate every 3 seconds }, getOptimalDistance: function getOptimalDistance() { var baseDistance = 250; switch (this.adaptiveStrategy) { case 'aggressive': return baseDistance - 50; case 'defensive': return baseDistance + 100; default: return baseDistance; } }, getApproachMultiplier: function getApproachMultiplier() { var playerHealthPercentage = playerFighter.health / playerFighter.maxHealth; var multiplier = 1.0; // More aggressive approach when player is weak if (playerHealthPercentage < 0.3) { multiplier = 1.5; } else if (playerHealthPercentage < 0.6) { multiplier = 1.2; } return multiplier; }, getTacticalMove: function getTacticalMove() { var baseMove = Math.random() < 0.5 ? -30 : 30; // Add tactical positioning based on player movement patterns if (this.playerMovementHistory.length >= 3) { var recentMoves = this.playerMovementHistory.slice(-3); var rightMovements = recentMoves.filter(function (move) { return move.direction === 'right'; }).length; if (rightMovements >= 2) { // Player moving right, position for intercept baseMove = 40; } else if (rightMovements === 0) { // Player moving left, position for intercept baseMove = -40; } } return baseMove; }, getPredictiveDodge: function getPredictiveDodge() { var baseDodge = Math.random() < 0.5 ? -60 : 60; // Predict player attack direction based on position if (playerFighter.x > enemyFighter.x) { // Player attacking from right, dodge left baseDodge = -Math.abs(baseDodge); } else { // Player attacking from left, dodge right baseDodge = Math.abs(baseDodge); } return baseDodge; }, makeCombatDecision: function makeCombatDecision(distance, currentTime) { var difficultySettings = this.getDifficultySettings(); var decision = { action: 'wait' }; // Enhanced decision making based on multiple factors var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800; var shouldBlock = playerAttackingRecently && Math.random() < difficultySettings.blockChance * 1.5; var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina; var action = Math.random(); if (distance < 350) { if (shouldBlock && !enemyFighter.isBlocking) { decision.action = 'block'; } else if (action < difficultySettings.attackChance && enemyFighter.canAttack && enemyFighter.stamina >= 25) { decision.action = 'attack'; decision.attackType = this.chooseAttackType(distance, staminaPercentage); } else if (action < difficultySettings.blockChance && !playerAttackingRecently) { decision.action = 'block'; } } else if (distance < 500 && enemyFighter.stamina >= 60 && Math.random() < difficultySettings.specialChance) { decision.action = 'special'; decision.damageMultiplier = 1.5; } return decision; }, chooseAttackType: function chooseAttackType(distance, staminaPercentage) { var attackType = Math.random(); if (distance < 200 && attackType < 0.4) { return 'punch'; } else if (distance < 300 && attackType < 0.7) { return 'kick'; } else if (distance < 180 && attackType < 0.9) { return 'grab'; } else if (staminaPercentage > 0.6 && Math.random() < 0.3) { return 'special'; } return 'punch'; }, executeAttack: function executeAttack(attackType, distance) { switch (attackType) { case 'punch': if (enemyFighter.attack()) { playerFighter.takeDamage(enemyFighter.attackPower); } break; case 'kick': if (enemyFighter.attack()) { LK.setTimeout(function () { // Kick delay effect }, 400); playerFighter.takeDamage(enemyFighter.attackPower * 2.0); } break; case 'grab': if (enemyFighter.attack()) { playerFighter.takeDamage(enemyFighter.attackPower * 1.2); // Intelligent grab positioning var pullDistance = this.difficulty === 'hard' ? 40 : 30; if (playerFighter.x > enemyFighter.x) { playerFighter.x -= pullDistance; } else { playerFighter.x += pullDistance; } } break; case 'special': if (enemyFighter.specialAttack()) { playerFighter.takeDamage(enemyFighter.attackPower * 2); } break; } }, calculateAdaptiveCooldown: function calculateAdaptiveCooldown(currentTime, difficultySettings) { var baseCooldown = difficultySettings.reactionTime; var cooldownVariation = baseCooldown * 0.3; // Reduce cooldown based on player aggression var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800; var playerAggressiveBonus = playerAttackingRecently ? 0.7 : 1.0; // Increase cooldown if enemy is low on stamina var staminaPenalty = enemyFighter.stamina < 30 ? 1.5 : 1.0; // Strategy-based cooldown modification var strategyMultiplier = 1.0; switch (this.adaptiveStrategy) { case 'aggressive': strategyMultiplier = 0.8; break; case 'defensive': strategyMultiplier = 1.2; break; } var finalCooldown = baseCooldown * playerAggressiveBonus * staminaPenalty * strategyMultiplier + Math.random() * cooldownVariation; return Math.max(finalCooldown, 100); // Minimum 100ms cooldown } }; function checkGameEnd() { if (playerFighter.health <= 0) { gameState = 'gameOver'; storage.lastScore = LK.getScore(); LK.showGameOver(); return true; } if (enemyFighter.health <= 0) { gameState = 'victory'; LK.setScore(LK.getScore() + 100); // Show victory screen gameplayContainer.visible = false; victoryContainer.visible = true; enemyDefeatedText.setText(enemyNames[currentEnemyIndex] + ' DEFEATED!'); progressText.setText('Enemies Defeated: ' + (currentEnemyIndex + 1) + '/' + totalEnemies); // Hide action buttons moveUpButton.visible = false; moveLeftButton.visible = false; moveRightButton.visible = false; moveDownButton.visible = false; attackButton.visible = false; kickButton.visible = false; blockButton.visible = false; return true; } if (timerMode === 'limited' && roundTimer <= 0) { gameState = 'timeUp'; storage.lastScore = LK.getScore(); if (playerFighter.health > enemyFighter.health) { LK.setScore(LK.getScore() + 50); storage.lastScore = LK.getScore(); LK.showYouWin(); } else { LK.showGameOver(); } return true; } return false; } continueButton.down = function (x, y, obj) { if (gameState === 'victory') { currentEnemyIndex++; if (currentEnemyIndex >= totalEnemies) { // All enemies defeated var finalText = new Text2('CHAMPION!', { size: 100, fill: 0xf39c12 }); finalText.anchor.set(0.5, 0.5); finalText.x = 2048 / 2; finalText.y = 1366; game.addChild(finalText); LK.setScore(LK.getScore() + 500); storage.lastScore = LK.getScore(); LK.showYouWin(); return; } // Start next fight victoryContainer.visible = false; gameplayContainer.visible = true; gameState = 'countdown'; battleCountdown = 3; countdownActive = true; // Reset and recreate both fighters to ensure proper character selection gameplayContainer.removeChild(playerFighter); gameplayContainer.removeChild(enemyFighter); playerFighter = gameplayContainer.addChild(new Fighter(true)); playerFighter.x = 2048 / 2 - 300; playerFighter.y = 1600; enemyFighter = gameplayContainer.addChild(new Fighter(false)); enemyFighter.x = 2048 / 2 + 300; enemyFighter.y = 1600; if (timerMode === 'limited') { roundTimer = 90; } else { roundTimer = -1; } } }; stopButton.down = function (x, y, obj) { if (gameState === 'victory') { LK.setScore(LK.getScore() + 50); storage.lastScore = LK.getScore(); LK.showYouWin(); } }; LK.playMusic('battleMusic'); game.update = function () { if (gameState === 'countdown') { if (countdownActive) { countdownText.visible = true; countdownText.setText(battleCountdown.toString()); if (LK.ticks % 60 === 0) { battleCountdown--; if (battleCountdown <= 0) { countdownActive = false; countdownText.visible = false; gameState = 'playing'; } } } } if (gameState === 'playing') { // Show action buttons when game starts moveUpButton.visible = true; moveLeftButton.visible = true; moveRightButton.visible = true; moveDownButton.visible = true; attackButton.visible = true; kickButton.visible = true; blockButton.visible = true; if (timerMode === 'limited') { if (LK.ticks % 60 === 0) { roundTimer--; timerText.setText(roundTimer.toString()); if (roundTimer <= 10) { timerText.tint = 0xe74c3c; } } } else { timerText.setText('∞'); } playerHealthBar.setValue(playerFighter.health); enemyHealthBar.setValue(enemyFighter.health); playerStaminaBar.setValue(playerFighter.stamina); enemyStaminaBar.setValue(enemyFighter.stamina); scoreText.setText('Score: ' + LK.getScore()); enemyAI.update(); // Update projectiles for (var i = playerProjectiles.length - 1; i >= 0; i--) { var projectile = playerProjectiles[i]; var deltaX = projectile.targetX - projectile.x; var deltaY = (projectile.targetY || enemyFighter.y - 50) - projectile.y; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); if (distance < 50) { // Hit enemy var damage = selectedCharacter === 'shark' ? playerFighter.attackPower * 1.8 : playerFighter.attackPower * 2; enemyFighter.takeDamage(damage); projectile.destroy(); playerProjectiles.splice(i, 1); } else if (distance > 800) { // Out of range projectile.destroy(); playerProjectiles.splice(i, 1); } else { // Move projectile projectile.x += deltaX / distance * projectile.speed; projectile.y += deltaY / distance * projectile.speed; } } checkGameEnd(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Button = Container.expand(function (assetName, text) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.down = function (x, y, obj) {
tween(buttonGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(buttonGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
};
return self;
});
var CharacterCard = Container.expand(function (characterType, name) {
var self = Container.call(this);
self.characterType = characterType;
self.isSelected = false;
var cardBg = self.attachAsset('characterCard', {
anchorX: 0.5,
anchorY: 0.5
});
var character = self.attachAsset(characterType + 'Fighter', {
anchorX: 0.5,
anchorY: 0.8,
y: -20
});
var nameText = new Text2(name, {
size: 30,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = 100;
self.addChild(nameText);
self.setSelected = function (selected) {
self.isSelected = selected;
if (selected) {
cardBg.tint = 0xf39c12;
tween(cardBg, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200
});
} else {
cardBg.tint = 0xFFFFFF;
tween(cardBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
};
self.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
selectedCharacter = self.characterType;
for (var i = 0; i < characterCards.length; i++) {
characterCards[i].setSelected(characterCards[i] === self);
}
console.log('Selected character:', selectedCharacter);
}
};
return self;
});
var Fighter = Container.expand(function (isPlayer) {
var self = Container.call(this);
self.isPlayer = isPlayer || false;
self.maxHealth = 300;
self.health = self.maxHealth;
self.maxStamina = 100;
self.stamina = self.maxStamina;
self.attackPower = 20;
self.isBlocking = false;
self.isAttacking = false;
self.canAttack = true;
self.staminaRegenRate = 0.5;
self.lastAttackTime = 0;
var assetName = 'playerFighter';
if (isPlayer) {
// Use the selected character for the player
assetName = selectedCharacter + 'Fighter';
console.log('Using player asset:', assetName, 'selectedCharacter:', selectedCharacter);
} else {
// Randomly select enemy type for variety
var enemyTypes = ['enemy', 'lizard', 'shark', 'wolf', 'bear', 'tiger', 'eagle'];
var randomType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
assetName = randomType + 'Fighter';
console.log('Using enemy asset:', assetName);
}
var fighterGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1
});
self.attack = function () {
if (!self.canAttack || self.stamina < 25) {
return false;
}
self.isAttacking = true;
self.canAttack = false;
self.stamina -= 25;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 100,
onFinish: function onFinish() {
tween(fighterGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
LK.getSound('punch').play();
// Add punch particles
if (self.isPlayer) {
var punchParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', self.x + 50, self.y - 100, 8));
}
LK.setTimeout(function () {
self.isAttacking = false;
self.canAttack = true;
}, 300);
return true;
};
self.block = function () {
if (self.stamina < 15) {
return false;
}
self.isBlocking = true;
self.stamina -= 15;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
tint: 0x3498db
}, {
duration: 200,
onFinish: function onFinish() {
tween(fighterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
LK.getSound('block').play();
// Add block particles
if (self.isPlayer) {
var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', self.x, self.y - 100, 12));
}
LK.setTimeout(function () {
self.isBlocking = false;
}, 400);
return true;
};
self.specialAttack = function () {
if (self.stamina < 60) {
return false;
}
self.stamina -= 60;
self.lastAttackTime = Date.now();
tween(fighterGraphics, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xffd700
}, {
duration: 300,
onFinish: function onFinish() {
tween(fighterGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0xffffff
}, {
duration: 300
});
}
});
LK.getSound('special').play();
return true;
};
self.takeDamage = function (damage) {
if (self.isBlocking) {
damage = Math.floor(damage * 0.2);
}
self.health -= damage;
if (self.health < 0) {
self.health = 0;
}
LK.effects.flashObject(self, 0xff0000, 200);
tween(fighterGraphics, {
x: fighterGraphics.x + (self.isPlayer ? -20 : 20)
}, {
duration: 100,
onFinish: function onFinish() {
tween(fighterGraphics, {
x: 0
}, {
duration: 100
});
}
});
};
self.update = function () {
var currentTime = Date.now();
// Only regenerate stamina if not attacking recently (1 second cooldown)
if (currentTime - self.lastAttackTime > 1000) {
if (self.stamina < self.maxStamina) {
self.stamina += self.staminaRegenRate;
if (self.stamina > self.maxStamina) {
self.stamina = self.maxStamina;
}
}
}
};
return self;
});
var HealthBar = Container.expand(function (maxValue) {
var self = Container.call(this);
self.maxValue = maxValue;
self.currentValue = maxValue;
var background = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
var bar = self.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
self.setValue = function (value) {
self.currentValue = value;
var percentage = value / self.maxValue;
bar.scaleX = percentage;
if (percentage > 0.6) {
bar.tint = 0x2ecc71;
} else if (percentage > 0.3) {
bar.tint = 0xf39c12;
} else {
bar.tint = 0xe74c3c;
}
};
return self;
});
var ParticleSystem = Container.expand(function (particleType, x, y, count) {
var self = Container.call(this);
self.particles = [];
self.particleType = particleType;
self.x = x;
self.y = y;
// Create particles
for (var i = 0; i < count; i++) {
var particle = self.addChild(LK.getAsset(particleType, {
anchorX: 0.5,
anchorY: 0.5
}));
// Set initial properties based on particle type
if (particleType === 'sparkParticle') {
particle.velocityX = (Math.random() - 0.5) * 200;
particle.velocityY = (Math.random() - 0.5) * 200 - 100;
particle.life = 1.0;
particle.decay = 0.02;
} else if (particleType === 'blockParticle') {
particle.velocityX = (Math.random() - 0.5) * 150;
particle.velocityY = (Math.random() - 0.5) * 150;
particle.life = 1.0;
particle.decay = 0.03;
} else if (particleType === 'hitParticle') {
particle.velocityX = (Math.random() - 0.5) * 300;
particle.velocityY = (Math.random() - 0.5) * 300 - 50;
particle.life = 1.0;
particle.decay = 0.025;
}
self.particles.push(particle);
}
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
// Update position
particle.x += particle.velocityX * 0.016; // 60fps
particle.y += particle.velocityY * 0.016;
// Apply gravity for spark and hit particles
if (particleType === 'sparkParticle' || particleType === 'hitParticle') {
particle.velocityY += 300 * 0.016; // Gravity
}
// Update life and alpha
particle.life -= particle.decay;
particle.alpha = particle.life;
// Remove dead particles
if (particle.life <= 0) {
particle.destroy();
self.particles.splice(i, 1);
}
}
// Remove system when all particles are gone
if (self.particles.length === 0) {
self.destroy();
}
};
return self;
});
var StaminaBar = Container.expand(function (maxValue) {
var self = Container.call(this);
self.maxValue = maxValue;
self.currentValue = maxValue;
var background = self.attachAsset('staminaBarBg', {
anchorX: 0,
anchorY: 0
});
var bar = self.attachAsset('staminaBar', {
anchorX: 0,
anchorY: 0
});
self.setValue = function (value) {
self.currentValue = value;
var percentage = value / self.maxValue;
bar.scaleX = percentage;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
var gameState = 'menu';
var roundTimer = 60;
var roundStartTime = 0;
var battleCountdown = 3;
var countdownActive = false;
var timerMode = 'unlimited'; // 'unlimited' or 'limited'
var selectedCharacter = 'shark';
var characterCards = [];
var currentEnemyIndex = 0;
var totalEnemies = 20;
var enemyNames = ['Razor Claw', 'Iron Fang', 'Storm Fury', 'Shadow Beast', 'Thunder Paws', 'Venom Strike', 'Blade Runner', 'Fire Tooth', 'Ice Crusher', 'Wind Slasher', 'Stone Jaw', 'Lightning Bolt', 'Dark Hunter', 'Flame Warrior', 'Frost Bite', 'Night Stalker', 'Blood Fang', 'Steel Claw', 'Wild Storm', 'Bone Breaker', 'Crimson Fang', 'Golden Claw', 'Silver Strike', 'Midnight Howl', 'Dawn Breaker', 'Skull Crusher', 'Void Walker', 'Star Slayer', 'Moon Fang', 'Sun Warrior'];
var menuContainer = game.addChild(new Container());
var characterSelectContainer = game.addChild(new Container());
var gameplayContainer = game.addChild(new Container());
// Create animated background for menu
var menuBg = menuContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366,
alpha: 0.3
}));
// Create fighting characters in background
var menuFighter1 = menuContainer.addChild(LK.getAsset('sharkFighter', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 - 400,
y: 1600,
alpha: 0.4
}));
var menuFighter2 = menuContainer.addChild(LK.getAsset('wolfFighter', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2 + 400,
y: 1600,
alpha: 0.4
}));
// Animate background fighters
tween(menuFighter1, {
x: menuFighter1.x + 50,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 1000,
loop: true,
yoyo: true
});
tween(menuFighter2, {
x: menuFighter2.x - 50,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 1200,
loop: true,
yoyo: true
});
var titleText = new Text2('FURRY FIGHTER ARENA', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 600;
menuContainer.addChild(titleText);
// Display previous game score
var previousScore = storage.lastScore || 0;
var previousScoreText = new Text2('Previous Score: ' + previousScore, {
size: 50,
fill: 0xecf0f1
});
previousScoreText.anchor.set(0.5, 0.5);
previousScoreText.x = 2048 / 2;
previousScoreText.y = 1000;
menuContainer.addChild(previousScoreText);
var startButton = new Button('menuButton', 'START COMBAT');
startButton.x = 2048 / 2;
startButton.y = 1200;
menuContainer.addChild(startButton);
startButton.down = function (x, y, obj) {
if (gameState === 'menu') {
gameState = 'characterSelect';
menuContainer.visible = false;
characterSelectContainer.visible = true;
}
};
var characterSelectTitle = new Text2('SELECT YOUR FIGHTER', {
size: 60,
fill: 0xFFFFFF
});
characterSelectTitle.anchor.set(0.5, 0.5);
characterSelectTitle.x = 2048 / 2;
characterSelectTitle.y = 400;
characterSelectContainer.addChild(characterSelectTitle);
var sharkCard = new CharacterCard('shark', 'SHARK');
sharkCard.x = 2048 / 2 - 300;
sharkCard.y = 1000;
characterSelectContainer.addChild(sharkCard);
characterCards.push(sharkCard);
var lizardCard = new CharacterCard('lizard', 'LIZARD');
lizardCard.x = 2048 / 2;
lizardCard.y = 1000;
characterSelectContainer.addChild(lizardCard);
characterCards.push(lizardCard);
var wolfCard = new CharacterCard('wolf', 'WOLF');
wolfCard.x = 2048 / 2 + 300;
wolfCard.y = 1000;
characterSelectContainer.addChild(wolfCard);
characterCards.push(wolfCard);
sharkCard.setSelected(true);
selectedCharacter = 'shark';
console.log('Initial selected character:', selectedCharacter);
var difficultyText = new Text2('DIFFICULTY: MEDIUM', {
size: 50,
fill: 0xFFFFFF
});
difficultyText.anchor.set(0.5, 0.5);
difficultyText.x = 2048 / 2;
difficultyText.y = 1300;
characterSelectContainer.addChild(difficultyText);
var difficultyButton = new Button('menuButton', 'CHANGE DIFFICULTY');
difficultyButton.x = 2048 / 2;
difficultyButton.y = 1400;
characterSelectContainer.addChild(difficultyButton);
var timerModeText = new Text2('TIMER MODE: UNLIMITED', {
size: 50,
fill: 0xFFFFFF
});
timerModeText.anchor.set(0.5, 0.5);
timerModeText.x = 2048 / 2;
timerModeText.y = 1500;
characterSelectContainer.addChild(timerModeText);
difficultyButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
if (enemyAI.difficulty === 'easy') {
enemyAI.difficulty = 'medium';
difficultyText.setText('DIFFICULTY: MEDIUM');
} else if (enemyAI.difficulty === 'medium') {
enemyAI.difficulty = 'hard';
difficultyText.setText('DIFFICULTY: HARD');
} else {
enemyAI.difficulty = 'easy';
difficultyText.setText('DIFFICULTY: EASY');
}
}
};
var timerModeButton = new Button('menuButton', 'TOGGLE TIMER');
timerModeButton.x = 2048 / 2;
timerModeButton.y = 1550;
characterSelectContainer.addChild(timerModeButton);
timerModeButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
if (timerMode === 'unlimited') {
timerMode = 'limited';
timerModeText.setText('TIMER MODE: 90 SECONDS');
} else {
timerMode = 'unlimited';
timerModeText.setText('TIMER MODE: UNLIMITED');
}
}
};
var fightButton = new Button('menuButton', 'FIGHT!');
fightButton.x = 2048 / 2;
fightButton.y = 1650;
characterSelectContainer.addChild(fightButton);
fightButton.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
gameState = 'countdown';
characterSelectContainer.visible = false;
gameplayContainer.visible = true;
// Show health and stamina bars when combat starts
playerHealthBar.visible = true;
enemyHealthBar.visible = true;
playerStaminaBar.visible = true;
enemyStaminaBar.visible = true;
// Recreate player fighter with selected character
gameplayContainer.removeChild(playerFighter);
playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600;
if (timerMode === 'limited') {
roundTimer = 90;
} else {
roundTimer = -1; // Unlimited time
}
battleCountdown = 3;
countdownActive = true;
// Reset enemy progression
currentEnemyIndex = 0;
// Shuffle enemy names for random encounters
for (var i = enemyNames.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = enemyNames[i];
enemyNames[i] = enemyNames[j];
enemyNames[j] = temp;
}
}
};
characterSelectContainer.visible = false;
gameplayContainer.visible = false;
var arena = gameplayContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 1800
}));
var arenaLine = gameplayContainer.addChild(LK.getAsset('arenaLine', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 1600
}));
var playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600; // Aligned with arena line
var enemyFighter = gameplayContainer.addChild(new Fighter(false));
enemyFighter.x = 2048 / 2 + 300;
enemyFighter.y = 1600; // Aligned with arena line
var playerHealthBar = new HealthBar(300);
playerHealthBar.x = 100;
playerHealthBar.y = 100;
playerHealthBar.visible = false;
LK.gui.topLeft.addChild(playerHealthBar);
var enemyHealthBar = new HealthBar(300);
enemyHealthBar.x = -500;
enemyHealthBar.y = 100;
enemyHealthBar.visible = false;
LK.gui.topRight.addChild(enemyHealthBar);
var playerStaminaBar = new StaminaBar(100);
playerStaminaBar.x = 100;
playerStaminaBar.y = 150;
playerStaminaBar.visible = false;
LK.gui.topLeft.addChild(playerStaminaBar);
var enemyStaminaBar = new StaminaBar(100);
enemyStaminaBar.x = -500;
enemyStaminaBar.y = 150;
enemyStaminaBar.visible = false;
LK.gui.topRight.addChild(enemyStaminaBar);
var timerText = new Text2('60', {
size: 80,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var countdownText = new Text2('3', {
size: 200,
fill: 0xf39c12
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 1366;
gameplayContainer.addChild(countdownText);
countdownText.visible = false;
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 100;
LK.gui.top.addChild(scoreText);
var actionSprite = LK.getAsset('actionSprite', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1000
});
gameplayContainer.addChild(actionSprite);
actionSprite.visible = false;
// Victory screen elements
var victoryContainer = game.addChild(new Container());
victoryContainer.visible = false;
var victoryBg = victoryContainer.addChild(LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366,
scaleX: 1.2,
scaleY: 1.5
}));
victoryBg.tint = 0x2c3e50;
victoryBg.alpha = 0.9;
var koText = new Text2('K.O.!', {
size: 150,
fill: 0xf39c12
});
koText.anchor.set(0.5, 0.5);
koText.x = 2048 / 2;
koText.y = 800;
victoryContainer.addChild(koText);
var victoryText = new Text2('YOU WIN!', {
size: 80,
fill: 0x2ecc71
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 2048 / 2;
victoryText.y = 950;
victoryContainer.addChild(victoryText);
var enemyDefeatedText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
enemyDefeatedText.anchor.set(0.5, 0.5);
enemyDefeatedText.x = 2048 / 2;
enemyDefeatedText.y = 1100;
victoryContainer.addChild(enemyDefeatedText);
var progressText = new Text2('', {
size: 50,
fill: 0xecf0f1
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 2048 / 2;
progressText.y = 1200;
victoryContainer.addChild(progressText);
var continueButton = new Button('menuButton', 'CONTINUE FIGHTING');
continueButton.x = 2048 / 2 - 250;
continueButton.y = 1400;
victoryContainer.addChild(continueButton);
var stopButton = new Button('menuButton', 'STOP HERE');
stopButton.x = 2048 / 2 + 250;
stopButton.y = 1400;
victoryContainer.addChild(stopButton);
function showActionSprite(actionType, color) {
if (gameState !== 'playing') {
return;
}
actionSprite.visible = true;
actionSprite.tint = color;
actionSprite.scaleX = 0.5;
actionSprite.scaleY = 0.5;
tween(actionSprite, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
actionSprite.visible = false;
actionSprite.alpha = 1;
actionSprite.scaleX = 1;
actionSprite.scaleY = 1;
}
});
}
// Movement controls in d-pad formation - bottom center-left positioning
var moveUpButton = new Button('moveButton', '↑');
moveUpButton.x = -400;
moveUpButton.y = -320;
moveUpButton.scaleX = 1.5;
moveUpButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveUpButton);
var moveLeftButton = new Button('moveButton', '←');
moveLeftButton.x = -500;
moveLeftButton.y = -220;
moveLeftButton.scaleX = 1.5;
moveLeftButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveLeftButton);
var moveRightButton = new Button('moveButton', '→');
moveRightButton.x = -300;
moveRightButton.y = -220;
moveRightButton.scaleX = 1.5;
moveRightButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveRightButton);
var moveDownButton = new Button('moveButton', '↓');
moveDownButton.x = -400;
moveDownButton.y = -120;
moveDownButton.scaleX = 1.5;
moveDownButton.scaleY = 1.5;
LK.gui.bottom.addChild(moveDownButton);
// Combat controls - bottom center positioning with better spacing
var attackButton = new Button('attackButton', 'PUNCH');
attackButton.x = 0;
attackButton.y = -320;
attackButton.scaleX = 1.5;
attackButton.scaleY = 1.5;
LK.gui.bottom.addChild(attackButton);
var kickButton = new Button('attackButton', 'KICK');
kickButton.x = 300;
kickButton.y = -320;
kickButton.scaleX = 1.5;
kickButton.scaleY = 1.5;
LK.gui.bottom.addChild(kickButton);
var blockButton = new Button('blockButton', 'BLOCK');
blockButton.x = 150;
blockButton.y = -180;
blockButton.scaleX = 1.5;
blockButton.scaleY = 1.5;
LK.gui.bottom.addChild(blockButton);
// Hide all action buttons initially
moveUpButton.visible = false;
moveLeftButton.visible = false;
moveRightButton.visible = false;
moveDownButton.visible = false;
attackButton.visible = false;
kickButton.visible = false;
blockButton.visible = false;
var playerSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
var playerProjectiles = [];
moveUpButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
// Jump functionality
tween(playerFighter, {
y: playerFighter.y - 100
}, {
duration: 300,
onFinish: function onFinish() {
tween(playerFighter, {
y: playerFighter.y + 100
}, {
duration: 300
});
}
});
};
moveLeftButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
if (playerFighter.x > 200) {
playerFighter.x -= currentSpeed;
}
};
moveRightButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentSpeed = selectedCharacter === 'lizard' ? 70 : selectedCharacter === 'wolf' ? 60 : 50;
if (playerFighter.x < 1848) {
playerFighter.x += currentSpeed;
}
};
moveDownButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
// Crouch functionality
tween(playerFighter, {
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(playerFighter, {
scaleY: 1
}, {
duration: 200
});
}, 500);
}
});
};
attackButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
showActionSprite('attack', 0xe74c3c);
if (playerFighter.attack()) {
var distance = Math.abs(playerFighter.x - enemyFighter.x);
if (distance < 350) {
var damage = playerFighter.attackPower;
enemyFighter.takeDamage(damage);
// Add hit particles on enemy
var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 10));
}
}
};
var kickCooldown = 0;
kickButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
var currentTime = Date.now();
if (currentTime < kickCooldown) {
return; // Kick is on cooldown
}
showActionSprite('kick', 0xff6b35);
if (playerFighter.attack()) {
// Add kick particles (more intense than punch)
var kickParticles = gameplayContainer.addChild(new ParticleSystem('sparkParticle', playerFighter.x + 60, playerFighter.y - 80, 15));
var distance = Math.abs(playerFighter.x - enemyFighter.x);
if (distance < 400) {
var damage = playerFighter.attackPower * 2.0;
enemyFighter.takeDamage(damage);
// Add more intense hit particles for kicks
var hitParticles = gameplayContainer.addChild(new ParticleSystem('hitParticle', enemyFighter.x, enemyFighter.y - 100, 15));
}
kickCooldown = currentTime + 800; // 800ms cooldown for kicks
}
};
blockButton.down = function (x, y, obj) {
if (gameState !== 'playing') {
return;
}
showActionSprite('block', 0x3498db);
playerFighter.block();
// Add additional block particles for visual feedback
var blockParticles = gameplayContainer.addChild(new ParticleSystem('blockParticle', playerFighter.x, playerFighter.y - 120, 15));
};
var enemyAI = {
nextActionTime: 0,
actionCooldown: 1000,
nextMoveTime: 0,
moveCooldown: 500,
difficulty: 'medium',
// easy, medium, hard
playerHealthHistory: [],
playerMovementHistory: [],
consecutiveAttacks: 0,
lastPlayerPosition: 0,
adaptiveStrategy: 'balanced',
// balanced, aggressive, defensive
strategyTimer: 0,
update: function update() {
if (gameState !== 'playing') {
return;
}
var currentTime = Date.now();
var distance = Math.abs(playerFighter.x - enemyFighter.x);
// Track player behavior for adaptive AI
this.trackPlayerBehavior(currentTime);
// Update adaptive strategy based on difficulty
this.updateAdaptiveStrategy(currentTime);
// Get difficulty-based multipliers
var difficultySettings = this.getDifficultySettings();
// Enhanced Movement AI with intelligent positioning
if (currentTime >= this.nextMoveTime) {
var moveAction = Math.random();
if (moveAction < difficultySettings.moveFrequency) {
var optimalDistance = this.getOptimalDistance();
if (distance > optimalDistance + 50) {
// Move closer with smart pathfinding
var approachSpeed = difficultySettings.moveSpeed * this.getApproachMultiplier();
if (playerFighter.x > enemyFighter.x && enemyFighter.x < 1848) {
enemyFighter.x += approachSpeed;
} else if (playerFighter.x < enemyFighter.x && enemyFighter.x > 200) {
enemyFighter.x -= approachSpeed;
}
} else if (distance < optimalDistance - 50) {
// Maintain optimal distance with tactical retreats
var retreatChance = difficultySettings.retreatChance;
if (Math.random() < retreatChance) {
var retreatSpeed = difficultySettings.moveSpeed * 0.8;
if (playerFighter.x > enemyFighter.x && enemyFighter.x > 200) {
enemyFighter.x -= retreatSpeed;
} else if (playerFighter.x < enemyFighter.x && enemyFighter.x < 1848) {
enemyFighter.x += retreatSpeed;
}
}
} else {
// Optimal distance - intelligent repositioning based on strategy
var repositionChance = difficultySettings.repositionChance;
if (Math.random() < repositionChance) {
var tacticalMove = this.getTacticalMove();
if (enemyFighter.x + tacticalMove > 200 && enemyFighter.x + tacticalMove < 1848) {
enemyFighter.x += tacticalMove;
}
}
}
}
this.nextMoveTime = currentTime + difficultySettings.moveCooldown + Math.random() * 200;
}
// Advanced Dodge/Evasion AI with predictive movement
if (playerFighter.isAttacking && distance < 400) {
var dodgeChance = difficultySettings.dodgeChance;
// Increase dodge chance if player is predictable
if (this.consecutiveAttacks > 2) {
dodgeChance *= 1.5;
}
if (Math.random() < dodgeChance && currentTime >= this.nextMoveTime) {
var dodgeDirection = this.getPredictiveDodge();
if (enemyFighter.x + dodgeDirection > 200 && enemyFighter.x + dodgeDirection < 1848) {
enemyFighter.x += dodgeDirection;
this.nextMoveTime = currentTime + 150; // Quick cooldown after dodge
}
}
}
// Intelligent Combat AI with pattern recognition
if (currentTime < this.nextActionTime) {
return;
}
var combatDecision = this.makeCombatDecision(distance, currentTime);
if (combatDecision.action === 'attack') {
this.executeAttack(combatDecision.attackType, distance);
} else if (combatDecision.action === 'block') {
enemyFighter.block();
} else if (combatDecision.action === 'special') {
if (enemyFighter.specialAttack()) {
var specialDamage = enemyFighter.attackPower * (combatDecision.damageMultiplier || 2);
playerFighter.takeDamage(specialDamage);
}
}
// Dynamic cooldown based on AI intelligence and player behavior
var finalCooldown = this.calculateAdaptiveCooldown(currentTime, difficultySettings);
this.nextActionTime = currentTime + finalCooldown;
},
getDifficultySettings: function getDifficultySettings() {
var settings = {
easy: {
moveFrequency: 0.3,
moveSpeed: 20,
retreatChance: 0.2,
repositionChance: 0.1,
moveCooldown: 800,
dodgeChance: 0.15,
attackChance: 0.25,
blockChance: 0.4,
specialChance: 0.05,
reactionTime: 1000,
patternRecognition: 0.1
},
medium: {
moveFrequency: 0.5,
moveSpeed: 35,
retreatChance: 0.35,
repositionChance: 0.25,
moveCooldown: 600,
dodgeChance: 0.3,
attackChance: 0.4,
blockChance: 0.55,
specialChance: 0.15,
reactionTime: 700,
patternRecognition: 0.3
},
hard: {
moveFrequency: 0.7,
moveSpeed: 50,
retreatChance: 0.5,
repositionChance: 0.4,
moveCooldown: 400,
dodgeChance: 0.45,
attackChance: 0.55,
blockChance: 0.7,
specialChance: 0.25,
reactionTime: 400,
patternRecognition: 0.6
}
};
return settings[this.difficulty];
},
trackPlayerBehavior: function trackPlayerBehavior(currentTime) {
// Track player health changes
this.playerHealthHistory.push({
time: currentTime,
health: playerFighter.health,
stamina: playerFighter.stamina
});
if (this.playerHealthHistory.length > 10) {
this.playerHealthHistory.shift();
}
// Track player movement patterns
if (this.lastPlayerPosition !== playerFighter.x) {
this.playerMovementHistory.push({
time: currentTime,
position: playerFighter.x,
direction: playerFighter.x > this.lastPlayerPosition ? 'right' : 'left'
});
this.lastPlayerPosition = playerFighter.x;
}
if (this.playerMovementHistory.length > 8) {
this.playerMovementHistory.shift();
}
// Track consecutive attacks
if (playerFighter.isAttacking) {
this.consecutiveAttacks++;
} else if (currentTime - (playerFighter.lastAttackTime || 0) > 1000) {
this.consecutiveAttacks = 0;
}
},
updateAdaptiveStrategy: function updateAdaptiveStrategy(currentTime) {
if (currentTime < this.strategyTimer) return;
var difficultySettings = this.getDifficultySettings();
var healthPercentage = enemyFighter.health / enemyFighter.maxHealth;
var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina;
// Switch strategies based on situation and difficulty intelligence
if (difficultySettings.patternRecognition > Math.random()) {
if (healthPercentage < 0.3) {
this.adaptiveStrategy = 'defensive';
} else if (playerFighter.health < enemyFighter.health && staminaPercentage > 0.6) {
this.adaptiveStrategy = 'aggressive';
} else {
this.adaptiveStrategy = 'balanced';
}
}
this.strategyTimer = currentTime + 3000; // Re-evaluate every 3 seconds
},
getOptimalDistance: function getOptimalDistance() {
var baseDistance = 250;
switch (this.adaptiveStrategy) {
case 'aggressive':
return baseDistance - 50;
case 'defensive':
return baseDistance + 100;
default:
return baseDistance;
}
},
getApproachMultiplier: function getApproachMultiplier() {
var playerHealthPercentage = playerFighter.health / playerFighter.maxHealth;
var multiplier = 1.0;
// More aggressive approach when player is weak
if (playerHealthPercentage < 0.3) {
multiplier = 1.5;
} else if (playerHealthPercentage < 0.6) {
multiplier = 1.2;
}
return multiplier;
},
getTacticalMove: function getTacticalMove() {
var baseMove = Math.random() < 0.5 ? -30 : 30;
// Add tactical positioning based on player movement patterns
if (this.playerMovementHistory.length >= 3) {
var recentMoves = this.playerMovementHistory.slice(-3);
var rightMovements = recentMoves.filter(function (move) {
return move.direction === 'right';
}).length;
if (rightMovements >= 2) {
// Player moving right, position for intercept
baseMove = 40;
} else if (rightMovements === 0) {
// Player moving left, position for intercept
baseMove = -40;
}
}
return baseMove;
},
getPredictiveDodge: function getPredictiveDodge() {
var baseDodge = Math.random() < 0.5 ? -60 : 60;
// Predict player attack direction based on position
if (playerFighter.x > enemyFighter.x) {
// Player attacking from right, dodge left
baseDodge = -Math.abs(baseDodge);
} else {
// Player attacking from left, dodge right
baseDodge = Math.abs(baseDodge);
}
return baseDodge;
},
makeCombatDecision: function makeCombatDecision(distance, currentTime) {
var difficultySettings = this.getDifficultySettings();
var decision = {
action: 'wait'
};
// Enhanced decision making based on multiple factors
var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800;
var shouldBlock = playerAttackingRecently && Math.random() < difficultySettings.blockChance * 1.5;
var staminaPercentage = enemyFighter.stamina / enemyFighter.maxStamina;
var action = Math.random();
if (distance < 350) {
if (shouldBlock && !enemyFighter.isBlocking) {
decision.action = 'block';
} else if (action < difficultySettings.attackChance && enemyFighter.canAttack && enemyFighter.stamina >= 25) {
decision.action = 'attack';
decision.attackType = this.chooseAttackType(distance, staminaPercentage);
} else if (action < difficultySettings.blockChance && !playerAttackingRecently) {
decision.action = 'block';
}
} else if (distance < 500 && enemyFighter.stamina >= 60 && Math.random() < difficultySettings.specialChance) {
decision.action = 'special';
decision.damageMultiplier = 1.5;
}
return decision;
},
chooseAttackType: function chooseAttackType(distance, staminaPercentage) {
var attackType = Math.random();
if (distance < 200 && attackType < 0.4) {
return 'punch';
} else if (distance < 300 && attackType < 0.7) {
return 'kick';
} else if (distance < 180 && attackType < 0.9) {
return 'grab';
} else if (staminaPercentage > 0.6 && Math.random() < 0.3) {
return 'special';
}
return 'punch';
},
executeAttack: function executeAttack(attackType, distance) {
switch (attackType) {
case 'punch':
if (enemyFighter.attack()) {
playerFighter.takeDamage(enemyFighter.attackPower);
}
break;
case 'kick':
if (enemyFighter.attack()) {
LK.setTimeout(function () {
// Kick delay effect
}, 400);
playerFighter.takeDamage(enemyFighter.attackPower * 2.0);
}
break;
case 'grab':
if (enemyFighter.attack()) {
playerFighter.takeDamage(enemyFighter.attackPower * 1.2);
// Intelligent grab positioning
var pullDistance = this.difficulty === 'hard' ? 40 : 30;
if (playerFighter.x > enemyFighter.x) {
playerFighter.x -= pullDistance;
} else {
playerFighter.x += pullDistance;
}
}
break;
case 'special':
if (enemyFighter.specialAttack()) {
playerFighter.takeDamage(enemyFighter.attackPower * 2);
}
break;
}
},
calculateAdaptiveCooldown: function calculateAdaptiveCooldown(currentTime, difficultySettings) {
var baseCooldown = difficultySettings.reactionTime;
var cooldownVariation = baseCooldown * 0.3;
// Reduce cooldown based on player aggression
var playerAttackingRecently = currentTime - (playerFighter.lastAttackTime || 0) < 800;
var playerAggressiveBonus = playerAttackingRecently ? 0.7 : 1.0;
// Increase cooldown if enemy is low on stamina
var staminaPenalty = enemyFighter.stamina < 30 ? 1.5 : 1.0;
// Strategy-based cooldown modification
var strategyMultiplier = 1.0;
switch (this.adaptiveStrategy) {
case 'aggressive':
strategyMultiplier = 0.8;
break;
case 'defensive':
strategyMultiplier = 1.2;
break;
}
var finalCooldown = baseCooldown * playerAggressiveBonus * staminaPenalty * strategyMultiplier + Math.random() * cooldownVariation;
return Math.max(finalCooldown, 100); // Minimum 100ms cooldown
}
};
function checkGameEnd() {
if (playerFighter.health <= 0) {
gameState = 'gameOver';
storage.lastScore = LK.getScore();
LK.showGameOver();
return true;
}
if (enemyFighter.health <= 0) {
gameState = 'victory';
LK.setScore(LK.getScore() + 100);
// Show victory screen
gameplayContainer.visible = false;
victoryContainer.visible = true;
enemyDefeatedText.setText(enemyNames[currentEnemyIndex] + ' DEFEATED!');
progressText.setText('Enemies Defeated: ' + (currentEnemyIndex + 1) + '/' + totalEnemies);
// Hide action buttons
moveUpButton.visible = false;
moveLeftButton.visible = false;
moveRightButton.visible = false;
moveDownButton.visible = false;
attackButton.visible = false;
kickButton.visible = false;
blockButton.visible = false;
return true;
}
if (timerMode === 'limited' && roundTimer <= 0) {
gameState = 'timeUp';
storage.lastScore = LK.getScore();
if (playerFighter.health > enemyFighter.health) {
LK.setScore(LK.getScore() + 50);
storage.lastScore = LK.getScore();
LK.showYouWin();
} else {
LK.showGameOver();
}
return true;
}
return false;
}
continueButton.down = function (x, y, obj) {
if (gameState === 'victory') {
currentEnemyIndex++;
if (currentEnemyIndex >= totalEnemies) {
// All enemies defeated
var finalText = new Text2('CHAMPION!', {
size: 100,
fill: 0xf39c12
});
finalText.anchor.set(0.5, 0.5);
finalText.x = 2048 / 2;
finalText.y = 1366;
game.addChild(finalText);
LK.setScore(LK.getScore() + 500);
storage.lastScore = LK.getScore();
LK.showYouWin();
return;
}
// Start next fight
victoryContainer.visible = false;
gameplayContainer.visible = true;
gameState = 'countdown';
battleCountdown = 3;
countdownActive = true;
// Reset and recreate both fighters to ensure proper character selection
gameplayContainer.removeChild(playerFighter);
gameplayContainer.removeChild(enemyFighter);
playerFighter = gameplayContainer.addChild(new Fighter(true));
playerFighter.x = 2048 / 2 - 300;
playerFighter.y = 1600;
enemyFighter = gameplayContainer.addChild(new Fighter(false));
enemyFighter.x = 2048 / 2 + 300;
enemyFighter.y = 1600;
if (timerMode === 'limited') {
roundTimer = 90;
} else {
roundTimer = -1;
}
}
};
stopButton.down = function (x, y, obj) {
if (gameState === 'victory') {
LK.setScore(LK.getScore() + 50);
storage.lastScore = LK.getScore();
LK.showYouWin();
}
};
LK.playMusic('battleMusic');
game.update = function () {
if (gameState === 'countdown') {
if (countdownActive) {
countdownText.visible = true;
countdownText.setText(battleCountdown.toString());
if (LK.ticks % 60 === 0) {
battleCountdown--;
if (battleCountdown <= 0) {
countdownActive = false;
countdownText.visible = false;
gameState = 'playing';
}
}
}
}
if (gameState === 'playing') {
// Show action buttons when game starts
moveUpButton.visible = true;
moveLeftButton.visible = true;
moveRightButton.visible = true;
moveDownButton.visible = true;
attackButton.visible = true;
kickButton.visible = true;
blockButton.visible = true;
if (timerMode === 'limited') {
if (LK.ticks % 60 === 0) {
roundTimer--;
timerText.setText(roundTimer.toString());
if (roundTimer <= 10) {
timerText.tint = 0xe74c3c;
}
}
} else {
timerText.setText('∞');
}
playerHealthBar.setValue(playerFighter.health);
enemyHealthBar.setValue(enemyFighter.health);
playerStaminaBar.setValue(playerFighter.stamina);
enemyStaminaBar.setValue(enemyFighter.stamina);
scoreText.setText('Score: ' + LK.getScore());
enemyAI.update();
// Update projectiles
for (var i = playerProjectiles.length - 1; i >= 0; i--) {
var projectile = playerProjectiles[i];
var deltaX = projectile.targetX - projectile.x;
var deltaY = (projectile.targetY || enemyFighter.y - 50) - projectile.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance < 50) {
// Hit enemy
var damage = selectedCharacter === 'shark' ? playerFighter.attackPower * 1.8 : playerFighter.attackPower * 2;
enemyFighter.takeDamage(damage);
projectile.destroy();
playerProjectiles.splice(i, 1);
} else if (distance > 800) {
// Out of range
projectile.destroy();
playerProjectiles.splice(i, 1);
} else {
// Move projectile
projectile.x += deltaX / distance * projectile.speed;
projectile.y += deltaY / distance * projectile.speed;
}
}
checkGameEnd();
}
};
Una arena al aire libre rodeada por muros altos con patrones geométricos azul oscuro. El suelo está cubierto de hierba púrpura que brilla tenuemente y tiene zonas con charcos de líquido azul resplandeciente que pueden reflejar efectos de ataques o provocar pequeñas explosiones visuales al contacto. Los árboles están dispuestos al fondo y tienen copas rojas con formas pixeladas, no interactúan con los personajes pero aportan un fondo vibrante. La iluminación es baja, con tonos neón que cambian ligeramente de intensidad durante el combate. El área de batalla es plana, con textura suave pero con efectos de distorsión en los bordes, como si el entorno estuviera parcialmente corrompido.. In-Game asset. 2d. High contrast. No shadows
Botón de golpe sin necesidad de que diga para que es, que sea un símbolo de un puño ardiente. In-Game asset. 2d. High contrast. No shadows
Símbolo de escudo pixelado con pixeles amarillos. In-Game asset. 2d. High contrast. No shadows
Toro furry fuerte sin camisa pixelado. In-Game asset. 2d. High contrast. No shadows
Lagarto furry fuerte sin camisa y con taparrabos, que en la cara lleve un cráneo de otro lagarto, que lleve colgantes y que sea pixeleado. In-Game asset. 2d. High contrast. No shadows
Tiburón furry fuerte sin camisa y con shorts, que en la cara lleve unas gafas de sol, que lleve colgantes y que sea pixeleado que se vea todo su cuerpo In-Game asset. 2d. High contrast. No shadows
Lobo blanco fuerte revelando sus pectorales pero usando una capa y un taparrabos, que se vea todo su cuerpo y pixelado. In-Game asset. 2d. High contrast. No shadows
Tigre furry fuerte con una marca de x en su pectoral y pixeleado y que se vea todo su cuerpo, con un taparrabos y una piernera con una daga In-Game asset. 2d. High contrast. No shadows
Barra de vida llamativa In-Game asset. 2d. High contrast. No shadows
Barra de energía llamativa. In-Game asset. 2d. High contrast. No shadows
Mordida, dientes de lobo cerrados. In-Game asset. 2d. High contrast. No shadows
Botón de líneas curvas en total 3 pixeleado. In-Game asset. 2d. High contrast. No shadows
Oso polar furry fuerte con bufanda y pantalones largos y sin camisa, pixeleado. In-Game asset. 2d. High contrast. No shadows
Aguila real furry fuerte cruzando los brazos sin camisa y gran pectoral con un taparrabos de hojas pixeleado todo el cuerpo. In-Game asset. 2d. High contrast. No shadows
Partículas al golpear pixeleado In-Game asset. 2d. High contrast. No shadows
Particula de escudo siendo golpeado pixeleado In-Game asset. 2d. High contrast. No shadows
Barra de vida vacia con un corazón roto In-Game asset. 2d. High contrast. No shadows
Barra de energia vacia In-Game asset. 2d. High contrast. No shadows
Una particular de rayo pixeleada. In-Game asset. 2d. High contrast. No shadows