/****
* 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;
};