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: 1185
Code edit (1 edits merged)
Please save this source code
User prompt
use hit sound when get hit
User prompt
when player get's hit, use playerHit asset
User prompt
ajoute un text nombre qui commence par 10 et qui diminue a chaque fois qu'un enemy passe le bas de l'écran, si le nombre passe à 0 c'est game over
User prompt
use heart asset for the heart that boss drops
User prompt
make bg scroll faster
User prompt
for level 11-20, play gameMusic2
User prompt
higher
User prompt
place the health bar a little higher
User prompt
place the health text and bar on player not in
User prompt
remove the gray rectangle behind the health color
User prompt
Move player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on topMove player creation after background so player appears on top
User prompt
fait que le jeu sois plus satisfaisant et Move player creation after background so player appears on top
User prompt
fait que player soit au dessus de background sinon on ne le voit pas
User prompt
✅ Modify Enemy collision logic to remove 10 HP when touching the player per 3 sec
User prompt
if touching an enemy, the enemy remove 10 hp
User prompt
les clones des bg doivent etre collés
User prompt
ajoute un clone du background qui ne bouge pas derriere les background qui bougent
User prompt
fait que le background defile vers le bas a l'infini et se recrée au dessus ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
use background asset for the background
User prompt
remove bosss music
User prompt
fait qu'il n'y ait pas 15 waves mais 10 aves seulement. Crée un nouvel asset enemy2 pour les niveaux 11 à 20 et leurs propre boss
User prompt
make the game funnier
User prompt
play game music
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var ComicalExplosion = Container.expand(function () {
var self = Container.call(this);
// Add a "BOOM!" text
var boomText = new Text2("BOOM!", {
size: 120,
fill: 0xFF0000
});
boomText.anchor.set(0.5, 0.5);
self.addChild(boomText);
self.isActive = true;
self.duration = 60; // 1 second
self.timer = 0;
self.update = function () {
if (self.isActive) {
self.timer++;
// Scale up and fade out
var progress = self.timer / self.duration;
var scale = 1 + progress * 2;
self.scale.set(scale, scale);
self.alpha = 1 - progress;
// Random rotation
self.rotation = Math.sin(self.timer * 0.2) * 0.3;
// Remove when done
if (self.timer >= self.duration) {
self.isActive = false;
}
}
};
return self;
});
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 > 15) {
shootChance = 0.015 + (wave - 15) * 0.001; // Increases with each wave after 15
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 > 15) {
laser.speed = 10 + Math.min(5, Math.floor((wave - 15) / 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;
}
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Flash the enemy red when hit
LK.effects.flashObject(self, 0xff0000, 300);
// Add a silly face when enemy is hit but not dead
if (self.health > 0) {
var sillyFace = new SillyFace();
sillyFace.x = self.x;
sillyFace.y = self.y - 50;
sillyFace.setExpression("dizzy");
game.addChild(sillyFace);
}
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);
// Add comical explosion
var comicalExplosion = new ComicalExplosion();
comicalExplosion.x = self.x;
comicalExplosion.y = self.y;
game.addChild(comicalExplosion);
// Shoot confetti
confetti.burst({
x: self.x,
y: self.y,
count: 30,
speed: 8,
spread: 360,
decay: 0.94,
gravity: 0.2
});
// 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 15)
var difficultyMult = wave > 15 ? 1.5 : 1;
// First remove any existing graphics
self.removeChildren();
// Add the appropriate graphic based on the wave
var assetType = wave > 15 ? '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 > 15) {
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;
// Add a silly crown to the boss
var crown = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 1.0,
tint: 0xFFD700,
scaleX: 0.8,
scaleY: 0.4
});
crown.y = -bossGraphics.height / 2 - 20;
// Add crown spikes
for (var i = 0; i < 3; i++) {
var spike = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 1.0,
tint: 0xFFD700,
scaleX: 0.2,
scaleY: 0.4
});
spike.x = (i - 1) * 40;
spike.y = crown.y - 20;
self.addChild(spike);
}
self.addChild(crown);
// Animate the crown
tween(crown, {
y: crown.y - 10
}, {
duration: 1000,
yoyo: true,
repeat: -1
});
// Flash with a fancy color
tween(bossGraphics, {
tint: 0xff0000
}, {
duration: 1000,
yoyo: true,
repeat: 3
});
// Add "BOSS FIGHT!" text
var bossText = new Text2("BOSS FIGHT!", {
size: 150,
fill: 0xFF0000
});
bossText.anchor.set(0.5, 0.5);
bossText.x = 2048 / 2;
bossText.y = 2732 / 3;
LK.gui.center.addChild(bossText);
// Animate the text
tween(bossText, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
LK.gui.center.removeChild(bossText);
}
});
// Shoot confetti for boss entrance
confetti.burst({
x: self.x,
y: self.y - 100,
count: 100,
speed: 10,
spread: 80,
decay: 0.94,
gravity: 0.3
});
};
// 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 position if it exists
if (healthBar) {
healthBar.x = self.x;
healthBar.y = self.y + 100;
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 - 40;
lasers.push(centerLaser);
game.addChild(centerLaser);
var leftLaser = new Laser();
leftLaser.x = self.x - 30;
leftLaser.y = self.y - 30;
leftLaser.rotation = -0.3;
lasers.push(leftLaser);
game.addChild(leftLaser);
var rightLaser = new Laser();
rightLaser.x = self.x + 30;
rightLaser.y = self.y - 30;
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 () {
// Show "KA-BOOM!" text
var kaboom = new Text2("KA-BOOM!", {
size: 200,
fill: 0xFF0000
});
kaboom.anchor.set(0.5, 0.5);
kaboom.x = 2048 / 2;
kaboom.y = 2732 / 2;
game.addChild(kaboom);
// Animate the text
tween(kaboom, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(kaboom);
}
});
// Massive confetti explosion
confetti.burst({
x: 2048 / 2,
y: 2732 / 2,
count: 200,
speed: 15,
spread: 360,
decay: 0.92,
gravity: 0.3
});
// 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;
// Flash the player red when hit
LK.effects.flashObject(self, 0xff0000, 300);
// Add a silly face above player when hit
var sillyFace = new SillyFace();
sillyFace.x = self.x;
sillyFace.y = self.y - 120;
// Choose expression based on health
var healthPercent = self.health / self.maxHealth;
if (healthPercent < 0.33) {
sillyFace.setExpression("dizzy");
} else if (healthPercent < 0.66) {
sillyFace.setExpression("surprised");
} else {
sillyFace.setExpression("happy");
}
game.addChild(sillyFace);
// 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;
// Change appearance based on type
if (newType === 'spreadshot') {
powerUpGraphics.tint = 0xff9900;
// Add a rotating star effect
var star = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xffff00,
scaleX: 0.5,
scaleY: 0.5
});
// Animate star
tween(star, {
rotation: Math.PI * 2
}, {
duration: 1500,
repeat: -1
});
self.addChild(star);
} else if (newType === 'shield') {
powerUpGraphics.tint = 0x33ccff;
// Add shield symbol
var shieldSymbol = LK.getAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x66ffff,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.7
});
// Pulse animation
tween(shieldSymbol, {
alpha: 0.3
}, {
duration: 800,
repeat: -1,
yoyo: true
});
self.addChild(shieldSymbol);
} else if (newType === 'bomb') {
powerUpGraphics.tint = 0xff3300;
// Add a tiny "BOOM" text
var boomTxt = new Text2("BOOM", {
size: 25,
fill: 0xFF5500
});
boomTxt.anchor.set(0.5, 0.5);
// Bounce animation
tween(boomTxt, {
y: -20
}, {
duration: 700,
repeat: -1,
yoyo: true
});
self.addChild(boomTxt);
} else if (newType === 'heart') {
powerUpGraphics.tint = 0xff0066;
// Add heart symbol
var heartSymbol = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
// Heartbeat animation
tween(heartSymbol, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 500,
repeat: -1,
yoyo: true
});
self.addChild(heartSymbol);
}
};
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 = 3000; // 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;
});
var SillyFace = Container.expand(function () {
var self = Container.call(this);
// Create facial parts
var face = self.attachAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700,
scaleX: 1.5,
scaleY: 1.5
});
face.alpha = 0.8;
// Create eyes
var leftEye = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000,
scaleX: 0.3,
scaleY: 0.3
});
leftEye.x = -30;
leftEye.y = -20;
var rightEye = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000,
scaleX: 0.3,
scaleY: 0.3
});
rightEye.x = 30;
rightEye.y = -20;
// Create mouth
var mouth = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x000000,
scaleX: 0.8,
scaleY: 0.2
});
mouth.y = 30;
self.addChild(leftEye);
self.addChild(rightEye);
self.addChild(mouth);
self.isActive = true;
self.duration = 90; // 1.5 seconds at 60fps
self.timer = 0;
// Available expressions: "surprised", "dizzy", "happy"
self.expression = "surprised";
self.setExpression = function (newExpression) {
self.expression = newExpression;
if (newExpression === "surprised") {
// Big round eyes, O-shaped mouth
leftEye.scale.set(0.4, 0.4);
rightEye.scale.set(0.4, 0.4);
mouth.scale.set(0.5, 0.5);
} else if (newExpression === "dizzy") {
// X-shaped eyes, crooked mouth
leftEye.rotation = Math.PI / 4;
rightEye.rotation = Math.PI / 4;
mouth.rotation = -0.2;
} else if (newExpression === "happy") {
// Regular eyes, wide smile
leftEye.scale.set(0.3, 0.3);
rightEye.scale.set(0.3, 0.3);
mouth.scale.set(0.8, 0.2);
mouth.y = 40;
}
};
self.update = function () {
if (self.isActive) {
self.timer++;
// Bobbing animation
self.y = self.y - Math.sin(self.timer * 0.1) * 2;
// Pulse animation
var scale = 1 + Math.sin(self.timer * 0.1) * 0.1;
self.scale.set(scale, scale);
// Remove when timer is up
if (self.timer >= self.duration) {
self.isActive = false;
}
}
};
// Default expression
self.setExpression("surprised");
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;
// UI elements
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.setText("Score: " + LK.getScore());
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
var waveTxt = new Text2('Wave: 1', {
size: 80,
fill: 0xFFFFFF
});
waveTxt.anchor.set(1, 0);
LK.gui.topLeft.addChild(waveTxt);
// Position it away from the top left corner (reserved for menu icon)
waveTxt.x = 250;
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
player.cooldownTime = 10; // Reduced cooldown between shots (from 30)
game.addChild(player);
// Create health bar
healthBar = new Container();
healthBarBg = LK.getAsset('baseBox', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x444444,
scaleX: 10,
scaleY: 0.5
});
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 //{6p} // Base height scale factor (visual size)
});
healthBarFill.x = -healthBarBg.width / 2; // Position fill bar's left edge at the background's left edge
// 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
healthBar.addChild(healthBarBg);
healthBar.addChild(healthBarFill);
healthBar.addChild(healthText);
// 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
});
}
});
healthBar.x = player.x;
healthBar.y = player.y + 100;
game.addChild(healthBar);
// 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.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 20, 25, and 30
if (wave >= 20 && wave % 5 === 0) {
enemy = new Boss2();
enemy.x = 2048 / 2;
enemy.y = -200;
// If this is the final boss (wave 30), set it to have higher HP
if (wave === 30) {
enemy.setAsFinalBoss();
}
} else {
enemy = new BossCat();
enemy.x = 2048 / 2;
enemy.y = -200;
// If this is the final boss of the first stage (wave 15), set it to have higher HP
if (wave === 15) {
enemy.setAsFinalBoss();
}
}
// Play boss music when boss appears
LK.getSound('boss').play();
// 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 <= 15) {
// Waves 7-15: 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 16-30: 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, silly faces, and comical explosions
var specialEffects = [];
var _iterator = _createForOfIteratorHelper(game.children),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var child = _step.value;
if (child instanceof Explosion || child instanceof SillyFace || child instanceof ComicalExplosion) {
specialEffects.push(child);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
for (var i = specialEffects.length - 1; i >= 0; i--) {
var effect = specialEffects[i];
effect.update();
if (!effect.isActive) {
game.removeChild(effect);
}
}
// Update player
player.update();
// Update shield if active
if (player.shield && player.shield.isActive) {
player.shield.update();
if (!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: " + 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)) {
if (player.hasShield) {
// Shield absorbs collision damage
if (player.shield) {
LK.effects.flashObject(player.shield, 0xffff00, 300);
}
} else {
// Player takes damage from collision
var collisionDamage = 30; // Reduced from 50 to make it less punishing
player.takeDamage(collisionDamage);
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: " + 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
// Win condition - player has survived 30 waves
if (wave > 30) {
LK.showYouWin();
return;
}
}
// Auto fire if player holds down finger (increased frequency)
if (LK.ticks % 10 === 0) {
player.shoot();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -6,8 +6,38 @@
/****
* Classes
****/
+var ComicalExplosion = Container.expand(function () {
+ var self = Container.call(this);
+ // Add a "BOOM!" text
+ var boomText = new Text2("BOOM!", {
+ size: 120,
+ fill: 0xFF0000
+ });
+ boomText.anchor.set(0.5, 0.5);
+ self.addChild(boomText);
+ self.isActive = true;
+ self.duration = 60; // 1 second
+ self.timer = 0;
+ self.update = function () {
+ if (self.isActive) {
+ self.timer++;
+ // Scale up and fade out
+ var progress = self.timer / self.duration;
+ var scale = 1 + progress * 2;
+ self.scale.set(scale, scale);
+ self.alpha = 1 - progress;
+ // Random rotation
+ self.rotation = Math.sin(self.timer * 0.2) * 0.3;
+ // Remove when done
+ if (self.timer >= self.duration) {
+ self.isActive = false;
+ }
+ }
+ };
+ return self;
+});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemyCat', {
anchorX: 0.5,
@@ -66,16 +96,39 @@
self.takeDamage = function (damage) {
self.health -= damage;
// Flash the enemy red when hit
LK.effects.flashObject(self, 0xff0000, 300);
+ // Add a silly face when enemy is hit but not dead
+ if (self.health > 0) {
+ var sillyFace = new SillyFace();
+ sillyFace.x = self.x;
+ sillyFace.y = self.y - 50;
+ sillyFace.setExpression("dizzy");
+ game.addChild(sillyFace);
+ }
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);
+ // Add comical explosion
+ var comicalExplosion = new ComicalExplosion();
+ comicalExplosion.x = self.x;
+ comicalExplosion.y = self.y;
+ game.addChild(comicalExplosion);
+ // Shoot confetti
+ confetti.burst({
+ x: self.x,
+ y: self.y,
+ count: 30,
+ speed: 8,
+ spread: 360,
+ decay: 0.94,
+ gravity: 0.2
+ });
// 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;
@@ -236,13 +289,77 @@
self.setAsFinalBoss = function () {
self.isFinalBoss = true;
self.health = 150; // Final boss has 150 HP (increased from 100)
self.pointValue = 500;
+ // Add a silly crown to the boss
+ var crown = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ tint: 0xFFD700,
+ scaleX: 0.8,
+ scaleY: 0.4
+ });
+ crown.y = -bossGraphics.height / 2 - 20;
+ // Add crown spikes
+ for (var i = 0; i < 3; i++) {
+ var spike = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 1.0,
+ tint: 0xFFD700,
+ scaleX: 0.2,
+ scaleY: 0.4
+ });
+ spike.x = (i - 1) * 40;
+ spike.y = crown.y - 20;
+ self.addChild(spike);
+ }
+ self.addChild(crown);
+ // Animate the crown
+ tween(crown, {
+ y: crown.y - 10
+ }, {
+ duration: 1000,
+ yoyo: true,
+ repeat: -1
+ });
+ // Flash with a fancy color
tween(bossGraphics, {
tint: 0xff0000
}, {
- duration: 1000
+ duration: 1000,
+ yoyo: true,
+ repeat: 3
});
+ // Add "BOSS FIGHT!" text
+ var bossText = new Text2("BOSS FIGHT!", {
+ size: 150,
+ fill: 0xFF0000
+ });
+ bossText.anchor.set(0.5, 0.5);
+ bossText.x = 2048 / 2;
+ bossText.y = 2732 / 3;
+ LK.gui.center.addChild(bossText);
+ // Animate the text
+ tween(bossText, {
+ scaleX: 2,
+ scaleY: 2,
+ alpha: 0
+ }, {
+ duration: 2000,
+ onFinish: function onFinish() {
+ LK.gui.center.removeChild(bossText);
+ }
+ });
+ // Shoot confetti for boss entrance
+ confetti.burst({
+ x: self.x,
+ y: self.y - 100,
+ count: 100,
+ speed: 10,
+ spread: 80,
+ decay: 0.94,
+ gravity: 0.3
+ });
};
// Override takeDamage to show health
var originalTakeDamage = self.takeDamage;
self.takeDamage = function (damage) {
@@ -571,8 +688,38 @@
self.hasSpreadshot = true;
self.spreadDuration = 180; // 3 seconds at 60fps (reduced from 5 seconds)
};
self.activateBomb = function () {
+ // Show "KA-BOOM!" text
+ var kaboom = new Text2("KA-BOOM!", {
+ size: 200,
+ fill: 0xFF0000
+ });
+ kaboom.anchor.set(0.5, 0.5);
+ kaboom.x = 2048 / 2;
+ kaboom.y = 2732 / 2;
+ game.addChild(kaboom);
+ // Animate the text
+ tween(kaboom, {
+ scaleX: 3,
+ scaleY: 3,
+ alpha: 0
+ }, {
+ duration: 1000,
+ onFinish: function onFinish() {
+ game.removeChild(kaboom);
+ }
+ });
+ // Massive confetti explosion
+ confetti.burst({
+ x: 2048 / 2,
+ y: 2732 / 2,
+ count: 200,
+ speed: 15,
+ spread: 360,
+ decay: 0.92,
+ gravity: 0.3
+ });
// Destroy all enemies on screen
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.isActive) {
@@ -588,8 +735,22 @@
var prevHealthPercent = self.health / self.maxHealth;
self.health -= damage;
// Flash the player red when hit
LK.effects.flashObject(self, 0xff0000, 300);
+ // Add a silly face above player when hit
+ var sillyFace = new SillyFace();
+ sillyFace.x = self.x;
+ sillyFace.y = self.y - 120;
+ // Choose expression based on health
+ var healthPercent = self.health / self.maxHealth;
+ if (healthPercent < 0.33) {
+ sillyFace.setExpression("dizzy");
+ } else if (healthPercent < 0.66) {
+ sillyFace.setExpression("surprised");
+ } else {
+ sillyFace.setExpression("happy");
+ }
+ game.addChild(sillyFace);
// Update health bar
if (healthBarFill) {
healthBarFill.scale.x = Math.max(0, self.health / self.maxHealth);
// Get new health percentage
@@ -690,14 +851,80 @@
self.type = newType;
// Change appearance based on type
if (newType === 'spreadshot') {
powerUpGraphics.tint = 0xff9900;
+ // Add a rotating star effect
+ var star = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0xffff00,
+ scaleX: 0.5,
+ scaleY: 0.5
+ });
+ // Animate star
+ tween(star, {
+ rotation: Math.PI * 2
+ }, {
+ duration: 1500,
+ repeat: -1
+ });
+ self.addChild(star);
} else if (newType === 'shield') {
powerUpGraphics.tint = 0x33ccff;
+ // Add shield symbol
+ var shieldSymbol = LK.getAsset('shield', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x66ffff,
+ scaleX: 0.3,
+ scaleY: 0.3,
+ alpha: 0.7
+ });
+ // Pulse animation
+ tween(shieldSymbol, {
+ alpha: 0.3
+ }, {
+ duration: 800,
+ repeat: -1,
+ yoyo: true
+ });
+ self.addChild(shieldSymbol);
} else if (newType === 'bomb') {
powerUpGraphics.tint = 0xff3300;
+ // Add a tiny "BOOM" text
+ var boomTxt = new Text2("BOOM", {
+ size: 25,
+ fill: 0xFF5500
+ });
+ boomTxt.anchor.set(0.5, 0.5);
+ // Bounce animation
+ tween(boomTxt, {
+ y: -20
+ }, {
+ duration: 700,
+ repeat: -1,
+ yoyo: true
+ });
+ self.addChild(boomTxt);
} else if (newType === 'heart') {
powerUpGraphics.tint = 0xff0066;
+ // Add heart symbol
+ var heartSymbol = LK.getAsset('heart', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.5,
+ scaleY: 0.5
+ });
+ // Heartbeat animation
+ tween(heartSymbol, {
+ scaleX: 0.7,
+ scaleY: 0.7
+ }, {
+ duration: 500,
+ repeat: -1,
+ yoyo: true
+ });
+ self.addChild(heartSymbol);
}
};
return self;
});
@@ -732,8 +959,93 @@
}
};
return self;
});
+var SillyFace = Container.expand(function () {
+ var self = Container.call(this);
+ // Create facial parts
+ var face = self.attachAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0xFFD700,
+ scaleX: 1.5,
+ scaleY: 1.5
+ });
+ face.alpha = 0.8;
+ // Create eyes
+ var leftEye = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x000000,
+ scaleX: 0.3,
+ scaleY: 0.3
+ });
+ leftEye.x = -30;
+ leftEye.y = -20;
+ var rightEye = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x000000,
+ scaleX: 0.3,
+ scaleY: 0.3
+ });
+ rightEye.x = 30;
+ rightEye.y = -20;
+ // Create mouth
+ var mouth = LK.getAsset('baseBox', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x000000,
+ scaleX: 0.8,
+ scaleY: 0.2
+ });
+ mouth.y = 30;
+ self.addChild(leftEye);
+ self.addChild(rightEye);
+ self.addChild(mouth);
+ self.isActive = true;
+ self.duration = 90; // 1.5 seconds at 60fps
+ self.timer = 0;
+ // Available expressions: "surprised", "dizzy", "happy"
+ self.expression = "surprised";
+ self.setExpression = function (newExpression) {
+ self.expression = newExpression;
+ if (newExpression === "surprised") {
+ // Big round eyes, O-shaped mouth
+ leftEye.scale.set(0.4, 0.4);
+ rightEye.scale.set(0.4, 0.4);
+ mouth.scale.set(0.5, 0.5);
+ } else if (newExpression === "dizzy") {
+ // X-shaped eyes, crooked mouth
+ leftEye.rotation = Math.PI / 4;
+ rightEye.rotation = Math.PI / 4;
+ mouth.rotation = -0.2;
+ } else if (newExpression === "happy") {
+ // Regular eyes, wide smile
+ leftEye.scale.set(0.3, 0.3);
+ rightEye.scale.set(0.3, 0.3);
+ mouth.scale.set(0.8, 0.2);
+ mouth.y = 40;
+ }
+ };
+ self.update = function () {
+ if (self.isActive) {
+ self.timer++;
+ // Bobbing animation
+ self.y = self.y - Math.sin(self.timer * 0.1) * 2;
+ // Pulse animation
+ var scale = 1 + Math.sin(self.timer * 0.1) * 0.1;
+ self.scale.set(scale, scale);
+ // Remove when timer is up
+ if (self.timer >= self.duration) {
+ self.isActive = false;
+ }
+ }
+ };
+ // Default expression
+ self.setExpression("surprised");
+ return self;
+});
/****
* Initialize Game
****/
@@ -1015,29 +1327,29 @@
game.update = function () {
if (!gameActive) {
return;
}
- // Track and update explosions
- var explosions = [];
+ // Track and update explosions, silly faces, and comical explosions
+ var specialEffects = [];
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);
+ if (child instanceof Explosion || child instanceof SillyFace || child instanceof ComicalExplosion) {
+ specialEffects.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);
+ for (var i = specialEffects.length - 1; i >= 0; i--) {
+ var effect = specialEffects[i];
+ effect.update();
+ if (!effect.isActive) {
+ game.removeChild(effect);
}
}
// Update player
player.update();
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