Code edit (9 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'isActive')' in or related to this line: 'if (!player.shield.isActive) {' Line Number: 1186
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemyCat', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'basic'; self.health = 1; self.speed = 6; self.pointValue = 10; self.isActive = true; self.movePattern = 'straight'; self.movementTime = 0; self.direction = 1; // 1 right, -1 left self.update = function () { if (self.isActive) { self.movementTime += 2; // Move based on pattern if (self.movePattern === 'straight') { self.y += self.speed; } else if (self.movePattern === 'zigzag') { self.y += self.speed; self.x += Math.sin(self.movementTime * 0.05) * 3; } else if (self.movePattern === 'teleport') { // Always move down self.y += self.speed; // And occasionally teleport horizontally if (self.movementTime % 120 === 0) { // Teleport every 2 seconds self.x = 100 + Math.random() * (2048 - 200); LK.effects.flashObject(self, 0xffffff, 300); } } // Advanced enemies occasionally shoot lasers with increasing frequency in higher waves var shootChance = 0.01; // Base chance if (wave > 10) { shootChance = 0.015 + (wave - 10) * 0.001; // Increases with each wave after 10 shootChance = Math.min(shootChance, 0.03); // Cap at 3% } if ((self.type === 'zigzag' || self.type === 'teleport') && Math.random() < shootChance) { var laser = new EnemyLaser(); // Adjust laser speed based on wave if (wave > 10) { laser.speed = 10 + Math.min(5, Math.floor((wave - 10) / 3)); } laser.x = self.x; laser.y = self.y + 30; enemyLasers.push(laser); game.addChild(laser); } // Remove enemy when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; // Decrease lives when enemy passes bottom of screen if (livesCount > 0 && self.type !== 'boss' && self.type !== 'boss2') { livesCount--; livesText.setText('Lives: ' + livesCount); // Flash the lives text red to indicate loss tween(livesText, { tint: 0xff0000 }, { duration: 300, onFinish: function onFinish() { tween(livesText, { tint: 0xffffff }, { duration: 300 }); } }); // Game over if lives reach zero if (livesCount <= 0) { gameActive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } } }; self.takeDamage = function (damage) { self.health -= damage; // Flash the enemy red when hit LK.effects.flashObject(self, 0xff0000, 300); if (self.health <= 0) { // Play explosion sound LK.getSound('explosion').play(); // Create explosion effect var explosion = new Explosion(); explosion.x = self.x; explosion.y = self.y; game.addChild(explosion); // Create particles for more dramatic effect for (var i = 0; i < 6; i++) { var particle = new Explosion(); particle.x = self.x + Math.random() * 60 - 30; particle.y = self.y + Math.random() * 60 - 30; particle.duration = 20 + Math.random() * 10; game.addChild(particle); } // Chance to drop power-up (15%) if (Math.random() < 0.15) { var powerUp = new PowerUp(); powerUp.x = self.x; powerUp.y = self.y; // Randomly choose power-up type var powerType = Math.random(); if (powerType < 0.5) { powerUp.setType('spreadshot'); } else if (powerType < 0.8) { powerUp.setType('shield'); } else { powerUp.setType('bomb'); } powerUps.push(powerUp); game.addChild(powerUp); } self.isActive = false; } }; self.setType = function (newType) { self.type = newType; // Get wave-based difficulty multiplier (increases after wave 10) var difficultyMult = wave > 10 ? 1.5 : 1; // First remove any existing graphics self.removeChildren(); // Add the appropriate graphic based on the wave var assetType = wave > 10 ? 'enemyCat2' : 'enemyCat'; var enemyGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5 }); // For enemyCat2, apply scaling since it's smaller by default if (wave > 10) { enemyGraphics.scale.set(3, 3); } if (newType === 'basic') { enemyGraphics.tint = 0xffcc00; self.health = Math.ceil(2 * difficultyMult); self.speed = Math.min(5, 3 * difficultyMult); self.pointValue = Math.ceil(10 * difficultyMult); self.movePattern = 'straight'; } else if (newType === 'fast') { enemyGraphics.tint = 0xff9900; self.health = Math.ceil(2 * difficultyMult); self.speed = Math.min(7, 5 * difficultyMult); self.pointValue = Math.ceil(15 * difficultyMult); self.movePattern = 'straight'; } else if (newType === 'zigzag') { enemyGraphics.tint = 0x66cc00; self.health = Math.ceil(3 * difficultyMult); self.speed = Math.min(5, 3 * difficultyMult); self.pointValue = Math.ceil(20 * difficultyMult); self.movePattern = 'zigzag'; } else if (newType === 'teleport') { enemyGraphics.tint = 0xcc33ff; self.health = Math.ceil(4 * difficultyMult); self.speed = Math.min(4, 2 * difficultyMult); self.pointValue = Math.ceil(30 * difficultyMult); self.movePattern = 'teleport'; } }; return self; }); var BossCat = Enemy.expand(function () { var self = Enemy.call(this); // Remove the previous graphic and add boss graphic self.removeChildren(); var bossGraphics = self.attachAsset('bossCat', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'boss'; self.health = 80; // First boss has 80 HP (increased from 50) self.speed = 1; self.pointValue = 200; self.movePattern = 'boss'; self.phase = 0; self.shootCooldown = 0; self.isFinalBoss = false; // Track if this is the final boss // Override update method self.update = function () { if (self.isActive) { self.movementTime++; // Boss movement pattern if (self.phase === 0) { // Move down to position self.y += self.speed; if (self.y >= 300) { self.phase = 1; self.movementTime = 0; } } else if (self.phase === 1) { // Move slowly towards player's position if (player && player.x) { // Calculate direction to player var directionX = player.x - self.x; // Move slowly towards player (0.5% of the distance per frame) self.x += directionX * 0.005; } // Add slight vertical movement self.y += Math.sin(self.movementTime * 0.01) * 1; // Phase transition based on health percentage var healthPercent = self.isFinalBoss ? self.health / 100 : self.health / 50; if (healthPercent <= 0.5 && self.phase < 2) { self.phase = 2; self.speed = 1.5; LK.effects.flashObject(self, 0xff0000, 1000); } } else if (self.phase === 2) { // Move towards player faster in aggressive phase if (player && player.x) { var directionX = player.x - self.x; // Move faster towards player (1% of the distance per frame) self.x += directionX * 0.01; } // Add some vertical movement self.y += Math.sin(self.movementTime * 0.02) * 2; } // Boss shooting logic self.shootCooldown--; if (self.shootCooldown <= 0) { // Shoot pattern based on phase if (self.phase === 1) { // Single shot during phase 1, less frequent self.shootLaser(); self.shootCooldown = 180; // 3 seconds (doubled from original) } else if (self.phase === 2) { // Double shot during phase 2, less frequent self.shootLaser(); self.shootLaser(-30, 0.3); self.shootCooldown = 120; // 2 seconds (doubled from original) } } } }; // Boss shooting method self.shootLaser = function (offsetX, rotation) { offsetX = offsetX || 0; rotation = rotation || 0; var laser = new EnemyLaser(); laser.x = self.x + offsetX; laser.y = self.y + 100; if (rotation !== 0) { laser.rotation = rotation; } enemyLasers.push(laser); game.addChild(laser); }; // Set boss as final boss self.setAsFinalBoss = function () { self.isFinalBoss = true; self.health = 150; // Final boss has 150 HP (increased from 100) self.pointValue = 500; tween(bossGraphics, { tint: 0xff0000 }, { duration: 1000 }); }; // Override takeDamage to show health var originalTakeDamage = self.takeDamage; self.takeDamage = function (damage) { originalTakeDamage.call(self, damage); // Update boss health display if (bossHealthText) { bossHealthText.setText("Boss HP: " + self.health); } // Drop heart power-up when boss is defeated if (self.health <= 0) { // 100% chance to drop heart from boss var heart = new PowerUp(); heart.x = self.x; heart.y = self.y; heart.setType('heart'); powerUps.push(heart); game.addChild(heart); } }; return self; }); var Boss2 = BossCat.expand(function () { var self = BossCat.call(this); // Replace boss graphic with new boss self.removeChildren(); var bossGraphics = self.attachAsset('enemyCat2', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3 }); self.type = 'boss2'; self.health = 200; // Second boss has 200 HP by default self.speed = 1.5; self.pointValue = 300; self.movementTime = 0; self.attackPattern = 0; self.attackTimer = 0; // Override update method var originalUpdate = self.update; self.update = function () { if (self.isActive) { self.movementTime++; self.attackTimer++; // Boss2 movement pattern if (self.phase === 0) { // Move down to position self.y += self.speed; if (self.y >= 350) { self.phase = 1; self.movementTime = 0; } } else if (self.phase === 1) { // More complex movement self.x += Math.sin(self.movementTime * 0.02) * 3; self.y += Math.cos(self.movementTime * 0.01) * 2; // Phase transition based on health percentage var healthPercent = self.isFinalBoss ? self.health / 250 : self.health / 200; if (healthPercent <= 0.5 && self.phase < 2) { self.phase = 2; self.speed = 2; self.attackPattern = 1; LK.effects.flashObject(self, 0xff0000, 1000); } } else if (self.phase === 2) { // More aggressive pattern self.x += Math.sin(self.movementTime * 0.03) * 5; self.y += Math.sin(self.movementTime * 0.02) * 3; // Occasionally teleport if (self.movementTime % 180 === 0) { self.x = 400 + Math.random() * (2048 - 800); LK.effects.flashObject(self, 0xffffff, 300); } } // Boss2 shooting logic self.shootCooldown--; if (self.shootCooldown <= 0) { if (self.phase === 1) { // Triple shot pattern self.shootLaser(); self.shootLaser(-50, -0.2); self.shootLaser(50, 0.2); self.shootCooldown = 150; } else if (self.phase === 2) { // More complex attack patterns if (self.attackPattern === 0) { // Spiral pattern for (var i = 0; i < 6; i++) { var angle = self.attackTimer * 0.01 + i * Math.PI / 3; var offsetX = Math.cos(angle) * 80; var offsetY = Math.sin(angle) * 80; self.shootLaser(offsetX, angle * 0.2); } self.shootCooldown = 240; self.attackPattern = 1; } else { // Targeted shots if (player && player.x) { var directionX = player.x - self.x; var angle = Math.atan2(player.y - self.y, directionX); self.shootLaser(0, angle * 0.3); self.shootLaser(-30, angle * 0.25); self.shootLaser(30, angle * 0.35); } self.shootCooldown = 180; self.attackPattern = 0; } } } } }; // Set boss as final boss self.setAsFinalBoss = function () { self.isFinalBoss = true; self.health = 250; // Final boss2 has 250 HP self.pointValue = 800; tween(bossGraphics, { tint: 0xff3300 }, { duration: 1000 }); }; // Override takeDamage to drop heart var originalTakeDamage = self.takeDamage; self.takeDamage = function (damage) { originalTakeDamage.call(self, damage); // Drop heart power-up when boss is defeated if (self.health <= 0) { // 100% chance to drop heart from boss var heart = new PowerUp(); heart.x = self.x; heart.y = self.y; heart.setType('heart'); powerUps.push(heart); game.addChild(heart); } }; return self; }); var EnemyLaser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5, tint: 0xff6600 }); self.speed = 20; // Increased from 8 self.damage = 1; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Remove laser when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; } } }; return self; }); var Explosion = Container.expand(function () { var self = Container.call(this); // Create the explosion frames (will be hidden at first except frame 1) var frame1 = self.attachAsset('explosionFrame1', { anchorX: 0.5, anchorY: 0.5 }); var frame2 = self.attachAsset('explosionFrame2', { anchorX: 0.5, anchorY: 0.5, visible: false }); var frame3 = self.attachAsset('explosionFrame3', { anchorX: 0.5, anchorY: 0.5, visible: false }); var frame4 = self.attachAsset('explosionFrame4', { anchorX: 0.5, anchorY: 0.5, visible: false }); self.isActive = true; self.duration = 40; // Duration increased slightly self.timer = 0; self.currentFrame = 1; self.frames = [frame1, frame2, frame3, frame4]; self.update = function () { if (self.isActive) { self.timer++; // Animation frame timing (10 frames per explosion frame) var frameIndex = Math.floor(self.timer / 10); if (frameIndex >= 0 && frameIndex < 4 && frameIndex !== self.currentFrame - 1) { // Hide all frames self.frames.forEach(function (frame) { frame.visible = false; }); // Show current frame self.currentFrame = frameIndex + 1; self.frames[frameIndex].visible = true; // Apply scale and rotation effects to current frame var progress = self.timer / self.duration; var currentScale = 1 + progress; self.frames[frameIndex].scale.set(currentScale, currentScale); self.frames[frameIndex].rotation = progress * Math.PI * 0.5; } // Remove when animation complete if (self.timer >= self.duration) { self.isActive = false; } } }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -30; self.damage = 1; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Remove laser when it goes off screen if (self.y < -50) { self.isActive = false; } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.shootCooldown = 0; self.cooldownTime = 30; // Frames between shots (increased from 15) self.hasShield = false; self.hasSpreadshot = false; self.spreadDuration = 0; self.shield = null; self.maxHealth = 100; self.health = self.maxHealth; // Starting with full health // Define health state thresholds self.healthStateThresholds = { green: 0.66, // Above 66% is green (full health) yellow: 0.33 // Above 33% is yellow, below is red }; self.update = function () { // Decrease cooldown if (self.shootCooldown > 0) { self.shootCooldown--; } // Decrease spreadshot duration if (self.hasSpreadshot) { self.spreadDuration--; if (self.spreadDuration <= 0) { self.hasSpreadshot = false; } } // Update health bar directly on player healthBarFill.scale.x = self.health / self.maxHealth; // Update health text if (healthText) { healthText.setText(Math.ceil(self.health) + "/" + self.maxHealth); } }; self.shoot = function () { if (self.shootCooldown <= 0) { if (self.hasSpreadshot) { // Create spread shot (3 lasers) var centerLaser = new Laser(); centerLaser.x = self.x; centerLaser.y = self.y - 60; lasers.push(centerLaser); game.addChild(centerLaser); var leftLaser = new Laser(); leftLaser.x = self.x - 40; leftLaser.y = self.y - 60; leftLaser.rotation = -0.3; lasers.push(leftLaser); game.addChild(leftLaser); var rightLaser = new Laser(); rightLaser.x = self.x + 40; rightLaser.y = self.y - 60; rightLaser.rotation = 0.3; lasers.push(rightLaser); game.addChild(rightLaser); } else { // Create single laser var laser = new Laser(); laser.x = self.x; laser.y = self.y - 40; lasers.push(laser); game.addChild(laser); } LK.getSound('shoot').play(); self.shootCooldown = self.cooldownTime; } }; self.activateShield = function () { // Remove existing shield if there is one if (self.shield && self.shield.isActive) { self.shield.isActive = false; game.removeChild(self.shield); } // Create new shield self.hasShield = true; self.shield = new Shield(); self.shield.x = self.x; self.shield.y = self.y; game.addChild(self.shield); return self.shield; }; self.activateSpreadshot = function () { self.hasSpreadshot = true; self.spreadDuration = 600; // 3 seconds at 60fps (reduced from 5 seconds) }; self.activateBomb = function () { // Destroy all enemies on screen for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (enemy.isActive) { enemy.takeDamage(999); // Instant kill LK.setScore(LK.getScore() + enemy.pointValue); } } // Visual effect for bomb LK.effects.flashScreen(0xff0000, 500); }; self.takeDamage = function (damage) { // Store previous health percentage to detect state transitions var prevHealthPercent = self.health / self.maxHealth; self.health -= damage; // Play hit sound LK.getSound('hitSound').play(); // Change player graphic to hit animation self.removeChildren(); self.attachAsset('playerHit', { anchorX: 0.5, anchorY: 0.5 }); // Add health bar and text back self.addChild(healthBarFill); self.addChild(healthText); // Return to normal graphic after a short delay LK.setTimeout(function () { self.removeChildren(); playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Add health bar and text back again self.addChild(healthBarFill); self.addChild(healthText); }, 300); // Flash the player red when hit LK.effects.flashObject(self, 0xff0000, 300); // Update health bar if (healthBarFill) { healthBarFill.scale.x = Math.max(0, self.health / self.maxHealth); // Get new health percentage var healthPercent = self.health / self.maxHealth; // Change health bar color based on percentage if (healthPercent >= 0.66) { healthBarFill.tint = 0x00ff00; // Green for high health } else if (healthPercent >= 0.33) { healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health } else { healthBarFill.tint = 0xff0000; // Red for low health } // Check for transition between health states if (prevHealthPercent > 0.66 && healthPercent <= 0.66 || prevHealthPercent > 0.33 && healthPercent <= 0.33) { // Visual effect for health state degradation tween(healthBarFill, { alpha: 0.2 }, { duration: 300, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 300 }); } }); } } // Check if player is dead if (self.health <= 0) { gameActive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } return self.health <= 0; // Return true if player died }; self.heal = function (amount) { // Store previous health percentage to detect state transitions var prevHealthPercent = self.health / self.maxHealth; self.health = Math.min(self.maxHealth, self.health + amount); // Update health bar if (healthBarFill) { healthBarFill.scale.x = self.health / self.maxHealth; // Get new health percentage var healthPercent = self.health / self.maxHealth; // Change health bar color based on percentage if (healthPercent >= 0.66) { healthBarFill.tint = 0x00ff00; // Green for high health } else if (healthPercent >= 0.33) { healthBarFill.tint = 0xffcc00; // Yellow/orange for medium health } else { healthBarFill.tint = 0xff0000; // Red for low health } // Check for transition between health states if (prevHealthPercent <= 0.33 && healthPercent > 0.33 || prevHealthPercent <= 0.66 && healthPercent > 0.66) { // Visual effect for health state improvement tween(healthBarFill, { alpha: 0.2 }, { duration: 300, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 300 }); } }); } } // Visual healing effect LK.effects.flashObject(self, 0x00ff00, 300); }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'spreadshot'; // Default type self.speed = 6; self.isActive = true; self.update = function () { if (self.isActive) { self.y += self.speed; // Rotate the power-up for visual effect powerUpGraphics.rotation += 0.05; // Remove power-up when it goes off screen if (self.y > 2732 + 50) { self.isActive = false; } } }; self.setType = function (newType) { self.type = newType; // Remove previous graphics self.removeChildren(); // Change appearance based on type if (newType === 'spreadshot') { powerUpGraphics = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'shield') { powerUpGraphics = self.attachAsset('powerUpShield', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'bomb') { powerUpGraphics = self.attachAsset('powerUpBomb', { anchorX: 0.5, anchorY: 0.5 }); } else if (newType === 'heart') { powerUpGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); } }; return self; }); var Shield = Container.expand(function () { var self = Container.call(this); var shieldGraphics = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.duration = 6000; // Shield lasts 3 seconds (reduced from 5) self.timeLeft = self.duration; self.isActive = true; self.update = function () { if (self.isActive) { self.timeLeft -= 1000 / 60; // Decrease time left (60 fps) // Fade out as shield expires shieldGraphics.alpha = 0.2 + self.timeLeft / self.duration * 0.5; // Rotate the shield for visual effect shieldGraphics.rotation += 0.01; // Deactivate shield when time runs out if (self.timeLeft <= 0) { self.isActive = false; // Remove shield reference from player if (player) { player.hasShield = false; player.shield = null; } // Remove this shield from the game when it expires game.removeChild(self); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000033 }); /**** * Game Code ****/ // Game state variables function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) { throw o; } } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) { return _arrayLikeToArray(r, a); } var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) { n[e] = r[e]; } return n; } var player; var lasers = []; var enemyLasers = []; var enemies = []; var powerUps = []; var wave = 1; var enemiesInWave = 5; var enemiesSpawned = 0; var spawnCooldown = 0; var gameActive = true; var bossWave = false; var bossHealthText; var healthBar; var healthBarBg; var healthBarFill; var livesCount = 10; var livesText; // UI elements var scoreTxt = new Text2('Score\r\n0', { size: 100, fill: 0xFFFFFF, dropShadow: true, align: 'center' }); scoreTxt.setText("Score\r\n" + LK.getScore()); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var waveTxt = new Text2('Wave\r\n1', { size: 80, fill: 0xFFFFFF, dropShadow: true, align: 'center' }); waveTxt.anchor.set(1.0, 0); LK.gui.topRight.addChild(waveTxt); // Position it away from the top left corner (reserved for menu icon) waveTxt.x = 0; // Lives counter display livesText = new Text2('Lives: ' + livesCount, { size: 80, fill: 0xFFFFFF }); livesText.anchor.set(0.5, 0); LK.gui.bottom.addChild(livesText); // Add background image var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); background.x = 2048 / 2; background.y = 2732 / 2; game.addChild(background); // Create background clone first to ensure it's below the player if (!game.backgroundClone) { // Create a clone of the background game.backgroundClone = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); // Position the clone directly above the original background game.backgroundClone.x = background.x; game.backgroundClone.y = background.y - background.height; game.addChild(game.backgroundClone); } // Create player after all background elements player = new Player(); player.x = 2048 / 2; player.y = 2732 - 200; player.cooldownTime = 10; // Reduced cooldown between shots (from 30) // Add player last so it appears on top of all background elements game.addChild(player); // Create health bar - directly attached to player healthBarFill = LK.getAsset('baseBox', { anchorX: 0, // Anchor at the left edge for scaling from left to right anchorY: 0.5, tint: 0x00ff00, // Set tint to green for full health explicitly in creation scaleX: 10, scaleY: 0.5 // Base height scale factor (visual size) }); // Ensure bar scale correctly represents 100% health at the start healthBarFill.scale.x = player.health / player.maxHealth; // Set scale based on current health percentage // Create health text display var healthText = new Text2('100/100', { size: 40, fill: 0xFFFFFF }); healthText.anchor.set(0.5, 0); healthText.y = 0; // Position below health bar // Attach directly to player player.addChild(healthBarFill); player.addChild(healthText); // Position relative to player - higher placement healthBarFill.y = -70; healthBarFill.x = -50; // Position health text above health bar healthText.y = -120; // Set initial animation for health bar to draw player's attention tween(healthBarFill, { alpha: 0.5 }, { duration: 500, onFinish: function onFinish() { tween(healthBarFill, { alpha: 1 }, { duration: 500 }); } }); // Start background music with fade in effect LK.playMusic('gameMusic', { fade: { start: 0, end: 1, duration: 1000 } }); // Game input handlers game.down = function (x, y, obj) { // Shoot when tapping anywhere player.shoot(); }; game.move = function (x, y, obj) { // Move player horizontally (keep vertical position fixed) if (gameActive) { player.x = x; // Keep player within game bounds if (player.x < 75) { player.x = 75; } if (player.x > 2048 - 75) { player.x = 2048 - 75; } // Update shield position if active if (player.hasShield && player.shield && player.shield.isActive) { player.shield.x = player.x; player.shield.y = player.y; } } }; // Spawn enemies function spawnEnemy() { var enemy; if (bossWave) { // Use Boss2 for waves 15 and 20 if (wave >= 15 && wave % 5 === 0) { enemy = new Boss2(); enemy.x = 2048 / 2; enemy.y = -200; // If this is the final boss (wave 20), set it to have higher HP if (wave === 20) { enemy.setAsFinalBoss(); } } else { enemy = new BossCat(); enemy.x = 2048 / 2; enemy.y = -200; // If this is the final boss of the first stage (wave 10), set it to have higher HP if (wave === 10) { enemy.setAsFinalBoss(); } } // Create boss health display bossHealthText = new Text2("Boss HP: " + enemy.health, { size: 60, fill: 0xFF6600 }); bossHealthText.anchor.set(0.5, 0); bossHealthText.y = 150; LK.gui.top.addChild(bossHealthText); } else { enemy = new Enemy(); enemy.x = 100 + Math.random() * (2048 - 200); enemy.y = -100; // Set random enemy type based on current wave var typeRoll = Math.random(); if (wave <= 2) { // Waves 1-2: Only basic enemies enemy.setType('basic'); } else if (wave <= 4) { // Waves 3-4: Basic and fast enemies if (typeRoll < 0.6) { enemy.setType('basic'); } else { enemy.setType('fast'); } } else if (wave <= 6) { // Waves 5-6: Add zigzag enemies if (typeRoll < 0.4) { enemy.setType('basic'); } else if (typeRoll < 0.7) { enemy.setType('fast'); } else { enemy.setType('zigzag'); } } else if (wave <= 10) { // Waves 7-10: All enemy types if (typeRoll < 0.3) { enemy.setType('basic'); } else if (typeRoll < 0.5) { enemy.setType('fast'); } else if (typeRoll < 0.8) { enemy.setType('zigzag'); } else { enemy.setType('teleport'); } } else { // Waves 11-20: Harder distribution with fewer basic enemies if (typeRoll < 0.15) { enemy.setType('basic'); } else if (typeRoll < 0.4) { enemy.setType('fast'); } else if (typeRoll < 0.7) { enemy.setType('zigzag'); } else { enemy.setType('teleport'); } } } enemies.push(enemy); game.addChild(enemy); enemiesSpawned++; } // Main game update loop game.update = function () { if (!gameActive) { return; } // Track and update explosions var explosions = []; var _iterator = _createForOfIteratorHelper(game.children), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var child = _step.value; if (child instanceof Explosion) { explosions.push(child); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } for (var i = explosions.length - 1; i >= 0; i--) { var explosion = explosions[i]; //explosion.update(); if (!explosion.isActive) { game.removeChild(explosion); } } // Set up background scrolling with two identical backgrounds side by side if (!game.backgroundClone) { // Create a clone of the background game.backgroundClone = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732 }); // Position the clone directly above the original background game.backgroundClone.x = background.x; game.backgroundClone.y = background.y - background.height; game.addChild(game.backgroundClone); } // Scroll both backgrounds background.y += 5; // Increased scroll speed game.backgroundClone.y += 5; // Same increased speed for clone // If original background goes completely off screen, move it above the clone if (background.y - background.height / 2 > 2732) { background.y = game.backgroundClone.y - background.height; } // If clone background goes completely off screen, move it above the original if (game.backgroundClone.y - game.backgroundClone.height / 2 > 2732) { game.backgroundClone.y = background.y - background.height; } // Update player //player.update(); // Update shield if active if (player.hasShield && player.shield) { //player.shield.update(); if (player.shield && !player.shield.isActive) { player.hasShield = false; game.removeChild(player.shield); player.shield = null; } } // Handle enemy spawning if (spawnCooldown <= 0) { if (enemiesSpawned < enemiesInWave) { spawnEnemy(); // Cooldown between spawns if (bossWave) { spawnCooldown = 1; // Boss spawns immediately } else { spawnCooldown = 60; // 1 second between normal enemy spawns } } } else { spawnCooldown--; } // Update lasers and check for collisions for (var i = lasers.length - 1; i >= 0; i--) { var laser = lasers[i]; //laser.update(); if (!laser.isActive) { game.removeChild(laser); lasers.splice(i, 1); continue; } // Check for collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (enemy.isActive && laser.isActive && laser.intersects(enemy)) { enemy.takeDamage(laser.damage); laser.isActive = false; if (!enemy.isActive) { LK.setScore(LK.getScore() + enemy.pointValue); scoreTxt.setText("Score\r\n" + LK.getScore()); game.removeChild(enemy); enemies.splice(j, 1); } break; } } } // Update enemy lasers and check for collisions with player for (var el = enemyLasers.length - 1; el >= 0; el--) { var enemyLaser = enemyLasers[el]; //enemyLaser.update(); if (!enemyLaser.isActive) { game.removeChild(enemyLaser); enemyLasers.splice(el, 1); continue; } // Check for collision with player if (enemyLaser.intersects(player)) { // If player has shield, block the laser if (player.hasShield) { enemyLaser.isActive = false; game.removeChild(enemyLaser); enemyLasers.splice(el, 1); // Flash shield to show impact if (player.shield) { LK.effects.flashObject(player.shield, 0xffff00, 300); } } else { // Player takes damage from laser - only one point of health var laserDamage = 1; player.takeDamage(laserDamage); enemyLaser.isActive = false; game.removeChild(enemyLaser); enemyLasers.splice(el, 1); if (!gameActive) { return; } // Return if player died } } } // Update enemies var activeEnemies = 0; for (var k = enemies.length - 1; k >= 0; k--) { var enemy = enemies[k]; //enemy.update(); if (!enemy.isActive) { game.removeChild(enemy); enemies.splice(k, 1); continue; } activeEnemies++; // Check collision with player if (enemy.intersects(player)) { // Initialize lastDamageTime if not set if (enemy.lastDamageTime === undefined) { enemy.lastDamageTime = 0; } // Check if 3 seconds (180 frames at 60fps) have passed since last damage var currentTime = LK.ticks; var damageInterval = 180; // 3 seconds at 60fps if (player.hasShield) { // Shield absorbs collision damage if (player.shield) { LK.effects.flashObject(player.shield, 0xffff00, 300); } } else { // Player takes damage from collision only every 3 seconds var collisionDamage = 10; // Apply damage only if enough time has passed if (currentTime - enemy.lastDamageTime >= damageInterval) { player.takeDamage(collisionDamage); enemy.lastDamageTime = currentTime; // Visual feedback that damage was applied LK.effects.flashObject(enemy, 0xff0000, 300); } if (!gameActive) { return; } // Return if player died } } } // Update power-ups for (var l = powerUps.length - 1; l >= 0; l--) { var powerUp = powerUps[l]; //powerUp.update(); if (!powerUp.isActive) { game.removeChild(powerUp); powerUps.splice(l, 1); continue; } // Check collision with player if (powerUp.intersects(player)) { // Apply power-up effect if (powerUp.type === 'spreadshot') { player.activateSpreadshot(); } else if (powerUp.type === 'shield') { player.activateShield(); } else if (powerUp.type === 'bomb') { player.activateBomb(); } else if (powerUp.type === 'heart') { player.heal(50); // Restore 50 health points } LK.getSound('powerup').play(); powerUp.isActive = false; game.removeChild(powerUp); powerUps.splice(l, 1); } } // Check if wave is complete if (enemiesSpawned >= enemiesInWave && activeEnemies === 0) { // Wave complete, start next wave wave++; waveTxt.setText("Wave\r\n" + wave); // Every 5th wave is a boss wave if (wave % 5 === 0) { bossWave = true; enemiesInWave = 1; } else { bossWave = false; // Reduced enemies per wave to make the game easier enemiesInWave = 5 + Math.floor(wave * 1.5); // Remove boss health display if it exists if (bossHealthText) { LK.gui.top.removeChild(bossHealthText); bossHealthText = null; } } enemiesSpawned = 0; spawnCooldown = 120; // 2 second delay between waves // Check for music changes between levels 1-10 and 11-20 if (wave == 11) { // Change to gameMusic2 for levels 11-20 LK.playMusic('gameMusic2', { fade: { start: 0, end: 1, duration: 1000 } }); } else if (wave == 1) { // Change back to gameMusic for levels 1-10 LK.playMusic('gameMusic', { fade: { start: 0, end: 1, duration: 1000 } }); } // Win condition - player has survived 20 waves if (wave > 20) { LK.showYouWin(); return; } } // Auto fire if player holds down finger (increased frequency) if (LK.ticks % 10 === 0) { player.shoot(); } };
===================================================================
--- original.js
+++ change.js
@@ -14,17 +14,17 @@
anchorY: 0.5
});
self.type = 'basic';
self.health = 1;
- self.speed = 2;
+ self.speed = 6;
self.pointValue = 10;
self.isActive = true;
self.movePattern = 'straight';
self.movementTime = 0;
self.direction = 1; // 1 right, -1 left
self.update = function () {
if (self.isActive) {
- self.movementTime++;
+ self.movementTime += 2;
// Move based on pattern
if (self.movePattern === 'straight') {
self.y += self.speed;
} else if (self.movePattern === 'zigzag') {
@@ -412,9 +412,9 @@
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff6600
});
- self.speed = 10; // Increased from 8
+ self.speed = 20; // Increased from 8
self.damage = 1;
self.isActive = true;
self.update = function () {
if (self.isActive) {
@@ -486,9 +486,9 @@
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
- self.speed = -15;
+ self.speed = -30;
self.damage = 1;
self.isActive = true;
self.update = function () {
if (self.isActive) {
@@ -588,9 +588,9 @@
return self.shield;
};
self.activateSpreadshot = function () {
self.hasSpreadshot = true;
- self.spreadDuration = 180; // 3 seconds at 60fps (reduced from 5 seconds)
+ self.spreadDuration = 600; // 3 seconds at 60fps (reduced from 5 seconds)
};
self.activateBomb = function () {
// Destroy all enemies on screen
for (var i = enemies.length - 1; i >= 0; i--) {
@@ -714,9 +714,9 @@
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'spreadshot'; // Default type
- self.speed = 3;
+ self.speed = 6;
self.isActive = true;
self.update = function () {
if (self.isActive) {
self.y += self.speed;
@@ -735,22 +735,19 @@
// Change appearance based on type
if (newType === 'spreadshot') {
powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
- anchorY: 0.5,
- tint: 0xff9900
+ anchorY: 0.5
});
} else if (newType === 'shield') {
powerUpGraphics = self.attachAsset('powerUpShield', {
anchorX: 0.5,
- anchorY: 0.5,
- tint: 0x33ccff
+ anchorY: 0.5
});
} else if (newType === 'bomb') {
- powerUpGraphics = self.attachAsset('powerUp', {
+ powerUpGraphics = self.attachAsset('powerUpBomb', {
anchorX: 0.5,
- anchorY: 0.5,
- tint: 0xff3300
+ anchorY: 0.5
});
} else if (newType === 'heart') {
powerUpGraphics = self.attachAsset('heart', {
anchorX: 0.5,
@@ -962,14 +959,15 @@
size: 40,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0);
-healthText.y = 30; // Position below health bar
+healthText.y = 0; // Position below health bar
// Attach directly to player
player.addChild(healthBarFill);
player.addChild(healthText);
// Position relative to player - higher placement
-healthBarFill.y = -80;
+healthBarFill.y = -70;
+healthBarFill.x = -50;
// Position health text above health bar
healthText.y = -120;
// Set initial animation for health bar to draw player's attention
tween(healthBarFill, {
explosion 💥. In-Game asset. 2d. High contrast. No shadows
a cat head. In-Game asset. 2d. High contrast
make this cat expression goes silly but angry
2 cucumbers inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
a shield inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
an explosion inside a glass bubble. In-Game asset. 2d. High contrast. No shadows
a heart inside a glass bubble. In-Game asset. 2d. High contrast. No shadows