/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AlienLaser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('beat_marker', { anchorX: 0.5, anchorY: 0.5 }); laserGraphics.tint = 0xFF0000; // Red lasers self.speed = 10; self.update = function () { self.y += self.speed; }; return self; }); var AlienShip = Container.expand(function () { var self = Container.call(this); var alienGraphics = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); alienGraphics.tint = 0xFF0000; // Red tint for alien ship self.health = 5; self.fireTimer = 0; self.fireInterval = 60; // Fire every second self.moveDirection = 1; self.speed = 2; self.update = function () { // Move side to side self.x += self.moveDirection * self.speed; if (self.x <= 200 || self.x >= 1848) { self.moveDirection *= -1; } // Fire lasers self.fireTimer++; if (self.fireTimer >= self.fireInterval) { self.fireTimer = 0; createAlienLaser(self.x, self.y + 100); } }; return self; }); var BeatMarker = Container.expand(function () { var self = Container.call(this); var markerGraphics = self.attachAsset('beat_marker', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.intensity = 1.0; self.update = function () { self.y += self.speed; // Fade out as it moves markerGraphics.alpha = Math.max(0, 1 - self.y / 2732); }; return self; }); var Note = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('note', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.collected = false; self.beatTime = 0; self.update = function () { self.y += self.speed; // Pulsing effect var pulse = 0.8 + Math.sin(LK.ticks * 0.2) * 0.2; noteGraphics.scaleX = pulse; noteGraphics.scaleY = pulse; }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.wasHit = false; self.update = function () { self.y += self.speed; }; return self; }); var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('beat_marker', { anchorX: 0.5, anchorY: 0.5 }); bulletGraphics.tint = 0x00FF00; // Green bullets bulletGraphics.rotation = Math.PI; self.speed = 15; self.update = function () { self.y -= self.speed; }; return self; }); var Ship = Container.expand(function () { var self = Container.call(this); var shipGraphics = self.attachAsset('ship', { anchorX: 0.5, anchorY: 0.5 }); self.speed = shipSpeed; self.targetX = 1024; self.isAlive = true; self.update = function () { if (!self.isAlive) return; // Smooth movement towards target var diff = self.targetX - self.x; self.x += diff * 0.15; // Keep ship in bounds if (self.x < 100) self.x = 100; if (self.x > 1948) self.x = 1948; }; return self; }); var TunnelSegment = Container.expand(function () { var self = Container.call(this); var tunnelGraphics = self.attachAsset('tunnel', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Game variables var ship; var tunnelSegments = []; var obstacles = []; var notes = []; var beatMarkers = []; var combo = 0; var beatTimer = 0; var beatInterval = 30; // frames between beats (60fps / 2 = 30 frames = 0.5 seconds) var gameSpeed = 8; var shipSpeed = 8; // Initial ship speed var shipLane = 1; // 0 = left, 1 = center, 2 = right var lanes = [512, 1024, 1536]; var obstacleHits = 0; // Counter for obstacle hits var immunityActive = false; // Immunity power state var immunityTimer = 0; // Timer for immunity duration var immunityDuration = 600; // 10 seconds at 60fps var alienShip = null; // Alien boss ship var playerBullets = []; // Player bullets var alienLasers = []; // Alien lasers var alienSpawned = false; // Track if alien has been spawned // UI Elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var comboTxt = new Text2('Combo: 0', { size: 50, fill: 0xFFA502 }); comboTxt.anchor.set(0, 0); comboTxt.x = 50; comboTxt.y = 150; LK.gui.addChild(comboTxt); var immunityTxt = new Text2('', { size: 45, fill: 0x00D2FF }); immunityTxt.anchor.set(0, 0); immunityTxt.x = 50; immunityTxt.y = 220; LK.gui.addChild(immunityTxt); // Initialize ship ship = game.addChild(new Ship()); ship.x = lanes[shipLane]; ship.y = 2400; // Create initial tunnel segments function createTunnelSegment(y) { var segment = new TunnelSegment(); segment.x = 1024; segment.y = y; segment.alpha = 0.3; return game.addChild(segment); } // Initialize tunnel for (var i = 0; i < 30; i++) { tunnelSegments.push(createTunnelSegment(i * 100 - 500)); } // Create obstacle function createObstacle(lane, y) { var obstacle = new Obstacle(); obstacle.x = lanes[lane]; obstacle.y = y; obstacles.push(obstacle); return game.addChild(obstacle); } // Create note function createNote(lane, y, beatTime) { var note = new Note(); note.x = lanes[lane]; note.y = y; note.beatTime = beatTime; notes.push(note); return game.addChild(note); } // Create beat marker function createBeatMarker() { var marker = new BeatMarker(); marker.x = ship.x; marker.y = ship.y + 100; // Spawn from back of ship instead of front beatMarkers.push(marker); return game.addChild(marker); } // Create player bullet function createPlayerBullet(x, y) { var bullet = new PlayerBullet(); bullet.x = x; bullet.y = y; playerBullets.push(bullet); return game.addChild(bullet); } // Create alien laser function createAlienLaser(x, y) { var laser = new AlienLaser(); laser.x = x; laser.y = y; alienLasers.push(laser); return game.addChild(laser); } // Create alien ship function createAlienShip() { alienShip = new AlienShip(); alienShip.x = 1024; alienShip.y = 400; return game.addChild(alienShip); } // Handle input for lane switching function handleInput(targetLane) { if (targetLane >= 0 && targetLane <= 2) { shipLane = targetLane; ship.targetX = lanes[shipLane]; } } // Touch controls game.down = function (x, y, obj) { // Divide screen into three lanes for touch control if (x < 683) { handleInput(0); // Left lane } else if (x < 1365) { handleInput(1); // Center lane } else { handleInput(2); // Right lane } // Check if touching on beat checkBeatTiming(); // Fire bullet if alien ship exists if (alienShip && ship.isAlive) { createPlayerBullet(ship.x, ship.y - 50); } }; function checkBeatTiming() { var beatAccuracy = Math.abs(beatTimer % beatInterval - beatInterval / 2); var maxAccuracy = beatInterval * 0.3; // 30% tolerance if (beatAccuracy <= maxAccuracy) { // Good timing tween(ship, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100 }); tween(ship, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); } else { // Bad timing LK.getSound('miss').play(); } updateUI(); } function updateUI() { scoreTxt.setText('Score: ' + LK.getScore()); comboTxt.setText('Combo: ' + combo); if (immunityActive) { var remainingSeconds = Math.ceil(immunityTimer / 60); immunityTxt.setText('IMMUNITY: ' + remainingSeconds + 's'); } else { immunityTxt.setText(''); } } // Spawn content based on beat function spawnContent() { if (beatTimer % beatInterval === 0) { // Create beat marker createBeatMarker(); // Randomly spawn obstacles and notes var spawnChance = Math.random(); // Check if there's enough space before spawning obstacle var canSpawnObstacle = true; for (var i = 0; i < obstacles.length; i++) { if (obstacles[i].y < 1000) { // Check if any obstacle is too close to top - increased distance canSpawnObstacle = false; break; } } if (spawnChance < 0.15 && canSpawnObstacle && LK.getScore() < 10000) { // Reduced from 0.3 to 0.15 // Spawn obstacle (only if score is below 10000) var obstacleLane = Math.floor(Math.random() * 3); createObstacle(obstacleLane, -100); } // Check if there's enough space before spawning note var canSpawnNote = true; for (var i = 0; i < notes.length; i++) { if (notes[i].y < 800) { // Check if any note is too close to top canSpawnNote = false; break; } } if (spawnChance > 0.6 && canSpawnNote) { // Spawn note var noteLane = Math.floor(Math.random() * 3); createNote(noteLane, -100, LK.ticks + 300); } } } // Game update loop game.update = function () { if (!ship.isAlive) return; beatTimer++; // Spawn new content spawnContent(); // Manage tunnel segments for (var i = tunnelSegments.length - 1; i >= 0; i--) { var segment = tunnelSegments[i]; if (segment.y > 2800) { segment.destroy(); tunnelSegments.splice(i, 1); // Add new segment at the top tunnelSegments.push(createTunnelSegment(-200)); } } // Check obstacle collisions for (var j = obstacles.length - 1; j >= 0; j--) { var obstacle = obstacles[j]; if (obstacle.y > 2800) { obstacle.destroy(); obstacles.splice(j, 1); continue; } if (!obstacle.wasHit && obstacle.intersects(ship)) { obstacle.wasHit = true; // Check if immunity is active if (!immunityActive) { obstacleHits++; // Increment obstacle hit counter combo = 0; LK.effects.flashScreen(0xff4757, 500); LK.getSound('miss').play(); // Reduce score LK.setScore(Math.max(0, LK.getScore() - 50)); } else { // Immunity protects from damage - just visual feedback LK.effects.flashScreen(0x00D2FF, 200); } updateUI(); // Check if hit 3 obstacles - game over with explosion if (obstacleHits >= 3) { ship.isAlive = false; // Ship explosion effect tween(ship, { scaleX: 2, scaleY: 2, alpha: 0, rotation: Math.PI * 2 }, { duration: 1000, onFinish: function onFinish() { LK.showGameOver(); } }); } // Check game over condition if (LK.getScore() <= -100) { ship.isAlive = false; LK.showGameOver(); } } } // Check note collections for (var k = notes.length - 1; k >= 0; k--) { var note = notes[k]; if (note.y > 2800) { // Reset combo when note is missed (not collected) if (!note.collected) { combo = 0; updateUI(); } note.destroy(); notes.splice(k, 1); continue; } if (!note.collected && note.intersects(ship)) { note.collected = true; // Check timing accuracy var timingAccuracy = Math.abs(beatTimer % beatInterval - beatInterval / 2); var maxAccuracy = beatInterval * 0.4; if (timingAccuracy <= maxAccuracy) { // Perfect timing - only time combo increases combo++; LK.setScore(LK.getScore() + 20 * combo); LK.getSound('notamusical').play(); // Increase ship speed shipSpeed += 0.1; ship.speed = shipSpeed; // Activate immunity power every 20 combo points if (combo % 20 === 0 && combo > 0) { immunityActive = true; immunityTimer = immunityDuration; // Visual feedback for immunity activation tween(ship, { tint: 0x00D2FF }, { duration: 300 }); } // Visual feedback tween(note, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 200 }); } else { // Poor timing - reset combo when missing note timing combo = 0; } note.destroy(); notes.splice(k, 1); updateUI(); } } // Update beat markers to follow ship and clean up for (var l = beatMarkers.length - 1; l >= 0; l--) { var marker = beatMarkers[l]; // Make beat marker follow ship's X position marker.x = ship.x; if (marker.y > 2800 || marker.alpha <= 0) { marker.destroy(); beatMarkers.splice(l, 1); } } // Increase difficulty over time if (LK.ticks % 1800 === 0) { // Every 30 seconds gameSpeed += 0.5; beatInterval = Math.max(20, beatInterval - 1); // Update speeds for all moving objects for (var m = 0; m < tunnelSegments.length; m++) { tunnelSegments[m].speed = gameSpeed; } for (var n = 0; n < obstacles.length; n++) { obstacles[n].speed = gameSpeed; } for (var o = 0; o < notes.length; o++) { notes[o].speed = gameSpeed; } for (var p = 0; p < beatMarkers.length; p++) { beatMarkers[p].speed = gameSpeed; } } // Tunnel pulsing effect based on beat var beatPulse = Math.sin(beatTimer % beatInterval / beatInterval * Math.PI * 2); for (var q = 0; q < tunnelSegments.length; q++) { tunnelSegments[q].alpha = 0.2 + Math.abs(beatPulse) * 0.3; } // Manage immunity timer if (immunityActive) { immunityTimer--; if (immunityTimer <= 0) { immunityActive = false; // Remove immunity visual effect tween(ship, { tint: 0xFFFFFF }, { duration: 300 }); } } // Spawn alien ship at 10000 points if (LK.getScore() >= 10000 && !alienSpawned) { alienSpawned = true; createAlienShip(); } // Manage player bullets for (var r = playerBullets.length - 1; r >= 0; r--) { var bullet = playerBullets[r]; if (bullet.y < -100) { bullet.destroy(); playerBullets.splice(r, 1); continue; } // Check collision with alien ship if (alienShip && bullet.intersects(alienShip)) { bullet.destroy(); playerBullets.splice(r, 1); alienShip.health--; // Flash alien ship when hit tween(alienShip, { tint: 0xFFFFFF }, { duration: 100 }); tween(alienShip, { tint: 0xFF0000 }, { duration: 100 }); // Destroy alien ship when health reaches 0 if (alienShip.health <= 0) { tween(alienShip, { scaleX: 2, scaleY: 2, alpha: 0, rotation: Math.PI * 2 }, { duration: 1000, onFinish: function onFinish() { if (alienShip) { alienShip.destroy(); alienShip = null; } // Show victory when alien ship is destroyed LK.showYouWin(); } }); LK.setScore(LK.getScore() + 1000); updateUI(); } } } // Manage alien lasers for (var s = alienLasers.length - 1; s >= 0; s--) { var laser = alienLasers[s]; if (laser.y > 2800) { laser.destroy(); alienLasers.splice(s, 1); continue; } // Check collision with player ship if (laser.intersects(ship) && ship.isAlive) { laser.destroy(); alienLasers.splice(s, 1); if (!immunityActive) { obstacleHits++; combo = 0; LK.effects.flashScreen(0xff4757, 500); LK.getSound('miss').play(); LK.setScore(Math.max(0, LK.getScore() - 50)); // Check if hit 3 times - game over if (obstacleHits >= 3) { ship.isAlive = false; tween(ship, { scaleX: 2, scaleY: 2, alpha: 0, rotation: Math.PI * 2 }, { duration: 1000, onFinish: function onFinish() { LK.showGameOver(); } }); } } else { LK.effects.flashScreen(0x00D2FF, 200); } updateUI(); } } }; // Start background music LK.playMusic('background');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AlienLaser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('beat_marker', {
anchorX: 0.5,
anchorY: 0.5
});
laserGraphics.tint = 0xFF0000; // Red lasers
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
var AlienShip = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
alienGraphics.tint = 0xFF0000; // Red tint for alien ship
self.health = 5;
self.fireTimer = 0;
self.fireInterval = 60; // Fire every second
self.moveDirection = 1;
self.speed = 2;
self.update = function () {
// Move side to side
self.x += self.moveDirection * self.speed;
if (self.x <= 200 || self.x >= 1848) {
self.moveDirection *= -1;
}
// Fire lasers
self.fireTimer++;
if (self.fireTimer >= self.fireInterval) {
self.fireTimer = 0;
createAlienLaser(self.x, self.y + 100);
}
};
return self;
});
var BeatMarker = Container.expand(function () {
var self = Container.call(this);
var markerGraphics = self.attachAsset('beat_marker', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.intensity = 1.0;
self.update = function () {
self.y += self.speed;
// Fade out as it moves
markerGraphics.alpha = Math.max(0, 1 - self.y / 2732);
};
return self;
});
var Note = Container.expand(function () {
var self = Container.call(this);
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.collected = false;
self.beatTime = 0;
self.update = function () {
self.y += self.speed;
// Pulsing effect
var pulse = 0.8 + Math.sin(LK.ticks * 0.2) * 0.2;
noteGraphics.scaleX = pulse;
noteGraphics.scaleY = pulse;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.wasHit = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('beat_marker', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphics.tint = 0x00FF00; // Green bullets
bulletGraphics.rotation = Math.PI;
self.speed = 15;
self.update = function () {
self.y -= self.speed;
};
return self;
});
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = shipSpeed;
self.targetX = 1024;
self.isAlive = true;
self.update = function () {
if (!self.isAlive) return;
// Smooth movement towards target
var diff = self.targetX - self.x;
self.x += diff * 0.15;
// Keep ship in bounds
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
};
return self;
});
var TunnelSegment = Container.expand(function () {
var self = Container.call(this);
var tunnelGraphics = self.attachAsset('tunnel', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Game variables
var ship;
var tunnelSegments = [];
var obstacles = [];
var notes = [];
var beatMarkers = [];
var combo = 0;
var beatTimer = 0;
var beatInterval = 30; // frames between beats (60fps / 2 = 30 frames = 0.5 seconds)
var gameSpeed = 8;
var shipSpeed = 8; // Initial ship speed
var shipLane = 1; // 0 = left, 1 = center, 2 = right
var lanes = [512, 1024, 1536];
var obstacleHits = 0; // Counter for obstacle hits
var immunityActive = false; // Immunity power state
var immunityTimer = 0; // Timer for immunity duration
var immunityDuration = 600; // 10 seconds at 60fps
var alienShip = null; // Alien boss ship
var playerBullets = []; // Player bullets
var alienLasers = []; // Alien lasers
var alienSpawned = false; // Track if alien has been spawned
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 50,
fill: 0xFFA502
});
comboTxt.anchor.set(0, 0);
comboTxt.x = 50;
comboTxt.y = 150;
LK.gui.addChild(comboTxt);
var immunityTxt = new Text2('', {
size: 45,
fill: 0x00D2FF
});
immunityTxt.anchor.set(0, 0);
immunityTxt.x = 50;
immunityTxt.y = 220;
LK.gui.addChild(immunityTxt);
// Initialize ship
ship = game.addChild(new Ship());
ship.x = lanes[shipLane];
ship.y = 2400;
// Create initial tunnel segments
function createTunnelSegment(y) {
var segment = new TunnelSegment();
segment.x = 1024;
segment.y = y;
segment.alpha = 0.3;
return game.addChild(segment);
}
// Initialize tunnel
for (var i = 0; i < 30; i++) {
tunnelSegments.push(createTunnelSegment(i * 100 - 500));
}
// Create obstacle
function createObstacle(lane, y) {
var obstacle = new Obstacle();
obstacle.x = lanes[lane];
obstacle.y = y;
obstacles.push(obstacle);
return game.addChild(obstacle);
}
// Create note
function createNote(lane, y, beatTime) {
var note = new Note();
note.x = lanes[lane];
note.y = y;
note.beatTime = beatTime;
notes.push(note);
return game.addChild(note);
}
// Create beat marker
function createBeatMarker() {
var marker = new BeatMarker();
marker.x = ship.x;
marker.y = ship.y + 100; // Spawn from back of ship instead of front
beatMarkers.push(marker);
return game.addChild(marker);
}
// Create player bullet
function createPlayerBullet(x, y) {
var bullet = new PlayerBullet();
bullet.x = x;
bullet.y = y;
playerBullets.push(bullet);
return game.addChild(bullet);
}
// Create alien laser
function createAlienLaser(x, y) {
var laser = new AlienLaser();
laser.x = x;
laser.y = y;
alienLasers.push(laser);
return game.addChild(laser);
}
// Create alien ship
function createAlienShip() {
alienShip = new AlienShip();
alienShip.x = 1024;
alienShip.y = 400;
return game.addChild(alienShip);
}
// Handle input for lane switching
function handleInput(targetLane) {
if (targetLane >= 0 && targetLane <= 2) {
shipLane = targetLane;
ship.targetX = lanes[shipLane];
}
}
// Touch controls
game.down = function (x, y, obj) {
// Divide screen into three lanes for touch control
if (x < 683) {
handleInput(0); // Left lane
} else if (x < 1365) {
handleInput(1); // Center lane
} else {
handleInput(2); // Right lane
}
// Check if touching on beat
checkBeatTiming();
// Fire bullet if alien ship exists
if (alienShip && ship.isAlive) {
createPlayerBullet(ship.x, ship.y - 50);
}
};
function checkBeatTiming() {
var beatAccuracy = Math.abs(beatTimer % beatInterval - beatInterval / 2);
var maxAccuracy = beatInterval * 0.3; // 30% tolerance
if (beatAccuracy <= maxAccuracy) {
// Good timing
tween(ship, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100
});
tween(ship, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
} else {
// Bad timing
LK.getSound('miss').play();
}
updateUI();
}
function updateUI() {
scoreTxt.setText('Score: ' + LK.getScore());
comboTxt.setText('Combo: ' + combo);
if (immunityActive) {
var remainingSeconds = Math.ceil(immunityTimer / 60);
immunityTxt.setText('IMMUNITY: ' + remainingSeconds + 's');
} else {
immunityTxt.setText('');
}
}
// Spawn content based on beat
function spawnContent() {
if (beatTimer % beatInterval === 0) {
// Create beat marker
createBeatMarker();
// Randomly spawn obstacles and notes
var spawnChance = Math.random();
// Check if there's enough space before spawning obstacle
var canSpawnObstacle = true;
for (var i = 0; i < obstacles.length; i++) {
if (obstacles[i].y < 1000) {
// Check if any obstacle is too close to top - increased distance
canSpawnObstacle = false;
break;
}
}
if (spawnChance < 0.15 && canSpawnObstacle && LK.getScore() < 10000) {
// Reduced from 0.3 to 0.15
// Spawn obstacle (only if score is below 10000)
var obstacleLane = Math.floor(Math.random() * 3);
createObstacle(obstacleLane, -100);
}
// Check if there's enough space before spawning note
var canSpawnNote = true;
for (var i = 0; i < notes.length; i++) {
if (notes[i].y < 800) {
// Check if any note is too close to top
canSpawnNote = false;
break;
}
}
if (spawnChance > 0.6 && canSpawnNote) {
// Spawn note
var noteLane = Math.floor(Math.random() * 3);
createNote(noteLane, -100, LK.ticks + 300);
}
}
}
// Game update loop
game.update = function () {
if (!ship.isAlive) return;
beatTimer++;
// Spawn new content
spawnContent();
// Manage tunnel segments
for (var i = tunnelSegments.length - 1; i >= 0; i--) {
var segment = tunnelSegments[i];
if (segment.y > 2800) {
segment.destroy();
tunnelSegments.splice(i, 1);
// Add new segment at the top
tunnelSegments.push(createTunnelSegment(-200));
}
}
// Check obstacle collisions
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
if (obstacle.y > 2800) {
obstacle.destroy();
obstacles.splice(j, 1);
continue;
}
if (!obstacle.wasHit && obstacle.intersects(ship)) {
obstacle.wasHit = true;
// Check if immunity is active
if (!immunityActive) {
obstacleHits++; // Increment obstacle hit counter
combo = 0;
LK.effects.flashScreen(0xff4757, 500);
LK.getSound('miss').play();
// Reduce score
LK.setScore(Math.max(0, LK.getScore() - 50));
} else {
// Immunity protects from damage - just visual feedback
LK.effects.flashScreen(0x00D2FF, 200);
}
updateUI();
// Check if hit 3 obstacles - game over with explosion
if (obstacleHits >= 3) {
ship.isAlive = false;
// Ship explosion effect
tween(ship, {
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 1000,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
// Check game over condition
if (LK.getScore() <= -100) {
ship.isAlive = false;
LK.showGameOver();
}
}
}
// Check note collections
for (var k = notes.length - 1; k >= 0; k--) {
var note = notes[k];
if (note.y > 2800) {
// Reset combo when note is missed (not collected)
if (!note.collected) {
combo = 0;
updateUI();
}
note.destroy();
notes.splice(k, 1);
continue;
}
if (!note.collected && note.intersects(ship)) {
note.collected = true;
// Check timing accuracy
var timingAccuracy = Math.abs(beatTimer % beatInterval - beatInterval / 2);
var maxAccuracy = beatInterval * 0.4;
if (timingAccuracy <= maxAccuracy) {
// Perfect timing - only time combo increases
combo++;
LK.setScore(LK.getScore() + 20 * combo);
LK.getSound('notamusical').play();
// Increase ship speed
shipSpeed += 0.1;
ship.speed = shipSpeed;
// Activate immunity power every 20 combo points
if (combo % 20 === 0 && combo > 0) {
immunityActive = true;
immunityTimer = immunityDuration;
// Visual feedback for immunity activation
tween(ship, {
tint: 0x00D2FF
}, {
duration: 300
});
}
// Visual feedback
tween(note, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200
});
} else {
// Poor timing - reset combo when missing note timing
combo = 0;
}
note.destroy();
notes.splice(k, 1);
updateUI();
}
}
// Update beat markers to follow ship and clean up
for (var l = beatMarkers.length - 1; l >= 0; l--) {
var marker = beatMarkers[l];
// Make beat marker follow ship's X position
marker.x = ship.x;
if (marker.y > 2800 || marker.alpha <= 0) {
marker.destroy();
beatMarkers.splice(l, 1);
}
}
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
gameSpeed += 0.5;
beatInterval = Math.max(20, beatInterval - 1);
// Update speeds for all moving objects
for (var m = 0; m < tunnelSegments.length; m++) {
tunnelSegments[m].speed = gameSpeed;
}
for (var n = 0; n < obstacles.length; n++) {
obstacles[n].speed = gameSpeed;
}
for (var o = 0; o < notes.length; o++) {
notes[o].speed = gameSpeed;
}
for (var p = 0; p < beatMarkers.length; p++) {
beatMarkers[p].speed = gameSpeed;
}
}
// Tunnel pulsing effect based on beat
var beatPulse = Math.sin(beatTimer % beatInterval / beatInterval * Math.PI * 2);
for (var q = 0; q < tunnelSegments.length; q++) {
tunnelSegments[q].alpha = 0.2 + Math.abs(beatPulse) * 0.3;
}
// Manage immunity timer
if (immunityActive) {
immunityTimer--;
if (immunityTimer <= 0) {
immunityActive = false;
// Remove immunity visual effect
tween(ship, {
tint: 0xFFFFFF
}, {
duration: 300
});
}
}
// Spawn alien ship at 10000 points
if (LK.getScore() >= 10000 && !alienSpawned) {
alienSpawned = true;
createAlienShip();
}
// Manage player bullets
for (var r = playerBullets.length - 1; r >= 0; r--) {
var bullet = playerBullets[r];
if (bullet.y < -100) {
bullet.destroy();
playerBullets.splice(r, 1);
continue;
}
// Check collision with alien ship
if (alienShip && bullet.intersects(alienShip)) {
bullet.destroy();
playerBullets.splice(r, 1);
alienShip.health--;
// Flash alien ship when hit
tween(alienShip, {
tint: 0xFFFFFF
}, {
duration: 100
});
tween(alienShip, {
tint: 0xFF0000
}, {
duration: 100
});
// Destroy alien ship when health reaches 0
if (alienShip.health <= 0) {
tween(alienShip, {
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 1000,
onFinish: function onFinish() {
if (alienShip) {
alienShip.destroy();
alienShip = null;
}
// Show victory when alien ship is destroyed
LK.showYouWin();
}
});
LK.setScore(LK.getScore() + 1000);
updateUI();
}
}
}
// Manage alien lasers
for (var s = alienLasers.length - 1; s >= 0; s--) {
var laser = alienLasers[s];
if (laser.y > 2800) {
laser.destroy();
alienLasers.splice(s, 1);
continue;
}
// Check collision with player ship
if (laser.intersects(ship) && ship.isAlive) {
laser.destroy();
alienLasers.splice(s, 1);
if (!immunityActive) {
obstacleHits++;
combo = 0;
LK.effects.flashScreen(0xff4757, 500);
LK.getSound('miss').play();
LK.setScore(Math.max(0, LK.getScore() - 50));
// Check if hit 3 times - game over
if (obstacleHits >= 3) {
ship.isAlive = false;
tween(ship, {
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 1000,
onFinish: function onFinish() {
LK.showGameOver();
}
});
}
} else {
LK.effects.flashScreen(0x00D2FF, 200);
}
updateUI();
}
}
};
// Start background music
LK.playMusic('background');