User prompt
bloklar müziğin ritmine göre düşsün
User prompt
arkadan tıkladığımız notalara göre bir müzik çalsın
Code edit (1 edits merged)
Please save this source code
User prompt
Piano Rhythm Tap
Initial prompt
bir piyano oyunu yapalım arkadan bir müzik çalsın arkadaki müziğe göre bloklar düşsün bloklara tam zamanında tıklayalım
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Block class: falling piano key var Block = Container.expand(function () { var self = Container.call(this); // Attach block asset var blockAsset = self.attachAsset('block', { anchorX: 0.5, anchorY: 0.5 }); // Track if block has been hit or missed self.hit = false; self.missed = false; // For hit effect self.showHitEffect = function () { var effect = LK.getAsset('hitEffect', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); self.addChild(effect); tween(effect, { alpha: 0 }, { duration: 300, easing: tween.linear, onFinish: function onFinish() { effect.destroy(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Piano note sounds for each lane (C, D, E, G as example) // Music (looping, but we will play it once per game) // Sound for miss // Sound for block hit // Block hit effect // Target line // Falling block (piano key) // --- GAME CONSTANTS --- var NUM_LANES = 4; var LANE_WIDTH = 400; // 2048/4 = 512, but leave some margin var BLOCK_WIDTH = 300; var BLOCK_HEIGHT = 120; var BLOCK_SPEED_START = 12; // px per frame (60fps) var BLOCK_SPEED_MAX = 32; var BLOCK_SPEED_INCREMENT = 0.5; // per level var BLOCK_SPAWN_INTERVAL = 48; // frames between blocks (will decrease as tempo increases) var BLOCK_SPAWN_INTERVAL_MIN = 18; var TARGET_LINE_Y = 2732 - 320; // 320px from bottom var HIT_WINDOW = 80; // px window for perfect hit var MISS_WINDOW = 120; // px window for miss // --- GAME STATE --- var blocks = []; var score = 0; var combo = 0; var bestCombo = 0; var blockSpeed = BLOCK_SPEED_START; var blockSpawnInterval = BLOCK_SPAWN_INTERVAL; var ticksSinceLastBlock = 0; var isPlaying = false; var songTicks = 0; var songLengthTicks = 60 * 60; // 60 seconds at 60fps (will end game if song ends) var nextTempoIncrease = 600; // every 10 seconds // --- LANE POSITIONS --- var laneXs = []; for (var i = 0; i < NUM_LANES; i++) { // Center blocks in each lane laneXs[i] = LANE_WIDTH / 2 + i * LANE_WIDTH + (2048 - NUM_LANES * LANE_WIDTH) / 2; } // --- GUI ELEMENTS --- // Score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Combo text var comboTxt = new Text2('', { size: 80, fill: 0xFFE066 }); comboTxt.anchor.set(0.5, 0); LK.gui.top.addChild(comboTxt); comboTxt.y = 130; // Best combo text var bestComboTxt = new Text2('', { size: 60, fill: 0xCCCCCC }); bestComboTxt.anchor.set(0.5, 0); LK.gui.top.addChild(bestComboTxt); bestComboTxt.y = 210; // --- TARGET LINE --- var targetLine = LK.getAsset('targetLine', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: TARGET_LINE_Y }); game.addChild(targetLine); // --- GAME START --- function startGame() { // Reset state for (var i = blocks.length - 1; i >= 0; i--) { blocks[i].destroy(); blocks.splice(i, 1); } score = 0; combo = 0; bestCombo = 0; blockSpeed = BLOCK_SPEED_START; blockSpawnInterval = BLOCK_SPAWN_INTERVAL; ticksSinceLastBlock = 0; isPlaying = true; songTicks = 0; nextTempoIncrease = 600; scoreTxt.setText('0'); comboTxt.setText(''); bestComboTxt.setText(''); // Start music LK.playMusic('pianoTrack', { loop: false }); } startGame(); // --- BLOCK SCHEDULING --- // For MVP, blocks are spawned randomly in lanes, but now in sync with the music beat using LK.music.getBeat API function spawnBlock() { var lane = Math.floor(Math.random() * NUM_LANES); var block = new Block(); block.x = laneXs[lane]; block.y = -BLOCK_HEIGHT / 2; block.lane = lane; block.hit = false; block.missed = false; blocks.push(block); game.addChild(block); } // --- BEAT SYNC SCHEDULING --- var lastBeat = -1; // --- GAME UPDATE --- game.update = function () { if (!isPlaying) return; songTicks++; ticksSinceLastBlock++; // Increase tempo every 10 seconds if (songTicks >= nextTempoIncrease) { if (blockSpeed < BLOCK_SPEED_MAX) blockSpeed += BLOCK_SPEED_INCREMENT; if (blockSpawnInterval > BLOCK_SPAWN_INTERVAL_MIN) blockSpawnInterval--; nextTempoIncrease += 600; } // Spawn new block on beat using LK.music.getBeat for beat-synced block drops var currentBeat = LK.music.getBeat && LK.music.getBeat('pianoTrack'); if (typeof currentBeat === "number" && currentBeat !== lastBeat) { spawnBlock(); lastBeat = currentBeat; ticksSinceLastBlock = 0; } // Move blocks for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; if (block.hit || block.missed) continue; block.y += blockSpeed; // Missed block (passed target line + window) if (block.y - TARGET_LINE_Y > MISS_WINDOW) { block.missed = true; combo = 0; comboTxt.setText(''); LK.getSound('miss').play(); // Flash screen red LK.effects.flashScreen(0xff0000, 600); // End game isPlaying = false; LK.stopMusic(); LK.showGameOver(); break; } } // End game if song ends if (songTicks > songLengthTicks) { isPlaying = false; LK.stopMusic(); LK.showYouWin(); } }; // --- INPUT HANDLING --- // Tap/click on falling block at the right time game.down = function (x, y, obj) { if (!isPlaying) return; // Only allow taps below the target line (to avoid accidental taps) if (y < TARGET_LINE_Y - BLOCK_HEIGHT) return; // Find the block closest to the target line in each lane var tapped = false; for (var i = 0; i < NUM_LANES; i++) { // Check if tap is in this lane var laneLeft = laneXs[i] - LANE_WIDTH / 2; var laneRight = laneXs[i] + LANE_WIDTH / 2; if (x >= laneLeft && x < laneRight) { // Find the first block in this lane within the hit window var bestBlock = null; var bestDist = 9999; for (var j = 0; j < blocks.length; j++) { var block = blocks[j]; if (block.lane !== i || block.hit || block.missed) continue; var dist = Math.abs(block.y - TARGET_LINE_Y); if (dist < HIT_WINDOW && dist < bestDist) { bestBlock = block; bestDist = dist; } } if (bestBlock) { // Hit! bestBlock.hit = true; tapped = true; score += 1; combo += 1; if (combo > bestCombo) bestCombo = combo; scoreTxt.setText(score + ''); comboTxt.setText(combo > 1 ? combo + ' combo!' : ''); bestComboTxt.setText('Best: ' + bestCombo); bestBlock.showHitEffect(); // Play a different piano note sound for each lane var noteId = 'piano_note_' + bestBlock.lane; if (LK.hasSound && LK.hasSound(noteId)) { LK.getSound(noteId).play(); } else { LK.getSound('hit').play(); } // Animate block fade out tween(bestBlock, { alpha: 0 }, { duration: 180, onFinish: function onFinish() { bestBlock.destroy(); } }); } break; } } if (!tapped) { // Missed tap (tapped empty lane or wrong time) combo = 0; comboTxt.setText(''); LK.getSound('miss').play(); LK.effects.flashScreen(0xff0000, 400); isPlaying = false; LK.stopMusic(); LK.showGameOver(); } }; // --- GAME OVER / WIN HANDLING --- // (Handled by LK engine, game will be reset automatically) // --- MUSIC RESTART ON GAME RESET --- LK.on('gameReset', function () { startGame(); });
===================================================================
--- original.js
+++ change.js
@@ -144,9 +144,9 @@
});
}
startGame();
// --- BLOCK SCHEDULING ---
-// For MVP, blocks are spawned randomly in lanes, in sync with the beat (every blockSpawnInterval ticks)
+// For MVP, blocks are spawned randomly in lanes, but now in sync with the music beat using LK.music.getBeat API
function spawnBlock() {
var lane = Math.floor(Math.random() * NUM_LANES);
var block = new Block();
block.x = laneXs[lane];
@@ -156,8 +156,10 @@
block.missed = false;
blocks.push(block);
game.addChild(block);
}
+// --- BEAT SYNC SCHEDULING ---
+var lastBeat = -1;
// --- GAME UPDATE ---
game.update = function () {
if (!isPlaying) return;
songTicks++;
@@ -167,11 +169,13 @@
if (blockSpeed < BLOCK_SPEED_MAX) blockSpeed += BLOCK_SPEED_INCREMENT;
if (blockSpawnInterval > BLOCK_SPAWN_INTERVAL_MIN) blockSpawnInterval--;
nextTempoIncrease += 600;
}
- // Spawn new block on beat
- if (ticksSinceLastBlock >= blockSpawnInterval) {
+ // Spawn new block on beat using LK.music.getBeat for beat-synced block drops
+ var currentBeat = LK.music.getBeat && LK.music.getBeat('pianoTrack');
+ if (typeof currentBeat === "number" && currentBeat !== lastBeat) {
spawnBlock();
+ lastBeat = currentBeat;
ticksSinceLastBlock = 0;
}
// Move blocks
for (var i = blocks.length - 1; i >= 0; i--) {