/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Beat Particle var BeatParticle = Container.expand(function () { var self = Container.call(this); var p = self.attachAsset('beatParticle', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.alpha = 1; self.scale = 1; self.update = function () { self.x += self.vx; self.y += self.vy; self.scale += 0.02; self.alpha -= 0.018; p.scaleX = p.scaleY = self.scale; if (self.alpha <= 0) { self.destroyed = true; } }; return self; }); // BreathBar: Visual breath meter with fill, danger, and update logic var BreathBar = Container.expand(function () { var self = Container.call(this); // Background var bg = self.attachAsset('breathBarBg', { anchorX: 0.5, anchorY: 0, x: 0, y: 0 }); // Danger zone (red, bottom) var danger = self.attachAsset('breathBarDanger', { anchorX: 0.5, anchorY: 0, x: 0, y: 20 }); // Fill (cyan, dynamic) var fill = self.attachAsset('breathBarFill', { anchorX: 0.5, anchorY: 0, x: 0, y: 20 }); // Bar state self.maxValue = 100; self.value = 100; self.drainPerTick = 0.18; // ~10s to empty self.minValue = 0; // Set fill height based on value self.setValue = function (v) { self.value = Math.max(self.minValue, Math.min(self.maxValue, v)); // Fill height: 0-660px, y=20 var fillHeight = Math.round(660 * (self.value / self.maxValue)); fill.height = fillHeight; fill.y = 20 + (660 - fillHeight); // Danger always at y=20, height=660 // Optionally, fade fill if low if (self.value < 20) { fill.alpha = 0.5 + 0.5 * (self.value / 20); } else { fill.alpha = 1; } }; // Drain bar per tick self.update = function () { self.setValue(self.value - self.drainPerTick); }; // Refill by 5% (e.g. on tap) self.refill = function () { var increase = self.maxValue * 0.05; self.setValue(self.value + increase); }; // Is bar empty? self.isEmpty = function () { return self.value <= self.minValue + 0.01; }; // Init self.setValue(self.value); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a1a }); /**** * Game Code ****/ // Music // Sound // Soundwave // Slogan Neon Bar // Beat Particle // Music Note // --- Breath Meter // Red Tap Button // Character: Big, cartoon beatboxer with headphones, hoodie, sneakers // --- Neon Slogan at Top --- function _typeof5(o) { "@babel/helpers - typeof"; return _typeof5 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof5(o); } function _typeof4(o) { "@babel/helpers - typeof"; return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof4(o); } function _typeof3(o) { "@babel/helpers - typeof"; return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof3(o); } function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } // --- Static Background (behind all elements) --- // Make sure the background fully covers the screen (2048x2732) var beatboxBg = LK.getAsset('beatbox_bg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, width: 2048, height: 2732 }); game.addChild(beatboxBg); var sloganText = new Text2('BEATBOX TAP STAR', { size: 140, fill: 0x00FFFF, font: "Impact, 'Arial Black', Tahoma" }); sloganText.anchor.set(0.5, 0.5); sloganText.x = 2048 / 2; sloganText.y = 130; game.addChild(sloganText); // --- Score Text (top right) --- var scoreText = new Text2('0', { size: 110, fill: 0xffffff, font: "Impact, 'Arial Black', Tahoma" }); scoreText.anchor.set(1, 0); // right-top scoreText.x = -10; // 10px from right edge scoreText.y = 30; // 30px from top (no breathbar) // Do not add to LK.gui.right here; will be added to game after breathBar is created // --- Best Score Text (bottom left corner) --- var bestScore = storage.bestScore || 0; var bestScoreText = new Text2('BEST: ' + bestScore, { size: 80, fill: 0xffe066, font: "Impact, 'Arial Black', Tahoma" }); bestScoreText.anchor.set(0, 1); // left-bottom bestScoreText.x = 40; // 40px from left edge bestScoreText.y = 2732 - 40; // 40px from bottom edge game.addChild(bestScoreText); // --- Beatboxer Character (center stage) --- // Character switching logic // Character style 0: Blue square placeholder var characterPlaceholder0 = LK.getAsset('characterPlaceholder', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 2350 }); // Character style 1: Pink ellipse placeholder var characterPlaceholder1 = LK.getAsset('beatboxerHead', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 2350, color: 0xff66cc }); characterPlaceholder1.visible = false; // Character style 2: Green box placeholder var characterPlaceholder2 = LK.getAsset('beatParticle', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 2350, color: 0x00ffcc }); characterPlaceholder2.visible = false; // Character style 3: Blue square placeholder (new) var characterPlaceholder3 = LK.getAsset('characterPlaceholderSquare', { anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 2350 }); characterPlaceholder3.visible = false; game.addChild(characterPlaceholder0); game.addChild(characterPlaceholder1); game.addChild(characterPlaceholder2); game.addChild(characterPlaceholder3); // Track which character is currently shown (0, 1, 2, 3) var characterStyle = 0; var characterList = [characterPlaceholder0, characterPlaceholder1, characterPlaceholder2, characterPlaceholder3]; // --- Beatboxer character instance removed as per instructions --- // --- Tap Button (bottom center) --- var tapButton = LK.getAsset('tapButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2350 //{1U} // moved up by 150px }); game.addChild(tapButton); // --- Animated Background Particles --- var beatParticles = []; // --- Game State --- var score = 0; var isGameOver = false; var canTap = true; var lastTapTick = 0; // Remove tap count and speedup logic; breathBar is always fast // --- Nickname and Leaderboard --- var nickname = storage.nickname || null; var leaderboard = storage.leaderboard || []; var leaderboardText = null; // --- Nickname Display (under sloganText, small font) --- var nicknameDisplayText = null; function updateNicknameDisplay() { if (!nicknameDisplayText) { nicknameDisplayText = new Text2('', { size: 90, fill: 0xcccccc, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); nicknameDisplayText.anchor.set(0.5, 0); nicknameDisplayText.x = 2048 / 2; nicknameDisplayText.y = sloganText.y + sloganText.height / 2 + 10; game.addChild(nicknameDisplayText); } nicknameDisplayText.setText(nickname ? nickname : ''); nicknameDisplayText.visible = !!nickname; } // --- Nickname Overlay (semi-transparent black) --- var nicknameOverlay = null; // --- Nickname Animation --- var nicknameAnimText = null; var nicknameAnimTimer = null; var nicknameAnimTicks = 0; var nicknameAnimBase = "BeatBoxer"; var nicknameAnimCurrent = ""; var nicknameAnimDone = false; // Assign a random nickname and animate it function assignRandomNicknameAndShow() { // If already set, skip if (nickname) return; nicknameAnimTicks = 0; nicknameAnimDone = false; // Create overlay (if not present) if (!nicknameOverlay) { nicknameOverlay = LK.getAsset('breathBarBg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, color: 0x000000 }); nicknameOverlay.alpha = 0.7; nicknameOverlay.interactive = false; game.addChild(nicknameOverlay); } else { nicknameOverlay.visible = true; } // Create animated nickname text if (nicknameAnimText) { nicknameAnimText.destroy(); nicknameAnimText = null; } nicknameAnimText = new Text2("YOUR NICKNAME IS ...", { size: 160, fill: 0xffffff, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); nicknameAnimText.anchor.set(0.5, 0.5); nicknameAnimText.x = 2048 / 2; nicknameAnimText.y = 700; game.addChild(nicknameAnimText); // Animate the number rolling for 1.2 seconds, then pick a random number nicknameAnimTimer = LK.setInterval(function () { nicknameAnimTicks++; // Animate number from 01 to 99 var num = Math.floor(Math.random() * 99) + 1; var numStr = (num < 10 ? "0" : "") + num; nicknameAnimCurrent = nicknameAnimBase + numStr; nicknameAnimText.setText("YOUR NICKNAME IS\n" + nicknameAnimCurrent); // After 1.2 seconds (about 18 frames), finalize nickname if (nicknameAnimTicks > 18) { LK.clearInterval(nicknameAnimTimer); nicknameAnimTimer = null; // Final random number var finalNum = Math.floor(Math.random() * 99) + 1; var finalNumStr = (finalNum < 10 ? "0" : "") + finalNum; nickname = nicknameAnimBase + finalNumStr; storage.nickname = nickname; nicknameAnimText.setText("YOUR NICKNAME IS\n" + nickname); nicknameAnimDone = true; // Remove after 1.2s LK.setTimeout(function () { if (nicknameAnimText) { nicknameAnimText.destroy(); nicknameAnimText = null; } updateNicknameDisplay(); gamePausedForNickname = false; }, 1200); } }, 65); // Pause game logic until nickname is set gamePausedForNickname = true; } // On first load, always clear storage and assign new nickname, then show Ready button function resetAndAssignNickname() { // Clear storage for nickname and leaderboard storage.nickname = null; storage.leaderboard = []; nickname = null; leaderboard = []; // Remove any previous nickname text if (nicknameAnimText) { nicknameAnimText.destroy(); nicknameAnimText = null; } // Remove nickname display if present if (nicknameDisplayText) { nicknameDisplayText.destroy(); nicknameDisplayText = null; } // Assign new nickname with animation assignRandomNicknameAndShow(); // After nickname animation is done, show Ready button function showReadyButtonWhenDone() { if (nicknameAnimDone) { // Show Ready button if (window.readyBtn) { window.readyBtn.destroy(); window.readyBtn = null; } var readyBtn = new Text2("READY", { size: 140, fill: 0x00ffcc, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); readyBtn.anchor.set(0.5, 0.5); readyBtn.x = 2048 / 2; readyBtn.y = 1100; game.addChild(readyBtn); window.readyBtn = readyBtn; readyBtn.interactive = true; readyBtn.buttonMode = true; readyBtn.down = function (x, y, obj) { // Remove button, unpause game if (window.readyBtn) { window.readyBtn.destroy(); window.readyBtn = null; } // Hide overlay when Ready is pressed if (nicknameOverlay) { nicknameOverlay.visible = false; } gamePausedForNickname = false; // Start background music when Ready is pressed // (Moved to first tap on red button) // Create and show breathBar (if not already) if (!breathBar) { breathBar = new BreathBar(); // Set fast drain from the start breathBar.drainPerTick = 0.36; // double the original speed // Place at right edge, below top margin (avoid top right 100x100) // breathBar.width is 80, so anchorX:0.5 means center is at x // Place 80px from right, 160px from top breathBar.x = 2048 - 80; breathBar.y = 160; game.addChild(breathBar); // Move scoreText below breathBar // scoreText is already created above, just move it scoreText.anchor.set(0.5, 0); // center-top scoreText.x = 2048 - 80; // align with breathBar.x scoreText.y = breathBar.y + 700 + 30; // breathBar height (700) + 30px margin // Remove from LK.gui.right if present, add to game if (scoreText.parent && scoreText.parent.removeChild) { scoreText.parent.removeChild(scoreText); } game.addChild(scoreText); } }; } else { LK.setTimeout(showReadyButtonWhenDone, 100); } } showReadyButtonWhenDone(); // Pause game logic until nickname is set and Ready pressed gamePausedForNickname = true; } resetAndAssignNickname(); function showLeaderboard() { if (leaderboardText) { leaderboardText.destroy(); leaderboardText = null; } var sorted = leaderboard.slice().sort(function (a, b) { return b.score - a.score; }).slice(0, 10); var lines = ['🏆 TOP SCORES 🏆']; for (var i = 0; i < sorted.length; i++) { lines.push(i + 1 + '. ' + sorted[i].nickname + ' - ' + sorted[i].score); } leaderboardText = new Text2(lines.join('\n'), { size: 80, fill: 0xffff00, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); leaderboardText.anchor.set(0.5, 0.5); leaderboardText.x = 2048 / 2; leaderboardText.y = 2732 / 2; game.addChild(leaderboardText); // Remove leaderboard after 3 seconds LK.setTimeout(function () { if (leaderboardText) { leaderboardText.destroy(); leaderboardText = null; } }, 3000); } // On first load, ask for nickname if not set var gamePausedForNickname = false; // --- BreathBar instance (created after Ready) --- var breathBar = null; // --- Helper: Animate Tap Button Glow --- function animateTapButtonGlow() { // Button press animation: scale down then up tween(tapButton, { scaleX: 0.92, scaleY: 0.92 }, { duration: 80, easing: tween.cubicOut, onFinish: function onFinish() { tween(tapButton, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.cubicIn }); } }); } // --- Helper: Add Beat Particle --- function spawnBeatParticle() { var p = new BeatParticle(); p.x = 2048 / 2; p.y = 1200 - 220; p.vx = (Math.random() - 0.5) * 1.5; p.vy = -1.5 - Math.random() * 1.5; p.alpha = 0.8 + Math.random() * 0.2; beatParticles.push(p); game.addChild(p); } // --- Tap Button Handler --- function handleTap(x, y, obj) { if (isGameOver || !canTap) { return; } // Only register tap if inside button var dx = x - tapButton.x; var dy = y - tapButton.y; var r = tapButton.width / 2; if (dx * dx + dy * dy > r * r) { return; } // Tap registered! canTap = false; lastTapTick = LK.ticks; // Animate animateTapButtonGlow(); spawnBeatParticle(); // Sound effects removed; only background music remains // Refill breathBar on tap if (breathBar) { breathBar.refill(); } // Update score and UI score++; scoreText.setText(score); // --- Motivational Text Animation --- if (score === 20 || score === 50 || score === 80) { var msg = ""; if (score === 20) msg = "SUPER!"; if (score === 50) msg = "EXCELLENT!"; if (score === 80) msg = "FANTASTIC!"; var motivText = new Text2(msg, { size: 200, fill: 0xffff00, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); motivText.anchor.set(0.5, 0.5); motivText.x = 2048 / 2; motivText.y = 900; motivText.alpha = 0.0; game.addChild(motivText); // Animate: fade in, scale up, then fade out motivText.scaleX = motivText.scaleY = 0.7; tween(motivText, { alpha: 1, scaleX: 1.1, scaleY: 1.1 }, { duration: 220, easing: tween.cubicOut, onFinish: function onFinish() { tween(motivText, { alpha: 0, scaleX: 1.25, scaleY: 1.25 }, { duration: 600, easing: tween.cubicIn, onFinish: function onFinish() { motivText.destroy(); } }); } }); } // No game over at 20, 50, or 80 taps; game continues // Switch character: loop through 3 styles // Hide all, show next characterList[characterStyle].visible = false; characterStyle = (characterStyle + 1) % characterList.length; characterList[characterStyle].visible = true; // Animate if Beatboxer // (No Beatboxer instance present, so no animation triggered here) // Win condition removed for endless play } // --- Tap Button Down/Up/Move --- var musicStarted = false; // Track if music has started game.down = function (x, y, obj) { if (gamePausedForNickname) return; // Block all background taps if Ready button is visible if (window.readyBtn) return; // Start background music on first tap of red button if (!musicStarted) { LK.playMusic('neonbeat', { fade: { start: 0, end: 1, duration: 1200 } }); musicStarted = true; } handleTap(x, y, obj); }; game.move = function (x, y, obj) { if (gamePausedForNickname) return; // Block all background move events if Ready button is visible if (window.readyBtn) return; // No drag needed, but allow repeated tap if (!canTap && LK.ticks - lastTapTick > 7) { canTap = true; } }; game.up = function (x, y, obj) { if (gamePausedForNickname) return; // Block all background up events if Ready button is visible if (window.readyBtn) return; // Allow next tap canTap = true; }; // --- Main Game Update --- game.update = function () { if (isGameOver || gamePausedForNickname) { // Still allow sloganText and background particles to animate // Animate sloganText neon pulse sloganText.alpha = 0.85 + 0.15 * Math.sin(LK.ticks * 0.08); sloganText.scaleX = sloganText.scaleY = 1 + 0.03 * Math.sin(LK.ticks * 0.07); // Animate background: spawn beat particles if (LK.ticks % 30 === 0) { spawnBeatParticle(); } // Update and cleanup beat particles for (var i = beatParticles.length - 1; i >= 0; i--) { var p = beatParticles[i]; p.update(); if (p.destroyed) { p.destroy(); beatParticles.splice(i, 1); } } // Prevent breathbar from draining or updating while waiting for Ready return; } // --- BreathBar logic (drain, refill, game over) --- if (breathBar) { breathBar.update(); if (breathBar.isEmpty() && !isGameOver) { isGameOver = true; // Stop background music when breathBar is empty LK.stopMusic(); // Update best score if needed if (score > bestScore) { bestScore = score; storage.bestScore = bestScore; if (bestScoreText) bestScoreText.setText('BEST: ' + bestScore); } // Show overlay background behind score var scoreOverlay = LK.getAsset('breathBarBg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, color: 0x000000 }); scoreOverlay.alpha = 0.7; scoreOverlay.interactive = false; game.addChild(scoreOverlay); // Show "Your Score Is" and the score in the center, but a bit higher var bigScoreText = new Text2("Your Score Is\n" + score, { size: 220, fill: 0xffff00, font: "Impact, 'Arial Black', Tahoma", align: 'center' }); bigScoreText.anchor.set(0.5, 0.5); bigScoreText.x = 2048 / 2; // Move further up (higher on the screen) bigScoreText.y = 800; game.addChild(bigScoreText); // Animate: fade in, scale up, then stay visible (do not fade out or destroy) bigScoreText.alpha = 0.0; bigScoreText.scaleX = bigScoreText.scaleY = 0.7; tween(bigScoreText, { alpha: 1, scaleX: 1.1, scaleY: 1.1 }, { duration: 420, easing: tween.cubicOut, onFinish: function onFinish() { // Do not fade out or destroy, keep on screen // Remove overlay and show game over after a short delay, but keep bigScoreText LK.setTimeout(function () { if (scoreOverlay) scoreOverlay.destroy(); LK.showGameOver(); }, 1500); } }); // Optionally, flash bar red tween(breathBar, { alpha: 0.2 }, { duration: 200, yoyo: true, repeat: 2, onFinish: function onFinish() { breathBar.alpha = 1; } }); } } // Animate sloganText neon pulse sloganText.alpha = 0.85 + 0.15 * Math.sin(LK.ticks * 0.08); sloganText.scaleX = sloganText.scaleY = 1 + 0.03 * Math.sin(LK.ticks * 0.07); // Animate background: spawn beat particles if (LK.ticks % 30 === 0) { spawnBeatParticle(); } // Update and cleanup beat particles for (var i = beatParticles.length - 1; i >= 0; i--) { var p = beatParticles[i]; p.update(); if (p.destroyed) { p.destroy(); beatParticles.splice(i, 1); } } }; // --- Play Music --- // (Music now starts after Ready is pressed, see readyBtn.down handler)
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Beat Particle
var BeatParticle = Container.expand(function () {
var self = Container.call(this);
var p = self.attachAsset('beatParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.alpha = 1;
self.scale = 1;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.scale += 0.02;
self.alpha -= 0.018;
p.scaleX = p.scaleY = self.scale;
if (self.alpha <= 0) {
self.destroyed = true;
}
};
return self;
});
// BreathBar: Visual breath meter with fill, danger, and update logic
var BreathBar = Container.expand(function () {
var self = Container.call(this);
// Background
var bg = self.attachAsset('breathBarBg', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 0
});
// Danger zone (red, bottom)
var danger = self.attachAsset('breathBarDanger', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 20
});
// Fill (cyan, dynamic)
var fill = self.attachAsset('breathBarFill', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 20
});
// Bar state
self.maxValue = 100;
self.value = 100;
self.drainPerTick = 0.18; // ~10s to empty
self.minValue = 0;
// Set fill height based on value
self.setValue = function (v) {
self.value = Math.max(self.minValue, Math.min(self.maxValue, v));
// Fill height: 0-660px, y=20
var fillHeight = Math.round(660 * (self.value / self.maxValue));
fill.height = fillHeight;
fill.y = 20 + (660 - fillHeight);
// Danger always at y=20, height=660
// Optionally, fade fill if low
if (self.value < 20) {
fill.alpha = 0.5 + 0.5 * (self.value / 20);
} else {
fill.alpha = 1;
}
};
// Drain bar per tick
self.update = function () {
self.setValue(self.value - self.drainPerTick);
};
// Refill by 5% (e.g. on tap)
self.refill = function () {
var increase = self.maxValue * 0.05;
self.setValue(self.value + increase);
};
// Is bar empty?
self.isEmpty = function () {
return self.value <= self.minValue + 0.01;
};
// Init
self.setValue(self.value);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a1a
});
/****
* Game Code
****/
// Music
// Sound
// Soundwave
// Slogan Neon Bar
// Beat Particle
// Music Note
// --- Breath Meter
// Red Tap Button
// Character: Big, cartoon beatboxer with headphones, hoodie, sneakers
// --- Neon Slogan at Top ---
function _typeof5(o) {
"@babel/helpers - typeof";
return _typeof5 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof5(o);
}
function _typeof4(o) {
"@babel/helpers - typeof";
return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof4(o);
}
function _typeof3(o) {
"@babel/helpers - typeof";
return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof3(o);
}
function _typeof2(o) {
"@babel/helpers - typeof";
return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof2(o);
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
// --- Static Background (behind all elements) ---
// Make sure the background fully covers the screen (2048x2732)
var beatboxBg = LK.getAsset('beatbox_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 2048,
height: 2732
});
game.addChild(beatboxBg);
var sloganText = new Text2('BEATBOX TAP STAR', {
size: 140,
fill: 0x00FFFF,
font: "Impact, 'Arial Black', Tahoma"
});
sloganText.anchor.set(0.5, 0.5);
sloganText.x = 2048 / 2;
sloganText.y = 130;
game.addChild(sloganText);
// --- Score Text (top right) ---
var scoreText = new Text2('0', {
size: 110,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
scoreText.anchor.set(1, 0); // right-top
scoreText.x = -10; // 10px from right edge
scoreText.y = 30; // 30px from top (no breathbar)
// Do not add to LK.gui.right here; will be added to game after breathBar is created
// --- Best Score Text (bottom left corner) ---
var bestScore = storage.bestScore || 0;
var bestScoreText = new Text2('BEST: ' + bestScore, {
size: 80,
fill: 0xffe066,
font: "Impact, 'Arial Black', Tahoma"
});
bestScoreText.anchor.set(0, 1); // left-bottom
bestScoreText.x = 40; // 40px from left edge
bestScoreText.y = 2732 - 40; // 40px from bottom edge
game.addChild(bestScoreText);
// --- Beatboxer Character (center stage) ---
// Character switching logic
// Character style 0: Blue square placeholder
var characterPlaceholder0 = LK.getAsset('characterPlaceholder', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2350
});
// Character style 1: Pink ellipse placeholder
var characterPlaceholder1 = LK.getAsset('beatboxerHead', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2350,
color: 0xff66cc
});
characterPlaceholder1.visible = false;
// Character style 2: Green box placeholder
var characterPlaceholder2 = LK.getAsset('beatParticle', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2350,
color: 0x00ffcc
});
characterPlaceholder2.visible = false;
// Character style 3: Blue square placeholder (new)
var characterPlaceholder3 = LK.getAsset('characterPlaceholderSquare', {
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 2350
});
characterPlaceholder3.visible = false;
game.addChild(characterPlaceholder0);
game.addChild(characterPlaceholder1);
game.addChild(characterPlaceholder2);
game.addChild(characterPlaceholder3);
// Track which character is currently shown (0, 1, 2, 3)
var characterStyle = 0;
var characterList = [characterPlaceholder0, characterPlaceholder1, characterPlaceholder2, characterPlaceholder3];
// --- Beatboxer character instance removed as per instructions ---
// --- Tap Button (bottom center) ---
var tapButton = LK.getAsset('tapButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2350 //{1U} // moved up by 150px
});
game.addChild(tapButton);
// --- Animated Background Particles ---
var beatParticles = [];
// --- Game State ---
var score = 0;
var isGameOver = false;
var canTap = true;
var lastTapTick = 0;
// Remove tap count and speedup logic; breathBar is always fast
// --- Nickname and Leaderboard ---
var nickname = storage.nickname || null;
var leaderboard = storage.leaderboard || [];
var leaderboardText = null;
// --- Nickname Display (under sloganText, small font) ---
var nicknameDisplayText = null;
function updateNicknameDisplay() {
if (!nicknameDisplayText) {
nicknameDisplayText = new Text2('', {
size: 90,
fill: 0xcccccc,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
nicknameDisplayText.anchor.set(0.5, 0);
nicknameDisplayText.x = 2048 / 2;
nicknameDisplayText.y = sloganText.y + sloganText.height / 2 + 10;
game.addChild(nicknameDisplayText);
}
nicknameDisplayText.setText(nickname ? nickname : '');
nicknameDisplayText.visible = !!nickname;
}
// --- Nickname Overlay (semi-transparent black) ---
var nicknameOverlay = null;
// --- Nickname Animation ---
var nicknameAnimText = null;
var nicknameAnimTimer = null;
var nicknameAnimTicks = 0;
var nicknameAnimBase = "BeatBoxer";
var nicknameAnimCurrent = "";
var nicknameAnimDone = false;
// Assign a random nickname and animate it
function assignRandomNicknameAndShow() {
// If already set, skip
if (nickname) return;
nicknameAnimTicks = 0;
nicknameAnimDone = false;
// Create overlay (if not present)
if (!nicknameOverlay) {
nicknameOverlay = LK.getAsset('breathBarBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
color: 0x000000
});
nicknameOverlay.alpha = 0.7;
nicknameOverlay.interactive = false;
game.addChild(nicknameOverlay);
} else {
nicknameOverlay.visible = true;
}
// Create animated nickname text
if (nicknameAnimText) {
nicknameAnimText.destroy();
nicknameAnimText = null;
}
nicknameAnimText = new Text2("YOUR NICKNAME IS ...", {
size: 160,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
nicknameAnimText.anchor.set(0.5, 0.5);
nicknameAnimText.x = 2048 / 2;
nicknameAnimText.y = 700;
game.addChild(nicknameAnimText);
// Animate the number rolling for 1.2 seconds, then pick a random number
nicknameAnimTimer = LK.setInterval(function () {
nicknameAnimTicks++;
// Animate number from 01 to 99
var num = Math.floor(Math.random() * 99) + 1;
var numStr = (num < 10 ? "0" : "") + num;
nicknameAnimCurrent = nicknameAnimBase + numStr;
nicknameAnimText.setText("YOUR NICKNAME IS\n" + nicknameAnimCurrent);
// After 1.2 seconds (about 18 frames), finalize nickname
if (nicknameAnimTicks > 18) {
LK.clearInterval(nicknameAnimTimer);
nicknameAnimTimer = null;
// Final random number
var finalNum = Math.floor(Math.random() * 99) + 1;
var finalNumStr = (finalNum < 10 ? "0" : "") + finalNum;
nickname = nicknameAnimBase + finalNumStr;
storage.nickname = nickname;
nicknameAnimText.setText("YOUR NICKNAME IS\n" + nickname);
nicknameAnimDone = true;
// Remove after 1.2s
LK.setTimeout(function () {
if (nicknameAnimText) {
nicknameAnimText.destroy();
nicknameAnimText = null;
}
updateNicknameDisplay();
gamePausedForNickname = false;
}, 1200);
}
}, 65);
// Pause game logic until nickname is set
gamePausedForNickname = true;
}
// On first load, always clear storage and assign new nickname, then show Ready button
function resetAndAssignNickname() {
// Clear storage for nickname and leaderboard
storage.nickname = null;
storage.leaderboard = [];
nickname = null;
leaderboard = [];
// Remove any previous nickname text
if (nicknameAnimText) {
nicknameAnimText.destroy();
nicknameAnimText = null;
}
// Remove nickname display if present
if (nicknameDisplayText) {
nicknameDisplayText.destroy();
nicknameDisplayText = null;
}
// Assign new nickname with animation
assignRandomNicknameAndShow();
// After nickname animation is done, show Ready button
function showReadyButtonWhenDone() {
if (nicknameAnimDone) {
// Show Ready button
if (window.readyBtn) {
window.readyBtn.destroy();
window.readyBtn = null;
}
var readyBtn = new Text2("READY", {
size: 140,
fill: 0x00ffcc,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
readyBtn.anchor.set(0.5, 0.5);
readyBtn.x = 2048 / 2;
readyBtn.y = 1100;
game.addChild(readyBtn);
window.readyBtn = readyBtn;
readyBtn.interactive = true;
readyBtn.buttonMode = true;
readyBtn.down = function (x, y, obj) {
// Remove button, unpause game
if (window.readyBtn) {
window.readyBtn.destroy();
window.readyBtn = null;
}
// Hide overlay when Ready is pressed
if (nicknameOverlay) {
nicknameOverlay.visible = false;
}
gamePausedForNickname = false;
// Start background music when Ready is pressed
// (Moved to first tap on red button)
// Create and show breathBar (if not already)
if (!breathBar) {
breathBar = new BreathBar();
// Set fast drain from the start
breathBar.drainPerTick = 0.36; // double the original speed
// Place at right edge, below top margin (avoid top right 100x100)
// breathBar.width is 80, so anchorX:0.5 means center is at x
// Place 80px from right, 160px from top
breathBar.x = 2048 - 80;
breathBar.y = 160;
game.addChild(breathBar);
// Move scoreText below breathBar
// scoreText is already created above, just move it
scoreText.anchor.set(0.5, 0); // center-top
scoreText.x = 2048 - 80; // align with breathBar.x
scoreText.y = breathBar.y + 700 + 30; // breathBar height (700) + 30px margin
// Remove from LK.gui.right if present, add to game
if (scoreText.parent && scoreText.parent.removeChild) {
scoreText.parent.removeChild(scoreText);
}
game.addChild(scoreText);
}
};
} else {
LK.setTimeout(showReadyButtonWhenDone, 100);
}
}
showReadyButtonWhenDone();
// Pause game logic until nickname is set and Ready pressed
gamePausedForNickname = true;
}
resetAndAssignNickname();
function showLeaderboard() {
if (leaderboardText) {
leaderboardText.destroy();
leaderboardText = null;
}
var sorted = leaderboard.slice().sort(function (a, b) {
return b.score - a.score;
}).slice(0, 10);
var lines = ['🏆 TOP SCORES 🏆'];
for (var i = 0; i < sorted.length; i++) {
lines.push(i + 1 + '. ' + sorted[i].nickname + ' - ' + sorted[i].score);
}
leaderboardText = new Text2(lines.join('\n'), {
size: 80,
fill: 0xffff00,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
leaderboardText.anchor.set(0.5, 0.5);
leaderboardText.x = 2048 / 2;
leaderboardText.y = 2732 / 2;
game.addChild(leaderboardText);
// Remove leaderboard after 3 seconds
LK.setTimeout(function () {
if (leaderboardText) {
leaderboardText.destroy();
leaderboardText = null;
}
}, 3000);
}
// On first load, ask for nickname if not set
var gamePausedForNickname = false;
// --- BreathBar instance (created after Ready) ---
var breathBar = null;
// --- Helper: Animate Tap Button Glow ---
function animateTapButtonGlow() {
// Button press animation: scale down then up
tween(tapButton, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 80,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(tapButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.cubicIn
});
}
});
}
// --- Helper: Add Beat Particle ---
function spawnBeatParticle() {
var p = new BeatParticle();
p.x = 2048 / 2;
p.y = 1200 - 220;
p.vx = (Math.random() - 0.5) * 1.5;
p.vy = -1.5 - Math.random() * 1.5;
p.alpha = 0.8 + Math.random() * 0.2;
beatParticles.push(p);
game.addChild(p);
}
// --- Tap Button Handler ---
function handleTap(x, y, obj) {
if (isGameOver || !canTap) {
return;
}
// Only register tap if inside button
var dx = x - tapButton.x;
var dy = y - tapButton.y;
var r = tapButton.width / 2;
if (dx * dx + dy * dy > r * r) {
return;
}
// Tap registered!
canTap = false;
lastTapTick = LK.ticks;
// Animate
animateTapButtonGlow();
spawnBeatParticle();
// Sound effects removed; only background music remains
// Refill breathBar on tap
if (breathBar) {
breathBar.refill();
}
// Update score and UI
score++;
scoreText.setText(score);
// --- Motivational Text Animation ---
if (score === 20 || score === 50 || score === 80) {
var msg = "";
if (score === 20) msg = "SUPER!";
if (score === 50) msg = "EXCELLENT!";
if (score === 80) msg = "FANTASTIC!";
var motivText = new Text2(msg, {
size: 200,
fill: 0xffff00,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
motivText.anchor.set(0.5, 0.5);
motivText.x = 2048 / 2;
motivText.y = 900;
motivText.alpha = 0.0;
game.addChild(motivText);
// Animate: fade in, scale up, then fade out
motivText.scaleX = motivText.scaleY = 0.7;
tween(motivText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 220,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(motivText, {
alpha: 0,
scaleX: 1.25,
scaleY: 1.25
}, {
duration: 600,
easing: tween.cubicIn,
onFinish: function onFinish() {
motivText.destroy();
}
});
}
});
}
// No game over at 20, 50, or 80 taps; game continues
// Switch character: loop through 3 styles
// Hide all, show next
characterList[characterStyle].visible = false;
characterStyle = (characterStyle + 1) % characterList.length;
characterList[characterStyle].visible = true;
// Animate if Beatboxer
// (No Beatboxer instance present, so no animation triggered here)
// Win condition removed for endless play
}
// --- Tap Button Down/Up/Move ---
var musicStarted = false; // Track if music has started
game.down = function (x, y, obj) {
if (gamePausedForNickname) return;
// Block all background taps if Ready button is visible
if (window.readyBtn) return;
// Start background music on first tap of red button
if (!musicStarted) {
LK.playMusic('neonbeat', {
fade: {
start: 0,
end: 1,
duration: 1200
}
});
musicStarted = true;
}
handleTap(x, y, obj);
};
game.move = function (x, y, obj) {
if (gamePausedForNickname) return;
// Block all background move events if Ready button is visible
if (window.readyBtn) return;
// No drag needed, but allow repeated tap
if (!canTap && LK.ticks - lastTapTick > 7) {
canTap = true;
}
};
game.up = function (x, y, obj) {
if (gamePausedForNickname) return;
// Block all background up events if Ready button is visible
if (window.readyBtn) return;
// Allow next tap
canTap = true;
};
// --- Main Game Update ---
game.update = function () {
if (isGameOver || gamePausedForNickname) {
// Still allow sloganText and background particles to animate
// Animate sloganText neon pulse
sloganText.alpha = 0.85 + 0.15 * Math.sin(LK.ticks * 0.08);
sloganText.scaleX = sloganText.scaleY = 1 + 0.03 * Math.sin(LK.ticks * 0.07);
// Animate background: spawn beat particles
if (LK.ticks % 30 === 0) {
spawnBeatParticle();
}
// Update and cleanup beat particles
for (var i = beatParticles.length - 1; i >= 0; i--) {
var p = beatParticles[i];
p.update();
if (p.destroyed) {
p.destroy();
beatParticles.splice(i, 1);
}
}
// Prevent breathbar from draining or updating while waiting for Ready
return;
}
// --- BreathBar logic (drain, refill, game over) ---
if (breathBar) {
breathBar.update();
if (breathBar.isEmpty() && !isGameOver) {
isGameOver = true;
// Stop background music when breathBar is empty
LK.stopMusic();
// Update best score if needed
if (score > bestScore) {
bestScore = score;
storage.bestScore = bestScore;
if (bestScoreText) bestScoreText.setText('BEST: ' + bestScore);
}
// Show overlay background behind score
var scoreOverlay = LK.getAsset('breathBarBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
color: 0x000000
});
scoreOverlay.alpha = 0.7;
scoreOverlay.interactive = false;
game.addChild(scoreOverlay);
// Show "Your Score Is" and the score in the center, but a bit higher
var bigScoreText = new Text2("Your Score Is\n" + score, {
size: 220,
fill: 0xffff00,
font: "Impact, 'Arial Black', Tahoma",
align: 'center'
});
bigScoreText.anchor.set(0.5, 0.5);
bigScoreText.x = 2048 / 2;
// Move further up (higher on the screen)
bigScoreText.y = 800;
game.addChild(bigScoreText);
// Animate: fade in, scale up, then stay visible (do not fade out or destroy)
bigScoreText.alpha = 0.0;
bigScoreText.scaleX = bigScoreText.scaleY = 0.7;
tween(bigScoreText, {
alpha: 1,
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 420,
easing: tween.cubicOut,
onFinish: function onFinish() {
// Do not fade out or destroy, keep on screen
// Remove overlay and show game over after a short delay, but keep bigScoreText
LK.setTimeout(function () {
if (scoreOverlay) scoreOverlay.destroy();
LK.showGameOver();
}, 1500);
}
});
// Optionally, flash bar red
tween(breathBar, {
alpha: 0.2
}, {
duration: 200,
yoyo: true,
repeat: 2,
onFinish: function onFinish() {
breathBar.alpha = 1;
}
});
}
}
// Animate sloganText neon pulse
sloganText.alpha = 0.85 + 0.15 * Math.sin(LK.ticks * 0.08);
sloganText.scaleX = sloganText.scaleY = 1 + 0.03 * Math.sin(LK.ticks * 0.07);
// Animate background: spawn beat particles
if (LK.ticks % 30 === 0) {
spawnBeatParticle();
}
// Update and cleanup beat particles
for (var i = beatParticles.length - 1; i >= 0; i--) {
var p = beatParticles[i];
p.update();
if (p.destroyed) {
p.destroy();
beatParticles.splice(i, 1);
}
}
};
// --- Play Music ---
// (Music now starts after Ready is pressed, see readyBtn.down handler)