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 = 2;
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++;
// 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 = 10; // 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 = -15;
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 = 180; // 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 = 3;
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,
tint: 0xff9900
});
} else if (newType === 'shield') {
powerUpGraphics = self.attachAsset('powerUpShield', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x33ccff
});
} else if (newType === 'bomb') {
powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff3300
});
} 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 = 30; // Position below health bar
// Attach directly to player
player.addChild(healthBarFill);
player.addChild(healthText);
// Position relative to player - higher placement
healthBarFill.y = -80;
// 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
@@ -1120,9 +1120,9 @@
_iterator.f();
}
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
- explosion.update();
+ //explosion.update();
if (!explosion.isActive) {
game.removeChild(explosion);
}
}
@@ -1151,12 +1151,12 @@
if (game.backgroundClone.y - game.backgroundClone.height / 2 > 2732) {
game.backgroundClone.y = background.y - background.height;
}
// Update player
- player.update();
+ //player.update();
// Update shield if active
if (player.hasShield && player.shield) {
- player.shield.update();
+ //player.shield.update();
if (player.shield && !player.shield.isActive) {
player.hasShield = false;
game.removeChild(player.shield);
player.shield = null;
@@ -1178,9 +1178,9 @@
}
// Update lasers and check for collisions
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
- laser.update();
+ //laser.update();
if (!laser.isActive) {
game.removeChild(laser);
lasers.splice(i, 1);
continue;
@@ -1203,9 +1203,9 @@
}
// Update enemy lasers and check for collisions with player
for (var el = enemyLasers.length - 1; el >= 0; el--) {
var enemyLaser = enemyLasers[el];
- enemyLaser.update();
+ //enemyLaser.update();
if (!enemyLaser.isActive) {
game.removeChild(enemyLaser);
enemyLasers.splice(el, 1);
continue;
@@ -1237,9 +1237,9 @@
// Update enemies
var activeEnemies = 0;
for (var k = enemies.length - 1; k >= 0; k--) {
var enemy = enemies[k];
- enemy.update();
+ //enemy.update();
if (!enemy.isActive) {
game.removeChild(enemy);
enemies.splice(k, 1);
continue;
@@ -1277,9 +1277,9 @@
}
// Update power-ups
for (var l = powerUps.length - 1; l >= 0; l--) {
var powerUp = powerUps[l];
- powerUp.update();
+ //powerUp.update();
if (!powerUp.isActive) {
game.removeChild(powerUp);
powerUps.splice(l, 1);
continue;
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