/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speedX = 0; self.speedY = 0; self.lifetime = 120; // 2 seconds at 60fps self.update = function () { self.x += self.speedX; self.y += self.speedY; self.lifetime--; // Fade out near end of lifetime if (self.lifetime < 30) { bulletGraphics.alpha = self.lifetime / 30; } }; 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 = 2; self.spawnBeat = LK.ticks; self.baseScale = 1; self.update = function () { // Pulse with beat var beatOffset = (LK.ticks - self.spawnBeat) % 30; if (beatOffset === 0) { enemyGraphics.scaleX = self.baseScale * 1.2; enemyGraphics.scaleY = self.baseScale * 1.2; tween(enemyGraphics, { scaleX: self.baseScale, scaleY: self.baseScale }, { duration: 150 }); } // Move towards player slowly var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * 0.8; self.y += dy / distance * 0.8; } }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xffffff, 200); if (self.health <= 0) { LK.getSound('hit').play(); return true; // Destroyed } return false; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.shootCooldown = 0; self.baseScale = 1; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } // Pulse with music beat (every 30 ticks = 0.5 seconds at 60fps) if (LK.ticks % 30 === 0) { playerGraphics.scaleX = self.baseScale * 1.3; playerGraphics.scaleY = self.baseScale * 1.3; tween(playerGraphics, { scaleX: self.baseScale, scaleY: self.baseScale }, { duration: 200 }); } }; self.shoot = function (targetX, targetY) { if (self.shootCooldown <= 0) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); bullet.speedX = dx / distance * 12; bullet.speedY = dy / distance * 12; bullets.push(bullet); game.addChild(bullet); self.shootCooldown = 10; LK.getSound('shoot').play(); } }; return self; }); var Target = Container.expand(function () { var self = Container.call(this); var targetGraphics = self.attachAsset('target', { anchorX: 0.5, anchorY: 0.5 }); self.spawnBeat = LK.ticks; self.baseScale = 1; self.rotationSpeed = 0.05; self.update = function () { targetGraphics.rotation += self.rotationSpeed; // Strong pulse with beat var beatOffset = (LK.ticks - self.spawnBeat) % 30; if (beatOffset === 0) { targetGraphics.scaleX = self.baseScale * 1.5; targetGraphics.scaleY = self.baseScale * 1.5; tween(targetGraphics, { scaleX: self.baseScale, scaleY: self.baseScale }, { duration: 200 }); } }; self.collect = function () { LK.getSound('collect').play(); // Beat timing bonus var beatOffset = (LK.ticks - self.spawnBeat) % 30; var bonus = 1; if (beatOffset < 5 || beatOffset > 25) { bonus = 2; // Perfect timing LK.effects.flashScreen(0x00ff00, 200); } LK.setScore(LK.getScore() + 10 * bonus); comboCount++; return true; // Collected }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game variables var player; var enemies = []; var targets = []; var bullets = []; var comboCount = 0; var beatCounter = 0; var arenaCenter = { x: 2048 / 2, y: 2732 / 2 }; var arenaRadius = 600; // Create arena var arenaRing = game.attachAsset('arenaRing', { anchorX: 0.5, anchorY: 0.5, x: arenaCenter.x, y: arenaCenter.y }); var arena = game.attachAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: arenaCenter.x, y: arenaCenter.y }); // Create player player = game.addChild(new Player()); player.x = arenaCenter.x; player.y = arenaCenter.y; // Create UI var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var comboTxt = new Text2('', { size: 60, fill: 0xFFAA00 }); comboTxt.anchor.set(1, 0); LK.gui.topRight.addChild(comboTxt); // Start music LK.playMusic('bgmusic'); // Input handling var isDragging = false; game.down = function (x, y, obj) { isDragging = true; // Shoot towards tap/click position player.shoot(x, y); }; game.move = function (x, y, obj) { if (isDragging) { // Keep player within arena bounds var dx = x - arenaCenter.x; var dy = y - arenaCenter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance <= arenaRadius - 40) { player.x = x; player.y = y; } else { // Clamp to arena edge var ratio = (arenaRadius - 40) / distance; player.x = arenaCenter.x + dx * ratio; player.y = arenaCenter.y + dy * ratio; } } }; game.up = function (x, y, obj) { isDragging = false; }; // Spawn function function spawnEnemy() { var enemy = new Enemy(); var angle = Math.random() * Math.PI * 2; var spawnRadius = arenaRadius - 50; enemy.x = arenaCenter.x + Math.cos(angle) * spawnRadius; enemy.y = arenaCenter.y + Math.sin(angle) * spawnRadius; enemies.push(enemy); game.addChild(enemy); } function spawnTarget() { var target = new Target(); var angle = Math.random() * Math.PI * 2; var spawnRadius = Math.random() * (arenaRadius - 100) + 50; target.x = arenaCenter.x + Math.cos(angle) * spawnRadius; target.y = arenaCenter.y + Math.sin(angle) * spawnRadius; targets.push(target); game.addChild(target); } // Main game loop game.update = function () { // Beat-based spawning (every 0.5 seconds = 30 ticks) if (LK.ticks % 30 === 0) { beatCounter++; // Arena pulse effect tween(arena, { scaleX: 1.05, scaleY: 1.05 }, { duration: 100 }); tween(arena, { scaleX: 1, scaleY: 1 }, { duration: 200 }); // Background color pulse var colors = [0x1a1a2e, 0x2a1a3e, 0x1a2a3e]; var colorIndex = beatCounter % colors.length; game.setBackgroundColor(colors[colorIndex]); // Spawn enemies and targets based on beat if (beatCounter % 4 === 0) { spawnEnemy(); } if (beatCounter % 6 === 0) { spawnTarget(); } // Increase difficulty over time if (beatCounter % 32 === 0 && beatCounter > 32) { spawnEnemy(); } } // Update bullets and check collisions for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Remove expired bullets if (bullet.lifetime <= 0) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check bullet-enemy collisions for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { if (enemy.takeDamage()) { enemy.destroy(); enemies.splice(j, 1); LK.setScore(LK.getScore() + 5); } bullet.destroy(); bullets.splice(i, 1); break; } } } // Check player-target collisions for (var k = targets.length - 1; k >= 0; k--) { var target = targets[k]; if (player.intersects(target)) { if (target.collect()) { target.destroy(); targets.splice(k, 1); } } } // Check player-enemy collisions (game over condition) for (var l = 0; l < enemies.length; l++) { var enemy = enemies[l]; if (player.intersects(enemy)) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Update UI scoreTxt.setText(LK.getScore().toString()); if (comboCount > 0) { comboTxt.setText('Combo: ' + comboCount); } else { comboTxt.setText(''); } // Reset combo if no recent collections if (LK.ticks % 180 === 0) { // Every 3 seconds comboCount = Math.max(0, comboCount - 1); } // Win condition if (LK.getScore() >= 500) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 0;
self.speedY = 0;
self.lifetime = 120; // 2 seconds at 60fps
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.lifetime--;
// Fade out near end of lifetime
if (self.lifetime < 30) {
bulletGraphics.alpha = self.lifetime / 30;
}
};
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 = 2;
self.spawnBeat = LK.ticks;
self.baseScale = 1;
self.update = function () {
// Pulse with beat
var beatOffset = (LK.ticks - self.spawnBeat) % 30;
if (beatOffset === 0) {
enemyGraphics.scaleX = self.baseScale * 1.2;
enemyGraphics.scaleY = self.baseScale * 1.2;
tween(enemyGraphics, {
scaleX: self.baseScale,
scaleY: self.baseScale
}, {
duration: 150
});
}
// Move towards player slowly
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * 0.8;
self.y += dy / distance * 0.8;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
LK.getSound('hit').play();
return true; // Destroyed
}
return false;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.baseScale = 1;
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Pulse with music beat (every 30 ticks = 0.5 seconds at 60fps)
if (LK.ticks % 30 === 0) {
playerGraphics.scaleX = self.baseScale * 1.3;
playerGraphics.scaleY = self.baseScale * 1.3;
tween(playerGraphics, {
scaleX: self.baseScale,
scaleY: self.baseScale
}, {
duration: 200
});
}
};
self.shoot = function (targetX, targetY) {
if (self.shootCooldown <= 0) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
bullet.speedX = dx / distance * 12;
bullet.speedY = dy / distance * 12;
bullets.push(bullet);
game.addChild(bullet);
self.shootCooldown = 10;
LK.getSound('shoot').play();
}
};
return self;
});
var Target = Container.expand(function () {
var self = Container.call(this);
var targetGraphics = self.attachAsset('target', {
anchorX: 0.5,
anchorY: 0.5
});
self.spawnBeat = LK.ticks;
self.baseScale = 1;
self.rotationSpeed = 0.05;
self.update = function () {
targetGraphics.rotation += self.rotationSpeed;
// Strong pulse with beat
var beatOffset = (LK.ticks - self.spawnBeat) % 30;
if (beatOffset === 0) {
targetGraphics.scaleX = self.baseScale * 1.5;
targetGraphics.scaleY = self.baseScale * 1.5;
tween(targetGraphics, {
scaleX: self.baseScale,
scaleY: self.baseScale
}, {
duration: 200
});
}
};
self.collect = function () {
LK.getSound('collect').play();
// Beat timing bonus
var beatOffset = (LK.ticks - self.spawnBeat) % 30;
var bonus = 1;
if (beatOffset < 5 || beatOffset > 25) {
bonus = 2; // Perfect timing
LK.effects.flashScreen(0x00ff00, 200);
}
LK.setScore(LK.getScore() + 10 * bonus);
comboCount++;
return true; // Collected
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var player;
var enemies = [];
var targets = [];
var bullets = [];
var comboCount = 0;
var beatCounter = 0;
var arenaCenter = {
x: 2048 / 2,
y: 2732 / 2
};
var arenaRadius = 600;
// Create arena
var arenaRing = game.attachAsset('arenaRing', {
anchorX: 0.5,
anchorY: 0.5,
x: arenaCenter.x,
y: arenaCenter.y
});
var arena = game.attachAsset('arena', {
anchorX: 0.5,
anchorY: 0.5,
x: arenaCenter.x,
y: arenaCenter.y
});
// Create player
player = game.addChild(new Player());
player.x = arenaCenter.x;
player.y = arenaCenter.y;
// Create UI
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var comboTxt = new Text2('', {
size: 60,
fill: 0xFFAA00
});
comboTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(comboTxt);
// Start music
LK.playMusic('bgmusic');
// Input handling
var isDragging = false;
game.down = function (x, y, obj) {
isDragging = true;
// Shoot towards tap/click position
player.shoot(x, y);
};
game.move = function (x, y, obj) {
if (isDragging) {
// Keep player within arena bounds
var dx = x - arenaCenter.x;
var dy = y - arenaCenter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= arenaRadius - 40) {
player.x = x;
player.y = y;
} else {
// Clamp to arena edge
var ratio = (arenaRadius - 40) / distance;
player.x = arenaCenter.x + dx * ratio;
player.y = arenaCenter.y + dy * ratio;
}
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Spawn function
function spawnEnemy() {
var enemy = new Enemy();
var angle = Math.random() * Math.PI * 2;
var spawnRadius = arenaRadius - 50;
enemy.x = arenaCenter.x + Math.cos(angle) * spawnRadius;
enemy.y = arenaCenter.y + Math.sin(angle) * spawnRadius;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnTarget() {
var target = new Target();
var angle = Math.random() * Math.PI * 2;
var spawnRadius = Math.random() * (arenaRadius - 100) + 50;
target.x = arenaCenter.x + Math.cos(angle) * spawnRadius;
target.y = arenaCenter.y + Math.sin(angle) * spawnRadius;
targets.push(target);
game.addChild(target);
}
// Main game loop
game.update = function () {
// Beat-based spawning (every 0.5 seconds = 30 ticks)
if (LK.ticks % 30 === 0) {
beatCounter++;
// Arena pulse effect
tween(arena, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 100
});
tween(arena, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
// Background color pulse
var colors = [0x1a1a2e, 0x2a1a3e, 0x1a2a3e];
var colorIndex = beatCounter % colors.length;
game.setBackgroundColor(colors[colorIndex]);
// Spawn enemies and targets based on beat
if (beatCounter % 4 === 0) {
spawnEnemy();
}
if (beatCounter % 6 === 0) {
spawnTarget();
}
// Increase difficulty over time
if (beatCounter % 32 === 0 && beatCounter > 32) {
spawnEnemy();
}
}
// Update bullets and check collisions
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Remove expired bullets
if (bullet.lifetime <= 0) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet-enemy collisions
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
if (enemy.takeDamage()) {
enemy.destroy();
enemies.splice(j, 1);
LK.setScore(LK.getScore() + 5);
}
bullet.destroy();
bullets.splice(i, 1);
break;
}
}
}
// Check player-target collisions
for (var k = targets.length - 1; k >= 0; k--) {
var target = targets[k];
if (player.intersects(target)) {
if (target.collect()) {
target.destroy();
targets.splice(k, 1);
}
}
}
// Check player-enemy collisions (game over condition)
for (var l = 0; l < enemies.length; l++) {
var enemy = enemies[l];
if (player.intersects(enemy)) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Update UI
scoreTxt.setText(LK.getScore().toString());
if (comboCount > 0) {
comboTxt.setText('Combo: ' + comboCount);
} else {
comboTxt.setText('');
}
// Reset combo if no recent collections
if (LK.ticks % 180 === 0) {
// Every 3 seconds
comboCount = Math.max(0, comboCount - 1);
}
// Win condition
if (LK.getScore() >= 500) {
LK.showYouWin();
}
};