/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Block = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 7.098; self.hitByBullet = false; self.update = function () { self.y += self.speed; }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -20; 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: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a0a }); /**** * Game Code ****/ // Game variables var player; var bullets = []; var blocks = []; var beatIndicator; var scoreMultiplier = 1; var consecutiveBeats = 0; var beatTolerance = 200; // milliseconds var lastBeatTime = 0; var beatInterval = 600; // milliseconds (100 BPM) var nextBlockSpawn = 0; var blockSpawnInterval = 144; var gameStartTime; var beatFlashDuration = 360; // UI Elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 120; scoreText.y = 50; LK.gui.topLeft.addChild(scoreText); var multiplierText = new Text2('x1', { size: 50, fill: 0x00FF00 }); multiplierText.anchor.set(1, 0); multiplierText.x = -120; multiplierText.y = 50; LK.gui.topRight.addChild(multiplierText); // Add concert venue background var concertBackground = game.addChild(LK.getAsset('concertVenue', { anchorX: 0.5, anchorY: 0.5 })); concertBackground.x = 1024; concertBackground.y = 1366; // Initialize player player = game.addChild(new Player()); player.x = 1024; player.y = 2500; // Beat indicator beatIndicator = game.addChild(LK.getAsset('beatIndicator', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 })); beatIndicator.x = 1024; beatIndicator.y = 300; // Start music and initialize game timer LK.playMusic('gameMusic'); gameStartTime = Date.now(); function isOnBeat() { var currentTime = Date.now() - gameStartTime; var timeSinceLastBeat = currentTime % beatInterval; return timeSinceLastBeat < beatTolerance || timeSinceLastBeat > beatInterval - beatTolerance; } function flashBeatIndicator() { beatIndicator.alpha = 1; tween(beatIndicator, { alpha: 0.3 }, { duration: beatFlashDuration }); tween(beatIndicator, { scaleX: 1.3, scaleY: 1.3 }, { duration: beatFlashDuration / 2 }); tween(beatIndicator, { scaleX: 1, scaleY: 1 }, { duration: beatFlashDuration / 2 }); } function updateScore(points, onBeat) { var finalPoints = points; if (onBeat) { finalPoints *= 2; consecutiveBeats++; scoreMultiplier = Math.min(1 + Math.floor(consecutiveBeats / 3), 5); multiplierText.setText('x' + scoreMultiplier); multiplierText.tint = 0x00ff00; tween(multiplierText, { tint: 0xffffff }, { duration: 300 }); } else { consecutiveBeats = 0; scoreMultiplier = 1; multiplierText.setText('x1'); } finalPoints *= scoreMultiplier; LK.setScore(LK.getScore() + finalPoints); scoreText.setText('Score: ' + LK.getScore()); } function spawnBlock() { // Create first block var block1 = new Block(); // Randomly choose spawn direction: 0=left, 1=center, 2=right var spawnDirection = Math.floor(Math.random() * 3); if (spawnDirection === 0) { // Left side spawn block1.x = Math.random() * 600 + 50; // Left third of screen } else if (spawnDirection === 1) { // Center spawn block1.x = Math.random() * 600 + 724; // Center third of screen } else { // Right side spawn block1.x = Math.random() * 600 + 1324; // Right third of screen } block1.y = -50; blocks.push(block1); game.addChild(block1); // Create second block directly below the first one var block2 = new Block(); block2.x = block1.x; // Same x position as first block block2.y = -200; // 150 pixels above the first block blocks.push(block2); game.addChild(block2); } function spawnBullet() { var bullet = new Bullet(); bullet.x = player.x; bullet.y = player.y - 50; bullets.push(bullet); game.addChild(bullet); LK.getSound('shoot').play(); } // Beat tracking game.update = function () { var currentTime = Date.now() - gameStartTime; var currentBeat = Math.floor(currentTime / beatInterval); // Flash beat indicator on beat if (currentBeat !== Math.floor((currentTime - 16) / beatInterval)) { flashBeatIndicator(); } // Spawn blocks if (LK.ticks > nextBlockSpawn) { spawnBlock(); nextBlockSpawn = LK.ticks + blockSpawnInterval; // Gradually increase difficulty if (blockSpawnInterval > 100) { blockSpawnInterval -= 3; } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; if (bullet.lastY === undefined) bullet.lastY = bullet.y; // Remove bullets that go off screen if (bullet.lastY >= -50 && bullet.y < -50) { bullet.destroy(); bullets.splice(i, 1); continue; } bullet.lastY = bullet.y; } // Update blocks and check collisions for (var j = blocks.length - 1; j >= 0; j--) { var block = blocks[j]; if (block.lastY === undefined) block.lastY = block.y; // Check if block reached bottom (game over condition) if (block.lastY < 2732 && block.y >= 2732) { LK.showGameOver(); return; } // Check bullet-block collisions for (var k = bullets.length - 1; k >= 0; k--) { var bullet = bullets[k]; if (bullet.intersects(block) && !block.hitByBullet) { block.hitByBullet = true; var onBeat = isOnBeat(); // Visual feedback if (onBeat) { LK.effects.flashObject(block, 0x00ff00, 200); LK.getSound('beatHit').play(); } else { LK.effects.flashObject(block, 0xffffff, 200); LK.getSound('hit').play(); } updateScore(10, onBeat); // Remove bullet and block bullet.destroy(); bullets.splice(k, 1); block.destroy(); blocks.splice(j, 1); break; } } block.lastY = block.y; } }; // Touch controls and dragging var dragNode = null; function handleMove(x, y, obj) { if (dragNode) { dragNode.x = x; // Keep player within screen bounds if (dragNode.x < 60) dragNode.x = 60; if (dragNode.x > 1988) dragNode.x = 1988; } } game.move = handleMove; game.down = function (x, y, obj) { // Set drag node to player for dragging dragNode = player; // Also call move handler right away to make effect instant handleMove(x, y, obj); // Spawn bullet on touch spawnBullet(); }; game.up = function (x, y, obj) { dragNode = null; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('block', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 7.098;
self.hitByBullet = false;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -20;
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: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a0a
});
/****
* Game Code
****/
// Game variables
var player;
var bullets = [];
var blocks = [];
var beatIndicator;
var scoreMultiplier = 1;
var consecutiveBeats = 0;
var beatTolerance = 200; // milliseconds
var lastBeatTime = 0;
var beatInterval = 600; // milliseconds (100 BPM)
var nextBlockSpawn = 0;
var blockSpawnInterval = 144;
var gameStartTime;
var beatFlashDuration = 360;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var multiplierText = new Text2('x1', {
size: 50,
fill: 0x00FF00
});
multiplierText.anchor.set(1, 0);
multiplierText.x = -120;
multiplierText.y = 50;
LK.gui.topRight.addChild(multiplierText);
// Add concert venue background
var concertBackground = game.addChild(LK.getAsset('concertVenue', {
anchorX: 0.5,
anchorY: 0.5
}));
concertBackground.x = 1024;
concertBackground.y = 1366;
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 2500;
// Beat indicator
beatIndicator = game.addChild(LK.getAsset('beatIndicator', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
}));
beatIndicator.x = 1024;
beatIndicator.y = 300;
// Start music and initialize game timer
LK.playMusic('gameMusic');
gameStartTime = Date.now();
function isOnBeat() {
var currentTime = Date.now() - gameStartTime;
var timeSinceLastBeat = currentTime % beatInterval;
return timeSinceLastBeat < beatTolerance || timeSinceLastBeat > beatInterval - beatTolerance;
}
function flashBeatIndicator() {
beatIndicator.alpha = 1;
tween(beatIndicator, {
alpha: 0.3
}, {
duration: beatFlashDuration
});
tween(beatIndicator, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: beatFlashDuration / 2
});
tween(beatIndicator, {
scaleX: 1,
scaleY: 1
}, {
duration: beatFlashDuration / 2
});
}
function updateScore(points, onBeat) {
var finalPoints = points;
if (onBeat) {
finalPoints *= 2;
consecutiveBeats++;
scoreMultiplier = Math.min(1 + Math.floor(consecutiveBeats / 3), 5);
multiplierText.setText('x' + scoreMultiplier);
multiplierText.tint = 0x00ff00;
tween(multiplierText, {
tint: 0xffffff
}, {
duration: 300
});
} else {
consecutiveBeats = 0;
scoreMultiplier = 1;
multiplierText.setText('x1');
}
finalPoints *= scoreMultiplier;
LK.setScore(LK.getScore() + finalPoints);
scoreText.setText('Score: ' + LK.getScore());
}
function spawnBlock() {
// Create first block
var block1 = new Block();
// Randomly choose spawn direction: 0=left, 1=center, 2=right
var spawnDirection = Math.floor(Math.random() * 3);
if (spawnDirection === 0) {
// Left side spawn
block1.x = Math.random() * 600 + 50; // Left third of screen
} else if (spawnDirection === 1) {
// Center spawn
block1.x = Math.random() * 600 + 724; // Center third of screen
} else {
// Right side spawn
block1.x = Math.random() * 600 + 1324; // Right third of screen
}
block1.y = -50;
blocks.push(block1);
game.addChild(block1);
// Create second block directly below the first one
var block2 = new Block();
block2.x = block1.x; // Same x position as first block
block2.y = -200; // 150 pixels above the first block
blocks.push(block2);
game.addChild(block2);
}
function spawnBullet() {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y - 50;
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
// Beat tracking
game.update = function () {
var currentTime = Date.now() - gameStartTime;
var currentBeat = Math.floor(currentTime / beatInterval);
// Flash beat indicator on beat
if (currentBeat !== Math.floor((currentTime - 16) / beatInterval)) {
flashBeatIndicator();
}
// Spawn blocks
if (LK.ticks > nextBlockSpawn) {
spawnBlock();
nextBlockSpawn = LK.ticks + blockSpawnInterval;
// Gradually increase difficulty
if (blockSpawnInterval > 100) {
blockSpawnInterval -= 3;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.lastY === undefined) bullet.lastY = bullet.y;
// Remove bullets that go off screen
if (bullet.lastY >= -50 && bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
bullet.lastY = bullet.y;
}
// Update blocks and check collisions
for (var j = blocks.length - 1; j >= 0; j--) {
var block = blocks[j];
if (block.lastY === undefined) block.lastY = block.y;
// Check if block reached bottom (game over condition)
if (block.lastY < 2732 && block.y >= 2732) {
LK.showGameOver();
return;
}
// Check bullet-block collisions
for (var k = bullets.length - 1; k >= 0; k--) {
var bullet = bullets[k];
if (bullet.intersects(block) && !block.hitByBullet) {
block.hitByBullet = true;
var onBeat = isOnBeat();
// Visual feedback
if (onBeat) {
LK.effects.flashObject(block, 0x00ff00, 200);
LK.getSound('beatHit').play();
} else {
LK.effects.flashObject(block, 0xffffff, 200);
LK.getSound('hit').play();
}
updateScore(10, onBeat);
// Remove bullet and block
bullet.destroy();
bullets.splice(k, 1);
block.destroy();
blocks.splice(j, 1);
break;
}
}
block.lastY = block.y;
}
};
// Touch controls and dragging
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
// Keep player within screen bounds
if (dragNode.x < 60) dragNode.x = 60;
if (dragNode.x > 1988) dragNode.x = 1988;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Set drag node to player for dragging
dragNode = player;
// Also call move handler right away to make effect instant
handleMove(x, y, obj);
// Spawn bullet on touch
spawnBullet();
};
game.up = function (x, y, obj) {
dragNode = null;
};