/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var DangerZone = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('danger_zone', { anchorX: 0.5, anchorY: 0.5 }); self.expandRate = 2; self.maxSize = 400; self.currentSize = 50; self.expanding = true; self.update = function () { if (self.expanding) { self.currentSize += self.expandRate; if (self.currentSize >= self.maxSize) { self.expanding = false; // Smooth transition to warning colors when fully expanded tween(graphics, { tint: 0xff0000, alpha: 0.9 }, { duration: 500, easing: tween.easeInOut }); } } var scale = self.currentSize / 200; graphics.scaleX = scale; graphics.scaleY = scale; // Beat pulse effect with smooth tweening if (beatPulse > 0) { // Intense pulse on beat tween(graphics, { alpha: 1.0, tint: 0xffffff }, { duration: 100, easing: tween.easeOut }); } else if (beatPulse === 0) { // Return to base state - fully opaque var baseAlpha = 1.0; // Always fully opaque var baseTint = self.expanding ? 0xff0080 : 0xff0000; tween(graphics, { alpha: baseAlpha, tint: baseTint }, { duration: 300, easing: tween.easeInOut }); } }; return self; }); var ObstacleSpinner = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('obstacle_spinner', { anchorX: 0.5, anchorY: 0.5 }); self.rotationSpeed = 0.02; self.beatScale = 1; self.update = function () { graphics.rotation += self.rotationSpeed; // Beat synchronization with smooth tweening if (beatPulse > 0) { // Smooth scale animation on beat tween(graphics, { scaleX: 1.4, scaleY: 1.4, tint: 0xffffff }, { duration: 200, easing: tween.easeOut }); // Spin faster on beat self.rotationSpeed = 0.05; } else if (beatPulse === 0) { // Return to normal scale tween(graphics, { scaleX: 1, scaleY: 1, tint: 0xff4444 }, { duration: 300, easing: tween.easeInOut }); // Normal rotation speed self.rotationSpeed = 0.02; } }; return self; }); var ObstacleWall = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('obstacle_wall', { anchorX: 0.5, anchorY: 0.5 }); self.moveSpeed = 3; self.direction = 1; // 1 for right, -1 for left self.update = function () { self.x += self.moveSpeed * self.direction; // Beat pulse effect with smooth tweening if (beatPulse > 0) { // Smooth scale and tint animation on beat tween(graphics, { scaleY: 1.5, tint: 0xffffff }, { duration: 150, easing: tween.easeOut }); // Brief speed boost on beat self.moveSpeed = 5; } else if (beatPulse === 0) { // Return to normal scale and tint tween(graphics, { scaleY: 1, tint: 0xff6666 }, { duration: 400, easing: tween.easeInOut }); // Normal speed self.moveSpeed = 3; } // Bounce off screen edges with smooth direction change if (self.x > 2048 - 150 || self.x < 150) { self.direction *= -1; // Add a brief flash when bouncing tween(graphics, { tint: 0xffff00 }, { duration: 100, onFinish: function onFinish() { tween(graphics, { tint: 0xff6666 }, { duration: 200 }); } }); } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.targetX = 0; self.targetY = 0; self.update = function () { // Smooth movement towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; self.x += dx * 0.15; self.y += dy * 0.15; // Pulse effect on beat with smooth tweening if (beatPulse > 0) { // Energetic pulse on beat tween(playerGraphics, { scaleX: 1.3, scaleY: 1.3, tint: 0xffffff }, { duration: 100, easing: tween.easeOut }); } else if (beatPulse === 0) { // Return to normal state tween(playerGraphics, { scaleX: 1, scaleY: 1, tint: 0x00ff88 }, { duration: 200, easing: tween.easeInOut }); } }; return self; }); var Projectile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.lifetime = 300; // ticks self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.lifetime--; // Rotate projectile to face movement direction graphics.rotation = Math.atan2(self.velocityY, self.velocityX); // Beat pulse with smooth tweening if (beatPulse > 0) { // Dramatic scale and color change on beat tween(graphics, { scaleX: 2, scaleY: 2, tint: 0xffffff }, { duration: 150, easing: tween.easeOut }); } else if (beatPulse === 0) { // Return to normal state tween(graphics, { scaleX: 1, scaleY: 1, tint: 0xffaa00 }, { duration: 250, easing: tween.easeInOut }); } // Warning effect when lifetime is low if (self.lifetime < 60 && self.lifetime % 10 === 0) { tween(graphics, { tint: 0xff0000 }, { duration: 100, onFinish: function onFinish() { tween(graphics, { tint: 0xffaa00 }, { duration: 100 }); } }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Game variables var player; var obstacles = []; var projectiles = []; var dangerZones = []; var gameTime = 0; var beatCounter = 0; var beatPulse = 0; // 0-1 value for beat synchronization var difficultyLevel = 1; var survivalTime = 0; var scoreMultiplier = 1; var scoreTimer = 0; // Timer for awarding points every 2 seconds // Initialize player player = game.addChild(new Player()); player.x = 1024; player.y = 1366; player.targetX = player.x; player.targetY = player.y; // Initialize starting score LK.setScore(10); // Score display var scoreTxt = new Text2('0', { size: 120, fill: 0x00FF88 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Survival time display var timeTxt = new Text2('0s', { size: 80, fill: 0xFFFFFF }); timeTxt.anchor.set(0, 0); timeTxt.x = 200; timeTxt.y = 100; LK.gui.topLeft.addChild(timeTxt); // Beat synchronization var beatTimer = 0; var beatInterval = 30; // ticks between beats (adjust for music tempo) // Obstacle spawn timers var spinnerSpawnTimer = 0; var wallSpawnTimer = 0; var projectileSpawnTimer = 0; var dangerZoneSpawnTimer = 0; // Touch controls game.down = function (x, y, obj) { player.targetX = x; player.targetY = y; }; game.move = function (x, y, obj) { player.targetX = x; player.targetY = y; }; // Spawn functions function spawnSpinner() { var spinner = new ObstacleSpinner(); // Ensure spawning in different screen quadrants for better coverage var quadrant = Math.floor(Math.random() * 4); switch (quadrant) { case 0: // Top-left spinner.x = Math.random() * 924 + 120; spinner.y = Math.random() * 1246 + 120; break; case 1: // Top-right spinner.x = Math.random() * 924 + 1004; spinner.y = Math.random() * 1246 + 120; break; case 2: // Bottom-left spinner.x = Math.random() * 924 + 120; spinner.y = Math.random() * 1246 + 1366; break; case 3: // Bottom-right spinner.x = Math.random() * 924 + 1004; spinner.y = Math.random() * 1246 + 1366; break; } // Entrance animation spinner.alpha = 0; spinner.scaleX = 0.3; spinner.scaleY = 0.3; tween(spinner, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeOut }); obstacles.push(spinner); game.addChild(spinner); } function spawnWall() { var wall = new ObstacleWall(); wall.x = Math.random() > 0.5 ? 150 : 1898; wall.y = Math.random() * (2732 - 300) + 150; wall.direction = wall.x < 1024 ? 1 : -1; // Entrance animation - slide in from edge var originalX = wall.x; wall.x = wall.direction === 1 ? -300 : 2348; wall.alpha = 0.5; tween(wall, { x: originalX, alpha: 1 }, { duration: 600, easing: tween.easeOut }); obstacles.push(wall); game.addChild(wall); } function spawnProjectile() { var projectile = new Projectile(); // Spawn from edges var side = Math.floor(Math.random() * 4); switch (side) { case 0: // top projectile.x = Math.random() * 2048; projectile.y = -20; break; case 1: // right projectile.x = 2068; projectile.y = Math.random() * 2732; break; case 2: // bottom projectile.x = Math.random() * 2048; projectile.y = 2752; break; case 3: // left projectile.x = -20; projectile.y = Math.random() * 2732; break; } // Aim towards player var dx = player.x - projectile.x; var dy = player.y - projectile.y; var distance = Math.sqrt(dx * dx + dy * dy); var speed = 4 + difficultyLevel; projectile.velocityX = dx / distance * speed; projectile.velocityY = dy / distance * speed; projectiles.push(projectile); game.addChild(projectile); } function spawnDangerZone() { var zone = new DangerZone(); // Strategic positioning - sometimes near player, sometimes in open areas var spawnType = Math.random(); if (spawnType < 0.3) { // Spawn near player (but not too close) var angle = Math.random() * Math.PI * 2; var distance = 300 + Math.random() * 400; zone.x = player.x + Math.cos(angle) * distance; zone.y = player.y + Math.sin(angle) * distance; // Keep within bounds zone.x = Math.max(200, Math.min(1848, zone.x)); zone.y = Math.max(200, Math.min(2532, zone.y)); } else { // Random position across different screen areas var region = Math.floor(Math.random() * 6); switch (region) { case 0: // Top area zone.x = Math.random() * 1648 + 200; zone.y = Math.random() * 600 + 200; break; case 1: // Bottom area zone.x = Math.random() * 1648 + 200; zone.y = Math.random() * 600 + 1932; break; case 2: // Left area zone.x = Math.random() * 600 + 200; zone.y = Math.random() * 2332 + 200; break; case 3: // Right area zone.x = Math.random() * 600 + 1248; zone.y = Math.random() * 2332 + 200; break; case 4: // Center area zone.x = Math.random() * 800 + 624; zone.y = Math.random() * 1000 + 866; break; default: // Random anywhere zone.x = Math.random() * 1648 + 200; zone.y = Math.random() * 2332 + 200; break; } } // Entrance animation - fade in with warning pulse, fully opaque zone.alpha = 0; tween(zone, { alpha: 1.0 }, { duration: 300, easing: tween.easeIn }); // Warning pulse sequence - no alpha changes, only tint changes LK.setTimeout(function () { tween(zone, { tint: 0xffffff }, { duration: 200 }); }, 100); LK.setTimeout(function () { tween(zone, { tint: 0xff0080 }, { duration: 200 }); }, 300); dangerZones.push(zone); game.addChild(zone); } // Start music LK.playMusic('pulse_track', { loop: true }); // Main game loop game.update = function () { gameTime++; survivalTime = Math.floor(gameTime / 60); // Award 10 points every 2 seconds (120 ticks) scoreTimer++; if (scoreTimer >= 120) { LK.setScore(LK.getScore() + 10); scoreTimer = 0; } // Beat synchronization beatTimer++; if (beatTimer >= beatInterval) { beatTimer = 0; beatCounter++; beatPulse = 1; LK.getSound('beat').play(); // Screen flash on beat if (beatCounter % 4 === 0) { LK.effects.flashScreen(0x00ff88, 100); } } // Decay beat pulse if (beatPulse > 0) { beatPulse -= 0.1; if (beatPulse < 0) beatPulse = 0; } // Increase difficulty over time if (survivalTime > 0 && survivalTime % 15 === 0 && gameTime % 60 === 0) { difficultyLevel = Math.min(5, Math.floor(survivalTime / 15) + 1); beatInterval = Math.max(20, 30 - difficultyLevel); } // Spawn obstacles based on beat and difficulty if (beatPulse === 1) { // On beat - spawn multiple obstacles per beat for better coverage if (beatCounter % Math.max(2, 4 - difficultyLevel) === 0) { spawnSpinner(); // Spawn additional spinners for higher difficulty if (difficultyLevel >= 3) { spawnSpinner(); } } if (beatCounter % Math.max(3, 6 - difficultyLevel) === 0) { spawnWall(); } if (beatCounter % Math.max(2, 3 - Math.floor(difficultyLevel / 2)) === 0) { spawnProjectile(); // Spawn additional projectiles for active gameplay if (difficultyLevel >= 2) { spawnProjectile(); } } if (beatCounter % Math.max(4, 8 - difficultyLevel) === 0) { spawnDangerZone(); } } else { // Off beat spawning for continuous action if (gameTime % Math.max(45, 90 - difficultyLevel * 10) === 0) { spawnSpinner(); } if (gameTime % Math.max(60, 120 - difficultyLevel * 15) === 0) { spawnProjectile(); } } // Additional continuous spawning to ensure active gameplay spinnerSpawnTimer++; wallSpawnTimer++; projectileSpawnTimer++; dangerZoneSpawnTimer++; // Ensure minimum obstacle presence if (obstacles.length < 3 + difficultyLevel && spinnerSpawnTimer > 90) { spawnSpinner(); spinnerSpawnTimer = 0; } if (obstacles.length < 2 && wallSpawnTimer > 120) { spawnWall(); wallSpawnTimer = 0; } if (projectiles.length < 2 + difficultyLevel && projectileSpawnTimer > 60) { spawnProjectile(); projectileSpawnTimer = 0; } if (dangerZones.length < 1 && dangerZoneSpawnTimer > 180) { spawnDangerZone(); dangerZoneSpawnTimer = 0; } // Clean up obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Remove off-screen obstacles if (obstacle.x < -200 || obstacle.x > 2248 || obstacle.y < -200 || obstacle.y > 2932) { obstacle.destroy(); obstacles.splice(i, 1); continue; } // Check collision with player if (player.intersects(obstacle)) { // Deduct 15 points for hitting obstacle var newScore = LK.getScore() - 15; LK.setScore(Math.max(0, newScore)); scoreTxt.setText(LK.getScore().toString()); LK.effects.flashScreen(0xff0000, 1000); LK.getSound('danger').play(); // Check if score is 0 or below - game over if (LK.getScore() <= 0) { LK.showGameOver(); return; } // Remove the obstacle that was hit obstacle.destroy(); obstacles.splice(i, 1); continue; } } // Clean up projectiles for (var j = projectiles.length - 1; j >= 0; j--) { var projectile = projectiles[j]; // Remove expired or off-screen projectiles if (projectile.lifetime <= 0 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) { projectile.destroy(); projectiles.splice(j, 1); continue; } // Check collision with obstacle walls - walls block projectiles var projectileBlocked = false; for (var w = 0; w < obstacles.length; w++) { if (obstacles[w] instanceof ObstacleWall && projectile.intersects(obstacles[w])) { // Projectile hits wall - destroy projectile and add visual effect var wall = obstacles[w]; // Create small explosion effect at collision point var wallHitEffect = LK.getAsset('explosion_effect', { anchorX: 0.5, anchorY: 0.5 }); wallHitEffect.x = projectile.x; wallHitEffect.y = projectile.y; wallHitEffect.scaleX = 0.3; wallHitEffect.scaleY = 0.3; wallHitEffect.alpha = 0.9; game.addChild(wallHitEffect); // Animate hit effect tween(wallHitEffect, { scaleX: 1.5, scaleY: 1.5, alpha: 0, tint: 0xffff00 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { wallHitEffect.destroy(); } }); // Flash the wall briefly to show impact var wallGraphics = wall.children[0]; tween(wallGraphics, { tint: 0xffffff }, { duration: 100, onFinish: function onFinish() { tween(wallGraphics, { tint: 0xff6666 }, { duration: 200 }); } }); // Award bonus points for projectile blocked by wall LK.setScore(LK.getScore() + 5); scoreTxt.setText(LK.getScore().toString()); projectile.destroy(); projectiles.splice(j, 1); projectileBlocked = true; break; } } if (projectileBlocked) { continue; } // Check collision with player if (player.intersects(projectile)) { // Deduct 15 points for hitting projectile var newScore = LK.getScore() - 15; LK.setScore(Math.max(0, newScore)); scoreTxt.setText(LK.getScore().toString()); LK.effects.flashScreen(0xff0000, 1000); LK.getSound('danger').play(); // Check if score is 0 or below - game over if (LK.getScore() <= 0) { LK.showGameOver(); return; } // Remove the projectile that was hit projectile.destroy(); projectiles.splice(j, 1); continue; } } // Clean up danger zones for (var k = dangerZones.length - 1; k >= 0; k--) { var zone = dangerZones[k]; // Remove fully expanded zones with disappearing effect if (!zone.expanding && zone.currentSize >= zone.maxSize) { // Create explosion effect at zone position var explosion = LK.getAsset('explosion_effect', { anchorX: 0.5, anchorY: 0.5 }); explosion.x = zone.x; explosion.y = zone.y; explosion.scaleX = 0.5; explosion.scaleY = 0.5; explosion.alpha = 0.8; game.addChild(explosion); // Animate explosion - expand and fade out tween(explosion, { scaleX: 3, scaleY: 3, alpha: 0, tint: 0xff4400 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { explosion.destroy(); } }); // Remove the danger zone immediately zone.destroy(); dangerZones.splice(k, 1); continue; } // Check collision with player (only when zone is large enough) if (zone.currentSize > 100 && player.intersects(zone)) { // Deduct 15 points for hitting danger zone var newScore = LK.getScore() - 15; LK.setScore(Math.max(0, newScore)); scoreTxt.setText(LK.getScore().toString()); LK.effects.flashScreen(0xff0000, 1000); LK.getSound('danger').play(); // Check if score is 0 or below - game over if (LK.getScore() <= 0) { LK.showGameOver(); return; } // Remove the danger zone that was hit zone.destroy(); dangerZones.splice(k, 1); continue; } } // Calculate score bonus based on survival time and proximity to danger var proximityBonus = 0; for (var m = 0; m < obstacles.length; m++) { var dist = Math.sqrt(Math.pow(player.x - obstacles[m].x, 2) + Math.pow(player.y - obstacles[m].y, 2)); if (dist < 150) { proximityBonus += Math.floor((150 - dist) / 10); } } // Add survival and proximity bonus to current score (don't overwrite collision penalties) var survivalBonus = survivalTime * 10; var totalBonus = survivalBonus + proximityBonus; if (totalBonus > 0) { // Reduce bonus rate significantly when score is 30 or higher var bonusDivisor = LK.getScore() >= 30 ? 600 : 60; // 10x slower bonus when score >= 30 LK.setScore(LK.getScore() + Math.floor(totalBonus / bonusDivisor)); // Add bonus at reduced rate } scoreTxt.setText(LK.getScore().toString()); timeTxt.setText(survivalTime + 's'); // Win condition (survive for 2 minutes) if (survivalTime >= 120) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DangerZone = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('danger_zone', {
anchorX: 0.5,
anchorY: 0.5
});
self.expandRate = 2;
self.maxSize = 400;
self.currentSize = 50;
self.expanding = true;
self.update = function () {
if (self.expanding) {
self.currentSize += self.expandRate;
if (self.currentSize >= self.maxSize) {
self.expanding = false;
// Smooth transition to warning colors when fully expanded
tween(graphics, {
tint: 0xff0000,
alpha: 0.9
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
var scale = self.currentSize / 200;
graphics.scaleX = scale;
graphics.scaleY = scale;
// Beat pulse effect with smooth tweening
if (beatPulse > 0) {
// Intense pulse on beat
tween(graphics, {
alpha: 1.0,
tint: 0xffffff
}, {
duration: 100,
easing: tween.easeOut
});
} else if (beatPulse === 0) {
// Return to base state - fully opaque
var baseAlpha = 1.0; // Always fully opaque
var baseTint = self.expanding ? 0xff0080 : 0xff0000;
tween(graphics, {
alpha: baseAlpha,
tint: baseTint
}, {
duration: 300,
easing: tween.easeInOut
});
}
};
return self;
});
var ObstacleSpinner = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('obstacle_spinner', {
anchorX: 0.5,
anchorY: 0.5
});
self.rotationSpeed = 0.02;
self.beatScale = 1;
self.update = function () {
graphics.rotation += self.rotationSpeed;
// Beat synchronization with smooth tweening
if (beatPulse > 0) {
// Smooth scale animation on beat
tween(graphics, {
scaleX: 1.4,
scaleY: 1.4,
tint: 0xffffff
}, {
duration: 200,
easing: tween.easeOut
});
// Spin faster on beat
self.rotationSpeed = 0.05;
} else if (beatPulse === 0) {
// Return to normal scale
tween(graphics, {
scaleX: 1,
scaleY: 1,
tint: 0xff4444
}, {
duration: 300,
easing: tween.easeInOut
});
// Normal rotation speed
self.rotationSpeed = 0.02;
}
};
return self;
});
var ObstacleWall = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('obstacle_wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveSpeed = 3;
self.direction = 1; // 1 for right, -1 for left
self.update = function () {
self.x += self.moveSpeed * self.direction;
// Beat pulse effect with smooth tweening
if (beatPulse > 0) {
// Smooth scale and tint animation on beat
tween(graphics, {
scaleY: 1.5,
tint: 0xffffff
}, {
duration: 150,
easing: tween.easeOut
});
// Brief speed boost on beat
self.moveSpeed = 5;
} else if (beatPulse === 0) {
// Return to normal scale and tint
tween(graphics, {
scaleY: 1,
tint: 0xff6666
}, {
duration: 400,
easing: tween.easeInOut
});
// Normal speed
self.moveSpeed = 3;
}
// Bounce off screen edges with smooth direction change
if (self.x > 2048 - 150 || self.x < 150) {
self.direction *= -1;
// Add a brief flash when bouncing
tween(graphics, {
tint: 0xffff00
}, {
duration: 100,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xff6666
}, {
duration: 200
});
}
});
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.update = function () {
// Smooth movement towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
self.x += dx * 0.15;
self.y += dy * 0.15;
// Pulse effect on beat with smooth tweening
if (beatPulse > 0) {
// Energetic pulse on beat
tween(playerGraphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xffffff
}, {
duration: 100,
easing: tween.easeOut
});
} else if (beatPulse === 0) {
// Return to normal state
tween(playerGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0x00ff88
}, {
duration: 200,
easing: tween.easeInOut
});
}
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.lifetime = 300; // ticks
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.lifetime--;
// Rotate projectile to face movement direction
graphics.rotation = Math.atan2(self.velocityY, self.velocityX);
// Beat pulse with smooth tweening
if (beatPulse > 0) {
// Dramatic scale and color change on beat
tween(graphics, {
scaleX: 2,
scaleY: 2,
tint: 0xffffff
}, {
duration: 150,
easing: tween.easeOut
});
} else if (beatPulse === 0) {
// Return to normal state
tween(graphics, {
scaleX: 1,
scaleY: 1,
tint: 0xffaa00
}, {
duration: 250,
easing: tween.easeInOut
});
}
// Warning effect when lifetime is low
if (self.lifetime < 60 && self.lifetime % 10 === 0) {
tween(graphics, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(graphics, {
tint: 0xffaa00
}, {
duration: 100
});
}
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Game variables
var player;
var obstacles = [];
var projectiles = [];
var dangerZones = [];
var gameTime = 0;
var beatCounter = 0;
var beatPulse = 0; // 0-1 value for beat synchronization
var difficultyLevel = 1;
var survivalTime = 0;
var scoreMultiplier = 1;
var scoreTimer = 0; // Timer for awarding points every 2 seconds
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
player.targetX = player.x;
player.targetY = player.y;
// Initialize starting score
LK.setScore(10);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0x00FF88
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Survival time display
var timeTxt = new Text2('0s', {
size: 80,
fill: 0xFFFFFF
});
timeTxt.anchor.set(0, 0);
timeTxt.x = 200;
timeTxt.y = 100;
LK.gui.topLeft.addChild(timeTxt);
// Beat synchronization
var beatTimer = 0;
var beatInterval = 30; // ticks between beats (adjust for music tempo)
// Obstacle spawn timers
var spinnerSpawnTimer = 0;
var wallSpawnTimer = 0;
var projectileSpawnTimer = 0;
var dangerZoneSpawnTimer = 0;
// Touch controls
game.down = function (x, y, obj) {
player.targetX = x;
player.targetY = y;
};
game.move = function (x, y, obj) {
player.targetX = x;
player.targetY = y;
};
// Spawn functions
function spawnSpinner() {
var spinner = new ObstacleSpinner();
// Ensure spawning in different screen quadrants for better coverage
var quadrant = Math.floor(Math.random() * 4);
switch (quadrant) {
case 0:
// Top-left
spinner.x = Math.random() * 924 + 120;
spinner.y = Math.random() * 1246 + 120;
break;
case 1:
// Top-right
spinner.x = Math.random() * 924 + 1004;
spinner.y = Math.random() * 1246 + 120;
break;
case 2:
// Bottom-left
spinner.x = Math.random() * 924 + 120;
spinner.y = Math.random() * 1246 + 1366;
break;
case 3:
// Bottom-right
spinner.x = Math.random() * 924 + 1004;
spinner.y = Math.random() * 1246 + 1366;
break;
}
// Entrance animation
spinner.alpha = 0;
spinner.scaleX = 0.3;
spinner.scaleY = 0.3;
tween(spinner, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
obstacles.push(spinner);
game.addChild(spinner);
}
function spawnWall() {
var wall = new ObstacleWall();
wall.x = Math.random() > 0.5 ? 150 : 1898;
wall.y = Math.random() * (2732 - 300) + 150;
wall.direction = wall.x < 1024 ? 1 : -1;
// Entrance animation - slide in from edge
var originalX = wall.x;
wall.x = wall.direction === 1 ? -300 : 2348;
wall.alpha = 0.5;
tween(wall, {
x: originalX,
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
obstacles.push(wall);
game.addChild(wall);
}
function spawnProjectile() {
var projectile = new Projectile();
// Spawn from edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// top
projectile.x = Math.random() * 2048;
projectile.y = -20;
break;
case 1:
// right
projectile.x = 2068;
projectile.y = Math.random() * 2732;
break;
case 2:
// bottom
projectile.x = Math.random() * 2048;
projectile.y = 2752;
break;
case 3:
// left
projectile.x = -20;
projectile.y = Math.random() * 2732;
break;
}
// Aim towards player
var dx = player.x - projectile.x;
var dy = player.y - projectile.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var speed = 4 + difficultyLevel;
projectile.velocityX = dx / distance * speed;
projectile.velocityY = dy / distance * speed;
projectiles.push(projectile);
game.addChild(projectile);
}
function spawnDangerZone() {
var zone = new DangerZone();
// Strategic positioning - sometimes near player, sometimes in open areas
var spawnType = Math.random();
if (spawnType < 0.3) {
// Spawn near player (but not too close)
var angle = Math.random() * Math.PI * 2;
var distance = 300 + Math.random() * 400;
zone.x = player.x + Math.cos(angle) * distance;
zone.y = player.y + Math.sin(angle) * distance;
// Keep within bounds
zone.x = Math.max(200, Math.min(1848, zone.x));
zone.y = Math.max(200, Math.min(2532, zone.y));
} else {
// Random position across different screen areas
var region = Math.floor(Math.random() * 6);
switch (region) {
case 0:
// Top area
zone.x = Math.random() * 1648 + 200;
zone.y = Math.random() * 600 + 200;
break;
case 1:
// Bottom area
zone.x = Math.random() * 1648 + 200;
zone.y = Math.random() * 600 + 1932;
break;
case 2:
// Left area
zone.x = Math.random() * 600 + 200;
zone.y = Math.random() * 2332 + 200;
break;
case 3:
// Right area
zone.x = Math.random() * 600 + 1248;
zone.y = Math.random() * 2332 + 200;
break;
case 4:
// Center area
zone.x = Math.random() * 800 + 624;
zone.y = Math.random() * 1000 + 866;
break;
default:
// Random anywhere
zone.x = Math.random() * 1648 + 200;
zone.y = Math.random() * 2332 + 200;
break;
}
}
// Entrance animation - fade in with warning pulse, fully opaque
zone.alpha = 0;
tween(zone, {
alpha: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
// Warning pulse sequence - no alpha changes, only tint changes
LK.setTimeout(function () {
tween(zone, {
tint: 0xffffff
}, {
duration: 200
});
}, 100);
LK.setTimeout(function () {
tween(zone, {
tint: 0xff0080
}, {
duration: 200
});
}, 300);
dangerZones.push(zone);
game.addChild(zone);
}
// Start music
LK.playMusic('pulse_track', {
loop: true
});
// Main game loop
game.update = function () {
gameTime++;
survivalTime = Math.floor(gameTime / 60);
// Award 10 points every 2 seconds (120 ticks)
scoreTimer++;
if (scoreTimer >= 120) {
LK.setScore(LK.getScore() + 10);
scoreTimer = 0;
}
// Beat synchronization
beatTimer++;
if (beatTimer >= beatInterval) {
beatTimer = 0;
beatCounter++;
beatPulse = 1;
LK.getSound('beat').play();
// Screen flash on beat
if (beatCounter % 4 === 0) {
LK.effects.flashScreen(0x00ff88, 100);
}
}
// Decay beat pulse
if (beatPulse > 0) {
beatPulse -= 0.1;
if (beatPulse < 0) beatPulse = 0;
}
// Increase difficulty over time
if (survivalTime > 0 && survivalTime % 15 === 0 && gameTime % 60 === 0) {
difficultyLevel = Math.min(5, Math.floor(survivalTime / 15) + 1);
beatInterval = Math.max(20, 30 - difficultyLevel);
}
// Spawn obstacles based on beat and difficulty
if (beatPulse === 1) {
// On beat - spawn multiple obstacles per beat for better coverage
if (beatCounter % Math.max(2, 4 - difficultyLevel) === 0) {
spawnSpinner();
// Spawn additional spinners for higher difficulty
if (difficultyLevel >= 3) {
spawnSpinner();
}
}
if (beatCounter % Math.max(3, 6 - difficultyLevel) === 0) {
spawnWall();
}
if (beatCounter % Math.max(2, 3 - Math.floor(difficultyLevel / 2)) === 0) {
spawnProjectile();
// Spawn additional projectiles for active gameplay
if (difficultyLevel >= 2) {
spawnProjectile();
}
}
if (beatCounter % Math.max(4, 8 - difficultyLevel) === 0) {
spawnDangerZone();
}
} else {
// Off beat spawning for continuous action
if (gameTime % Math.max(45, 90 - difficultyLevel * 10) === 0) {
spawnSpinner();
}
if (gameTime % Math.max(60, 120 - difficultyLevel * 15) === 0) {
spawnProjectile();
}
}
// Additional continuous spawning to ensure active gameplay
spinnerSpawnTimer++;
wallSpawnTimer++;
projectileSpawnTimer++;
dangerZoneSpawnTimer++;
// Ensure minimum obstacle presence
if (obstacles.length < 3 + difficultyLevel && spinnerSpawnTimer > 90) {
spawnSpinner();
spinnerSpawnTimer = 0;
}
if (obstacles.length < 2 && wallSpawnTimer > 120) {
spawnWall();
wallSpawnTimer = 0;
}
if (projectiles.length < 2 + difficultyLevel && projectileSpawnTimer > 60) {
spawnProjectile();
projectileSpawnTimer = 0;
}
if (dangerZones.length < 1 && dangerZoneSpawnTimer > 180) {
spawnDangerZone();
dangerZoneSpawnTimer = 0;
}
// Clean up obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Remove off-screen obstacles
if (obstacle.x < -200 || obstacle.x > 2248 || obstacle.y < -200 || obstacle.y > 2932) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with player
if (player.intersects(obstacle)) {
// Deduct 15 points for hitting obstacle
var newScore = LK.getScore() - 15;
LK.setScore(Math.max(0, newScore));
scoreTxt.setText(LK.getScore().toString());
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('danger').play();
// Check if score is 0 or below - game over
if (LK.getScore() <= 0) {
LK.showGameOver();
return;
}
// Remove the obstacle that was hit
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
}
// Clean up projectiles
for (var j = projectiles.length - 1; j >= 0; j--) {
var projectile = projectiles[j];
// Remove expired or off-screen projectiles
if (projectile.lifetime <= 0 || projectile.x < -50 || projectile.x > 2098 || projectile.y < -50 || projectile.y > 2782) {
projectile.destroy();
projectiles.splice(j, 1);
continue;
}
// Check collision with obstacle walls - walls block projectiles
var projectileBlocked = false;
for (var w = 0; w < obstacles.length; w++) {
if (obstacles[w] instanceof ObstacleWall && projectile.intersects(obstacles[w])) {
// Projectile hits wall - destroy projectile and add visual effect
var wall = obstacles[w];
// Create small explosion effect at collision point
var wallHitEffect = LK.getAsset('explosion_effect', {
anchorX: 0.5,
anchorY: 0.5
});
wallHitEffect.x = projectile.x;
wallHitEffect.y = projectile.y;
wallHitEffect.scaleX = 0.3;
wallHitEffect.scaleY = 0.3;
wallHitEffect.alpha = 0.9;
game.addChild(wallHitEffect);
// Animate hit effect
tween(wallHitEffect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
tint: 0xffff00
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
wallHitEffect.destroy();
}
});
// Flash the wall briefly to show impact
var wallGraphics = wall.children[0];
tween(wallGraphics, {
tint: 0xffffff
}, {
duration: 100,
onFinish: function onFinish() {
tween(wallGraphics, {
tint: 0xff6666
}, {
duration: 200
});
}
});
// Award bonus points for projectile blocked by wall
LK.setScore(LK.getScore() + 5);
scoreTxt.setText(LK.getScore().toString());
projectile.destroy();
projectiles.splice(j, 1);
projectileBlocked = true;
break;
}
}
if (projectileBlocked) {
continue;
}
// Check collision with player
if (player.intersects(projectile)) {
// Deduct 15 points for hitting projectile
var newScore = LK.getScore() - 15;
LK.setScore(Math.max(0, newScore));
scoreTxt.setText(LK.getScore().toString());
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('danger').play();
// Check if score is 0 or below - game over
if (LK.getScore() <= 0) {
LK.showGameOver();
return;
}
// Remove the projectile that was hit
projectile.destroy();
projectiles.splice(j, 1);
continue;
}
}
// Clean up danger zones
for (var k = dangerZones.length - 1; k >= 0; k--) {
var zone = dangerZones[k];
// Remove fully expanded zones with disappearing effect
if (!zone.expanding && zone.currentSize >= zone.maxSize) {
// Create explosion effect at zone position
var explosion = LK.getAsset('explosion_effect', {
anchorX: 0.5,
anchorY: 0.5
});
explosion.x = zone.x;
explosion.y = zone.y;
explosion.scaleX = 0.5;
explosion.scaleY = 0.5;
explosion.alpha = 0.8;
game.addChild(explosion);
// Animate explosion - expand and fade out
tween(explosion, {
scaleX: 3,
scaleY: 3,
alpha: 0,
tint: 0xff4400
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
// Remove the danger zone immediately
zone.destroy();
dangerZones.splice(k, 1);
continue;
}
// Check collision with player (only when zone is large enough)
if (zone.currentSize > 100 && player.intersects(zone)) {
// Deduct 15 points for hitting danger zone
var newScore = LK.getScore() - 15;
LK.setScore(Math.max(0, newScore));
scoreTxt.setText(LK.getScore().toString());
LK.effects.flashScreen(0xff0000, 1000);
LK.getSound('danger').play();
// Check if score is 0 or below - game over
if (LK.getScore() <= 0) {
LK.showGameOver();
return;
}
// Remove the danger zone that was hit
zone.destroy();
dangerZones.splice(k, 1);
continue;
}
}
// Calculate score bonus based on survival time and proximity to danger
var proximityBonus = 0;
for (var m = 0; m < obstacles.length; m++) {
var dist = Math.sqrt(Math.pow(player.x - obstacles[m].x, 2) + Math.pow(player.y - obstacles[m].y, 2));
if (dist < 150) {
proximityBonus += Math.floor((150 - dist) / 10);
}
}
// Add survival and proximity bonus to current score (don't overwrite collision penalties)
var survivalBonus = survivalTime * 10;
var totalBonus = survivalBonus + proximityBonus;
if (totalBonus > 0) {
// Reduce bonus rate significantly when score is 30 or higher
var bonusDivisor = LK.getScore() >= 30 ? 600 : 60; // 10x slower bonus when score >= 30
LK.setScore(LK.getScore() + Math.floor(totalBonus / bonusDivisor)); // Add bonus at reduced rate
}
scoreTxt.setText(LK.getScore().toString());
timeTxt.setText(survivalTime + 's');
// Win condition (survive for 2 minutes)
if (survivalTime >= 120) {
LK.showYouWin();
}
};
Sawblade with blue inside. No background. Transparent background. Blank background. No shadows. 3d. In-Game asset. flat
Bomb. No background. Transparent background. Blank background. No shadows. 3d. In-Game asset. flat
Explosion. No background. Transparent background. Blank background. No shadows. 3d. In-Game asset. flat
Pink and green enemy. No background. Transparent background. Blank background. No shadows. 3d. In-Game asset. flat