/**** * Classes ****/ // BackgroundContainer class to handle background elements var BackgroundContainer = Container.expand(function () { var self = Container.call(this); var background = self.attachAsset('gameBackground', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); return self; }); var EnemyBullet = Container.expand(function (shooter, target) { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 50; self.shooter = shooter; self.target = target; self._move_migrated = function () { var dx = self.target.x - self.shooter.x; var dy = self.target.y - self.shooter.y; var distance = Math.sqrt(dx * dx + dy * dy); self.x += self.speed * dx / distance; self.y += self.speed * dy / distance; }; }); // ForegroundContainer class to handle foreground elements var ForegroundContainer = Container.expand(function () { var self = Container.call(this); // Add foreground elements here return self; }); // ForegroundContainer class to handle foreground elements // MidgroundContainer class to handle midground elements var MidgroundContainer = Container.expand(function () { var self = Container.call(this); // Add midground elements here return self; }); var Platform = Container.expand(function () { var self = Container.call(this); var platformGraphics = self.attachAsset('Platform', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Platform_Enemy = Container.expand(function () { var self = Container.call(this); var platformGraphics = self.attachAsset('Platform_Enemy', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Projectile class var Projectile = Container.expand(function (shooter, target) { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 50; self.shooter = shooter; self.target = target; self._move_migrated = function () { var dx = self.target.x - self.shooter.x; var dy = self.target.y - self.shooter.y; var distance = Math.sqrt(dx * dx + dy * dy); self.x += self.speed * dx / distance; self.y += self.speed * dy / distance; }; }); // Assets will be automatically generated based on usage in the code. // Tank class var Tank = Container.expand(function (isEnemy) { var self = Container.call(this); this.isEnemy = isEnemy || false; self.baseHP = 100; // Base health points of the tank self.HP = self.baseHP; // Current health points of the tank self.Accuracy = 0.80; // Accuracy of the tank's shots self.minDmg = 10; // Minimum damage the tank can inflict self.maxDmg = 20; // Maximum damage the tank can inflict self.isEnemy = self.isEnemy ? true : false; var tankGraphics = self.attachAsset(self.isEnemy ? 'enemyTank' : 'tank', { anchorX: 0.5, anchorY: 0.5 }); self.direction = self.isEnemy ? 2 : 0; // 0: up, 1: right, 2: down, 3: left self.shoot = function (targetTank) { // Calculate damage based on minDmg and maxDmg var damage = Math.floor(Math.random() * (self.maxDmg - self.minDmg + 1)) + self.minDmg; // Simulate accuracy var hit = Math.random() < self.Accuracy; if (hit) { LK.getSound('Shoot_Player').play(); // Apply damage to targetTank.HP targetTank.HP -= damage; gameState.isAnimating = true; } }; }); // TankStatsHUD class for displaying tank stats var TankStatsHUD = Container.expand(function (x, y, tank) { var self = Container.call(this); self.x = x; self.y = y; self.tank = tank; // Initialize HUD texts as properties to avoid redundancy // Initialize HUD texts as properties to avoid redundancy // Helper function to create HUD text elements function createHUDTextElement() { return self.addChild(new Text2('', { size: statTextProperties.size, fill: statTextProperties.fill, stroke: statTextProperties.stroke, strokeThickness: statTextProperties.strokeThickness, width: statTextProperties.width, align: statTextProperties.align })); } self.hpText = createHUDTextElement(); self.accuracyText = createHUDTextElement(); self.minDmgText = createHUDTextElement(); self.maxDmgText = createHUDTextElement(); // Set initial positions self.hpText.y = 0; self.accuracyText.y = 130; self.minDmgText.y = 260; self.maxDmgText.y = 390; // Consolidated method to update HUD with tank stats self.updateHUD = function () { // Update all stats in a single method to streamline HUD updates self.hpText.setText("Health: ".concat(self.tank.HP)); self.accuracyText.setText("Accuracy: ".concat(Math.round(self.tank.Accuracy * 100), "%")); self.minDmgText.setText("Min Dmg: ".concat(self.tank.minDmg)); self.maxDmgText.setText("Max Dmg: ".concat(self.tank.maxDmg)); }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Init game with black background }); /**** * Game Code ****/ // Define roundText for displaying current round function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } // Initialize gameState before defining roundText var backgroundContainer = new BackgroundContainer(); var midgroundContainer = new MidgroundContainer(); var platform = new Platform(); platform.x = 2048 / 2; platform.y = 2732 / 2 + 1050; midgroundContainer.addChild(platform); var platformEnemy = new Platform_Enemy(); platformEnemy.x = 2048 / 2; platformEnemy.y = 2732 / 2 - 1050; midgroundContainer.addChild(platformEnemy); var foregroundContainer = new ForegroundContainer(); game.addChild(backgroundContainer); game.addChild(midgroundContainer); game.addChild(foregroundContainer); var gameState = { currentRound: 1, tanks: [] // Initialize tanks as an empty array // other gameState properties }; var roundText = new Text2('Round: ' + gameState.currentRound.toString(), { size: 100, fill: "#ffffff", stroke: "#000000", strokeThickness: 15, anchorX: 0.5, anchorY: 0.5 }); foregroundContainer.addChild(roundText); roundText.x = 2048 / 2 - 200; roundText.y = 2732 / 2; var statTextProperties = { size: 60, fill: "#ffffff", stroke: "#000000", strokeThickness: 10, width: 400, align: "center" }; // Define a single source of truth for stat upgrades var statUpgrades = { 'HP': 20, // Match player's tank upgrade value 'Accuracy': 0.04, // Match player's tank upgrade value 'MinDmg': 5, // Match player's tank upgrade value 'MaxDmg': 5 // Match player's tank upgrade value }; function applyStatUpgrade(selectedUpgrade, tank) { if (statUpgrades.hasOwnProperty(selectedUpgrade)) { var upgradeValue = statUpgrades[selectedUpgrade]; switch (selectedUpgrade) { case 'HP': tank.baseHP += upgradeValue; tank.HP += upgradeValue; // Increase current HP by upgradeValue instead of setting it to new baseHP break; case 'Accuracy': tank.Accuracy = Math.min(1.0, tank.Accuracy + upgradeValue); break; case 'MinDmg': tank.minDmg += upgradeValue; break; case 'MaxDmg': tank.maxDmg += upgradeValue; break; } } // Listen for stat change events to dynamically update available upgrades and refresh upgrade buttons game.on('statChange', function (tank) { gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) { if (upgrade === 'Accuracy' && tank.Accuracy >= 1.0) { return false; // Exclude Accuracy if it's already at or above 100% } if (upgrade === 'MinDmg' && tank.minDmg >= tank.maxDmg) { return false; // Exclude MinDmg if it's equal to or greater than MaxDmg } if (upgrade === 'MaxDmg' && tank.maxDmg <= tank.minDmg) { return false; // Exclude MaxDmg if it's not greater than MinDmg } return true; // Include all other upgrades }); handleUpgradesAndButtons(); // Refresh upgrade buttons based on updated available upgrades }); } // This function now applies to both player and enemy tanks using the same stat upgrades // Consolidated upgrade logic into a single function for clarity and maintainability function applyUpgrades(tank) { // Consolidated upgrade logic into a single function for clarity and maintainability // This function now applies to both player and enemy tanks using the same stat upgrades // Dynamically update and manage upgrade button visibility within this function gameState.upgradesAvailable.forEach(function (upgrade) { applyStatUpgrade(upgrade, tank); }); // Refresh upgrade buttons to reflect current game state and available upgrades handleUpgradesAndButtons(); } // Consolidated function to handle upgrades and dynamically create buttons function handleUpgradesAndButtons() { // Remove existing upgrade buttons before creating new ones game.children.forEach(function (child) { if (child.id && child.id.startsWith('Upgrade_')) { child.destroy(); } }); LK.getSound('Upgrade_Screen').play(); // Updated to check and update upgrade button visibility based on tank stats // Emit statChange event whenever a stat is upgraded game.emit('statChange', tank); gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) { if (upgrade === 'Accuracy' && gameState.playerTank.Accuracy >= 1.0) { return false; // Exclude Accuracy if it's already at or above 100% } if (upgrade === 'MinDmg') { return gameState.playerTank.minDmg < gameState.playerTank.maxDmg; } // After MaxDmg upgrade, check if MinDmg upgrade should be visible if (upgrade === 'MaxDmg') { // After MaxDmg upgrade, check if MinDmg upgrade should be visible if (gameState.playerTank.minDmg < gameState.playerTank.maxDmg) { // Ensure MinDmg upgrade button is visible if conditions are met if (!gameState.upgradesAvailable.includes('MinDmg')) { gameState.upgradesAvailable.push('MinDmg'); } } } return true; // Include all other upgrades }).forEach(function (upgrade, index) { var upgradeBtn = new Container(); var btnGraphics = upgradeBtn.attachAsset('Upgrade_Btn', { anchorX: 0.5, anchorY: 0.5 }); // Positioning and event listener for upgradeBtn omitted for brevity game.addChild(upgradeBtn); }); } // Helper function to select a random upgrade for the enemy function selectRandomUpgrade(tank) { var validUpgrades = gameState.upgradesAvailable.filter(function (upgrade) { // Example condition to filter out upgrades, can be expanded return !(upgrade === 'Accuracy' && tank.Accuracy >= 1.0); }); var randomIndex = Math.floor(Math.random() * validUpgrades.length); return validUpgrades[randomIndex]; } // Initialize gameState before defining tanks to avoid 'currentRound' being undefined // Redundant upgrade text display code successfully removed // Function to reset game state for a new round function resetGameStateForNewRound() { // Select a single random upgrade for the enemy ensuring only one stat is upgraded per round function selectSingleRandomUpgradeForEnemy() { // Ensure only one stat is upgraded per round if (gameState.currentRound === gameState.lastUpgradedRound) { return; } // Exit if upgrade already applied this round var validUpgrades = Object.keys(statUpgrades).filter(function (upgrade) { // Conditions to filter out maximized stats if (upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0) { return false; } if (upgrade === 'HP' && gameState.enemyTank.HP >= gameState.enemyTank.baseHP) { return false; } if (upgrade === 'MinDmg' && (gameState.enemyTank.minDmg >= gameState.enemyTank.maxDmg - 5 || gameState.enemyTank.minDmg === gameState.enemyTank.maxDmg)) { return false; } if (upgrade === 'MaxDmg' && (gameState.enemyTank.maxDmg >= 50 || gameState.enemyTank.minDmg === gameState.enemyTank.maxDmg)) { return false; } return true; }); if (validUpgrades.length > 0) { var randomUpgrade = validUpgrades[Math.floor(Math.random() * validUpgrades.length)]; applyStatUpgrade(randomUpgrade, gameState.enemyTank); gameState.lastUpgradedRound = gameState.currentRound; // Mark this round as upgraded } } // Reset the flag to false at the end of the round to allow for a single upgrade in the next round gameState.playerTurn = true; // Give the turn back to the player gameState.roundIncremented = false; // Reset the round increment flag gameState.isAnimating = false; // Ensure no animations are running // Define startingHP for both tanks to ensure it's available for resetting // Clear all bullets from the previous round to prevent applying damage from the last bullet bullets.forEach(function (bullet) { bullet.destroy(); }); bullets = []; // Reset both tanks' HP to their baseHP at the beginning of a new round gameState.playerTank.HP = gameState.playerTank.baseHP; gameState.enemyTank.HP = gameState.enemyTank.baseHP; // Update both player and enemy HUDs to reflect the reset state playerTankHUD.updateHUD(); enemyTankHUD.updateHUD(); } // Consolidated function for damage calculation and text display function calculateDamage(shooter, target) { var hit = Math.random() < shooter.Accuracy; if (hit) { var damage = Math.floor(Math.random() * (shooter.maxDmg - shooter.minDmg + 1)) + shooter.minDmg; target.HP = Math.max(0, target.HP - damage); // Initiate shake effect var originalX = target.x; var originalY = target.y; var shakeDuration = 200; // Duration in milliseconds var shakeStartTime = Date.now(); var shake = function shake() { if (Date.now() - shakeStartTime < shakeDuration) { // Randomly adjust target's position to simulate stronger shaking target.x = originalX + Math.random() * 20 - 10; // Shake range -10 to 10 pixels on x-axis target.y = originalY + Math.random() * 20 - 10; // Shake range -10 to 10 pixels on y-axis LK.setTimeout(shake, 16); // Approximately 60 frames per second } else { // Reset target's position after shaking target.x = originalX; target.y = originalY; } }; shake(); displayDamageText(damage, target.x, target.y); if (target === gameState.playerTank) { playerTankHUD.updateHUD(); } return true; } else { displayMissIndicator(target.x, target.y); return false; } } // Helper function to display damage text function displayDamageText(damage, x, y) { var damageText = new Text2(damage.toString(), { size: 150, // Increased size from 120 to 180 fill: "#ff0000", stroke: "#000000", strokeThickness: 15, anchorX: 0.5, anchorY: 0.5 }); damageText.position.set(x - 80, y - 80); game.addChild(damageText); LK.setTimeout(function () { return damageText.destroy(); }, 600); } // Helper function to display miss indicator function displayMissIndicator(x, y) { var missIndicator = LK.getAsset('miss', { anchorX: 0.5, anchorY: 0.5, x: x, y: y }); game.addChild(missIndicator); LK.setTimeout(function () { return missIndicator.destroy(); }, 1000); } // Define triggerPlayerShoot function globally to ensure it's accessible throughout the script function triggerPlayerShoot() { LK.getSound('Shoot_Player').play(); var projectile = new Projectile(playerTank, enemyTank); projectile.x = playerTank.x; projectile.y = playerTank.y - 150; // Positioning logic for shooting upwards game.addChild(projectile); bullets.push(projectile); gameState.isAnimating = true; // Indicate an action is taking place, requiring animation. } // Define triggerEnemyShoot function globally to ensure it's accessible throughout the script // Define triggerEnemyShoot function globally to ensure it's accessible throughout the script function triggerEnemyShoot() { LK.getSound('Shoot_Enemy').play(); var enemyProjectile = new EnemyBullet(gameState.enemyTank, gameState.playerTank); enemyProjectile.x = gameState.enemyTank.x; enemyProjectile.y = gameState.enemyTank.y + 100; // Adjusted positioning for enemy shooting logic game.addChild(enemyProjectile); bullets.push(enemyProjectile); gameState.isAnimating = true; // Ensure this is set to true to prevent immediate subsequent actions } // Initialize gameState with unique identifiers to prevent global scope conflicts var allUpgrades = ['HP', 'Accuracy', 'MinDmg', 'MaxDmg']; // Define shootingInterval in the global scope to manage shooting intervals var shootingInterval = null; // Define bullets array in the global scope for easy access and manipulation var bullets = []; // Initialize player and enemy tanks within the gameState to ensure a single source of truth gameState.playerTank = new Tank(false); // Player's tank gameState.enemyTank = new Tank(true); // Enemy's tank // Initialize player tank var playerTank = new Tank(false); // Player's tank playerTank.x = 1024; // Center horizontally playerTank.y = 2732 - 300; // Moved 100 pixels higher gameState.playerTank = playerTank; // Assign playerTank to gameState game.addChild(gameState.playerTank); gameState.tanks.push(gameState.playerTank); game.addChild(gameState.playerTank); gameState.tanks.push(gameState.playerTank); // Initialize enemy tank var enemyTank = new Tank(true); // Enemy's tank enemyTank.x = 1024; // Center horizontally enemyTank.y = 300; // Moved 100 pixels lower gameState.enemyTank = enemyTank; // Assign enemyTank to gameState game.addChild(gameState.enemyTank); gameState.tanks.push(gameState.enemyTank); game.addChild(gameState.enemyTank); gameState.tanks.push(gameState.enemyTank); // Instantiate TankStatsHUD for the player tank var playerTankHUD = new TankStatsHUD(-600, -515, gameState.playerTank); // Center above the player tank LK.gui.bottom.addChild(playerTankHUD); // Instantiate TankStatsHUD for the enemy tank and ensure it's visible from the start var enemyTankHUD = new TankStatsHUD(-600, +50, gameState.enemyTank); // Position at the top of the screen enemyTankHUD.updateHUD(); // Update HUD to make it visible from the start LK.gui.top.addChild(enemyTankHUD); // Handle touch events to rotate and move the tank // Removed tank rotation on screen tap // Define a function to manage the shooting interval function manageShootingInterval(action) { if (action === 'start') { // Clear existing interval if any if (shootingInterval) { manageShootingInterval('stop'); // Use the dedicated function to stop shooting } // Start a new shooting interval shootingInterval = LK.setInterval(function () { if (gameState.isAnimating || gameState.playerTank.HP <= 0 || gameState.enemyTank.HP <= 0) { return; // Prevent firing if any condition is met. } if (gameState.currentRound === 1 || gameState.playerTurn) { triggerPlayerShoot(); } else { triggerEnemyShoot(); } }, 1000); } else if (action === 'stop') { // Clear the shooting interval if (shootingInterval) { LK.clearInterval(shootingInterval); } } } // Initially start the shooting interval manageShootingInterval('start'); // Move bullets LK.on('tick', function () { // Implement a pre-check at the beginning of this function to halt actions if a tank's HP is 0. if (gameState.playerTank.HP <= 0 || gameState.enemyTank.HP <= 0) { // Consider implementing logic here to pause the game and trigger any end-of-round or game over logic. gameState.isAnimating = false; // Halt animations. return; // Exit the tick function early. } playerTankHUD.updateHUD(); var _loop = function _loop() { if (bullets[i]) { bullets[i]._move_migrated(); } // Check for collision with tanks if (bullets[i].intersects(playerTank) && bullets[i] instanceof EnemyBullet) { // Correctly identify shooter as enemyTank and target as playerTank for damage calculation if (calculateDamage(enemyTank, playerTank)) { // Ensure enemyTank is the shooter and playerTank is the target playerTankHUD.updateHUD(); // Update player tank HUD stats // Check if either tank's HP reaches 0 to pause game and show upgrades if (playerTank.HP === 0) { gameState.isPaused = true; // Stop all actions immediately LK.clearInterval(shootingInterval); // Stop shooting immediately game.off('down'); // Disable movement immediately LK.showGameOver(); // End game if player tank HP drops to 0 } else if (enemyTank.HP === 0) { // Delay pausing the game until after the bullet is destroyed bullets[i].destroy(); // Remove bullet from game bullets.splice(i, 1); // Remove bullet from bullets array gameState.isPaused = true; // Stop all actions immediately LK.clearInterval(shootingInterval); // Stop shooting immediately game.off('down'); // Disable movement immediately LK.setTimeout(showUpgradeOptions, 100); // Delay showing upgrade options to ensure bullet is removed } } bullets[i].destroy(); // Remove bullet from game bullets.splice(i, 1); // Remove bullet from bullets array gameState.playerTurn = true; // Switch turn to player gameState.isAnimating = false; // End animation state return { v: void 0 }; // Exit the loop } else if (bullets[i].intersects(enemyTank) && bullets[i] instanceof Projectile) { // Invoke calculateDamage for player bullet hitting enemy tank if (calculateDamage(gameState.playerTank, enemyTank)) { enemyTankHUD.updateHUD(); // Refresh enemy tank HUD stats if (enemyTank.HP === 0) { LK.getSound('Upgrade_Screen').play(); // Play Upgrade_Screen sound when enemy tank reaches 0 HP // Set game state to paused gameState.isPaused = true; // Clear shooting interval to pause shooting LK.clearInterval(shootingInterval); // Disable movement by removing event listeners game.off('down'); // Display upgrade options for the player to select // Initialize upgrade buttons for player selection // Dynamically update the list of available upgrades based on current tank stats // After applying the upgrade, update the player and enemy tank HUD to reflect changes playerTankHUD.updateHUD(); enemyTankHUD.updateHUD(); // Filter upgrades based on new stats gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) { if (upgrade === 'Accuracy' && gameState.playerTank.Accuracy >= 1.0) { return false; // Exclude Accuracy if it's already at or above 100% } if (upgrade === 'MinDmg' && gameState.playerTank.minDmg >= gameState.playerTank.maxDmg) { return false; // Exclude MinDmg if it's equal to or greater than MaxDmg } return true; // Include all other upgrades }); // Iterate over the filtered list of upgrades to display upgrade buttons // Define individual positions for each upgrade button var upgradePositions = { 'HP': { x: 80, y: 2040 }, 'Accuracy': { x: 80, y: 2225 }, 'MinDmg': { x: 80, y: 2410 }, 'MaxDmg': { x: 80, y: 2595 } }; gameState.upgradesAvailable.forEach(function (upgrade) { var pos = upgradePositions[upgrade]; var upgradeBtn = LK.getAsset('Upgrade_Btn', { x: pos.x, y: pos.y, anchorX: 0.5, anchorY: 0.5, id: 'Upgrade_' + upgrade }); upgradeBtn.on('down', function () { LK.getSound('Upgrade_Btn').play(); // Play Upgrade_Btn sound when any upgrade button is pressed if (upgrade === 'HP') { LK.getSound('Upg_HP').play(); // Play Upg_HP sound when HP upgrade button is pressed } else if (upgrade === 'Accuracy') { LK.getSound('Upg_Acc').play(); // Play Upg_Acc sound when Accuracy upgrade button is pressed } else if (upgrade === 'MinDmg') { LK.getSound('Upg_Dmg_Min').play(); // Play Upg_Dmg_Min sound when MinDmg upgrade button is pressed } else if (upgrade === 'MaxDmg') { LK.getSound('Upg_Dmg_Max').play(); // Play Upg_Dmg_Max sound when MaxDmg upgrade button is pressed } gameState.playerSelectedUpgrade = upgrade; applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank); var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) { return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0); }); var randomUpgradeIndex = Math.floor(Math.random() * filteredUpgrades.length); gameState.enemySelectedUpgrade = filteredUpgrades[randomUpgradeIndex]; applyStatUpgrade(gameState.enemySelectedUpgrade, gameState.enemyTank); // Remove all upgrade buttons after selection game.children = game.children.filter(function (child) { return !child.id || !child.id.startsWith('Upgrade_'); }); manageShootingInterval('start'); gameState.isPaused = false; gameState.playerTurn = true; gameState.isAnimating = false; gameState.currentRound += 1; // Increment the round number roundText.setText('Round: ' + gameState.currentRound.toString()); // Update the round text resetGameStateForNewRound(); }); game.addChild(upgradeBtn); }); // Ensure round management is correctly handled at the end of each round if (!gameState.isAnimating && gameState.playerTank.HP > 0 && gameState.enemyTank.HP > 0) { manageGameRound(); // Correctly increment and manage round transitions only when conditions are met } return { v: void 0 }; // Exit the loop to avoid executing further code in this tick } } bullets[i].destroy(); bullets.splice(i, 1); gameState.playerTurn = false; // Switch to enemy's turn after player bullet hits triggerEnemyShoot(); // Trigger enemy to shoot immediately after player's bullet hits return { v: void 0 }; } // Remove bullets that go off-screen if (bullets[i].y < 0) { bullets[i].destroy(); bullets.splice(i, 1); // gameState.isAnimating = false; // Moved to a more appropriate location after enemy's turn gameState.playerTurn = !gameState.playerTurn; // Reset gameState.isAnimating to false after ensuring all animations and hit calculations are complete if (!gameState.playerTurn) { LK.setTimeout(function () { gameState.isAnimating = false; }, 1000); // Assuming 1 second is enough for the enemy's bullet to reach the player or go off-screen } } }, _ret; for (var i = bullets.length - 1; i >= 0; i--) { _ret = _loop(); if (_ret) { return _ret.v; } } }); function showUpgradeOptions() { LK.getSound('Upgrade_Screen').play(); // Display upgrade options for the player to select gameState.upgradesAvailable.forEach(function (upgrade, index) { // Removed incorrect positioning logic for upgrade buttons to ensure they appear correctly relative to their corresponding stats upgradeBtn.on('down', function () { gameState.playerSelectedUpgrade = upgrade; // Define applyPlayerUpgrade function to apply the selected upgrade to the player's tank function applyPlayerUpgrade() { applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank); // Directly call handleUpgradesAndButtons to update upgrade button visibility based on stat changes handleUpgradesAndButtons(); // Listen for stat change events to dynamically update available upgrades and refresh upgrade buttons game.on('statChange', function (tank) { gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) { if (upgrade === 'Accuracy' && tank.Accuracy >= 1.0) { return false; // Exclude Accuracy if it's already at or above 100% } if (upgrade === 'MinDmg' && tank.minDmg >= tank.maxDmg) { return false; // Exclude MinDmg if it's equal to or greater than MaxDmg } if (upgrade === 'MaxDmg' && tank.maxDmg <= tank.minDmg) { return false; // Exclude MaxDmg if it's not greater than MinDmg } return true; // Include all other upgrades }); handleUpgradesAndButtons(); // Refresh upgrade buttons based on updated available upgrades }); } // Dynamically create upgrade buttons based on updated available upgrades gameState.upgradesAvailable.forEach(function (upgrade, index) { var upgradeBtn = LK.getAsset('Upgrade_Btn', { // Correct positioning logic will be applied elsewhere id: 'Upgrade_' + upgrade // Assign a unique ID based on the upgrade type }); upgradeBtn.on('down', function () { gameState.playerSelectedUpgrade = upgrade; applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank); // Filter out Accuracy upgrade if enemy's Accuracy is already at 100%, then randomly select and apply an upgrade var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) { return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0); }); var randomUpgradeIndex = Math.floor(Math.random() * filteredUpgrades.length); gameState.enemySelectedUpgrade = filteredUpgrades[randomUpgradeIndex]; applyStatUpgrade(gameState.enemySelectedUpgrade, gameState.enemyTank); // Hide all upgrade buttons and texts game.children.forEach(function (child) { if (child.id && child.id.startsWith('Upgrade_')) { child.destroy(); } }); // Restart shooting interval after upgrade selection using the dedicated function manageShootingInterval('start'); // Resume game after upgrade selection gameState.isPaused = false; // Ensure Game State is Correctly Managed gameState.playerTurn = true; // It's player's turn after selecting an upgrade gameState.isAnimating = false; // No animations are running at the start of a new round resetGameStateForNewRound(); }); game.addChild(upgradeBtn); var upgradeText = new Text2(upgrade, { size: 40, fill: "#000000", x: upgradeBtn.x, y: upgradeBtn.y, anchorX: 0.5, anchorY: 0.5, id: 'Upgrade_Text_' + upgrade // Assign a unique ID for the text based on the upgrade type }); game.addChild(upgradeText); }); // Resume game after upgrade selection gameState.isPaused = false; // Allow game actions to continue // Clear existing shooting interval before setting a new one if (shootingInterval) { LK.clearInterval(shootingInterval); } // Set up a new shooting interval shootingInterval = LK.setInterval(function () { if (!gameState.isPaused) { if (gameState.playerTurn) { triggerPlayerShoot(); } else { triggerEnemyShoot(); } } }, 1000); // Adjust timing as necessary // Re-attach event listeners for player movement and actions game.on('down', function (x, y, obj) { // Movement and action logic here, ensuring it only executes when the game is not paused }); resetGameStateForNewRound(); // Reset the game state for a new round gameState.playerTurn = true; // Player starts shooting after selecting an upgrade }); game.addChild(upgradeBtn); var upgradeText = new Text2(upgrade, { size: 40, fill: "#000000", x: upgradeBtn.x, y: upgradeBtn.y, anchorX: 0.5, anchorY: 0.5 }); game.addChild(upgradeText); }); function applyRandomUpgradeToEnemy() { var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) { return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0); }); var randomUpgrade = filteredUpgrades[Math.floor(Math.random() * filteredUpgrades.length)]; applyStatUpgrade(randomUpgrade, gameState.enemyTank); } // Define roundText for displaying current round var roundText = new Text2('Round: ' + gameState.currentRound.toString(), { size: 60, fill: "#ffffff", stroke: "#000000", strokeThickness: 10, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); foregroundContainer.addChild(roundText); // Ensure round management is handled in a single function to prevent multiple increments function manageGameRound() { if (!gameState.roundIncremented) { gameState.roundIncremented = true; // Ensure round is only incremented once per logical game round } roundText.setText('Round: ' + gameState.currentRound.toString()); // Update the round text to display the new round number LK.effects.flashScreen(0x00FF00, 500); // Flash the screen green to indicate round advancement } // Call manageGameRound() where necessary instead of directly manipulating gameState.currentRound } ; // Display upgrade options for the player to select
/****
* Classes
****/
// BackgroundContainer class to handle background elements
var BackgroundContainer = Container.expand(function () {
var self = Container.call(this);
var background = self.attachAsset('gameBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
return self;
});
var EnemyBullet = Container.expand(function (shooter, target) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 50;
self.shooter = shooter;
self.target = target;
self._move_migrated = function () {
var dx = self.target.x - self.shooter.x;
var dy = self.target.y - self.shooter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.x += self.speed * dx / distance;
self.y += self.speed * dy / distance;
};
});
// ForegroundContainer class to handle foreground elements
var ForegroundContainer = Container.expand(function () {
var self = Container.call(this);
// Add foreground elements here
return self;
});
// ForegroundContainer class to handle foreground elements
// MidgroundContainer class to handle midground elements
var MidgroundContainer = Container.expand(function () {
var self = Container.call(this);
// Add midground elements here
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('Platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Platform_Enemy = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('Platform_Enemy', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Projectile class
var Projectile = Container.expand(function (shooter, target) {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 50;
self.shooter = shooter;
self.target = target;
self._move_migrated = function () {
var dx = self.target.x - self.shooter.x;
var dy = self.target.y - self.shooter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
self.x += self.speed * dx / distance;
self.y += self.speed * dy / distance;
};
});
// Assets will be automatically generated based on usage in the code.
// Tank class
var Tank = Container.expand(function (isEnemy) {
var self = Container.call(this);
this.isEnemy = isEnemy || false;
self.baseHP = 100; // Base health points of the tank
self.HP = self.baseHP; // Current health points of the tank
self.Accuracy = 0.80; // Accuracy of the tank's shots
self.minDmg = 10; // Minimum damage the tank can inflict
self.maxDmg = 20; // Maximum damage the tank can inflict
self.isEnemy = self.isEnemy ? true : false;
var tankGraphics = self.attachAsset(self.isEnemy ? 'enemyTank' : 'tank', {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = self.isEnemy ? 2 : 0; // 0: up, 1: right, 2: down, 3: left
self.shoot = function (targetTank) {
// Calculate damage based on minDmg and maxDmg
var damage = Math.floor(Math.random() * (self.maxDmg - self.minDmg + 1)) + self.minDmg;
// Simulate accuracy
var hit = Math.random() < self.Accuracy;
if (hit) {
LK.getSound('Shoot_Player').play();
// Apply damage to targetTank.HP
targetTank.HP -= damage;
gameState.isAnimating = true;
}
};
});
// TankStatsHUD class for displaying tank stats
var TankStatsHUD = Container.expand(function (x, y, tank) {
var self = Container.call(this);
self.x = x;
self.y = y;
self.tank = tank;
// Initialize HUD texts as properties to avoid redundancy
// Initialize HUD texts as properties to avoid redundancy
// Helper function to create HUD text elements
function createHUDTextElement() {
return self.addChild(new Text2('', {
size: statTextProperties.size,
fill: statTextProperties.fill,
stroke: statTextProperties.stroke,
strokeThickness: statTextProperties.strokeThickness,
width: statTextProperties.width,
align: statTextProperties.align
}));
}
self.hpText = createHUDTextElement();
self.accuracyText = createHUDTextElement();
self.minDmgText = createHUDTextElement();
self.maxDmgText = createHUDTextElement();
// Set initial positions
self.hpText.y = 0;
self.accuracyText.y = 130;
self.minDmgText.y = 260;
self.maxDmgText.y = 390;
// Consolidated method to update HUD with tank stats
self.updateHUD = function () {
// Update all stats in a single method to streamline HUD updates
self.hpText.setText("Health: ".concat(self.tank.HP));
self.accuracyText.setText("Accuracy: ".concat(Math.round(self.tank.Accuracy * 100), "%"));
self.minDmgText.setText("Min Dmg: ".concat(self.tank.minDmg));
self.maxDmgText.setText("Max Dmg: ".concat(self.tank.maxDmg));
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Init game with black background
});
/****
* Game Code
****/
// Define roundText for displaying current round
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) {
return t;
}
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) {
return i;
}
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
// Initialize gameState before defining roundText
var backgroundContainer = new BackgroundContainer();
var midgroundContainer = new MidgroundContainer();
var platform = new Platform();
platform.x = 2048 / 2;
platform.y = 2732 / 2 + 1050;
midgroundContainer.addChild(platform);
var platformEnemy = new Platform_Enemy();
platformEnemy.x = 2048 / 2;
platformEnemy.y = 2732 / 2 - 1050;
midgroundContainer.addChild(platformEnemy);
var foregroundContainer = new ForegroundContainer();
game.addChild(backgroundContainer);
game.addChild(midgroundContainer);
game.addChild(foregroundContainer);
var gameState = {
currentRound: 1,
tanks: [] // Initialize tanks as an empty array
// other gameState properties
};
var roundText = new Text2('Round: ' + gameState.currentRound.toString(), {
size: 100,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 15,
anchorX: 0.5,
anchorY: 0.5
});
foregroundContainer.addChild(roundText);
roundText.x = 2048 / 2 - 200;
roundText.y = 2732 / 2;
var statTextProperties = {
size: 60,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 10,
width: 400,
align: "center"
};
// Define a single source of truth for stat upgrades
var statUpgrades = {
'HP': 20,
// Match player's tank upgrade value
'Accuracy': 0.04,
// Match player's tank upgrade value
'MinDmg': 5,
// Match player's tank upgrade value
'MaxDmg': 5 // Match player's tank upgrade value
};
function applyStatUpgrade(selectedUpgrade, tank) {
if (statUpgrades.hasOwnProperty(selectedUpgrade)) {
var upgradeValue = statUpgrades[selectedUpgrade];
switch (selectedUpgrade) {
case 'HP':
tank.baseHP += upgradeValue;
tank.HP += upgradeValue; // Increase current HP by upgradeValue instead of setting it to new baseHP
break;
case 'Accuracy':
tank.Accuracy = Math.min(1.0, tank.Accuracy + upgradeValue);
break;
case 'MinDmg':
tank.minDmg += upgradeValue;
break;
case 'MaxDmg':
tank.maxDmg += upgradeValue;
break;
}
}
// Listen for stat change events to dynamically update available upgrades and refresh upgrade buttons
game.on('statChange', function (tank) {
gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) {
if (upgrade === 'Accuracy' && tank.Accuracy >= 1.0) {
return false; // Exclude Accuracy if it's already at or above 100%
}
if (upgrade === 'MinDmg' && tank.minDmg >= tank.maxDmg) {
return false; // Exclude MinDmg if it's equal to or greater than MaxDmg
}
if (upgrade === 'MaxDmg' && tank.maxDmg <= tank.minDmg) {
return false; // Exclude MaxDmg if it's not greater than MinDmg
}
return true; // Include all other upgrades
});
handleUpgradesAndButtons(); // Refresh upgrade buttons based on updated available upgrades
});
}
// This function now applies to both player and enemy tanks using the same stat upgrades
// Consolidated upgrade logic into a single function for clarity and maintainability
function applyUpgrades(tank) {
// Consolidated upgrade logic into a single function for clarity and maintainability
// This function now applies to both player and enemy tanks using the same stat upgrades
// Dynamically update and manage upgrade button visibility within this function
gameState.upgradesAvailable.forEach(function (upgrade) {
applyStatUpgrade(upgrade, tank);
});
// Refresh upgrade buttons to reflect current game state and available upgrades
handleUpgradesAndButtons();
}
// Consolidated function to handle upgrades and dynamically create buttons
function handleUpgradesAndButtons() {
// Remove existing upgrade buttons before creating new ones
game.children.forEach(function (child) {
if (child.id && child.id.startsWith('Upgrade_')) {
child.destroy();
}
});
LK.getSound('Upgrade_Screen').play();
// Updated to check and update upgrade button visibility based on tank stats
// Emit statChange event whenever a stat is upgraded
game.emit('statChange', tank);
gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) {
if (upgrade === 'Accuracy' && gameState.playerTank.Accuracy >= 1.0) {
return false; // Exclude Accuracy if it's already at or above 100%
}
if (upgrade === 'MinDmg') {
return gameState.playerTank.minDmg < gameState.playerTank.maxDmg;
}
// After MaxDmg upgrade, check if MinDmg upgrade should be visible
if (upgrade === 'MaxDmg') {
// After MaxDmg upgrade, check if MinDmg upgrade should be visible
if (gameState.playerTank.minDmg < gameState.playerTank.maxDmg) {
// Ensure MinDmg upgrade button is visible if conditions are met
if (!gameState.upgradesAvailable.includes('MinDmg')) {
gameState.upgradesAvailable.push('MinDmg');
}
}
}
return true; // Include all other upgrades
}).forEach(function (upgrade, index) {
var upgradeBtn = new Container();
var btnGraphics = upgradeBtn.attachAsset('Upgrade_Btn', {
anchorX: 0.5,
anchorY: 0.5
});
// Positioning and event listener for upgradeBtn omitted for brevity
game.addChild(upgradeBtn);
});
}
// Helper function to select a random upgrade for the enemy
function selectRandomUpgrade(tank) {
var validUpgrades = gameState.upgradesAvailable.filter(function (upgrade) {
// Example condition to filter out upgrades, can be expanded
return !(upgrade === 'Accuracy' && tank.Accuracy >= 1.0);
});
var randomIndex = Math.floor(Math.random() * validUpgrades.length);
return validUpgrades[randomIndex];
}
// Initialize gameState before defining tanks to avoid 'currentRound' being undefined
// Redundant upgrade text display code successfully removed
// Function to reset game state for a new round
function resetGameStateForNewRound() {
// Select a single random upgrade for the enemy ensuring only one stat is upgraded per round
function selectSingleRandomUpgradeForEnemy() {
// Ensure only one stat is upgraded per round
if (gameState.currentRound === gameState.lastUpgradedRound) {
return;
} // Exit if upgrade already applied this round
var validUpgrades = Object.keys(statUpgrades).filter(function (upgrade) {
// Conditions to filter out maximized stats
if (upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0) {
return false;
}
if (upgrade === 'HP' && gameState.enemyTank.HP >= gameState.enemyTank.baseHP) {
return false;
}
if (upgrade === 'MinDmg' && (gameState.enemyTank.minDmg >= gameState.enemyTank.maxDmg - 5 || gameState.enemyTank.minDmg === gameState.enemyTank.maxDmg)) {
return false;
}
if (upgrade === 'MaxDmg' && (gameState.enemyTank.maxDmg >= 50 || gameState.enemyTank.minDmg === gameState.enemyTank.maxDmg)) {
return false;
}
return true;
});
if (validUpgrades.length > 0) {
var randomUpgrade = validUpgrades[Math.floor(Math.random() * validUpgrades.length)];
applyStatUpgrade(randomUpgrade, gameState.enemyTank);
gameState.lastUpgradedRound = gameState.currentRound; // Mark this round as upgraded
}
}
// Reset the flag to false at the end of the round to allow for a single upgrade in the next round
gameState.playerTurn = true; // Give the turn back to the player
gameState.roundIncremented = false; // Reset the round increment flag
gameState.isAnimating = false; // Ensure no animations are running
// Define startingHP for both tanks to ensure it's available for resetting
// Clear all bullets from the previous round to prevent applying damage from the last bullet
bullets.forEach(function (bullet) {
bullet.destroy();
});
bullets = [];
// Reset both tanks' HP to their baseHP at the beginning of a new round
gameState.playerTank.HP = gameState.playerTank.baseHP;
gameState.enemyTank.HP = gameState.enemyTank.baseHP;
// Update both player and enemy HUDs to reflect the reset state
playerTankHUD.updateHUD();
enemyTankHUD.updateHUD();
}
// Consolidated function for damage calculation and text display
function calculateDamage(shooter, target) {
var hit = Math.random() < shooter.Accuracy;
if (hit) {
var damage = Math.floor(Math.random() * (shooter.maxDmg - shooter.minDmg + 1)) + shooter.minDmg;
target.HP = Math.max(0, target.HP - damage);
// Initiate shake effect
var originalX = target.x;
var originalY = target.y;
var shakeDuration = 200; // Duration in milliseconds
var shakeStartTime = Date.now();
var shake = function shake() {
if (Date.now() - shakeStartTime < shakeDuration) {
// Randomly adjust target's position to simulate stronger shaking
target.x = originalX + Math.random() * 20 - 10; // Shake range -10 to 10 pixels on x-axis
target.y = originalY + Math.random() * 20 - 10; // Shake range -10 to 10 pixels on y-axis
LK.setTimeout(shake, 16); // Approximately 60 frames per second
} else {
// Reset target's position after shaking
target.x = originalX;
target.y = originalY;
}
};
shake();
displayDamageText(damage, target.x, target.y);
if (target === gameState.playerTank) {
playerTankHUD.updateHUD();
}
return true;
} else {
displayMissIndicator(target.x, target.y);
return false;
}
}
// Helper function to display damage text
function displayDamageText(damage, x, y) {
var damageText = new Text2(damage.toString(), {
size: 150,
// Increased size from 120 to 180
fill: "#ff0000",
stroke: "#000000",
strokeThickness: 15,
anchorX: 0.5,
anchorY: 0.5
});
damageText.position.set(x - 80, y - 80);
game.addChild(damageText);
LK.setTimeout(function () {
return damageText.destroy();
}, 600);
}
// Helper function to display miss indicator
function displayMissIndicator(x, y) {
var missIndicator = LK.getAsset('miss', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
});
game.addChild(missIndicator);
LK.setTimeout(function () {
return missIndicator.destroy();
}, 1000);
}
// Define triggerPlayerShoot function globally to ensure it's accessible throughout the script
function triggerPlayerShoot() {
LK.getSound('Shoot_Player').play();
var projectile = new Projectile(playerTank, enemyTank);
projectile.x = playerTank.x;
projectile.y = playerTank.y - 150; // Positioning logic for shooting upwards
game.addChild(projectile);
bullets.push(projectile);
gameState.isAnimating = true; // Indicate an action is taking place, requiring animation.
}
// Define triggerEnemyShoot function globally to ensure it's accessible throughout the script
// Define triggerEnemyShoot function globally to ensure it's accessible throughout the script
function triggerEnemyShoot() {
LK.getSound('Shoot_Enemy').play();
var enemyProjectile = new EnemyBullet(gameState.enemyTank, gameState.playerTank);
enemyProjectile.x = gameState.enemyTank.x;
enemyProjectile.y = gameState.enemyTank.y + 100; // Adjusted positioning for enemy shooting logic
game.addChild(enemyProjectile);
bullets.push(enemyProjectile);
gameState.isAnimating = true; // Ensure this is set to true to prevent immediate subsequent actions
}
// Initialize gameState with unique identifiers to prevent global scope conflicts
var allUpgrades = ['HP', 'Accuracy', 'MinDmg', 'MaxDmg'];
// Define shootingInterval in the global scope to manage shooting intervals
var shootingInterval = null;
// Define bullets array in the global scope for easy access and manipulation
var bullets = [];
// Initialize player and enemy tanks within the gameState to ensure a single source of truth
gameState.playerTank = new Tank(false); // Player's tank
gameState.enemyTank = new Tank(true); // Enemy's tank
// Initialize player tank
var playerTank = new Tank(false); // Player's tank
playerTank.x = 1024; // Center horizontally
playerTank.y = 2732 - 300; // Moved 100 pixels higher
gameState.playerTank = playerTank; // Assign playerTank to gameState
game.addChild(gameState.playerTank);
gameState.tanks.push(gameState.playerTank);
game.addChild(gameState.playerTank);
gameState.tanks.push(gameState.playerTank);
// Initialize enemy tank
var enemyTank = new Tank(true); // Enemy's tank
enemyTank.x = 1024; // Center horizontally
enemyTank.y = 300; // Moved 100 pixels lower
gameState.enemyTank = enemyTank; // Assign enemyTank to gameState
game.addChild(gameState.enemyTank);
gameState.tanks.push(gameState.enemyTank);
game.addChild(gameState.enemyTank);
gameState.tanks.push(gameState.enemyTank);
// Instantiate TankStatsHUD for the player tank
var playerTankHUD = new TankStatsHUD(-600, -515, gameState.playerTank); // Center above the player tank
LK.gui.bottom.addChild(playerTankHUD);
// Instantiate TankStatsHUD for the enemy tank and ensure it's visible from the start
var enemyTankHUD = new TankStatsHUD(-600, +50, gameState.enemyTank); // Position at the top of the screen
enemyTankHUD.updateHUD(); // Update HUD to make it visible from the start
LK.gui.top.addChild(enemyTankHUD);
// Handle touch events to rotate and move the tank
// Removed tank rotation on screen tap
// Define a function to manage the shooting interval
function manageShootingInterval(action) {
if (action === 'start') {
// Clear existing interval if any
if (shootingInterval) {
manageShootingInterval('stop'); // Use the dedicated function to stop shooting
}
// Start a new shooting interval
shootingInterval = LK.setInterval(function () {
if (gameState.isAnimating || gameState.playerTank.HP <= 0 || gameState.enemyTank.HP <= 0) {
return; // Prevent firing if any condition is met.
}
if (gameState.currentRound === 1 || gameState.playerTurn) {
triggerPlayerShoot();
} else {
triggerEnemyShoot();
}
}, 1000);
} else if (action === 'stop') {
// Clear the shooting interval
if (shootingInterval) {
LK.clearInterval(shootingInterval);
}
}
}
// Initially start the shooting interval
manageShootingInterval('start');
// Move bullets
LK.on('tick', function () {
// Implement a pre-check at the beginning of this function to halt actions if a tank's HP is 0.
if (gameState.playerTank.HP <= 0 || gameState.enemyTank.HP <= 0) {
// Consider implementing logic here to pause the game and trigger any end-of-round or game over logic.
gameState.isAnimating = false; // Halt animations.
return; // Exit the tick function early.
}
playerTankHUD.updateHUD();
var _loop = function _loop() {
if (bullets[i]) {
bullets[i]._move_migrated();
}
// Check for collision with tanks
if (bullets[i].intersects(playerTank) && bullets[i] instanceof EnemyBullet) {
// Correctly identify shooter as enemyTank and target as playerTank for damage calculation
if (calculateDamage(enemyTank, playerTank)) {
// Ensure enemyTank is the shooter and playerTank is the target
playerTankHUD.updateHUD(); // Update player tank HUD stats
// Check if either tank's HP reaches 0 to pause game and show upgrades
if (playerTank.HP === 0) {
gameState.isPaused = true; // Stop all actions immediately
LK.clearInterval(shootingInterval); // Stop shooting immediately
game.off('down'); // Disable movement immediately
LK.showGameOver(); // End game if player tank HP drops to 0
} else if (enemyTank.HP === 0) {
// Delay pausing the game until after the bullet is destroyed
bullets[i].destroy(); // Remove bullet from game
bullets.splice(i, 1); // Remove bullet from bullets array
gameState.isPaused = true; // Stop all actions immediately
LK.clearInterval(shootingInterval); // Stop shooting immediately
game.off('down'); // Disable movement immediately
LK.setTimeout(showUpgradeOptions, 100); // Delay showing upgrade options to ensure bullet is removed
}
}
bullets[i].destroy(); // Remove bullet from game
bullets.splice(i, 1); // Remove bullet from bullets array
gameState.playerTurn = true; // Switch turn to player
gameState.isAnimating = false; // End animation state
return {
v: void 0
}; // Exit the loop
} else if (bullets[i].intersects(enemyTank) && bullets[i] instanceof Projectile) {
// Invoke calculateDamage for player bullet hitting enemy tank
if (calculateDamage(gameState.playerTank, enemyTank)) {
enemyTankHUD.updateHUD(); // Refresh enemy tank HUD stats
if (enemyTank.HP === 0) {
LK.getSound('Upgrade_Screen').play(); // Play Upgrade_Screen sound when enemy tank reaches 0 HP
// Set game state to paused
gameState.isPaused = true;
// Clear shooting interval to pause shooting
LK.clearInterval(shootingInterval);
// Disable movement by removing event listeners
game.off('down');
// Display upgrade options for the player to select
// Initialize upgrade buttons for player selection
// Dynamically update the list of available upgrades based on current tank stats
// After applying the upgrade, update the player and enemy tank HUD to reflect changes
playerTankHUD.updateHUD();
enemyTankHUD.updateHUD();
// Filter upgrades based on new stats
gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) {
if (upgrade === 'Accuracy' && gameState.playerTank.Accuracy >= 1.0) {
return false; // Exclude Accuracy if it's already at or above 100%
}
if (upgrade === 'MinDmg' && gameState.playerTank.minDmg >= gameState.playerTank.maxDmg) {
return false; // Exclude MinDmg if it's equal to or greater than MaxDmg
}
return true; // Include all other upgrades
});
// Iterate over the filtered list of upgrades to display upgrade buttons
// Define individual positions for each upgrade button
var upgradePositions = {
'HP': {
x: 80,
y: 2040
},
'Accuracy': {
x: 80,
y: 2225
},
'MinDmg': {
x: 80,
y: 2410
},
'MaxDmg': {
x: 80,
y: 2595
}
};
gameState.upgradesAvailable.forEach(function (upgrade) {
var pos = upgradePositions[upgrade];
var upgradeBtn = LK.getAsset('Upgrade_Btn', {
x: pos.x,
y: pos.y,
anchorX: 0.5,
anchorY: 0.5,
id: 'Upgrade_' + upgrade
});
upgradeBtn.on('down', function () {
LK.getSound('Upgrade_Btn').play(); // Play Upgrade_Btn sound when any upgrade button is pressed
if (upgrade === 'HP') {
LK.getSound('Upg_HP').play(); // Play Upg_HP sound when HP upgrade button is pressed
} else if (upgrade === 'Accuracy') {
LK.getSound('Upg_Acc').play(); // Play Upg_Acc sound when Accuracy upgrade button is pressed
} else if (upgrade === 'MinDmg') {
LK.getSound('Upg_Dmg_Min').play(); // Play Upg_Dmg_Min sound when MinDmg upgrade button is pressed
} else if (upgrade === 'MaxDmg') {
LK.getSound('Upg_Dmg_Max').play(); // Play Upg_Dmg_Max sound when MaxDmg upgrade button is pressed
}
gameState.playerSelectedUpgrade = upgrade;
applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank);
var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) {
return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0);
});
var randomUpgradeIndex = Math.floor(Math.random() * filteredUpgrades.length);
gameState.enemySelectedUpgrade = filteredUpgrades[randomUpgradeIndex];
applyStatUpgrade(gameState.enemySelectedUpgrade, gameState.enemyTank);
// Remove all upgrade buttons after selection
game.children = game.children.filter(function (child) {
return !child.id || !child.id.startsWith('Upgrade_');
});
manageShootingInterval('start');
gameState.isPaused = false;
gameState.playerTurn = true;
gameState.isAnimating = false;
gameState.currentRound += 1; // Increment the round number
roundText.setText('Round: ' + gameState.currentRound.toString()); // Update the round text
resetGameStateForNewRound();
});
game.addChild(upgradeBtn);
});
// Ensure round management is correctly handled at the end of each round
if (!gameState.isAnimating && gameState.playerTank.HP > 0 && gameState.enemyTank.HP > 0) {
manageGameRound(); // Correctly increment and manage round transitions only when conditions are met
}
return {
v: void 0
}; // Exit the loop to avoid executing further code in this tick
}
}
bullets[i].destroy();
bullets.splice(i, 1);
gameState.playerTurn = false; // Switch to enemy's turn after player bullet hits
triggerEnemyShoot(); // Trigger enemy to shoot immediately after player's bullet hits
return {
v: void 0
};
}
// Remove bullets that go off-screen
if (bullets[i].y < 0) {
bullets[i].destroy();
bullets.splice(i, 1);
// gameState.isAnimating = false; // Moved to a more appropriate location after enemy's turn
gameState.playerTurn = !gameState.playerTurn;
// Reset gameState.isAnimating to false after ensuring all animations and hit calculations are complete
if (!gameState.playerTurn) {
LK.setTimeout(function () {
gameState.isAnimating = false;
}, 1000); // Assuming 1 second is enough for the enemy's bullet to reach the player or go off-screen
}
}
},
_ret;
for (var i = bullets.length - 1; i >= 0; i--) {
_ret = _loop();
if (_ret) {
return _ret.v;
}
}
});
function showUpgradeOptions() {
LK.getSound('Upgrade_Screen').play();
// Display upgrade options for the player to select
gameState.upgradesAvailable.forEach(function (upgrade, index) {
// Removed incorrect positioning logic for upgrade buttons to ensure they appear correctly relative to their corresponding stats
upgradeBtn.on('down', function () {
gameState.playerSelectedUpgrade = upgrade;
// Define applyPlayerUpgrade function to apply the selected upgrade to the player's tank
function applyPlayerUpgrade() {
applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank);
// Directly call handleUpgradesAndButtons to update upgrade button visibility based on stat changes
handleUpgradesAndButtons();
// Listen for stat change events to dynamically update available upgrades and refresh upgrade buttons
game.on('statChange', function (tank) {
gameState.upgradesAvailable = allUpgrades.filter(function (upgrade) {
if (upgrade === 'Accuracy' && tank.Accuracy >= 1.0) {
return false; // Exclude Accuracy if it's already at or above 100%
}
if (upgrade === 'MinDmg' && tank.minDmg >= tank.maxDmg) {
return false; // Exclude MinDmg if it's equal to or greater than MaxDmg
}
if (upgrade === 'MaxDmg' && tank.maxDmg <= tank.minDmg) {
return false; // Exclude MaxDmg if it's not greater than MinDmg
}
return true; // Include all other upgrades
});
handleUpgradesAndButtons(); // Refresh upgrade buttons based on updated available upgrades
});
}
// Dynamically create upgrade buttons based on updated available upgrades
gameState.upgradesAvailable.forEach(function (upgrade, index) {
var upgradeBtn = LK.getAsset('Upgrade_Btn', {
// Correct positioning logic will be applied elsewhere
id: 'Upgrade_' + upgrade // Assign a unique ID based on the upgrade type
});
upgradeBtn.on('down', function () {
gameState.playerSelectedUpgrade = upgrade;
applyStatUpgrade(gameState.playerSelectedUpgrade, gameState.playerTank);
// Filter out Accuracy upgrade if enemy's Accuracy is already at 100%, then randomly select and apply an upgrade
var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) {
return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0);
});
var randomUpgradeIndex = Math.floor(Math.random() * filteredUpgrades.length);
gameState.enemySelectedUpgrade = filteredUpgrades[randomUpgradeIndex];
applyStatUpgrade(gameState.enemySelectedUpgrade, gameState.enemyTank);
// Hide all upgrade buttons and texts
game.children.forEach(function (child) {
if (child.id && child.id.startsWith('Upgrade_')) {
child.destroy();
}
});
// Restart shooting interval after upgrade selection using the dedicated function
manageShootingInterval('start');
// Resume game after upgrade selection
gameState.isPaused = false;
// Ensure Game State is Correctly Managed
gameState.playerTurn = true; // It's player's turn after selecting an upgrade
gameState.isAnimating = false; // No animations are running at the start of a new round
resetGameStateForNewRound();
});
game.addChild(upgradeBtn);
var upgradeText = new Text2(upgrade, {
size: 40,
fill: "#000000",
x: upgradeBtn.x,
y: upgradeBtn.y,
anchorX: 0.5,
anchorY: 0.5,
id: 'Upgrade_Text_' + upgrade // Assign a unique ID for the text based on the upgrade type
});
game.addChild(upgradeText);
});
// Resume game after upgrade selection
gameState.isPaused = false; // Allow game actions to continue
// Clear existing shooting interval before setting a new one
if (shootingInterval) {
LK.clearInterval(shootingInterval);
}
// Set up a new shooting interval
shootingInterval = LK.setInterval(function () {
if (!gameState.isPaused) {
if (gameState.playerTurn) {
triggerPlayerShoot();
} else {
triggerEnemyShoot();
}
}
}, 1000); // Adjust timing as necessary
// Re-attach event listeners for player movement and actions
game.on('down', function (x, y, obj) {
// Movement and action logic here, ensuring it only executes when the game is not paused
});
resetGameStateForNewRound(); // Reset the game state for a new round
gameState.playerTurn = true; // Player starts shooting after selecting an upgrade
});
game.addChild(upgradeBtn);
var upgradeText = new Text2(upgrade, {
size: 40,
fill: "#000000",
x: upgradeBtn.x,
y: upgradeBtn.y,
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(upgradeText);
});
function applyRandomUpgradeToEnemy() {
var filteredUpgrades = gameState.upgradesAvailable.filter(function (upgrade) {
return !(upgrade === 'Accuracy' && gameState.enemyTank.Accuracy >= 1.0);
});
var randomUpgrade = filteredUpgrades[Math.floor(Math.random() * filteredUpgrades.length)];
applyStatUpgrade(randomUpgrade, gameState.enemyTank);
}
// Define roundText for displaying current round
var roundText = new Text2('Round: ' + gameState.currentRound.toString(), {
size: 60,
fill: "#ffffff",
stroke: "#000000",
strokeThickness: 10,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
foregroundContainer.addChild(roundText);
// Ensure round management is handled in a single function to prevent multiple increments
function manageGameRound() {
if (!gameState.roundIncremented) {
gameState.roundIncremented = true; // Ensure round is only incremented once per logical game round
}
roundText.setText('Round: ' + gameState.currentRound.toString()); // Update the round text to display the new round number
LK.effects.flashScreen(0x00FF00, 500); // Flash the screen green to indicate round advancement
}
// Call manageGameRound() where necessary instead of directly manipulating gameState.currentRound
}
; // Display upgrade options for the player to select
isometric stone wall platform. top-down bird-eye view perspective. 8-bit pixelated. grey soft-color palette.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a fox with its skull visible on its right side of its head and grey fur with a pale orange on its eyes. Single Game Texture. In-Game asset. 2d. Blank background. medium contrast. No shadows. cartoony. birdside view. full body. not facing the camera
make a single black bullet with yellow lines.. Single Game Texture. In-Game asset. 2d. Blank background. medium contrast. No shadows. cartoony. birdside view. full body. not facing the camera
red upgrade button with a "+" sign on it.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.