User prompt
If the player misses the first incoming note, the next notes—even if hit—should not be counted until the first missed note is cleared.
User prompt
The note icon shouldn’t stretch sideways; it should be stretched vertically with shorter sides.
User prompt
Make the note boxes rectangular and a bit longer.
User prompt
Make the music note symbol rectangular.
User prompt
Make the gun even bigger.
User prompt
Increase the size of the gun.
User prompt
Set the gun’s firing rate to normal speed; it’s still too fast.
User prompt
Some notes still don’t register hits even though I’m shooting them correctly; please fix this.
User prompt
Reduce the gun’s firing rate a bit more.
User prompt
The gun's firing speed should be slowed down a bit. Also, fix the issue where some notes are hit but not counted as hits.
User prompt
The gun should fire continuously without stopping.
User prompt
Make the gun fire fast.
User prompt
Make the gun fire a bit faster.
User prompt
In the game, the notes fall too quickly in all modes. Please slow them down.
User prompt
The gun should automatically fire in sync with the speed of the falling notes. The player, using head movements, only needs to aim the crosshair at the notes — no manual shooting is required. ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Nota Avcısı: Yüzle Nişan Al!
Initial prompt
*Game Concept:* Notes fall from the top of the screen in multiple columns. A fixed gun is placed at the bottom-left corner. The player controls the aim by moving their head (FaceKit integration), and the crosshair moves accordingly on the screen. When the player taps a note while aiming at it, the note is shot and triggers a musical sound. *Features:* - Multiple falling note columns, each representing different piano notes - Fixed gun in bottom-left corner - Crosshair follows player’s head movement (FaceKit) - Tap a note while aiming to shoot and play the corresponding sound - Notes fall in sync with different music tracks (randomly chosen each round) - Difficulty increases every 10 points by speeding up the notes - Game title includes buttons to select speed: Slow, Normal, Fast - Gameplay hint: “Move your head to aim and tap notes to shoot” displayed on screen Türkçe yap
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Ball class: the fixed shooter at bottom left var Ball = Container.expand(function () { var self = Container.call(this); var ballAsset = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, width: BALL_SIZE, height: BALL_SIZE, color: 0xffffff, shape: 'ellipse' }); return self; }); // Bullet class: fired from ball towards crosshair var Bullet = Container.expand(function () { var self = Container.call(this); var bulletAsset = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5, width: BULLET_SIZE, height: BULLET_SIZE, color: 0x00e6e6, shape: 'ellipse' }); self.vx = 0; self.vy = 0; self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Crosshair class: follows facekit position var Crosshair = Container.expand(function () { var self = Container.call(this); var crossAsset = self.attachAsset('crosshair', { anchorX: 0.5, anchorY: 0.5, width: CROSS_SIZE, height: CROSS_SIZE, color: 0xff0000, shape: 'ellipse' }); return self; }); // MusicNoteEffect class: floating music note symbol when a note is hit var MusicNoteEffect = Container.expand(function () { var self = Container.call(this); // Use a Text2 object for the music note symbol var noteSymbol = new Text2("♪", { size: 120, fill: "#fff" }); noteSymbol.anchor.set(0.5, 0.5); self.addChild(noteSymbol); // Animate: float up and fade out self.start = function (startX, startY) { self.x = startX; self.y = startY; self.alpha = 1; // Tween upward and fade out tween(self, { y: self.y - 220, alpha: 0 }, { duration: 700, easing: tween.cubicOut, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // NotaggNote class: falling notagg note (special note, ends game if tapped) var NotaggNote = Container.expand(function () { var self = Container.call(this); var notaggAsset = self.attachAsset('Notagg', { anchorX: 0.5, anchorY: 0.5, width: NOTE_WIDTH, height: NOTE_HEIGHT }); self.column = 0; self.speed = noteFallSpeed; self.hit = false; self.isNotagg = true; // flag for special handling self.update = function () { self.y += self.speed; }; return self; }); // Note class: falling note var Note = Container.expand(function () { var self = Container.call(this); // Randomly pick a color for the note var color = NOTE_COLORS[Math.floor(Math.random() * NOTE_COLORS.length)]; var noteAsset = self.attachAsset('note', { anchorX: 0.5, anchorY: 0.5, width: NOTE_WIDTH, // now wider height: NOTE_HEIGHT, color: color, shape: 'box' }); self.column = 0; // which column this note is in self.speed = noteFallSpeed; // will be set on spawn self.hit = false; // has this note been hit self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181a20 }); /**** * Game Code ****/ // Note: All note assets will be ellipses with different colors for variety // --- Constants --- // Ensure Notagg matches note image size var NOTE_COLORS = [0xffe066, 0x66b3ff, 0xff66a3, 0x7cff66, 0xff8c66]; var GAME_W = 2048; var GAME_H = 2732; // --- Dynamic Gradient Background --- // We'll use two large colored rectangles, tweening their tints and alpha for a subtle animated gradient effect. var bgLayer1 = null; var bgLayer2 = null; var bgGradientColors = [0x8635f1, // purple 0x66b3ff, // blue 0xff66a3, // pink 0x7cff66, // green 0xffe066, // yellow 0xb39ddb // lavender ]; var bgColorIdx1 = 0; var bgColorIdx2 = 1; var bgTweenDuration = 8000; // ms, slightly longer for smoother transitions function setupGradientBackground() { // Remove if already present if (bgLayer1) { bgLayer1.destroy(); bgLayer1 = null; } if (bgLayer2) { bgLayer2.destroy(); bgLayer2 = null; } // Layer 1 bgLayer1 = LK.getAsset('softbg2', { anchorX: 0.5, anchorY: 0.5, width: GAME_W * 1.1, height: GAME_H * 1.1, x: GAME_W / 2, y: GAME_H / 2, // Start with first color, slightly more visible tint: bgGradientColors[bgColorIdx1], alpha: 0.32 }); // Layer 2 bgLayer2 = LK.getAsset('softbg2', { anchorX: 0.5, anchorY: 0.5, width: GAME_W * 1.1, height: GAME_H * 1.1, x: GAME_W / 2, y: GAME_H / 2, // Start with second color, slightly more visible tint: bgGradientColors[bgColorIdx2], alpha: 0.22 }); // Add to back of display list game.addChildAt(bgLayer1, 0); game.addChildAt(bgLayer2, 1); // Start the animation loop animateGradientBackground(); } function animateGradientBackground() { // Pick next color indices var nextIdx1 = (bgColorIdx1 + 1) % bgGradientColors.length; var nextIdx2 = (bgColorIdx2 + 1) % bgGradientColors.length; // Animate tints and alpha for both layers, smoothly transitioning to next color tween(bgLayer1, { tint: bgGradientColors[nextIdx1], alpha: 0.32 }, { duration: bgTweenDuration, easing: tween.easeInOut, onFinish: function onFinish() { bgColorIdx1 = nextIdx1; animateGradientBackground(); } }); tween(bgLayer2, { tint: bgGradientColors[nextIdx2], alpha: 0.22 }, { duration: bgTweenDuration, easing: tween.easeInOut, onFinish: function onFinish() { bgColorIdx2 = nextIdx2; } }); } // Call setupGradientBackground once at game start setupGradientBackground(); var BALL_SIZE = 420; var NOTE_WIDTH = 180; // was 120, now wider for less thin look var NOTE_HEIGHT = 180; // reduced from 260 to make notes less long var CROSS_SIZE = 160; var BULLET_SIZE = 60; var NOTE_COLS = 5; var NOTE_MARGIN = 60; var NOTE_AREA_W = GAME_W - 2 * NOTE_MARGIN; var NOTE_COL_W = NOTE_AREA_W / NOTE_COLS; var NOTE_START_Y = -NOTE_HEIGHT; var BALL_X = 180; var BALL_Y = GAME_H - 220; var CROSS_MIN_X = 200; var CROSS_MAX_X = GAME_W - 200; var CROSS_MIN_Y = 200; var CROSS_MAX_Y = GAME_H - 400; var BULLET_SPEED = 48; // px per frame // --- Game State --- var notes = []; var bullets = []; var crosshair = null; var ball = null; var scoreTxt = null; var tipTxt = null; var lastNoteSpawnTick = 0; var noteFallSpeed = 12; // will be set by difficulty var noteSpawnInterval = 60; // ticks between notes, will be set by difficulty var difficulty = null; // 'slow', 'normal', 'fast' var gameStarted = false; var canShoot = true; var lastScore = 0; var musicTracks = [{ id: 'music1', name: 'Parça 1' }, { id: 'music2', name: 'Parça 2' }, { id: 'music3', name: 'Parça 3' }]; var currentMusic = null; // --- Difficulty Presets --- // Slowed down for all modes var DIFFICULTY_PRESETS = { 'slow': { noteFallSpeed: 5, noteSpawnInterval: 120 }, 'normal': { noteFallSpeed: 7, noteSpawnInterval: 90 }, 'fast': { noteFallSpeed: 10, noteSpawnInterval: 60 } }; // --- UI: Difficulty Selection --- var diffBtns = []; function showDifficultyMenu() { // Play menu music if not already playing LK.stopMusic(); LK.playMusic('Menu1', { loop: true }); // Hide facekit video feed if visible if (facekit && typeof facekit.setVisible === "function") { facekit.setVisible(false); } // Add Backr image as background if (!game._diffMenuBackr) { var backr = LK.getAsset('Backr', { anchorX: 0.5, anchorY: 0.5, width: GAME_W, height: GAME_H, x: GAME_W / 2, y: GAME_H / 2, scaleMode: 'nearest' // prevent blurriness by using nearest neighbor scaling }); if (typeof backr.setScaleMode === "function") { backr.setScaleMode('nearest'); } game.addChild(backr); game._diffMenuBackr = backr; } var btnLabels = [{ key: 'slow', label: 'Slow' }, { key: 'normal', label: 'Normal' }, { key: 'fast', label: 'Fast' }]; var btnW = 500, btnH = 180, btnGap = 60; var startY = GAME_H / 2 - (btnLabels.length * btnH + (btnLabels.length - 1) * btnGap) / 2; for (var i = 0; i < btnLabels.length; i++) { var btn = new Container(); var bg = btn.attachAsset('btnbg', { anchorX: 0.5, anchorY: 0.5, width: btnW, height: btnH, color: 0x222a38, shape: 'box' }); var txt = new Text2(btnLabels[i].label, { size: 90, fill: "#fff" }); txt.anchor.set(0.5, 0.5); txt.x = 0; txt.y = 0; btn.addChild(txt); btn.x = GAME_W / 2; btn.y = startY + i * (btnH + btnGap); btn.difficulty = btnLabels[i].key; btn.down = function (x, y, obj) { startGame(this.difficulty); }; game.addChild(btn); diffBtns.push(btn); } // Show tip if (!tipTxt) { tipTxt = new Text2("AIM AT THE NOTES BY\nMOVING YOUR HEAD\nAND FIRE THE GUN BY\nTAPPING THE SCREEN.", { size: 70, fill: 0xFFFFFF }); tipTxt.anchor.set(0.5, 0); } // Place btnbg behind tipTxt, sized to match tipTxt if (!game._tipBg) { // Use tipTxt.width/height after anchor set var bgPadX = 60; var bgPadY = 40; var btnbgW = tipTxt.width + bgPadX; var btnbgH = tipTxt.height + bgPadY; var tipBg = LK.getAsset('btnbg', { anchorX: 0.5, anchorY: 0, width: btnbgW, height: btnbgH, color: 0x000000, shape: 'box' }); tipBg.x = GAME_W / 2; tipBg.y = 180 - bgPadY / 2; game.addChild(tipBg); game._tipBg = tipBg; } tipTxt.x = GAME_W / 2; tipTxt.y = 180; game.addChild(tipTxt); } // Remove difficulty menu function hideDifficultyMenu() { // Restore facekit video feed if (facekit && typeof facekit.setVisible === "function") { facekit.setVisible(true); } // Remove Backr background if present if (game._diffMenuBackr) { game._diffMenuBackr.destroy(); game._diffMenuBackr = null; } for (var i = 0; i < diffBtns.length; i++) { diffBtns[i].destroy(); } diffBtns = []; if (tipTxt) { tipTxt.destroy(); tipTxt = null; if (game._tipBg) { game._tipBg.destroy(); game._tipBg = null; } } } // --- Start Game --- function startGame(diffKey) { difficulty = diffKey; noteFallSpeed = DIFFICULTY_PRESETS[diffKey].noteFallSpeed; noteSpawnInterval = DIFFICULTY_PRESETS[diffKey].noteSpawnInterval; gameStarted = false; // Will be set to true after countdown // Stop menu music if playing LK.stopMusic(); hideDifficultyMenu(); LK.setScore(0); lastScore = 0; // Clean up any existing notes and bullets before starting for (var i = 0; i < notes.length; i++) { if (notes[i]) notes[i].destroy(); } notes = []; for (var i = 0; i < bullets.length; i++) { if (bullets[i]) bullets[i].destroy(); } bullets = []; // Play PH6 only in fast mode, and make it more dominant in randomization var musicChoices; if (difficulty === 'fast') { // PH6 is more dominant: add it multiple times to increase its chance musicChoices = ['Ph6', 'Ph6', 'Ph6', 'Piano1', 'P2', 'P3', 'P4', 'P5']; } else { musicChoices = ['Piano1', 'P2', 'P3', 'P4', 'P5']; } var selectedMusic = musicChoices[Math.floor(Math.random() * musicChoices.length)]; // Stop any currently playing music before starting new one LK.stopMusic(); // Play the selected music with default options (looping, full volume) LK.playMusic(selectedMusic, { loop: true, fade: { start: 0, end: 1, duration: 400 } }); // Ball ball = new Ball(); ball.x = BALL_X; ball.y = BALL_Y; game.addChild(ball); // Crosshair crosshair = new Crosshair(); crosshair.x = BALL_X + 400; crosshair.y = BALL_Y - 400; game.addChild(crosshair); // Score if (!scoreTxt) { scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); } scoreTxt.setText(0); // Remove tipTxt immediately if present when game starts if (tipTxt) { tipTxt.destroy(); tipTxt = null; } // --- 3 2 1 Go! Countdown --- var countdownColors = ["#ff2d2d", "#ffe066", "#7cff66", "#a259ff"]; var countdownTexts = ["3", "2", "1", "Go!"]; var countdownObjs = []; var countdownIdx = 0; function showCountdownStep(idx) { // Remove previous countdown text if any for (var i = 0; i < countdownObjs.length; i++) { if (countdownObjs[i]) { countdownObjs[i].destroy(); } } countdownObjs = []; if (idx < countdownTexts.length) { var txt = new Text2(countdownTexts[idx], { size: idx === 3 ? 180 : 160, fill: countdownColors[idx] }); txt.anchor.set(0.5, 0.5); txt.x = GAME_W / 2; txt.y = GAME_H / 2; game.addChild(txt); countdownObjs.push(txt); // Animate scale up and fade out txt.scale.set(1, 1); txt.alpha = 1; tween(txt, { scaleX: 1.25, scaleY: 1.25, alpha: 0.0 }, { duration: 600, delay: 400, onFinish: function onFinish() { txt.destroy(); } }); // Next step after 800ms LK.setTimeout(function () { showCountdownStep(idx + 1); }, 800); } else { // Countdown finished, start game gameStarted = true; } } showCountdownStep(0); } // --- End Game --- function endGame(win) { // Clean up for (var i = 0; i < notes.length; i++) { if (notes[i]) notes[i].destroy(); } notes = []; for (var i = 0; i < bullets.length; i++) { if (bullets[i]) bullets[i].destroy(); } bullets = []; if (ball) { ball.destroy(); ball = null; } if (crosshair) { crosshair.destroy(); crosshair = null; } gameStarted = false; LK.stopMusic(); if (win) { // Show win, then play menu music after popup closes LK.showYouWin(); LK.setTimeout(function () { LK.stopMusic(); LK.playMusic('Menu1', { loop: true }); }, 1200); } else { LK.showGameOver(); LK.setTimeout(function () { LK.stopMusic(); LK.playMusic('Menu1', { loop: true }); }, 1200); } } // --- Note Spawning --- function spawnNote() { // 15% chance to spawn NotaggNote, otherwise normal Note var isNotagg = Math.random() < 0.15; var note; if (isNotagg) { note = new NotaggNote(); } else { note = new Note(); } // Pick a random column, now including the far left (index 0) so notes can fall above the gun // allowedCols now includes 0,1,2,3,4 (all columns) var allowedCols = []; for (var i = 0; i < NOTE_COLS; i++) { allowedCols.push(i); } // Increase position variation: allow some random offset within each column var col = allowedCols[Math.floor(Math.random() * allowedCols.length)]; note.column = col; // Add random offset within the column for more variation var colOffset = 0; if (difficulty === 'slow') { colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.3); // up to ±15% of col width } else if (difficulty === 'normal') { colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.5); // up to ±25% of col width } else if (difficulty === 'fast') { colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.7); // up to ±35% of col width } note.x = NOTE_MARGIN + NOTE_COL_W / 2 + col * NOTE_COL_W + colOffset; note.y = NOTE_START_Y; // Increase falling speed slightly per mode if (difficulty === 'slow') { note.speed = noteFallSpeed + 1.2 + Math.random() * 0.8; // 1.2-2.0 px/frame more } else if (difficulty === 'normal') { note.speed = noteFallSpeed + 2.2 + Math.random() * 1.2; // 2.2-3.4 px/frame more } else if (difficulty === 'fast') { note.speed = noteFallSpeed + 3.2 + Math.random() * 1.8; // 3.2-5 px/frame more } else { note.speed = noteFallSpeed; } notes.push(note); game.addChild(note); } // --- Difficulty Increase --- function maybeIncreaseDifficulty() { var score = LK.getScore(); if (score > 0 && score % 10 === 0 && score !== lastScore) { // Increase speed and spawn rate noteFallSpeed += 2; if (noteSpawnInterval > 20) noteSpawnInterval -= 6; lastScore = score; } } // --- Facekit Crosshair Update --- function updateCrosshair() { if (!crosshair) return; // Use facekit.noseTip or facekit.mouthCenter for aiming var fx = facekit.noseTip ? facekit.noseTip.x : facekit.mouthCenter ? facekit.mouthCenter.x : GAME_W / 2; var fy = facekit.noseTip ? facekit.noseTip.y : facekit.mouthCenter ? facekit.mouthCenter.y : GAME_H / 2; // Clamp to play area if (fx < CROSS_MIN_X) fx = CROSS_MIN_X; if (fx > CROSS_MAX_X) fx = CROSS_MAX_X; if (fy < CROSS_MIN_Y) fy = CROSS_MIN_Y; if (fy > CROSS_MAX_Y) fy = CROSS_MAX_Y; // Instantly set crosshair position (no smoothing, no tween) crosshair.x = fx; crosshair.y = fy; } // --- Fire Bullet --- function fireBullet() { if (!canShoot || !gameStarted) return; canShoot = false; // Find if crosshair is over a note var hitNote = null; for (var i = 0; i < notes.length; i++) { var n = notes[i]; if (!n.hit && crosshair && crosshair.intersects(n)) { hitNote = n; break; } } // Fire bullet towards crosshair var b = new Bullet(); b.x = ball.x; b.y = ball.y; // Direction vector var dx = crosshair.x - ball.x; var dy = crosshair.y - ball.y; var len = Math.sqrt(dx * dx + dy * dy); if (len === 0) { dx = 0; dy = -1; len = 1; } b.vx = BULLET_SPEED * dx / len; b.vy = BULLET_SPEED * dy / len; bullets.push(b); game.addChild(b); // If hitNote, mark as hit (so only one bullet per note) if (hitNote) { // If it's a NotaggNote, end game immediately if (hitNote.isNotagg) { endGame(false); return; } hitNote.hit = true; } // Play note sound (simulate: play a sound per note column) // Stop all note sounds before playing a new one to prevent overlap for (var i = 0; i < NOTE_COLS; i++) { var s = LK.getSound('note' + i); if (s && typeof s.stop === "function") s.stop(); } var soundId = 'note' + (hitNote ? hitNote.column : Math.floor(Math.random() * NOTE_COLS)); LK.getSound(soundId).play(); // Allow next shot after a normal delay (normal fire rate) LK.setTimeout(function () { canShoot = true; }, 320); } // --- Main Game Loop --- game.down = function (x, y, obj) { if (gameStarted) { fireBullet(); } }; game.update = function () { if (!gameStarted) return; // --- Optimize: Use local variables, avoid per-frame allocations, and minimize nested loops --- // Update crosshair position from facekit updateCrosshair(); // Spawn notes if (LK.ticks - lastNoteSpawnTick >= noteSpawnInterval) { spawnNote(); lastNoteSpawnTick = LK.ticks; } // --- Update notes --- // Use a single pass to update and remove notes that are offscreen or hit for (var i = notes.length - 1; i >= 0; i--) { var n = notes[i]; n.update(); // If note falls below screen, trigger game over for all except NotaggNote if (n.y > GAME_H + NOTE_HEIGHT / 2) { // If it's a NotaggNote, just remove it, do not end game if (n.isNotagg) { n.visible = false; n.destroy(); notes.splice(i, 1); continue; } // For all other notes, reaching the bottom is game over endGame(false); return; } } // --- Update bullets --- // Use local references to avoid repeated property lookups for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove bullet if out of bounds if (b.x < -100 || b.x > GAME_W + 100 || b.y < -100 || b.y > GAME_H + 100) { b.destroy(); bullets.splice(i, 1); continue; } // --- Optimize: Only check for collisions with visible, unhit notes --- var bulletHit = false; for (var j = notes.length - 1; j >= 0; j--) { var n = notes[j]; if (n.hit || n.visible === false) continue; // Initialize lastWasIntersecting if not set if (typeof b.lastWasIntersecting === "undefined") b.lastWasIntersecting = false; var isIntersecting = b.intersects(n); // Make hitbox more forgiving: allow hit if bullet is close to note center (within 0.6*NOTE_WIDTH and 0.6*NOTE_HEIGHT) var forgivingHit = false; var dx = Math.abs(b.x - n.x); var dy = Math.abs(b.y - n.y); if (dx < NOTE_WIDTH * 0.6 && dy < NOTE_HEIGHT * 0.6) { forgivingHit = true; } // Only allow hit if note is not already hit and not already destroyed, and bullet just started intersecting or is within forgiving hitbox if (b.lastWasIntersecting === false && isIntersecting || forgivingHit) { // If it's a NotaggNote, end game immediately if (n.isNotagg) { endGame(false); return; } n.hit = true; // Mark as hit immediately to prevent double hits notes.splice(j, 1); // Remove from notes array immediately to prevent further processing LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); // Animate note color to gray/black, then remove if (n.children && n.children.length > 0 && n.children[0]) { var noteAsset = n.children[0]; tween(noteAsset, { tint: 0x222222 }, { duration: 60, onFinish: function (noteAsset, n) { return function () { if (noteAsset && noteAsset.parent) { noteAsset.parent.removeChild(noteAsset); } n.visible = false; n.destroy(); }; }(noteAsset, n) }); } else { n.visible = false; n.destroy(); } // Spawn floating music note effect at note position var effect = new MusicNoteEffect(); effect.start(n.x, n.y); game.addChild(effect); b.destroy(); bullets.splice(i, 1); // Difficulty up maybeIncreaseDifficulty(); // Win condition: 50 points if (LK.getScore() >= 50) { endGame(true); return; } bulletHit = true; break; } b.lastWasIntersecting = isIntersecting; } if (bulletHit) continue; } }; // --- Show Difficulty Menu on Start --- showDifficultyMenu(); // Prevent in-game sounds from playing in the menu by disabling their playback when not in game // Patch LK.getSound to return a dummy object with a no-op play() if not gameStarted var _LK_getSound = LK.getSound; LK.getSound = function (id) { if (!gameStarted) { return { play: function play() {} }; } return _LK_getSound.call(LK, id); }; /**** * Asset Initialization (for static analysis) ****/ // Notes (5 columns, 5 colors) for (var i = 0; i < NOTE_COLS; i++) {} // Ball // Crosshair // Bullet // Button background // Music tracks
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Ball class: the fixed shooter at bottom left
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballAsset = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
width: BALL_SIZE,
height: BALL_SIZE,
color: 0xffffff,
shape: 'ellipse'
});
return self;
});
// Bullet class: fired from ball towards crosshair
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
width: BULLET_SIZE,
height: BULLET_SIZE,
color: 0x00e6e6,
shape: 'ellipse'
});
self.vx = 0;
self.vy = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Crosshair class: follows facekit position
var Crosshair = Container.expand(function () {
var self = Container.call(this);
var crossAsset = self.attachAsset('crosshair', {
anchorX: 0.5,
anchorY: 0.5,
width: CROSS_SIZE,
height: CROSS_SIZE,
color: 0xff0000,
shape: 'ellipse'
});
return self;
});
// MusicNoteEffect class: floating music note symbol when a note is hit
var MusicNoteEffect = Container.expand(function () {
var self = Container.call(this);
// Use a Text2 object for the music note symbol
var noteSymbol = new Text2("♪", {
size: 120,
fill: "#fff"
});
noteSymbol.anchor.set(0.5, 0.5);
self.addChild(noteSymbol);
// Animate: float up and fade out
self.start = function (startX, startY) {
self.x = startX;
self.y = startY;
self.alpha = 1;
// Tween upward and fade out
tween(self, {
y: self.y - 220,
alpha: 0
}, {
duration: 700,
easing: tween.cubicOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
// NotaggNote class: falling notagg note (special note, ends game if tapped)
var NotaggNote = Container.expand(function () {
var self = Container.call(this);
var notaggAsset = self.attachAsset('Notagg', {
anchorX: 0.5,
anchorY: 0.5,
width: NOTE_WIDTH,
height: NOTE_HEIGHT
});
self.column = 0;
self.speed = noteFallSpeed;
self.hit = false;
self.isNotagg = true; // flag for special handling
self.update = function () {
self.y += self.speed;
};
return self;
});
// Note class: falling note
var Note = Container.expand(function () {
var self = Container.call(this);
// Randomly pick a color for the note
var color = NOTE_COLORS[Math.floor(Math.random() * NOTE_COLORS.length)];
var noteAsset = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5,
width: NOTE_WIDTH,
// now wider
height: NOTE_HEIGHT,
color: color,
shape: 'box'
});
self.column = 0; // which column this note is in
self.speed = noteFallSpeed; // will be set on spawn
self.hit = false; // has this note been hit
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181a20
});
/****
* Game Code
****/
// Note: All note assets will be ellipses with different colors for variety
// --- Constants ---
// Ensure Notagg matches note image size
var NOTE_COLORS = [0xffe066, 0x66b3ff, 0xff66a3, 0x7cff66, 0xff8c66];
var GAME_W = 2048;
var GAME_H = 2732;
// --- Dynamic Gradient Background ---
// We'll use two large colored rectangles, tweening their tints and alpha for a subtle animated gradient effect.
var bgLayer1 = null;
var bgLayer2 = null;
var bgGradientColors = [0x8635f1,
// purple
0x66b3ff,
// blue
0xff66a3,
// pink
0x7cff66,
// green
0xffe066,
// yellow
0xb39ddb // lavender
];
var bgColorIdx1 = 0;
var bgColorIdx2 = 1;
var bgTweenDuration = 8000; // ms, slightly longer for smoother transitions
function setupGradientBackground() {
// Remove if already present
if (bgLayer1) {
bgLayer1.destroy();
bgLayer1 = null;
}
if (bgLayer2) {
bgLayer2.destroy();
bgLayer2 = null;
}
// Layer 1
bgLayer1 = LK.getAsset('softbg2', {
anchorX: 0.5,
anchorY: 0.5,
width: GAME_W * 1.1,
height: GAME_H * 1.1,
x: GAME_W / 2,
y: GAME_H / 2,
// Start with first color, slightly more visible
tint: bgGradientColors[bgColorIdx1],
alpha: 0.32
});
// Layer 2
bgLayer2 = LK.getAsset('softbg2', {
anchorX: 0.5,
anchorY: 0.5,
width: GAME_W * 1.1,
height: GAME_H * 1.1,
x: GAME_W / 2,
y: GAME_H / 2,
// Start with second color, slightly more visible
tint: bgGradientColors[bgColorIdx2],
alpha: 0.22
});
// Add to back of display list
game.addChildAt(bgLayer1, 0);
game.addChildAt(bgLayer2, 1);
// Start the animation loop
animateGradientBackground();
}
function animateGradientBackground() {
// Pick next color indices
var nextIdx1 = (bgColorIdx1 + 1) % bgGradientColors.length;
var nextIdx2 = (bgColorIdx2 + 1) % bgGradientColors.length;
// Animate tints and alpha for both layers, smoothly transitioning to next color
tween(bgLayer1, {
tint: bgGradientColors[nextIdx1],
alpha: 0.32
}, {
duration: bgTweenDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
bgColorIdx1 = nextIdx1;
animateGradientBackground();
}
});
tween(bgLayer2, {
tint: bgGradientColors[nextIdx2],
alpha: 0.22
}, {
duration: bgTweenDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
bgColorIdx2 = nextIdx2;
}
});
}
// Call setupGradientBackground once at game start
setupGradientBackground();
var BALL_SIZE = 420;
var NOTE_WIDTH = 180; // was 120, now wider for less thin look
var NOTE_HEIGHT = 180; // reduced from 260 to make notes less long
var CROSS_SIZE = 160;
var BULLET_SIZE = 60;
var NOTE_COLS = 5;
var NOTE_MARGIN = 60;
var NOTE_AREA_W = GAME_W - 2 * NOTE_MARGIN;
var NOTE_COL_W = NOTE_AREA_W / NOTE_COLS;
var NOTE_START_Y = -NOTE_HEIGHT;
var BALL_X = 180;
var BALL_Y = GAME_H - 220;
var CROSS_MIN_X = 200;
var CROSS_MAX_X = GAME_W - 200;
var CROSS_MIN_Y = 200;
var CROSS_MAX_Y = GAME_H - 400;
var BULLET_SPEED = 48; // px per frame
// --- Game State ---
var notes = [];
var bullets = [];
var crosshair = null;
var ball = null;
var scoreTxt = null;
var tipTxt = null;
var lastNoteSpawnTick = 0;
var noteFallSpeed = 12; // will be set by difficulty
var noteSpawnInterval = 60; // ticks between notes, will be set by difficulty
var difficulty = null; // 'slow', 'normal', 'fast'
var gameStarted = false;
var canShoot = true;
var lastScore = 0;
var musicTracks = [{
id: 'music1',
name: 'Parça 1'
}, {
id: 'music2',
name: 'Parça 2'
}, {
id: 'music3',
name: 'Parça 3'
}];
var currentMusic = null;
// --- Difficulty Presets ---
// Slowed down for all modes
var DIFFICULTY_PRESETS = {
'slow': {
noteFallSpeed: 5,
noteSpawnInterval: 120
},
'normal': {
noteFallSpeed: 7,
noteSpawnInterval: 90
},
'fast': {
noteFallSpeed: 10,
noteSpawnInterval: 60
}
};
// --- UI: Difficulty Selection ---
var diffBtns = [];
function showDifficultyMenu() {
// Play menu music if not already playing
LK.stopMusic();
LK.playMusic('Menu1', {
loop: true
});
// Hide facekit video feed if visible
if (facekit && typeof facekit.setVisible === "function") {
facekit.setVisible(false);
}
// Add Backr image as background
if (!game._diffMenuBackr) {
var backr = LK.getAsset('Backr', {
anchorX: 0.5,
anchorY: 0.5,
width: GAME_W,
height: GAME_H,
x: GAME_W / 2,
y: GAME_H / 2,
scaleMode: 'nearest' // prevent blurriness by using nearest neighbor scaling
});
if (typeof backr.setScaleMode === "function") {
backr.setScaleMode('nearest');
}
game.addChild(backr);
game._diffMenuBackr = backr;
}
var btnLabels = [{
key: 'slow',
label: 'Slow'
}, {
key: 'normal',
label: 'Normal'
}, {
key: 'fast',
label: 'Fast'
}];
var btnW = 500,
btnH = 180,
btnGap = 60;
var startY = GAME_H / 2 - (btnLabels.length * btnH + (btnLabels.length - 1) * btnGap) / 2;
for (var i = 0; i < btnLabels.length; i++) {
var btn = new Container();
var bg = btn.attachAsset('btnbg', {
anchorX: 0.5,
anchorY: 0.5,
width: btnW,
height: btnH,
color: 0x222a38,
shape: 'box'
});
var txt = new Text2(btnLabels[i].label, {
size: 90,
fill: "#fff"
});
txt.anchor.set(0.5, 0.5);
txt.x = 0;
txt.y = 0;
btn.addChild(txt);
btn.x = GAME_W / 2;
btn.y = startY + i * (btnH + btnGap);
btn.difficulty = btnLabels[i].key;
btn.down = function (x, y, obj) {
startGame(this.difficulty);
};
game.addChild(btn);
diffBtns.push(btn);
}
// Show tip
if (!tipTxt) {
tipTxt = new Text2("AIM AT THE NOTES BY\nMOVING YOUR HEAD\nAND FIRE THE GUN BY\nTAPPING THE SCREEN.", {
size: 70,
fill: 0xFFFFFF
});
tipTxt.anchor.set(0.5, 0);
}
// Place btnbg behind tipTxt, sized to match tipTxt
if (!game._tipBg) {
// Use tipTxt.width/height after anchor set
var bgPadX = 60;
var bgPadY = 40;
var btnbgW = tipTxt.width + bgPadX;
var btnbgH = tipTxt.height + bgPadY;
var tipBg = LK.getAsset('btnbg', {
anchorX: 0.5,
anchorY: 0,
width: btnbgW,
height: btnbgH,
color: 0x000000,
shape: 'box'
});
tipBg.x = GAME_W / 2;
tipBg.y = 180 - bgPadY / 2;
game.addChild(tipBg);
game._tipBg = tipBg;
}
tipTxt.x = GAME_W / 2;
tipTxt.y = 180;
game.addChild(tipTxt);
}
// Remove difficulty menu
function hideDifficultyMenu() {
// Restore facekit video feed
if (facekit && typeof facekit.setVisible === "function") {
facekit.setVisible(true);
}
// Remove Backr background if present
if (game._diffMenuBackr) {
game._diffMenuBackr.destroy();
game._diffMenuBackr = null;
}
for (var i = 0; i < diffBtns.length; i++) {
diffBtns[i].destroy();
}
diffBtns = [];
if (tipTxt) {
tipTxt.destroy();
tipTxt = null;
if (game._tipBg) {
game._tipBg.destroy();
game._tipBg = null;
}
}
}
// --- Start Game ---
function startGame(diffKey) {
difficulty = diffKey;
noteFallSpeed = DIFFICULTY_PRESETS[diffKey].noteFallSpeed;
noteSpawnInterval = DIFFICULTY_PRESETS[diffKey].noteSpawnInterval;
gameStarted = false; // Will be set to true after countdown
// Stop menu music if playing
LK.stopMusic();
hideDifficultyMenu();
LK.setScore(0);
lastScore = 0;
// Clean up any existing notes and bullets before starting
for (var i = 0; i < notes.length; i++) {
if (notes[i]) notes[i].destroy();
}
notes = [];
for (var i = 0; i < bullets.length; i++) {
if (bullets[i]) bullets[i].destroy();
}
bullets = [];
// Play PH6 only in fast mode, and make it more dominant in randomization
var musicChoices;
if (difficulty === 'fast') {
// PH6 is more dominant: add it multiple times to increase its chance
musicChoices = ['Ph6', 'Ph6', 'Ph6', 'Piano1', 'P2', 'P3', 'P4', 'P5'];
} else {
musicChoices = ['Piano1', 'P2', 'P3', 'P4', 'P5'];
}
var selectedMusic = musicChoices[Math.floor(Math.random() * musicChoices.length)];
// Stop any currently playing music before starting new one
LK.stopMusic();
// Play the selected music with default options (looping, full volume)
LK.playMusic(selectedMusic, {
loop: true,
fade: {
start: 0,
end: 1,
duration: 400
}
});
// Ball
ball = new Ball();
ball.x = BALL_X;
ball.y = BALL_Y;
game.addChild(ball);
// Crosshair
crosshair = new Crosshair();
crosshair.x = BALL_X + 400;
crosshair.y = BALL_Y - 400;
game.addChild(crosshair);
// Score
if (!scoreTxt) {
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
}
scoreTxt.setText(0);
// Remove tipTxt immediately if present when game starts
if (tipTxt) {
tipTxt.destroy();
tipTxt = null;
}
// --- 3 2 1 Go! Countdown ---
var countdownColors = ["#ff2d2d", "#ffe066", "#7cff66", "#a259ff"];
var countdownTexts = ["3", "2", "1", "Go!"];
var countdownObjs = [];
var countdownIdx = 0;
function showCountdownStep(idx) {
// Remove previous countdown text if any
for (var i = 0; i < countdownObjs.length; i++) {
if (countdownObjs[i]) {
countdownObjs[i].destroy();
}
}
countdownObjs = [];
if (idx < countdownTexts.length) {
var txt = new Text2(countdownTexts[idx], {
size: idx === 3 ? 180 : 160,
fill: countdownColors[idx]
});
txt.anchor.set(0.5, 0.5);
txt.x = GAME_W / 2;
txt.y = GAME_H / 2;
game.addChild(txt);
countdownObjs.push(txt);
// Animate scale up and fade out
txt.scale.set(1, 1);
txt.alpha = 1;
tween(txt, {
scaleX: 1.25,
scaleY: 1.25,
alpha: 0.0
}, {
duration: 600,
delay: 400,
onFinish: function onFinish() {
txt.destroy();
}
});
// Next step after 800ms
LK.setTimeout(function () {
showCountdownStep(idx + 1);
}, 800);
} else {
// Countdown finished, start game
gameStarted = true;
}
}
showCountdownStep(0);
}
// --- End Game ---
function endGame(win) {
// Clean up
for (var i = 0; i < notes.length; i++) {
if (notes[i]) notes[i].destroy();
}
notes = [];
for (var i = 0; i < bullets.length; i++) {
if (bullets[i]) bullets[i].destroy();
}
bullets = [];
if (ball) {
ball.destroy();
ball = null;
}
if (crosshair) {
crosshair.destroy();
crosshair = null;
}
gameStarted = false;
LK.stopMusic();
if (win) {
// Show win, then play menu music after popup closes
LK.showYouWin();
LK.setTimeout(function () {
LK.stopMusic();
LK.playMusic('Menu1', {
loop: true
});
}, 1200);
} else {
LK.showGameOver();
LK.setTimeout(function () {
LK.stopMusic();
LK.playMusic('Menu1', {
loop: true
});
}, 1200);
}
}
// --- Note Spawning ---
function spawnNote() {
// 15% chance to spawn NotaggNote, otherwise normal Note
var isNotagg = Math.random() < 0.15;
var note;
if (isNotagg) {
note = new NotaggNote();
} else {
note = new Note();
}
// Pick a random column, now including the far left (index 0) so notes can fall above the gun
// allowedCols now includes 0,1,2,3,4 (all columns)
var allowedCols = [];
for (var i = 0; i < NOTE_COLS; i++) {
allowedCols.push(i);
}
// Increase position variation: allow some random offset within each column
var col = allowedCols[Math.floor(Math.random() * allowedCols.length)];
note.column = col;
// Add random offset within the column for more variation
var colOffset = 0;
if (difficulty === 'slow') {
colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.3); // up to ±15% of col width
} else if (difficulty === 'normal') {
colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.5); // up to ±25% of col width
} else if (difficulty === 'fast') {
colOffset = (Math.random() - 0.5) * (NOTE_COL_W * 0.7); // up to ±35% of col width
}
note.x = NOTE_MARGIN + NOTE_COL_W / 2 + col * NOTE_COL_W + colOffset;
note.y = NOTE_START_Y;
// Increase falling speed slightly per mode
if (difficulty === 'slow') {
note.speed = noteFallSpeed + 1.2 + Math.random() * 0.8; // 1.2-2.0 px/frame more
} else if (difficulty === 'normal') {
note.speed = noteFallSpeed + 2.2 + Math.random() * 1.2; // 2.2-3.4 px/frame more
} else if (difficulty === 'fast') {
note.speed = noteFallSpeed + 3.2 + Math.random() * 1.8; // 3.2-5 px/frame more
} else {
note.speed = noteFallSpeed;
}
notes.push(note);
game.addChild(note);
}
// --- Difficulty Increase ---
function maybeIncreaseDifficulty() {
var score = LK.getScore();
if (score > 0 && score % 10 === 0 && score !== lastScore) {
// Increase speed and spawn rate
noteFallSpeed += 2;
if (noteSpawnInterval > 20) noteSpawnInterval -= 6;
lastScore = score;
}
}
// --- Facekit Crosshair Update ---
function updateCrosshair() {
if (!crosshair) return;
// Use facekit.noseTip or facekit.mouthCenter for aiming
var fx = facekit.noseTip ? facekit.noseTip.x : facekit.mouthCenter ? facekit.mouthCenter.x : GAME_W / 2;
var fy = facekit.noseTip ? facekit.noseTip.y : facekit.mouthCenter ? facekit.mouthCenter.y : GAME_H / 2;
// Clamp to play area
if (fx < CROSS_MIN_X) fx = CROSS_MIN_X;
if (fx > CROSS_MAX_X) fx = CROSS_MAX_X;
if (fy < CROSS_MIN_Y) fy = CROSS_MIN_Y;
if (fy > CROSS_MAX_Y) fy = CROSS_MAX_Y;
// Instantly set crosshair position (no smoothing, no tween)
crosshair.x = fx;
crosshair.y = fy;
}
// --- Fire Bullet ---
function fireBullet() {
if (!canShoot || !gameStarted) return;
canShoot = false;
// Find if crosshair is over a note
var hitNote = null;
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
if (!n.hit && crosshair && crosshair.intersects(n)) {
hitNote = n;
break;
}
}
// Fire bullet towards crosshair
var b = new Bullet();
b.x = ball.x;
b.y = ball.y;
// Direction vector
var dx = crosshair.x - ball.x;
var dy = crosshair.y - ball.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len === 0) {
dx = 0;
dy = -1;
len = 1;
}
b.vx = BULLET_SPEED * dx / len;
b.vy = BULLET_SPEED * dy / len;
bullets.push(b);
game.addChild(b);
// If hitNote, mark as hit (so only one bullet per note)
if (hitNote) {
// If it's a NotaggNote, end game immediately
if (hitNote.isNotagg) {
endGame(false);
return;
}
hitNote.hit = true;
}
// Play note sound (simulate: play a sound per note column)
// Stop all note sounds before playing a new one to prevent overlap
for (var i = 0; i < NOTE_COLS; i++) {
var s = LK.getSound('note' + i);
if (s && typeof s.stop === "function") s.stop();
}
var soundId = 'note' + (hitNote ? hitNote.column : Math.floor(Math.random() * NOTE_COLS));
LK.getSound(soundId).play();
// Allow next shot after a normal delay (normal fire rate)
LK.setTimeout(function () {
canShoot = true;
}, 320);
}
// --- Main Game Loop ---
game.down = function (x, y, obj) {
if (gameStarted) {
fireBullet();
}
};
game.update = function () {
if (!gameStarted) return;
// --- Optimize: Use local variables, avoid per-frame allocations, and minimize nested loops ---
// Update crosshair position from facekit
updateCrosshair();
// Spawn notes
if (LK.ticks - lastNoteSpawnTick >= noteSpawnInterval) {
spawnNote();
lastNoteSpawnTick = LK.ticks;
}
// --- Update notes ---
// Use a single pass to update and remove notes that are offscreen or hit
for (var i = notes.length - 1; i >= 0; i--) {
var n = notes[i];
n.update();
// If note falls below screen, trigger game over for all except NotaggNote
if (n.y > GAME_H + NOTE_HEIGHT / 2) {
// If it's a NotaggNote, just remove it, do not end game
if (n.isNotagg) {
n.visible = false;
n.destroy();
notes.splice(i, 1);
continue;
}
// For all other notes, reaching the bottom is game over
endGame(false);
return;
}
}
// --- Update bullets ---
// Use local references to avoid repeated property lookups
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove bullet if out of bounds
if (b.x < -100 || b.x > GAME_W + 100 || b.y < -100 || b.y > GAME_H + 100) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// --- Optimize: Only check for collisions with visible, unhit notes ---
var bulletHit = false;
for (var j = notes.length - 1; j >= 0; j--) {
var n = notes[j];
if (n.hit || n.visible === false) continue;
// Initialize lastWasIntersecting if not set
if (typeof b.lastWasIntersecting === "undefined") b.lastWasIntersecting = false;
var isIntersecting = b.intersects(n);
// Make hitbox more forgiving: allow hit if bullet is close to note center (within 0.6*NOTE_WIDTH and 0.6*NOTE_HEIGHT)
var forgivingHit = false;
var dx = Math.abs(b.x - n.x);
var dy = Math.abs(b.y - n.y);
if (dx < NOTE_WIDTH * 0.6 && dy < NOTE_HEIGHT * 0.6) {
forgivingHit = true;
}
// Only allow hit if note is not already hit and not already destroyed, and bullet just started intersecting or is within forgiving hitbox
if (b.lastWasIntersecting === false && isIntersecting || forgivingHit) {
// If it's a NotaggNote, end game immediately
if (n.isNotagg) {
endGame(false);
return;
}
n.hit = true; // Mark as hit immediately to prevent double hits
notes.splice(j, 1); // Remove from notes array immediately to prevent further processing
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
// Animate note color to gray/black, then remove
if (n.children && n.children.length > 0 && n.children[0]) {
var noteAsset = n.children[0];
tween(noteAsset, {
tint: 0x222222
}, {
duration: 60,
onFinish: function (noteAsset, n) {
return function () {
if (noteAsset && noteAsset.parent) {
noteAsset.parent.removeChild(noteAsset);
}
n.visible = false;
n.destroy();
};
}(noteAsset, n)
});
} else {
n.visible = false;
n.destroy();
}
// Spawn floating music note effect at note position
var effect = new MusicNoteEffect();
effect.start(n.x, n.y);
game.addChild(effect);
b.destroy();
bullets.splice(i, 1);
// Difficulty up
maybeIncreaseDifficulty();
// Win condition: 50 points
if (LK.getScore() >= 50) {
endGame(true);
return;
}
bulletHit = true;
break;
}
b.lastWasIntersecting = isIntersecting;
}
if (bulletHit) continue;
}
};
// --- Show Difficulty Menu on Start ---
showDifficultyMenu();
// Prevent in-game sounds from playing in the menu by disabling their playback when not in game
// Patch LK.getSound to return a dummy object with a no-op play() if not gameStarted
var _LK_getSound = LK.getSound;
LK.getSound = function (id) {
if (!gameStarted) {
return {
play: function play() {}
};
}
return _LK_getSound.call(LK, id);
};
/****
* Asset Initialization (for static analysis)
****/
// Notes (5 columns, 5 colors)
for (var i = 0; i < NOTE_COLS; i++) {}
// Ball
// Crosshair
// Bullet
// Button background
// Music tracks