/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Drop = Container.expand(function (dropType) { var self = Container.call(this); self.dropType = dropType; var dropGraphics = self.attachAsset(dropType, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.update = function () { self.y += self.speed; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.shootTimer = 0; var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave var minInterval = Math.max(60, 360 - waveReduction); // Minimum 1 second interval var maxInterval = Math.max(120, 600 - waveReduction); // Minimum 2 second max interval self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level self.moveSpeed = 2; self.note = 0; // Musical note value self.update = function () { self.shootTimer++; if (self.shootTimer >= self.shootInterval) { self.shoot(); self.shootTimer = 0; var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave var minInterval = Math.max(60, 360 - waveReduction); // Minimum 1 second interval var maxInterval = Math.max(120, 600 - waveReduction); // Minimum 2 second max interval self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level } // Add subtle horizontal sway movement for more fluid feel if (LK.ticks % 180 === 0) { var sideMovement = (Math.random() - 0.5) * 60; var targetX = Math.max(50, Math.min(1998, self.x + sideMovement)); tween(self, { x: targetX }, { duration: 1500 + Math.random() * 1000, easing: tween.easeInOut }); } }; self.shoot = function () { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 20; enemyBullets.push(bullet); game.addChild(bullet); }; self.takeDamage = function (damage) { self.health -= damage * rhythmMultiplier; if (self.health <= 0) { // Drop system - chance to drop items var dropChance = Math.random() * 100; if (dropChance < 2) { // 2% chance for powerup1 var drop = new Drop('powerup1'); drop.x = self.x; drop.y = self.y; drops.push(drop); game.addChild(drop); } else if (dropChance < 3) { // 1% chance for powerup2 var drop = new Drop('powerup2'); drop.x = self.x; drop.y = self.y; drops.push(drop); game.addChild(drop); } else if (dropChance < 4) { // 1% chance for lifeup var drop = new Drop('lifeup'); drop.x = self.x; drop.y = self.y; drops.push(drop); game.addChild(drop); } self.destroy(); return true; } return false; }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.update = function () { self.y += self.speed; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); self.speed = 8; self.lives = 3; self.canShoot = true; self.shootCooldown = 0; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; if (self.shootCooldown <= 0) { self.canShoot = true; } } // Keep player within screen bounds if (self.x < 60) self.x = 60; if (self.x > 2048 - 60) self.x = 2048 - 60; }; self.shoot = function () { if (!self.canShoot) return false; self.canShoot = false; self.shootCooldown = 15; // Determine number of bullets based on powerup var bulletCount = 1; if (currentPowerup === 'powerup1') { bulletCount = 3; } // Create bullets for (var i = 0; i < bulletCount; i++) { var bullet = new PlayerBullet(currentPowerup); if (bulletCount === 1) { bullet.x = self.x; } else { bullet.x = self.x + (i - 1) * 30; // Spread bullets } bullet.y = self.y - 40; playerBullets.push(bullet); game.addChild(bullet); } LK.getSound('shoot').play(); // 1 in 20 chance to play rhythmBonus sound if (Math.random() < 0.05) { LK.getSound('rhythmBonus').play(); } // Check if shooting in rhythm var timeSinceLastBeat = LK.ticks * 16.67 % beatInterval; var rhythmWindow = beatInterval * 0.15; if (timeSinceLastBeat < rhythmWindow || timeSinceLastBeat > beatInterval - rhythmWindow) { rhythmMultiplier = Math.min(rhythmMultiplier + 0.1, 2.0); } else { rhythmMultiplier = Math.max(rhythmMultiplier - 0.05, 1.0); } return true; }; return self; }); var PlayerBullet = Container.expand(function (bulletType) { var self = Container.call(this); self.bulletType = bulletType || 'normal'; var assetName = 'playerBullet'; if (self.bulletType === 'powerup1') { assetName = 'powebullet1'; } else if (self.bulletType === 'powerup2') { assetName = 'powerbullet2'; } var bulletGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.speed = -12; self.damage = 1; self.piercing = self.bulletType === 'powerup2'; self.update = function () { self.y += self.speed; }; return self; }); var SuperBoss = Container.expand(function () { var self = Container.call(this); var bossGraphics = self.attachAsset('superboss', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, tint: 0xff0000 }); self.health = 100; self.maxHealth = 100; self.shootTimer = 0; var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave var minInterval = Math.max(60, 180 - waveReduction); // Minimum 1 second interval var maxInterval = Math.max(120, 480 - waveReduction); // Minimum 2 second max interval self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level self.moveSpeed = 1; self.moveDirection = 1; self.update = function () { // Boss movement - side to side self.x += self.moveSpeed * self.moveDirection; if (self.x <= 200 || self.x >= 1848) { self.moveDirection *= -1; } // Boss shooting self.shootTimer++; if (self.shootTimer >= self.shootInterval) { self.shoot(); self.shootTimer = 0; var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave var minInterval = Math.max(60, 180 - waveReduction); // Minimum 1 second interval var maxInterval = Math.max(120, 480 - waveReduction); // Minimum 2 second max interval self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level } // Update boss color based on health var healthPercent = self.health / self.maxHealth; if (healthPercent > 0.6) { bossGraphics.tint = 0xff0000; // Red } else if (healthPercent > 0.3) { bossGraphics.tint = 0xff8800; // Orange } else { bossGraphics.tint = 0xffff00; // Yellow } }; self.shoot = function () { // Shoot multiple bullets in different directions for (var i = -2; i <= 2; i++) { var bullet = new EnemyBullet(); bullet.x = self.x + i * 50; bullet.y = self.y + 50; bullet.speed = 3 + Math.abs(i) * 0.5; enemyBullets.push(bullet); game.addChild(bullet); } }; self.takeDamage = function (damage) { self.health -= damage * rhythmMultiplier; LK.effects.flashObject(self, 0xffffff, 100); if (self.health <= 0) { self.destroy(); return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000011 }); /**** * Game Code ****/ var gameStarted = false; var startButton = game.addChild(LK.getAsset('start', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 4 })); startButton.x = 1024; // Center horizontally startButton.y = 1366; // Center vertically var player = game.addChild(new Player()); player.x = 1024; player.y = 2600; player.visible = false; // Hide player until game starts var playerBullets = []; var enemyBullets = []; var enemies = []; var currentWave = 1; var enemiesKilled = 0; var totalEnemiesInWave = 0; var waveStarted = false; var waveDelay = 0; var rhythmMultiplier = 1.0; var beatInterval = 500; // milliseconds var lastBeatTime = 0; var enemyFormationX = 0; var enemyFormationDirection = 1; var enemyDropDistance = 60; var shouldDropEnemies = false; var superBoss = null; var bossActive = false; var bossDefeated = false; var drops = []; var currentPowerup = null; // Sound management for bonus sounds var currentBonusSoundName = null; var currentBonusSoundTimeout = null; var bonusSounds = ['bonusmusic', 'bonusmusic2', 'bonusmusic3', 'bonusmusic4', 'bonusmusic5']; function playRandomBonusSound() { // Only play if no bonus sound is currently playing if (currentBonusSoundName === null) { var randomSoundName = bonusSounds[Math.floor(Math.random() * bonusSounds.length)]; var randomSound = LK.getSound(randomSoundName); currentBonusSoundName = randomSoundName; randomSound.play(); // Clear any existing timeout if (currentBonusSoundTimeout !== null) { LK.clearTimeout(currentBonusSoundTimeout); } // Set a longer timeout to ensure sound finishes before allowing new ones // Using 2500ms to be safe that the sound completes currentBonusSoundTimeout = LK.setTimeout(function () { currentBonusSoundName = null; currentBonusSoundTimeout = null; }, 2500); } } // UI Elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); scoreTxt.x = 20; scoreTxt.y = 20; LK.gui.topLeft.addChild(scoreTxt); var livesTxt = new Text2('Lives: 3', { size: 60, fill: 0xFFFFFF }); livesTxt.anchor.set(1, 0); livesTxt.x = -20; livesTxt.y = 20; LK.gui.topRight.addChild(livesTxt); var waveTxt = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); waveTxt.anchor.set(0.5, 0); waveTxt.x = 0; waveTxt.y = 20; LK.gui.top.addChild(waveTxt); var rhythmTxt = new Text2('Rhythm: 1.0x', { size: 50, fill: 0xFFFF00 }); rhythmTxt.anchor.set(0.5, 0); rhythmTxt.x = 0; rhythmTxt.y = 100; LK.gui.top.addChild(rhythmTxt); function createWave(waveNumber) { enemies = []; enemiesKilled = 0; var rows = 3 + Math.floor(waveNumber / 3); var cols = 8 + Math.floor(waveNumber / 2); totalEnemiesInWave = rows * cols; var startX = (2048 - cols * 100) / 2; var startY = 200; for (var row = 0; row < rows; row++) { for (var col = 0; col < cols; col++) { var enemy = new Enemy(); enemy.x = startX + col * 100; enemy.y = startY + row * 80; enemy.note = (row * cols + col) % 12; // Assign musical notes enemies.push(enemy); game.addChild(enemy); } } enemyFormationX = 0; enemyFormationDirection = 1; waveStarted = true; // Increase tempo with each wave beatInterval = Math.max(300, 500 - waveNumber * 20); } function updateEnemyFormation() { if (enemies.length === 0) return; var moveDistance = 4 + Math.floor(currentWave / 2); var shouldMove = LK.ticks % Math.max(1, 20 - currentWave * 1.5) === 0; if (shouldMove) { if (shouldDropEnemies) { // Drop enemies down for (var i = 0; i < enemies.length; i++) { enemies[i].y += enemyDropDistance; } shouldDropEnemies = false; } else { // Move all enemies horizontally in synchronized formation using tween var hitEdge = false; var targetDirection = moveDistance * enemyFormationDirection; // Check if any enemy would hit the edge for (var i = 0; i < enemies.length; i++) { var newX = enemies[i].x + targetDirection; if (newX <= 50 || newX >= 1998) { hitEdge = true; break; } } // Move all enemies together with synchronized tween animation for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; tween(enemy, { x: enemy.x + targetDirection }, { duration: 300, easing: tween.easeInOut }); } if (hitEdge) { enemyFormationDirection *= -1; shouldDropEnemies = true; } } } } function checkCollisions() { // Player bullets vs enemies for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; var bulletHit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { if (enemy.takeDamage(bullet.damage)) { enemies.splice(j, 1); enemiesKilled++; var baseScore = 100 * Math.floor(rhythmMultiplier); LK.setScore(LK.getScore() + baseScore); LK.getSound('enemyHit').play(); // Play random bonus sound effect with 15% chance if (Math.random() < 0.15) { playRandomBonusSound(); } LK.effects.flashObject(enemy, 0xffffff, 200); } if (!bullet.piercing) { bullet.destroy(); playerBullets.splice(i, 1); bulletHit = true; break; } else { bulletHit = false; // Allow piercing bullets to continue } } } // Player bullets vs super boss if (!bulletHit && superBoss && bullet.intersects(superBoss)) { if (superBoss.takeDamage(bullet.damage)) { superBoss = null; bossActive = false; bossDefeated = true; var bossScore = 5000 * Math.floor(rhythmMultiplier); LK.setScore(LK.getScore() + bossScore); LK.getSound('enemyHit').play(); // Play random bonus sound effect with 15% chance if (Math.random() < 0.15) { playRandomBonusSound(); } } if (!bullet.piercing) { bullet.destroy(); playerBullets.splice(i, 1); bulletHit = true; } } if (!bulletHit && bullet.y < -20) { bullet.destroy(); playerBullets.splice(i, 1); } } // Player vs drops for (var i = drops.length - 1; i >= 0; i--) { var drop = drops[i]; if (drop.intersects(player)) { if (drop.dropType === 'lifeup') { player.lives = Math.min(player.lives + 1, 5); } else { currentPowerup = drop.dropType; } drop.destroy(); drops.splice(i, 1); } else if (drop.y > 2732) { drop.destroy(); drops.splice(i, 1); } } // Enemy bullets vs player for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.intersects(player)) { player.lives--; currentPowerup = null; // Reset powerup when player loses a life bullet.destroy(); enemyBullets.splice(i, 1); LK.getSound('playerHit').play(); LK.effects.flashObject(player, 0xff0000, 500); if (player.lives <= 0) { LK.showGameOver(); return; } } else if (bullet.y > 2732) { bullet.destroy(); enemyBullets.splice(i, 1); } } // Check if enemies reached player for (var i = 0; i < enemies.length; i++) { if (enemies[i].y > 2500) { LK.showGameOver(); return; } } // Check if super boss reached player if (superBoss && superBoss.y > 2500) { LK.showGameOver(); return; } } function updateUI() { scoreTxt.setText('Score: ' + LK.getScore()); livesTxt.setText('Lives: ' + player.lives); waveTxt.setText('Wave: ' + currentWave); rhythmTxt.setText('Rhythm: ' + rhythmMultiplier.toFixed(1) + 'x'); // Color rhythm multiplier text based on value if (rhythmMultiplier > 1.5) { rhythmTxt.tint = 0x00ff00; } else if (rhythmMultiplier > 1.2) { rhythmTxt.tint = 0xffff00; } else { rhythmTxt.tint = 0xffffff; } } // Touch controls var dragStartX = 0; var isDragging = false; var lastTouchTime = 0; game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; startButton.visible = false; // Hide start button player.visible = true; // Show player when game starts // Start background music LK.playMusic('bgmusic'); // Initialize first wave createWave(currentWave); return; } isDragging = true; // Stop any existing tween for immediate response tween.stop(player, { x: true }); // Quick tween to clicked position for responsive feel tween(player, { x: x }, { duration: 100, easing: tween.easeOut }); var currentTime = Date.now(); if (currentTime - lastTouchTime < 300) { // Double tap to shoot player.shoot(); } lastTouchTime = currentTime; }; game.move = function (x, y, obj) { if (!gameStarted) return; // Stop any existing tween to prevent conflicts tween.stop(player, { x: true }); // Calculate distance for dynamic duration var distance = Math.abs(x - player.x); // Dynamic duration based on distance - closer targets move faster var duration = Math.min(Math.max(distance * 0.8, 50), 200); // Use smooth easing for natural movement tween(player, { x: x }, { duration: duration, easing: tween.easeOut }); }; game.up = function (x, y, obj) { if (!gameStarted) return; isDragging = false; // Shoot on mouse up for better control player.shoot(); }; game.update = function () { if (!gameStarted) return; updateEnemyFormation(); checkCollisions(); updateUI(); // Gradually decay rhythm multiplier rhythmMultiplier = Math.max(rhythmMultiplier - 0.001, 1.0); // Check if wave is complete if (enemies.length === 0 && waveStarted && !bossActive) { waveStarted = false; bossActive = true; bossDefeated = false; // Spawn super boss superBoss = new SuperBoss(); superBoss.x = 1024; superBoss.y = 300; game.addChild(superBoss); } // Check if boss is defeated if (bossDefeated && !waveStarted) { waveDelay = 120; // 2 second delay currentWave++; bossDefeated = false; if (currentWave > 10) { LK.showYouWin(); return; } } // Start next wave after delay if (!waveStarted && waveDelay > 0) { waveDelay--; if (waveDelay <= 0) { createWave(currentWave); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Drop = Container.expand(function (dropType) {
var self = Container.call(this);
self.dropType = dropType;
var dropGraphics = self.attachAsset(dropType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.shootTimer = 0;
var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave
var minInterval = Math.max(60, 360 - waveReduction); // Minimum 1 second interval
var maxInterval = Math.max(120, 600 - waveReduction); // Minimum 2 second max interval
self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level
self.moveSpeed = 2;
self.note = 0; // Musical note value
self.update = function () {
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave
var minInterval = Math.max(60, 360 - waveReduction); // Minimum 1 second interval
var maxInterval = Math.max(120, 600 - waveReduction); // Minimum 2 second max interval
self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level
}
// Add subtle horizontal sway movement for more fluid feel
if (LK.ticks % 180 === 0) {
var sideMovement = (Math.random() - 0.5) * 60;
var targetX = Math.max(50, Math.min(1998, self.x + sideMovement));
tween(self, {
x: targetX
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut
});
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 20;
enemyBullets.push(bullet);
game.addChild(bullet);
};
self.takeDamage = function (damage) {
self.health -= damage * rhythmMultiplier;
if (self.health <= 0) {
// Drop system - chance to drop items
var dropChance = Math.random() * 100;
if (dropChance < 2) {
// 2% chance for powerup1
var drop = new Drop('powerup1');
drop.x = self.x;
drop.y = self.y;
drops.push(drop);
game.addChild(drop);
} else if (dropChance < 3) {
// 1% chance for powerup2
var drop = new Drop('powerup2');
drop.x = self.x;
drop.y = self.y;
drops.push(drop);
game.addChild(drop);
} else if (dropChance < 4) {
// 1% chance for lifeup
var drop = new Drop('lifeup');
drop.x = self.x;
drop.y = self.y;
drops.push(drop);
game.addChild(drop);
}
self.destroy();
return true;
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = 8;
self.lives = 3;
self.canShoot = true;
self.shootCooldown = 0;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
if (self.shootCooldown <= 0) {
self.canShoot = true;
}
}
// Keep player within screen bounds
if (self.x < 60) self.x = 60;
if (self.x > 2048 - 60) self.x = 2048 - 60;
};
self.shoot = function () {
if (!self.canShoot) return false;
self.canShoot = false;
self.shootCooldown = 15;
// Determine number of bullets based on powerup
var bulletCount = 1;
if (currentPowerup === 'powerup1') {
bulletCount = 3;
}
// Create bullets
for (var i = 0; i < bulletCount; i++) {
var bullet = new PlayerBullet(currentPowerup);
if (bulletCount === 1) {
bullet.x = self.x;
} else {
bullet.x = self.x + (i - 1) * 30; // Spread bullets
}
bullet.y = self.y - 40;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
// 1 in 20 chance to play rhythmBonus sound
if (Math.random() < 0.05) {
LK.getSound('rhythmBonus').play();
}
// Check if shooting in rhythm
var timeSinceLastBeat = LK.ticks * 16.67 % beatInterval;
var rhythmWindow = beatInterval * 0.15;
if (timeSinceLastBeat < rhythmWindow || timeSinceLastBeat > beatInterval - rhythmWindow) {
rhythmMultiplier = Math.min(rhythmMultiplier + 0.1, 2.0);
} else {
rhythmMultiplier = Math.max(rhythmMultiplier - 0.05, 1.0);
}
return true;
};
return self;
});
var PlayerBullet = Container.expand(function (bulletType) {
var self = Container.call(this);
self.bulletType = bulletType || 'normal';
var assetName = 'playerBullet';
if (self.bulletType === 'powerup1') {
assetName = 'powebullet1';
} else if (self.bulletType === 'powerup2') {
assetName = 'powerbullet2';
}
var bulletGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -12;
self.damage = 1;
self.piercing = self.bulletType === 'powerup2';
self.update = function () {
self.y += self.speed;
};
return self;
});
var SuperBoss = Container.expand(function () {
var self = Container.call(this);
var bossGraphics = self.attachAsset('superboss', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3,
tint: 0xff0000
});
self.health = 100;
self.maxHealth = 100;
self.shootTimer = 0;
var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave
var minInterval = Math.max(60, 180 - waveReduction); // Minimum 1 second interval
var maxInterval = Math.max(120, 480 - waveReduction); // Minimum 2 second max interval
self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level
self.moveSpeed = 1;
self.moveDirection = 1;
self.update = function () {
// Boss movement - side to side
self.x += self.moveSpeed * self.moveDirection;
if (self.x <= 200 || self.x >= 1848) {
self.moveDirection *= -1;
}
// Boss shooting
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
var waveReduction = (currentWave - 1) * 60; // Reduce by 1 second (60 frames) per wave
var minInterval = Math.max(60, 180 - waveReduction); // Minimum 1 second interval
var maxInterval = Math.max(120, 480 - waveReduction); // Minimum 2 second max interval
self.shootInterval = minInterval + Math.random() * (maxInterval - minInterval); // Dynamic interval based on wave level
}
// Update boss color based on health
var healthPercent = self.health / self.maxHealth;
if (healthPercent > 0.6) {
bossGraphics.tint = 0xff0000; // Red
} else if (healthPercent > 0.3) {
bossGraphics.tint = 0xff8800; // Orange
} else {
bossGraphics.tint = 0xffff00; // Yellow
}
};
self.shoot = function () {
// Shoot multiple bullets in different directions
for (var i = -2; i <= 2; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 50;
bullet.y = self.y + 50;
bullet.speed = 3 + Math.abs(i) * 0.5;
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage * rhythmMultiplier;
LK.effects.flashObject(self, 0xffffff, 100);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000011
});
/****
* Game Code
****/
var gameStarted = false;
var startButton = game.addChild(LK.getAsset('start', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
}));
startButton.x = 1024; // Center horizontally
startButton.y = 1366; // Center vertically
var player = game.addChild(new Player());
player.x = 1024;
player.y = 2600;
player.visible = false; // Hide player until game starts
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var currentWave = 1;
var enemiesKilled = 0;
var totalEnemiesInWave = 0;
var waveStarted = false;
var waveDelay = 0;
var rhythmMultiplier = 1.0;
var beatInterval = 500; // milliseconds
var lastBeatTime = 0;
var enemyFormationX = 0;
var enemyFormationDirection = 1;
var enemyDropDistance = 60;
var shouldDropEnemies = false;
var superBoss = null;
var bossActive = false;
var bossDefeated = false;
var drops = [];
var currentPowerup = null;
// Sound management for bonus sounds
var currentBonusSoundName = null;
var currentBonusSoundTimeout = null;
var bonusSounds = ['bonusmusic', 'bonusmusic2', 'bonusmusic3', 'bonusmusic4', 'bonusmusic5'];
function playRandomBonusSound() {
// Only play if no bonus sound is currently playing
if (currentBonusSoundName === null) {
var randomSoundName = bonusSounds[Math.floor(Math.random() * bonusSounds.length)];
var randomSound = LK.getSound(randomSoundName);
currentBonusSoundName = randomSoundName;
randomSound.play();
// Clear any existing timeout
if (currentBonusSoundTimeout !== null) {
LK.clearTimeout(currentBonusSoundTimeout);
}
// Set a longer timeout to ensure sound finishes before allowing new ones
// Using 2500ms to be safe that the sound completes
currentBonusSoundTimeout = LK.setTimeout(function () {
currentBonusSoundName = null;
currentBonusSoundTimeout = null;
}, 2500);
}
}
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 20;
scoreTxt.y = 20;
LK.gui.topLeft.addChild(scoreTxt);
var livesTxt = new Text2('Lives: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(1, 0);
livesTxt.x = -20;
livesTxt.y = 20;
LK.gui.topRight.addChild(livesTxt);
var waveTxt = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
waveTxt.anchor.set(0.5, 0);
waveTxt.x = 0;
waveTxt.y = 20;
LK.gui.top.addChild(waveTxt);
var rhythmTxt = new Text2('Rhythm: 1.0x', {
size: 50,
fill: 0xFFFF00
});
rhythmTxt.anchor.set(0.5, 0);
rhythmTxt.x = 0;
rhythmTxt.y = 100;
LK.gui.top.addChild(rhythmTxt);
function createWave(waveNumber) {
enemies = [];
enemiesKilled = 0;
var rows = 3 + Math.floor(waveNumber / 3);
var cols = 8 + Math.floor(waveNumber / 2);
totalEnemiesInWave = rows * cols;
var startX = (2048 - cols * 100) / 2;
var startY = 200;
for (var row = 0; row < rows; row++) {
for (var col = 0; col < cols; col++) {
var enemy = new Enemy();
enemy.x = startX + col * 100;
enemy.y = startY + row * 80;
enemy.note = (row * cols + col) % 12; // Assign musical notes
enemies.push(enemy);
game.addChild(enemy);
}
}
enemyFormationX = 0;
enemyFormationDirection = 1;
waveStarted = true;
// Increase tempo with each wave
beatInterval = Math.max(300, 500 - waveNumber * 20);
}
function updateEnemyFormation() {
if (enemies.length === 0) return;
var moveDistance = 4 + Math.floor(currentWave / 2);
var shouldMove = LK.ticks % Math.max(1, 20 - currentWave * 1.5) === 0;
if (shouldMove) {
if (shouldDropEnemies) {
// Drop enemies down
for (var i = 0; i < enemies.length; i++) {
enemies[i].y += enemyDropDistance;
}
shouldDropEnemies = false;
} else {
// Move all enemies horizontally in synchronized formation using tween
var hitEdge = false;
var targetDirection = moveDistance * enemyFormationDirection;
// Check if any enemy would hit the edge
for (var i = 0; i < enemies.length; i++) {
var newX = enemies[i].x + targetDirection;
if (newX <= 50 || newX >= 1998) {
hitEdge = true;
break;
}
}
// Move all enemies together with synchronized tween animation
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
tween(enemy, {
x: enemy.x + targetDirection
}, {
duration: 300,
easing: tween.easeInOut
});
}
if (hitEdge) {
enemyFormationDirection *= -1;
shouldDropEnemies = true;
}
}
}
}
function checkCollisions() {
// Player bullets vs enemies
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
var bulletHit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage(bullet.damage)) {
enemies.splice(j, 1);
enemiesKilled++;
var baseScore = 100 * Math.floor(rhythmMultiplier);
LK.setScore(LK.getScore() + baseScore);
LK.getSound('enemyHit').play();
// Play random bonus sound effect with 15% chance
if (Math.random() < 0.15) {
playRandomBonusSound();
}
LK.effects.flashObject(enemy, 0xffffff, 200);
}
if (!bullet.piercing) {
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
break;
} else {
bulletHit = false; // Allow piercing bullets to continue
}
}
}
// Player bullets vs super boss
if (!bulletHit && superBoss && bullet.intersects(superBoss)) {
if (superBoss.takeDamage(bullet.damage)) {
superBoss = null;
bossActive = false;
bossDefeated = true;
var bossScore = 5000 * Math.floor(rhythmMultiplier);
LK.setScore(LK.getScore() + bossScore);
LK.getSound('enemyHit').play();
// Play random bonus sound effect with 15% chance
if (Math.random() < 0.15) {
playRandomBonusSound();
}
}
if (!bullet.piercing) {
bullet.destroy();
playerBullets.splice(i, 1);
bulletHit = true;
}
}
if (!bulletHit && bullet.y < -20) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
// Player vs drops
for (var i = drops.length - 1; i >= 0; i--) {
var drop = drops[i];
if (drop.intersects(player)) {
if (drop.dropType === 'lifeup') {
player.lives = Math.min(player.lives + 1, 5);
} else {
currentPowerup = drop.dropType;
}
drop.destroy();
drops.splice(i, 1);
} else if (drop.y > 2732) {
drop.destroy();
drops.splice(i, 1);
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.intersects(player)) {
player.lives--;
currentPowerup = null; // Reset powerup when player loses a life
bullet.destroy();
enemyBullets.splice(i, 1);
LK.getSound('playerHit').play();
LK.effects.flashObject(player, 0xff0000, 500);
if (player.lives <= 0) {
LK.showGameOver();
return;
}
} else if (bullet.y > 2732) {
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Check if enemies reached player
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].y > 2500) {
LK.showGameOver();
return;
}
}
// Check if super boss reached player
if (superBoss && superBoss.y > 2500) {
LK.showGameOver();
return;
}
}
function updateUI() {
scoreTxt.setText('Score: ' + LK.getScore());
livesTxt.setText('Lives: ' + player.lives);
waveTxt.setText('Wave: ' + currentWave);
rhythmTxt.setText('Rhythm: ' + rhythmMultiplier.toFixed(1) + 'x');
// Color rhythm multiplier text based on value
if (rhythmMultiplier > 1.5) {
rhythmTxt.tint = 0x00ff00;
} else if (rhythmMultiplier > 1.2) {
rhythmTxt.tint = 0xffff00;
} else {
rhythmTxt.tint = 0xffffff;
}
}
// Touch controls
var dragStartX = 0;
var isDragging = false;
var lastTouchTime = 0;
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
startButton.visible = false; // Hide start button
player.visible = true; // Show player when game starts
// Start background music
LK.playMusic('bgmusic');
// Initialize first wave
createWave(currentWave);
return;
}
isDragging = true;
// Stop any existing tween for immediate response
tween.stop(player, {
x: true
});
// Quick tween to clicked position for responsive feel
tween(player, {
x: x
}, {
duration: 100,
easing: tween.easeOut
});
var currentTime = Date.now();
if (currentTime - lastTouchTime < 300) {
// Double tap to shoot
player.shoot();
}
lastTouchTime = currentTime;
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
// Stop any existing tween to prevent conflicts
tween.stop(player, {
x: true
});
// Calculate distance for dynamic duration
var distance = Math.abs(x - player.x);
// Dynamic duration based on distance - closer targets move faster
var duration = Math.min(Math.max(distance * 0.8, 50), 200);
// Use smooth easing for natural movement
tween(player, {
x: x
}, {
duration: duration,
easing: tween.easeOut
});
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
isDragging = false;
// Shoot on mouse up for better control
player.shoot();
};
game.update = function () {
if (!gameStarted) return;
updateEnemyFormation();
checkCollisions();
updateUI();
// Gradually decay rhythm multiplier
rhythmMultiplier = Math.max(rhythmMultiplier - 0.001, 1.0);
// Check if wave is complete
if (enemies.length === 0 && waveStarted && !bossActive) {
waveStarted = false;
bossActive = true;
bossDefeated = false;
// Spawn super boss
superBoss = new SuperBoss();
superBoss.x = 1024;
superBoss.y = 300;
game.addChild(superBoss);
}
// Check if boss is defeated
if (bossDefeated && !waveStarted) {
waveDelay = 120; // 2 second delay
currentWave++;
bossDefeated = false;
if (currentWave > 10) {
LK.showYouWin();
return;
}
}
// Start next wave after delay
if (!waveStarted && waveDelay > 0) {
waveDelay--;
if (waveDelay <= 0) {
createWave(currentWave);
}
}
};
nave espacial extraterrestre. In-Game asset. 2d. High contrast. No shadows
un bala lazer de nergia. In-Game asset. 2d. High contrast. No shadows
monster space ship. In-Game asset. 2d. High contrast. No shadows
una espada roja con destellos. In-Game asset. 2d. High contrast. No shadows
espada azul con destellos. In-Game asset. 2d. High contrast. No shadows
un rayo lazer con destellos de fuego alrededor. In-Game asset. 2d. High contrast. No shadows
rayo láser azul con fuego azul alrededor. In-Game asset. 2d. High contrast. No shadows
una esfera blanca con destellos con alas de angel a los lados. In-Game asset. 2d. High contrast. No shadows
una imagen que diga "start" en letras grandes con una fuente alusiva a lso que se usan en video juegos de color metal brillante. In-Game asset. 2d. High contrast. No shadows