User prompt
Add falling Star image to assets
User prompt
Shooting stars I can edit
User prompt
Let me add image assets to the shooting stars myself
User prompt
Let me add my own picture to the shooting stars ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Shooting star stays clear for 2 seconds
User prompt
Shooting star stays clear for 3 seconds
User prompt
Shooting star stays clear for 10 seconds
User prompt
Shooting stars disappeared at the end of the screen
User prompt
Shooting stars disappear after 45 seconds
User prompt
Shooting stars disappear after 20 seconds
User prompt
Shooting stars disappear after 5 seconds
User prompt
The stars disappeared after 5 seconds
User prompt
Let the stars be a little clear
User prompt
3 stars pass
User prompt
Let the color of the shooting star be white
User prompt
Shooting star pass slowly
User prompt
Let a large shooting star pass through the background on each wave
User prompt
Let a shooting star pass behind you in every wave
User prompt
2x the size of the background stars
User prompt
triple the background stars
User prompt
double the background stars
User prompt
Please fix the bug: '[object Object]addChildAt: The index 1 supplied is out of bounds 0' in or related to this line: 'game.addChildAt(star, 1);' Line Number: 269
User prompt
fix background stars
User prompt
Can you fix the background bugs?
User prompt
After wave 5 you start seeing planets in the background
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Alien class
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienSprite = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = alienSprite.width;
self.height = alienSprite.height;
self.speed = 2.5;
self.hp = 1;
self.wave = 1;
self.lastX = self.x;
self.lastY = self.y;
self.lastIntersecting = false;
self.isDead = false;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
// Alien2 class (different look, stats)
var Alien2 = Container.expand(function () {
var self = Container.call(this);
var alienSprite = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0x00eaff
});
self.width = alienSprite.width;
self.height = alienSprite.height;
self.speed = 2.8;
self.hp = 2;
self.wave = 1;
self.lastX = self.x;
self.lastY = self.y;
self.lastIntersecting = false;
self.isDead = false;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
// Alien3 class (different look, stats)
var Alien3 = Container.expand(function () {
var self = Container.call(this);
var alienSprite = self.attachAsset('bonus', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1,
tint: 0xff6f00
});
self.width = alienSprite.width;
self.height = alienSprite.height;
self.speed = 3.2;
self.hp = 3;
self.wave = 1;
self.lastX = self.x;
self.lastY = self.y;
self.lastIntersecting = false;
self.isDead = false;
self.update = function () {
self.lastY = self.y;
self.y += self.speed;
};
return self;
});
// Bonus box class
var BonusBox = Container.expand(function () {
var self = Container.call(this);
var bonusSprite = self.attachAsset('bonus', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bonusSprite.width;
self.height = bonusSprite.height;
self.lastY = self.y;
self.lastIntersecting = false;
self.type = null; // Set on spawn
self.fallSpeed = 8; // Speed at which the bonus moves toward the player
self.update = function () {
// Move toward the player's current position
if (typeof player !== "undefined" && player !== null) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2) {
// Normalize and move toward player
self.x += dx / dist * self.fallSpeed;
self.y += dy / dist * self.fallSpeed;
}
}
};
return self;
});
// Crystal class
var Crystal = Container.expand(function () {
var self = Container.call(this);
var crystalSprite = self.attachAsset('crystal', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = crystalSprite.width;
self.height = crystalSprite.height;
self.lastY = self.y;
self.lastIntersecting = false;
self.fallSpeed = 12; // Speed at which the crystal falls toward the player
self.update = function () {
// Move toward the player's current position
if (typeof player !== "undefined" && player !== null) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 2) {
// Normalize and move toward player
self.x += dx / dist * self.fallSpeed;
self.y += dy / dist * self.fallSpeed;
}
}
};
return self;
});
// Laser class
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserSprite = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 1
});
self.width = laserSprite.width;
self.height = laserSprite.height;
self.speed = 32;
self.pierce = false;
self.lastY = self.y;
self.lastIntersecting = false;
self.update = function () {
self.y -= self.speed;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = playerSprite.width;
self.height = playerSprite.height;
self.shootCooldown = 0;
self.moveSpeed = 32; // px per tick when dragged
self.leftLimit = 0 + self.width / 2 + 40;
self.rightLimit = 2048 - self.width / 2 - 40;
self.powered = false;
self.powerTimer = 0;
self.powerType = null;
// For powerup visuals
self.setPower = function (type, duration) {
self.powered = true;
self.powerType = type;
self.powerTimer = duration;
if (type === 'rapid') {
playerSprite.tint = 0xffe100;
} else if (type === 'pierce') {
playerSprite.tint = 0x00ffb0;
} else if (type === 'shield') {
playerSprite.tint = 0x00eaff;
}
};
self.clearPower = function () {
self.powered = false;
self.powerType = null;
self.powerTimer = 0;
playerSprite.tint = 0xffffff;
};
self.update = function () {
if (self.powered) {
self.powerTimer--;
if (self.powerTimer <= 0) {
self.clearPower();
}
}
};
return self;
});
// ShootingStar class for large shooting star background effect
var ShootingStar = Container.expand(function () {
var self = Container.call(this);
// Use a white ellipse, much larger than normal stars
var size = randInt(120, 180);
var starSprite = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 100,
scaleY: size / 100 * 0.5,
// stretched for comet look
tint: 0xffffff,
// always white
alpha: 0.85
});
self.width = size;
self.height = size * 0.5;
self.speedX = randInt(5, 9); // slow horizontal speed
self.speedY = randInt(2, 4); // slow downward speed
self.active = false;
self.visible = false;
self.alpha = 0.85;
self.update = function () {
if (!self.active) return;
self.x += self.speedX;
self.y += self.speedY;
if (self.clearTimer > 0) {
self.clearTimer--;
self.alpha = 0.85;
} else {
// Fade out as it moves
if (self.alpha > 0.1) {
self.alpha -= 0.012;
}
}
// If out of screen, hide and deactivate
if (self.x > GAME_WIDTH + self.width || self.y > GAME_HEIGHT + self.height) {
self.active = false;
self.visible = false;
}
};
// Start the shooting star from a random left/top position
self.launch = function () {
self.x = randInt(-200, 200);
self.y = randInt(-120, 120);
self.speedX = randInt(5, 9);
self.speedY = randInt(2, 4);
self.alpha = 0.85;
self.clearTimer = 180; // 3 seconds at 60fps
self.active = true;
self.visible = true;
};
return self;
});
// Star class for background stars
var Star = Container.expand(function () {
var self = Container.call(this);
// Use a white ellipse as a star, randomize size (doubled)
var size = randInt(4, 12);
var starSprite = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 100,
scaleY: size / 100,
tint: 0xffffff
});
self.width = size;
self.height = size;
self.speed = randInt(1, 4) * 0.2; // slow speed for parallax
self.alpha = Math.random() * 0.25 + 0.75;
self.update = function () {
self.y += self.speed;
if (self.y > GAME_HEIGHT + self.height) {
self.y = -self.height;
self.x = randInt(0, GAME_WIDTH);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
// Player
// Alien (enemy)
// Player bullet (laser)
// Crystal (collectible)
// Bonus box
// Sound effects
// Music
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// --- Starfield background ---
var NUM_STARS = 480;
var stars = [];
for (var i = 0; i < NUM_STARS; i++) {
var star = new Star();
star.x = randInt(0, GAME_WIDTH);
star.y = randInt(0, GAME_HEIGHT);
stars.push(star);
// Always add stars at the end so they are above planets (index 0) and below gameplay
game.addChild(star);
}
// --- Large shooting stars (background effect, three per wave) ---
var shootingStars = [];
for (var i = 0; i < 3; i++) {
var s = new ShootingStar();
s.visible = false;
shootingStars.push(s);
game.addChild(s); // Add after planets, before gameplay (stars are already above planets)
}
var lastShootingStarWave = 0;
// --- Planets background (appear after wave 5) ---
var planets = [];
var PLANET_ASSETS = [{
id: 'centerCircle',
scale: 3.5,
tint: 0x3a7cff
},
// blue
{
id: 'centerCircle',
scale: 2.8,
tint: 0xffe100
},
// yellow
{
id: 'centerCircle',
scale: 2.2,
tint: 0xff6f00
},
// orange
{
id: 'centerCircle',
scale: 2.5,
tint: 0x00eaff
},
// cyan
{
id: 'centerCircle',
scale: 3.0,
tint: 0x00ffb0
} // green
];
var PLANET_MIN_Y = 400;
var PLANET_MAX_Y = GAME_HEIGHT - 800;
var PLANET_MIN_X = 200;
var PLANET_MAX_X = GAME_WIDTH - 200;
var PLANET_SPEED = 0.5; // slow drift
function spawnPlanets() {
// Only spawn if not already present
if (planets.length > 0) return;
for (var i = 0; i < PLANET_ASSETS.length; i++) {
var p = new Container();
var asset = PLANET_ASSETS[i];
var planetSprite = p.attachAsset(asset.id, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: asset.scale,
scaleY: asset.scale,
tint: asset.tint,
alpha: 0.7
});
p.width = planetSprite.width * asset.scale;
p.height = planetSprite.height * asset.scale;
p.x = randInt(PLANET_MIN_X, PLANET_MAX_X);
p.y = randInt(PLANET_MIN_Y, PLANET_MAX_Y);
p.speed = PLANET_SPEED * (0.7 + Math.random() * 0.6); // vary speed a bit
p.driftX = (Math.random() - 0.5) * 0.2; // slight horizontal drift
p.update = function () {
this.y += this.speed;
this.x += this.driftX;
if (this.y > GAME_HEIGHT + this.height) {
this.y = -this.height;
this.x = randInt(PLANET_MIN_X, PLANET_MAX_X);
// Ensure planet is always at the back after looping
if (this.parent) {
this.parent.removeChild(this);
this.parent.addChildAt(this, 0);
}
}
};
planets.push(p);
// Add behind stars (planets are background)
game.addChildAt(p, 0); // Always add at index 0 so planets are behind all stars and gameplay
}
}
function removePlanets() {
for (var i = 0; i < planets.length; i++) {
if (planets[i].parent) {
planets[i].parent.removeChild(planets[i]);
}
planets[i].destroy();
}
planets = [];
}
var GROUND_Y = GAME_HEIGHT - 220;
var PLAYER_START_X = GAME_WIDTH / 2;
var PLAYER_START_Y = GROUND_Y;
var PLAYER_MIN_X = 160 + 40;
var PLAYER_MAX_X = GAME_WIDTH - 160 - 40;
var ENEMY_START_X_MIN = 160;
var ENEMY_START_X_MAX = GAME_WIDTH - 160;
// Define Y spawn range for enemies (top margin to bottom margin for bonus box spawn)
var ENEMY_START_Y_MIN = 0;
var ENEMY_START_Y_MAX = GAME_HEIGHT - 400;
// Define 3 fixed road X positions for aliens to spawn and move along (top to bottom)
var ROAD_X_POSITIONS = [ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.2), ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.5), ENEMY_START_X_MIN + Math.floor((ENEMY_START_X_MAX - ENEMY_START_X_MIN) * 0.8)];
var LASER_COOLDOWN = 18; // ticks
var LASER_COOLDOWN_RAPID = 6;
// Track current firing cooldown, increases as waves progress
var currentLaserCooldown = LASER_COOLDOWN;
var currentLaserCooldownRapid = LASER_COOLDOWN_RAPID;
var CRYSTAL_COLLECT_DIST = 120;
var BONUS_COLLECT_DIST = 120;
var CRYSTAL_MOVE_STEP = 180; // How much movement area expands per crystal
var MAX_CRYSTALS = 8;
var WAVE_ENEMY_BASE = 10;
var WAVE_ENEMY_INC = 5; // Increase by 5 each wave
var WAVE_SPEED_INC = 0.5;
var WAVE_HP_INC = 1;
var BONUS_WAVE_INTERVAL = 3;
var POWERUP_DURATION = 360; // 6 seconds at 60fps
// Game state
var player = null;
var aliens = [];
var lasers = [];
var crystals = [];
var bonuses = [];
var dragNode = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastMoveX = 0;
var lastMoveY = 0;
var lastAlienSpawnTick = 0;
var wave = 1;
var enemiesLeft = 0;
var enemiesToSpawn = 0;
var enemiesKilled = 0;
var aliensKilledThisWave = 0; // Track aliens killed in current wave
var crystalsCollected = 0;
var leftLimit = PLAYER_MIN_X;
var rightLimit = PLAYER_MAX_X;
var bonusActive = false;
var bonusType = null;
// Double shot powerup state
var doubleShotActive = false;
var doubleShotTimer = 0;
// Removed score and scoreTxt, replaced by crystalTxt
var waveTxt = null;
var powerupTxt = null;
var gameOver = false;
var youWin = false;
// GUI
// Crystal icon in upper left (avoid top left 100x100 for menu)
// Crystal icon and count, aligned and sized together
var crystalIcon = LK.getAsset('crystal', {
anchorX: 0,
anchorY: 0.5
});
crystalIcon.x = 20;
crystalIcon.y = 160 + 40; // center of 80px icon at 160+40=200
crystalIcon.width = 100;
crystalIcon.height = 100;
LK.gui.topLeft.addChild(crystalIcon);
// Crystal count text, vertically centered with icon, same height
var crystalTxt = new Text2('0', {
size: 100,
fill: 0x00eaff
});
crystalTxt.anchor.set(0, 0.5);
crystalTxt.x = crystalIcon.x + crystalIcon.width + 24;
crystalTxt.y = crystalIcon.y;
LK.gui.topLeft.addChild(crystalTxt);
waveTxt = new Text2('Wave 1', {
size: 80,
fill: 0xAAFFFF
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
waveTxt.y = 120;
powerupTxt = new Text2('', {
size: 70,
fill: 0xFFE100
});
powerupTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(powerupTxt);
powerupTxt.y = 220;
// Start music
LK.playMusic('bgmusic');
// Spawn player
player = new Player();
player.x = PLAYER_START_X;
player.y = PLAYER_START_Y;
game.addChild(player);
// Set initial movement limits
leftLimit = player.leftLimit;
rightLimit = player.rightLimit;
// Start first wave
function startWave(waveNum) {
wave = waveNum;
waveTxt.setText('Wave ' + wave);
// Set enemiesToSpawn to 30 for each wave, so wave increases every 30 aliens
enemiesToSpawn = 30;
enemiesLeft = enemiesToSpawn;
lastAlienSpawnTick = LK.ticks;
aliensKilledThisWave = 0; // Reset for new wave
// Increase firing speed by 0.2x (reduce cooldown by 20%) each wave
if (wave > 1) {
currentLaserCooldown = Math.max(2, Math.floor(LASER_COOLDOWN * Math.pow(0.8, wave - 1)));
currentLaserCooldownRapid = Math.max(2, Math.floor(LASER_COOLDOWN_RAPID * Math.pow(0.8, wave - 1)));
}
}
startWave(1);
// Utility: clamp
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// Utility: random int
function randInt(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// Utility: random powerup
function randomPowerup() {
var arr = ['rapid', 'pierce', 'shield'];
return arr[randInt(0, arr.length - 1)];
}
// Handle movement (dragging)
function handleMove(x, y, obj) {
if (dragNode === player) {
// Clamp to current movement limits
var newX = clamp(x, leftLimit, rightLimit);
player.x = newX;
lastMoveX = newX;
lastMoveY = player.y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch/click is on player or below
if (y > GROUND_Y - 200) {
dragNode = player;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Main game update
game.update = function () {
// Update background stars
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Update shooting stars (background effect)
for (var i = 0; i < shootingStars.length; i++) {
shootingStars[i].update();
}
// Launch all shooting stars at the start of each wave, with slight offset for variety
if (lastShootingStarWave !== wave) {
for (var i = 0; i < shootingStars.length; i++) {
shootingStars[i].launch();
// Offset their starting x/y for visual spread
shootingStars[i].x += i * 180;
shootingStars[i].y += i * 60;
}
lastShootingStarWave = wave;
}
// Planets appear after wave 5
if (wave > 5) {
if (planets.length === 0) spawnPlanets();
for (var i = 0; i < planets.length; i++) {
planets[i].update();
}
} else {
if (planets.length > 0) removePlanets();
}
if (gameOver || youWin) return;
// Player update (powerup timer)
player.update();
// Aliens update
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
alien.update();
// Check if alien reached bottom edge (player dies)
if (alien.y > GAME_HEIGHT + alien.height / 2) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
gameOver = true;
return;
}
// Check collision with player (if shielded, destroy alien)
if (player.powered && player.powerType === 'shield' && alien.intersects(player)) {
LK.getSound('alien_die').play();
LK.effects.flashObject(alien, 0x00eaff, 400);
alien.isDead = true;
aliens.splice(i, 1);
alien.destroy();
continue;
}
}
// Lasers update
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
laser.update();
// Remove if off screen
if (laser.y < -100) {
lasers.splice(i, 1);
laser.destroy();
continue;
}
// Check collision with aliens
var hit = false;
for (var j = aliens.length - 1; j >= 0; j--) {
var alien = aliens[j];
if (!alien.isDead && laser.intersects(alien)) {
alien.hp -= player.powered && player.powerType === 'pierce' ? 2 : 1;
if (alien.hp <= 0) {
// Alien dies
LK.getSound('alien_die').play();
LK.effects.flashObject(alien, 0xff0000, 400);
alien.isDead = true;
// Drop crystal
var crystal = new Crystal();
crystal.x = alien.x;
crystal.y = alien.y;
crystals.push(crystal);
game.addChild(crystal);
// Remove alien
aliens.splice(j, 1);
alien.destroy();
enemiesLeft--;
enemiesKilled++;
aliensKilledThisWave++;
// Every 30 aliens, increase wave by 1 (only if all 30 were killed in this wave)
if (aliensKilledThisWave > 0 && aliensKilledThisWave % 30 === 0 && enemiesLeft === 0) {
startWave(wave + 1);
// Bonus box every BONUS_WAVE_INTERVAL after wave increment
if ((wave + 1) % BONUS_WAVE_INTERVAL === 0) {
var bonus = new BonusBox();
// Spawn bonus above the player, so it comes down toward the player
bonus.x = player.x;
bonus.y = -bonus.height / 2;
bonus.type = randomPowerup();
bonuses.push(bonus);
game.addChild(bonus);
}
return; // Prevent double wave start if also enemiesLeft==0
}
// New wave?
if (enemiesLeft <= 0) {
// No wave increase here, handled by 30 aliens killed logic
}
}
hit = true;
if (!(player.powered && player.powerType === 'pierce')) break;
}
}
if (hit && !(player.powered && player.powerType === 'pierce')) {
lasers.splice(i, 1);
laser.destroy();
}
}
// Crystals update
for (var i = crystals.length - 1; i >= 0; i--) {
var crystal = crystals[i];
// If player close enough, collect
var dx = player.x - crystal.x;
var dy = player.y - crystal.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < CRYSTAL_COLLECT_DIST) {
LK.getSound('crystal_get').play();
LK.effects.flashObject(crystal, 0x00eaff, 400);
crystals.splice(i, 1);
crystal.destroy();
// Expand movement area and always update score
crystalsCollected++;
crystalTxt.setText(crystalsCollected);
if (crystalsCollected <= MAX_CRYSTALS) {
leftLimit = Math.max(PLAYER_MIN_X - crystalsCollected * CRYSTAL_MOVE_STEP, 80 + player.width / 2);
rightLimit = Math.min(PLAYER_MAX_X + crystalsCollected * CRYSTAL_MOVE_STEP, GAME_WIDTH - 80 - player.width / 2);
}
}
}
// Bonus boxes update
for (var i = bonuses.length - 1; i >= 0; i--) {
var bonus = bonuses[i];
var dx = player.x - bonus.x;
var dy = player.y - bonus.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < BONUS_COLLECT_DIST) {
LK.getSound('bonus_get').play();
LK.effects.flashObject(bonus, 0xffe100, 400);
bonuses.splice(i, 1);
bonus.destroy();
// Grant powerup
player.setPower(bonus.type, POWERUP_DURATION);
// Double shot for 5 seconds if bonus is collected
doubleShotActive = true;
doubleShotTimer = 300; // 5 seconds at 60fps
// Player and lasers turn red for duration of double shot
if (typeof playerRedTimer === "undefined") {
playerRedTimer = 0;
}
playerRedTimer = 300; // 5 seconds at 60fps (match double shot)
if (player && player.attachAsset) {
// Set player sprite red
var pSprite = player.children && player.children.length > 0 ? player.children[0] : null;
if (pSprite && pSprite.tint !== undefined) {
pSprite.tint = 0xff0000;
}
}
// Set all current lasers to red
for (var li = 0; li < lasers.length; li++) {
var l = lasers[li];
var lSprite = l.children && l.children.length > 0 ? l.children[0] : null;
if (lSprite && lSprite.tint !== undefined) {
lSprite.tint = 0xff0000;
}
}
if (bonus.type === 'rapid') {
powerupTxt.setText('Rapid Fire!');
} else if (bonus.type === 'pierce') {
powerupTxt.setText('Piercing Shots!');
} else if (bonus.type === 'shield') {
powerupTxt.setText('Shield!');
}
}
}
// Powerup text timer
if (player.powered) {
powerupTxt.alpha = 1;
} else {
if (powerupTxt.alpha > 0) {
powerupTxt.alpha -= 0.04;
if (powerupTxt.alpha < 0) powerupTxt.alpha = 0;
}
powerupTxt.setText('');
}
// Keep player and lasers red while double shot is active, revert when double shot ends
if (doubleShotActive) {
// Keep player and lasers red
if (player && player.attachAsset) {
var pSprite = player.children && player.children.length > 0 ? player.children[0] : null;
if (pSprite && pSprite.tint !== undefined) {
pSprite.tint = 0xff0000;
}
}
for (var li = 0; li < lasers.length; li++) {
var l = lasers[li];
var lSprite = l.children && l.children.length > 0 ? l.children[0] : null;
if (lSprite && lSprite.tint !== undefined) {
lSprite.tint = 0xff0000;
}
}
} else {
// Revert player and lasers to normal color
if (player && player.attachAsset) {
var pSprite = player.children && player.children.length > 0 ? player.children[0] : null;
if (pSprite && pSprite.tint !== undefined) {
pSprite.tint = 0xffffff;
}
}
for (var li = 0; li < lasers.length; li++) {
var l = lasers[li];
var lSprite = l.children && l.children.length > 0 ? l.children[0] : null;
if (lSprite && lSprite.tint !== undefined) {
lSprite.tint = 0xffffff;
}
}
}
// Double shot timer logic
if (doubleShotActive) {
doubleShotTimer--;
if (doubleShotTimer <= 0) {
doubleShotActive = false;
}
}
// Player auto-fire
var cooldown = player.powered && player.powerType === 'rapid' ? currentLaserCooldownRapid : currentLaserCooldown;
if (player.shootCooldown > 0) player.shootCooldown--;
// Find nearest alien in range
var nearestAlien = null;
var minDist = 99999;
for (var i = 0; i < aliens.length; i++) {
var alien = aliens[i];
var dx = alien.x - player.x;
var dy = alien.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dy > 0) continue; // Only shoot aliens above the player
if (dist < minDist) {
minDist = dist;
nearestAlien = alien;
}
}
if (nearestAlien && player.shootCooldown <= 0) {
// Fire laser(s)
if (doubleShotActive) {
// Double shot: fire two lasers slightly offset
var laser1 = new Laser();
laser1.x = player.x - 32;
laser1.y = player.y - player.height / 2 + 10;
if (player.powered && player.powerType === 'pierce') {
laser1.pierce = true;
}
// Make laser red if double shot is active
var l1Sprite = laser1.children && laser1.children.length > 0 ? laser1.children[0] : null;
if (l1Sprite && l1Sprite.tint !== undefined) {
l1Sprite.tint = 0xff0000;
}
lasers.push(laser1);
game.addChild(laser1);
var laser2 = new Laser();
laser2.x = player.x + 32;
laser2.y = player.y - player.height / 2 + 10;
if (player.powered && player.powerType === 'pierce') {
laser2.pierce = true;
}
// Make laser red if double shot is active
var l2Sprite = laser2.children && laser2.children.length > 0 ? laser2.children[0] : null;
if (l2Sprite && l2Sprite.tint !== undefined) {
l2Sprite.tint = 0xff0000;
}
lasers.push(laser2);
game.addChild(laser2);
player.shootCooldown = cooldown;
LK.getSound('laser_shoot').play();
} else {
// Single shot
var laser = new Laser();
laser.x = player.x;
laser.y = player.y - player.height / 2 + 10;
if (player.powered && player.powerType === 'pierce') {
laser.pierce = true;
}
lasers.push(laser);
game.addChild(laser);
player.shootCooldown = cooldown;
LK.getSound('laser_shoot').play();
}
} else if (player.shootCooldown > 0) {
// Prevent firing if still in cooldown
player.shootCooldown--;
}
// Spawn aliens for current wave
if (enemiesToSpawn > 0 && LK.ticks - lastAlienSpawnTick > 24) {
var alien;
// Every 3 waves, use the same alien type for 3 full waves in a row
var waveType = Math.floor((wave - 1) / 3) % 3;
if (waveType === 0) {
alien = new Alien();
alien.speed = 2.5 + (wave - 1) * WAVE_SPEED_INC;
alien.hp = 1 + Math.floor((wave - 1) * WAVE_HP_INC / 2);
} else if (waveType === 1) {
alien = new Alien2();
alien.speed = 2.8 + (wave - 1) * WAVE_SPEED_INC;
alien.hp = 2 + Math.floor((wave - 1) * WAVE_HP_INC / 2);
} else {
alien = new Alien3();
alien.speed = 3.2 + (wave - 1) * WAVE_SPEED_INC;
alien.hp = 3 + Math.floor((wave - 1) * WAVE_HP_INC / 2);
}
// Pick a random road for the alien to spawn on (X position)
var roadIdx = randInt(0, ROAD_X_POSITIONS.length - 1);
alien.x = ROAD_X_POSITIONS[roadIdx];
alien.y = -alien.height / 2;
alien.wave = wave;
aliens.push(alien);
game.addChild(alien);
enemiesToSpawn--;
lastAlienSpawnTick = LK.ticks;
}
}; ===================================================================
--- original.js
+++ change.js
@@ -221,11 +221,10 @@
self.update = function () {
if (!self.active) return;
self.x += self.speedX;
self.y += self.speedY;
- // Hold clear for 10 seconds (600 ticks), then fade out
- if (self.clearTicks > 0) {
- self.clearTicks--;
+ if (self.clearTimer > 0) {
+ self.clearTimer--;
self.alpha = 0.85;
} else {
// Fade out as it moves
if (self.alpha > 0.1) {
@@ -244,9 +243,9 @@
self.y = randInt(-120, 120);
self.speedX = randInt(5, 9);
self.speedY = randInt(2, 4);
self.alpha = 0.85;
- self.clearTicks = 600; // 10 seconds at 60fps
+ self.clearTimer = 180; // 3 seconds at 60fps
self.active = true;
self.visible = true;
};
return self;
A triangular spaceship. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
alien creature drawing. In-Game asset. 2d. High contrast. No shadows
blue crystal. In-Game asset. 2d. High contrast. No shadows
draw thick long laser bullet. In-Game asset. 2d. High contrast. No shadows
remove bonus text
spaceship. In-Game asset. 2d. High contrast. No shadows