User prompt
create a confettiAnim class; use note and note2 assets with futuristic blue tint that fall from above top of screen; call it when runner returned to initial position ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
adapt runner to show rotateAnim before idleAnim; only call idleAnim after rotateAnim end
Code edit (3 edits merged)
Please save this source code
User prompt
in Runner add a rotationAnim function, show the frames runnerRotation_01, runnerRotation_02, runnerRotation_03; call it at IdleAnim start
Code edit (3 edits merged)
Please save this source code
User prompt
in teleportAnim, play beamEnter on beam appearance and beamTeleport before runner move up
Code edit (1 edits merged)
Please save this source code
User prompt
in teleportAnim, after beam appearance, animate move the runner to y -800 in 2 sec ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
call teleportAnim after 2sec of idleAnim
Code edit (2 edits merged)
Please save this source code
User prompt
in runner class, add a teleportAnim that create a temporary beam asset (x=1024, y =0) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Analyze deeply checkSongEnd() and Runner.update() to fix the fact that runner is invisible when ruturning to initial position after song ends. Don't break anything
User prompt
your fix didn't work because run frames alpha are changed both in checkSongEnd() and in Runner.update() => logic should be in runner.update; checkSongEnd should only set the proper flags ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
currently end song end, runner disapears the reapears with idleAnim => keep runner running until he reaches inital position, and the hide run frame to show idleAnim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when song ends, return runner and boll to initial position (1024,2000) and 0 rotation just before calling idleAnim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when song ends, return runner to 1024,2000 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a special function in Runner for IdleAnim; use assets runnerIdleDir8001 to runnerIdleDir8020; call it after song end ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
speakers out anim should work even if !songStarted (currently speakers stay still)
User prompt
wait 2sec before speakers out anim
User prompt
Now handle sond end by - stopping song play - set songStarted to false but don't show startbutton - animate speakers out : opposite of entrance anim - stop runner running anim - stop gates spawning - stop orbs spawning - stop gates spawning - stop background anim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Now handle sond end by stop song , setting songStarted to false and all hat is required
Code edit (4 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BackgroundManager = Container.expand(function () { var self = Container.call(this); self.bg0 = self.attachAsset('background01', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 2.4, scaleY: 2.4, alpha: 1 }); self.bg1 = self.attachAsset('background01', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 1.1, scaleY: 1.1, alpha: 1 }); self.bg2 = self.attachAsset('background01', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.5, scaleY: 0.5, alpha: 1 }); self.bg3 = self.attachAsset('background01', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.22, scaleY: 0.22, alpha: 1 }); self.bg4 = self.attachAsset('background01', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.11, scaleY: 0.11, alpha: 1 }); self.tore0 = self.attachAsset('tore', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 1.2, scaleY: 1.2, alpha: 0 }); self.tore1 = self.attachAsset('tore', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.6, scaleY: 0.6, alpha: 0 }); self.tore2 = self.attachAsset('tore', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.26, scaleY: 0.26, alpha: 0 }); self.tore3 = self.attachAsset('tore', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.12, scaleY: 0.12, alpha: 0 }); if (isDebug) { self.bg1.tint = 0xFF0000; self.tore1.tint = 0x00FF00; self.bg2.tint = 0x00FFFF; self.tore2.tint = 0xFF00FF; self.bg3.tint = 0xfff200; } self.bgAnimationSpeed = globalSpeed / 1000; self.bgAnimationAcceleration = 2; self.backgrounds = [self.bg0, self.tore0, self.bg1, self.tore1, self.bg2, self.tore2, self.bg3, self.tore3, self.bg4]; self.bgAnimStartTime = Date.now(); self.update = function () { if (!songStarted) { // Stop all background animations when song ends tween.stop(self.bg0, { scaleX: true, scaleY: true }); tween.stop(self.bg1, { scaleX: true, scaleY: true }); tween.stop(self.bg2, { scaleX: true, scaleY: true }); tween.stop(self.bg3, { scaleX: true, scaleY: true }); tween.stop(self.bg4, { scaleX: true, scaleY: true }); tween.stop(self.tore0, { scaleX: true, scaleY: true }); tween.stop(self.tore1, { scaleX: true, scaleY: true }); tween.stop(self.tore2, { scaleX: true, scaleY: true }); tween.stop(self.tore3, { scaleX: true, scaleY: true }); return; } var now = Date.now(); var elapsed = now - self.bgAnimStartTime; var resetTriggered = false; for (var i = 0; i < self.backgrounds.length; i++) { var bg = self.backgrounds[i]; bg.scaleX += self.bgAnimationSpeed * bg.scaleX; bg.scaleY = bg.scaleX; if (bg.scaleX > 3.0) { bg.scaleX = 0.12; bg.scaleY = bg.scaleX; } bg.tint = 0x1697b8; } }; return self; }); var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5, tint: currentColor, alpha: isDebug ? 1 : 0 }); self.speedX = 0; self.speedY = 0; self.lastIntersectingGates = {}; self.lastIntersectingOrbs = {}; // Track which orbs we've intersected self.update = function () { if (!songStarted) { return; } if (runner) { self.x = runner.x; self.y = runner.y; } if (gateManager && gateManager.gates) { for (var i = gateManager.gates.length - 1; i >= 0; i--) { var gate = gateManager.gates[i]; var gateId = gate.gateId; if (self.lastIntersectingGates[gateId] === undefined) { self.lastIntersectingGates[gateId] = false; } var currentIntersecting = gate.gateAsset.scaleX >= minGateDetectionScale && gate.gateAsset.scaleX <= maxGateDetectionScale && self.intersects(gate.boundingBox); if (!self.lastIntersectingGates[gateId] && currentIntersecting) { // Spawn LooseOrbsAnim at ball position with gate's angle var looseOrbsAnim = new LooseOrbsAnim(gate.directionAngle); looseOrbsAnim.x = self.x; looseOrbsAnim.y = self.y; game.addChild(looseOrbsAnim); playHitSound(); // Calculate penalty based on hit timing var now = Date.now(); if (now - lastGateHitTime <= 1000) { // Hit within 1 second - double the penalty (max -10) gatePenaltyValue = Math.max(-10, gatePenaltyValue * 2); } else { // More than 1 second - reset to -2 gatePenaltyValue = -2; } lastGateHitTime = now; // Reduce score by calculated penalty but don't go negative var currentScore = LK.getScore(); var newScore = Math.max(0, currentScore + gatePenaltyValue); LK.setScore(newScore); if (game.updateScore) { game.updateScore(); } // Show penalty text with current penalty value if (scoreLabel && scoreLabel.showPenalty) { scoreLabel.showPenalty(gatePenaltyValue); } if (!gate.isDestroying) { gate.isDestroying = true; tween(gate, { scaleX: 0, scaleY: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { gateManager.destroyGate(gate); } }); } } self.lastIntersectingGates[gateId] = currentIntersecting; } } // Check for orb intersections if (orbManager && orbManager.orbs) { for (var i = orbManager.orbs.length - 1; i >= 0; i--) { var orb = orbManager.orbs[i]; var orbId = orb.orbId; if (self.lastIntersectingOrbs[orbId] === undefined) { self.lastIntersectingOrbs[orbId] = false; } var currentIntersecting = orb.currentScale >= minOrbDetectionScale && orb.currentScale <= maxOrbDetectionScale && self.intersects(orb.boundingBox); if (!self.lastIntersectingOrbs[orbId] && currentIntersecting) { // Spawn SparkAnim at ball position var sparkAnim = new SparkAnim(); sparkAnim.x = self.x; sparkAnim.y = self.y; game.addChild(sparkAnim); // Orb collected - play sound and increase score LK.getSound('grab').play(); LK.setScore(LK.getScore() + 1); if (game.updateScore) { game.updateScore(); } // Destroy the orb orb.destroy(); orbManager.orbs.splice(i, 1); delete self.lastIntersectingOrbs[orbId]; continue; } self.lastIntersectingOrbs[orbId] = currentIntersecting; } } }; return self; }); var Gate = Container.expand(function () { var self = Container.call(this); self.gateAsset = self.attachAsset('gate', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366, scaleX: 0.26, scaleY: 0.26, alpha: 1, visible: false }); self.directionAngle = 0; self.boundingBox = self.attachAsset('boundingBox', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2450, alpha: 1 }); /* width: 200, heigh: 100, */ self.gateColor = 0xFFFFFF; self.gateId = null; self.setColor = function (color) { self.gateColor = color; self.gateAsset.tint = color; { self.boundingBox.alpha = 0.9; } }; self.updateScale = function (newScale) { self.gateAsset.scaleX = newScale; self.gateAsset.scaleY = newScale; self.gateAsset.alpha = Math.min(1, newScale + 0.66); self.boundingBox.scaleX = newScale; self.boundingBox.scaleY = newScale; var distance = (2450 - 1366) * newScale; self.boundingBox.x = centerX + distance * Math.cos(self.directionAngle + Math.PI * 0.5); self.boundingBox.y = centerY + distance * Math.sin(self.directionAngle + Math.PI * 0.5); self.boundingBox.rotation = self.directionAngle; }; return self; }); var GateManager = Container.expand(function () { var self = Container.call(this); self.gates = []; self.gateAnimStartTime = Date.now(); self.gateAnimationSpeed = globalSpeed / 1000; self.currentSong = songListV3[0]; self.songStartTime = Date.now(); self.currentNoteIndex = 0; self.noteSpawnScale = 0.12; self.lastGateAngle = null; self.lastProcessedBeat = -1; self.spawnGateAtTime = function () { var beatValue = null; if (self.currentNoteIndex < self.currentSong.songBeats.length) { beatValue = self.currentSong.songBeats[self.currentNoteIndex].beat; } var keyNumber = parseInt(beatValue, 10) || 1; var noteKey = 'Key' + keyNumber; var keyColor = keyColorMap[noteKey] || currentColor; var startScale = self.noteSpawnScale; var endScale = 1.0; var speed = self.gateAnimationSpeed; var timeToReachPlayer = Math.log(endScale / startScale) / speed; var beatAngle = centerAngle; if (beatValue === "1") { beatAngle = rightAngle; } else if (beatValue === "2") { beatAngle = leftAngle; } else { beatAngle = centerAngle; } self.lastGateAngle = beatAngle; var allAngles = [leftAngle, centerAngle, rightAngle]; var gateAngles = []; for (var i = 0; i < allAngles.length; i++) { if (allAngles[i] !== beatAngle) { gateAngles.push(allAngles[i]); } } var beatTime = self.currentSong.songBeats[self.currentNoteIndex].time; var now = Date.now(); var songElapsed = now - self.songStartTime; var spawnTime = beatTime - timeToReachPlayer; // Spawn gates for (var j = 0; j < gateAngles.length; j++) { var gate = new Gate(); gate.setColor(keyColor); gate.updateScale(self.noteSpawnScale); gate.spawnTime = Date.now() + 200 / globalSpeed; gate.colorIndex = 0; gate.gateId = getNextGateId(); gate.noteKey = noteKey; gate.directionAngle = gateAngles[j]; gate.gateAsset.rotation = gateAngles[j]; if (songElapsed >= spawnTime) { self.gates.push(gate); self.addChild(gate); } else { (function (g) { LK.setTimeout(function () { self.gates.push(g); self.addChild(g); }, spawnTime - songElapsed); })(gate); } } // When spawning 2 gates, spawn an Orb at the free angle (beatAngle) if (gateAngles.length === 2 && orbManager) { if (songElapsed >= spawnTime) { orbManager.spawnOrb(beatAngle); } else { (function (angle) { LK.setTimeout(function () { orbManager.spawnOrb(angle); }, spawnTime - songElapsed); })(beatAngle); } } }; self.update = function () { if (!songStarted) { return; } var now = Date.now(); var songElapsed = now - self.songStartTime; if (self.currentNoteIndex < self.currentSong.songBeats.length) { var nextBeat = self.currentSong.songBeats[self.currentNoteIndex]; if (songElapsed >= nextBeat.time) { if (now - lastBeatTime >= skipBeatDelay) { self.spawnGateAtTime(); lastBeatTime = now; } self.currentNoteIndex++; } } for (var i = self.gates.length - 1; i >= 0; i--) { var gate = self.gates[i]; var currentScale = gate.gateAsset.scaleX; var newScale = currentScale + self.gateAnimationSpeed * currentScale; if (newScale > 3.0) { gate.destroy(); self.gates.splice(i, 1); } else { gate.updateScale(newScale); } } self.checkSongEnd(); }; self.resetSong = function () { self.songStartTime = Date.now(); self.currentNoteIndex = 0; self.lastGateAngle = null; }; self.checkSongEnd = function () { if (self.currentNoteIndex >= self.currentSong.songBeats.length) { var songDuration = self.currentSong.duration || 156000; // Use duration from songListV3 var songElapsed = Date.now() - self.songStartTime; if (songElapsed >= songDuration && songStarted) { // Handle song end songStarted = false; LK.stopMusic(); // Stop progress bar animation if (progressBar) { tween.stop(progressBar.bar, { width: true }); } // Animate speakers out with opposite entrance animation after 2 second delay if (speakerManager && speakerManager.speakers) { LK.setTimeout(function () { for (var i = 0; i < speakerManager.speakers.length; i++) { var speaker = speakerManager.speakers[i]; var exitX, exitY; if (i === 0) { // Left speaker - exit to left exitX = speaker.x - 800; exitY = speaker.y; } else if (i === 1) { // Center speaker - exit to top exitX = speaker.x; exitY = speaker.y - 800; } else { // Right speaker - exit to right exitX = speaker.x + 800; exitY = speaker.y; } tween(speaker, { x: exitX, y: exitY, alpha: 0 }, { duration: 1200, easing: tween.easeIn, onFinish: function onFinish() { // Clear speakers array after all animations complete if (i === speakerManager.speakers.length - 1) { speakerManager.speakers = []; } } }); } }, 1000); } // Return runner and ball to initial position while keeping runner animation running if (runner) { // Set flags for runner to handle transition runner.isReturningToInitial = true; runner.shouldStartIdleAfterReturn = true; // Reset idle state in case it was playing runner.isPlayingIdleAnim = false; tween(runner, { x: 1024, y: 2000, rotation: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { runner.isReturningToInitial = false; runner.shouldStartIdleAfterReturn = false; runner.startIdleSequence(); } }); } if (ball) { tween(ball, { x: 1024, y: 2000, rotation: 0 }, { duration: 1000, easing: tween.easeOut }); } // Clear all gates for (var j = self.gates.length - 1; j >= 0; j--) { self.gates[j].destroy(); } self.gates = []; // Don't reset song here since we want to keep the state } } }; self.destroyGate = function (gate) { var index = self.gates.indexOf(gate); if (index > -1) { self.gates.splice(index, 1); gate.destroy(); } }; return self; }); var LooseOrbsAnim = Container.expand(function (gateAngle) { var self = Container.call(this); self.orbs = []; self.lifetime = 2000; self.spawnTime = Date.now(); self.gateAngle = gateAngle || 0; // Store the gate angle // Spawn multiple orbs (3-6 orbs) var orbCount = 3 + Math.floor(Math.random() * 3); var randScale = 0.3 + Math.random() * 0.4; for (var i = 0; i < orbCount; i++) { var orbAsset = self.attachAsset('orb', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, scaleX: randScale, scaleY: randScale }); // Random initial position offset orbAsset.x = (Math.random() - 0.5) * 100; orbAsset.y = (Math.random() - 0.5) * 100; // Use gate angle to influence orb spawn direction var baseAngle = self.gateAngle - Math.PI / 2; // Opposite direction from gate var angleSpread = Math.PI * 0.6; // 108 degrees spread var angle = baseAngle + (Math.random() - 0.5) * angleSpread; var speed = 200 + Math.random() * 200; orbAsset.velocityX = Math.cos(angle) * speed; orbAsset.velocityY = Math.sin(angle) * speed - 200; // Initial upward bias orbAsset.gravity = 1200; // Gravity acceleration self.orbs.push(orbAsset); // Animate orb scale and alpha over time (delayed by 2 seconds) LK.setTimeout(function () { tween(orbAsset, { alpha: 0 }, { duration: self.lifetime, easing: tween.easeOut }); }, 1000); // Rotation animation tween(orbAsset, { rotation: Math.PI * 6 - Math.random() * Math.PI * 12 }, { duration: self.lifetime, easing: tween.linear }); } // Update method for physics simulation self.update = function () { var deltaTime = 16 / 1000; // Assume 60fps for (var i = 0; i < self.orbs.length; i++) { var orb = self.orbs[i]; // Apply gravity to velocity orb.velocityY += orb.gravity * deltaTime; // Update position based on velocity orb.x += orb.velocityX * deltaTime; orb.y += orb.velocityY * deltaTime; orb.scaleX += 0.4 * deltaTime; orb.scaleY = orb.scaleX; } // Check if animation is complete var elapsed = Date.now() - self.spawnTime; if (elapsed >= self.lifetime) { self.destroy(); } }; return self; }); var Note = Container.expand(function () { var self = Container.call(this); var noteGraphics = self.attachAsset('note', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); self.velocity = { x: 0, y: -5 }; self.lifetime = 800; self.spawnTime = Date.now(); self.noteType = 'note'; self.noteColor = 0xFFFFFF; self.setNoteType = function (type) { self.noteType = type; noteGraphics.destroy(); noteGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); noteGraphics.tint = self.noteColor; }; self.setColor = function (color) { self.noteColor = color; noteGraphics.tint = color; }; self.setVelocity = function (vx, vy) { self.velocity.x = vx; self.velocity.y = vy; }; self.update = function () { self.x += self.velocity.x; self.y += self.velocity.y; var elapsed = Date.now() - self.spawnTime; if (elapsed > self.lifetime) { self.alpha = Math.max(0, 1 - (elapsed - self.lifetime) / 500); } if (elapsed > self.lifetime + 500 || self.y < -100 || self.y > 2832 || self.x < -100 || self.x > 2148) { self.shouldDestroy = true; } }; return self; }); var NoteSparks = Container.expand(function () { var self = Container.call(this); self.notes = []; self.spawnRate = 500; self.lastSpawnTime = 0; self.spawnEnabled = false; self.spawnX = 1024; self.spawnY = 1366; self.spawnVelocityRange = { x: { min: -2, max: 2 }, y: { min: -8, max: -4 } }; self.noteColors = [0xFF073A, 0x39FF14, 0x00FFFF, 0xF3F315, 0xFF61F6]; self.setSpawnPosition = function (x, y) { self.spawnX = x; self.spawnY = y; }; self.setSpawnEnabled = function (enabled) { self.spawnEnabled = enabled; }; self.setSpawnRate = function (rate) { self.spawnRate = rate; }; self.spawnNote = function () { var note = new Note(); note.x = self.spawnX + (Math.random() - 0.5) * 50; note.y = self.spawnY; var vx = self.spawnVelocityRange.x.min + Math.random() * (self.spawnVelocityRange.x.max - self.spawnVelocityRange.x.min); var vy = self.spawnVelocityRange.y.min + Math.random() * (self.spawnVelocityRange.y.max - self.spawnVelocityRange.y.min); note.setVelocity(vx, vy); note.setNoteType(Math.random() > 0.5 ? 'note' : 'note2'); var color = self.noteColors[Math.floor(Math.random() * self.noteColors.length)]; note.setColor(color); note.rotation = (Math.random() - 0.5) * 0.5; self.notes.push(note); self.addChild(note); }; self.spawnBurst = function (count) { for (var i = 0; i < count; i++) { self.spawnNote(); } }; self.update = function () { var now = Date.now(); if (self.spawnEnabled && now - self.lastSpawnTime >= self.spawnRate) { self.spawnNote(); self.lastSpawnTime = now; } for (var i = self.notes.length - 1; i >= 0; i--) { var note = self.notes[i]; if (note.shouldDestroy) { note.destroy(); self.notes.splice(i, 1); } } }; return self; }); var Orb = Container.expand(function () { var self = Container.call(this); var frames = ['orb0', 'orb1', 'orb2', 'orb3', 'orb4', 'orb5']; var orbAssets = []; var currentFrameIndex = 0; var animationInterval = 100; // milliseconds per frame var lastFrameTime = 0; self.directionAngle = 0; self.orbId = null; self.initialSize = 200; self.orbAngleOffsetRatio = 0.15; self.spawnTime = Date.now(); self.currentScale = 0.12; // Track current scale like gates do var glowGraphics = self.attachAsset('glow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8, width: self.initialSize * 1.5, height: self.initialSize * 1.5, blendMode: 1 }); // Add bounding box for collision detection self.boundingBox = self.attachAsset('boundingCircle', { anchorX: 0.5, anchorY: 0.5, width: self.initialSize * 0.5, height: self.initialSize * 0.5, alpha: 0 }); var _rotateGlow = function rotateGlow() { tween(glowGraphics, { rotation: glowGraphics.rotation + Math.PI * 2 }, { duration: 3000, easing: tween.linear, onFinish: _rotateGlow }); }; _rotateGlow(); // Pulsing scale animation var _pulseGlow = function pulseGlow() { tween(glowGraphics, { scaleX: 0.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(glowGraphics, { scaleX: 1.6, scaleY: 1.6 }, { duration: 500, easing: tween.easeInOut, onFinish: _pulseGlow }); } }); }; _pulseGlow(); for (var i = 0; i < frames.length; i++) { var asset = self.attachAsset(frames[i], { anchorX: 0.5, anchorY: 0.5, alpha: 0, width: self.initialSize, height: self.initialSize }); orbAssets.push(asset); } // Set the first frame to be visible initially if (orbAssets.length > 0) { orbAssets[0].alpha = 1; } self.updateScale = function (newScale) { self.currentScale = newScale; // Update all frame assets scale and alpha exactly like gates for (var i = 0; i < orbAssets.length; i++) { orbAssets[i].scaleX = newScale; orbAssets[i].scaleY = newScale; // Only update alpha for the currently visible frame if (i === currentFrameIndex) { orbAssets[i].alpha = Math.min(1, newScale + 0.66); } } // Update position based on scale exactly like gates do var distance = (2450 - 1366) * newScale; var angle = self.directionAngle; if (angle != centerAngle) { angle += Math.sign(angle) * self.orbAngleOffsetRatio; } self.x = centerX + distance * Math.cos(angle + Math.PI * 0.5); self.y = centerY + distance * Math.sin(angle + Math.PI * 0.5); self.rotation = angle; }; self.update = function () { var now = Date.now(); if (now - lastFrameTime >= animationInterval) { // Get current scale to maintain proper alpha var currentScale = orbAssets[0].scaleX; var targetAlpha = Math.min(1, currentScale + 0.66); // Fade out the current frame tween(orbAssets[currentFrameIndex], { alpha: 0 }, { duration: animationInterval / 2 }); // Move to the next frame currentFrameIndex = (currentFrameIndex + 1) % frames.length; // Fade in the next frame with proper alpha based on scale tween(orbAssets[currentFrameIndex], { alpha: targetAlpha }, { duration: animationInterval / 2 }); lastFrameTime = now; } }; return self; }); var OrbManager = Container.expand(function () { var self = Container.call(this); self.orbs = []; self.orbSpawnInterval = 1000; // Spawn every 1000ms for now, adjust as needed self.lastOrbSpawnTime = 0; self.orbSpawnScale = 0.12; // Same as gateManager.noteSpawnScale self.orbEndScale = 1.0; self.orbAnimationDuration = 2000; // ms self.spawnOrb = function (angle) { var orb = new Orb(); orb.orbId = getNextGateId(); orb.directionAngle = angle || centerAngle; orb.spawnTime = Date.now(); // Set initial position exactly like gates orb.x = centerX; orb.y = centerY; orb.rotation = angle; orb.updateScale(self.orbSpawnScale); self.orbs.push(orb); self.addChild(orb); // Update last spawn time self.lastOrbSpawnTime = Date.now(); }; self.update = function () { if (!songStarted) { // Clear all orbs when song ends if (self.orbs.length > 0) { for (var i = self.orbs.length - 1; i >= 0; i--) { self.orbs[i].destroy(); } self.orbs = []; } return; } // Check if we need to spawn an orb var now = Date.now(); if (now - self.lastOrbSpawnTime >= 600) { // Check if there's a gate spawn planned in the next 300ms var hasPlannedSpawn = false; if (gateManager && gateManager.currentNoteIndex < gateManager.currentSong.songBeats.length) { var nextBeat = gateManager.currentSong.songBeats[gateManager.currentNoteIndex]; var songElapsed = now - gateManager.songStartTime; var timeToNextBeat = nextBeat.time - songElapsed; if (timeToNextBeat <= 300 && timeToNextBeat > 0) { hasPlannedSpawn = true; } } // Only spawn orb if no gate spawn is planned soon if (!hasPlannedSpawn) { // Spawn orb at centerAngle if no orb was spawned recently self.spawnOrb(centerAngle); self.lastOrbSpawnTime = now; } } // Animate orbs similar to gates for (var i = self.orbs.length - 1; i >= 0; i--) { var orb = self.orbs[i]; var currentScale = orb.currentScale; var newScale = currentScale + gateManager.gateAnimationSpeed * currentScale; if (newScale > 3.0) { orb.destroy(); self.orbs.splice(i, 1); } else { orb.updateScale(newScale); } } }; return self; }); var ProgressBar = Container.expand(function () { var self = Container.call(this); // Background frame (border) self.frame = self.attachAsset('progressFrame', { anchorX: 0.0, anchorY: 0.5, alpha: 0.8 }); // Progress bar (fill) self.bar = self.attachAsset('progressBar', { anchorX: 0.0, anchorY: 0.5, alpha: 0.8 }); // Position bar inside frame self.bar.x = -0; //self.bar.y = 0; // Set initial progress to 0 self.setProgress = function (progress) { progress = Math.max(0, Math.min(1, progress)); // Clamp between 0 and 1 self.bar.width = self.frame.width * progress; }; self.startProgressAnimation = function () { // Get song duration from songListV3 var songDuration = 0; if (gateManager && gateManager.currentSong && gateManager.currentSong.duration) { songDuration = gateManager.currentSong.duration; } if (songDuration > 0) { // Reset progress to 0 and start tween animation self.setProgress(0); tween(self.bar, { width: self.frame.width }, { duration: songDuration, easing: tween.linear }); } }; self.update = function () { // Progress is now handled by tween animation // No need for manual progress calculation }; self.setProgress(0); // Start with empty progress return self; }); var Runner = Container.expand(function () { var self = Container.call(this); // Setup frame animation with assets 001 to 012 var frameAssets = []; var currentFrameIndex = 0; var animationInterval = 2; // milliseconds per frame var lastFrameTime = 0; // Create all 12 frames for (var i = 1; i <= 12; i++) { var frameId = 'runnerDir4_' + (i < 10 ? '00' + i : '0' + i); var asset = self.attachAsset(frameId, { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF, alpha: 0 // Start with all frames hidden }); frameAssets.push(asset); } // Show first frame if (frameAssets.length > 0) { frameAssets[0].alpha = 1; } self.speedX = 0; self.speedY = 0; self.lastIntersectingGates = {}; self.tickCounter = 0; // Setup idle animation frames for when song ends self.idleFrameAssets = []; var currentIdleFrameIndex = 0; var idleAnimationInterval = 100; // milliseconds per frame for idle animation var lastIdleFrameTime = 0; self.isPlayingIdleAnim = false; self.isReturningToInitial = false; self.shouldStartIdleAfterReturn = false; // Make frameAssets accessible from outside self.frameAssets = frameAssets; // Create all 20 idle frames (runnerIdleDir8001 to runnerIdleDir8020) for (var i = 1; i <= 20; i++) { var idleFrameId = 'runnerIdleDir8' + (i < 10 ? '00' + i : '0' + i); var idleAsset = self.attachAsset(idleFrameId, { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF, alpha: 0 // Start with all frames hidden }); self.idleFrameAssets.push(idleAsset); } self.teleportAnim = function () { // Create temporary beam asset at x=1024, y=0 var beam = game.addChild(LK.getAsset('beam', { anchorX: 0.5, anchorY: 0.0, x: 1024, y: 0, alpha: 0, scaleY: 0 })); // Play beamEnter sound on beam appearance LK.getSound('beamEnter').play(); // Animate beam appearance tween(beam, { alpha: 0.8, scaleY: 1.0 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { // Play beamTeleport sound before runner moves up LK.getSound('beamTeleport').play(); // Animate runner moving up to y=-800 tween(self, { y: -800, scaleX: 0.1, alpha: 0.3 }, { duration: 1200, easing: tween.easeInOut, onFinish: function onFinish() { // Keep beam visible for a moment then fade out tween(beam, { alpha: 0, scaleY: 0 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Destroy beam after animation beam.destroy(); } }); } }); } }); }; self.rotationAnim = function () { // Create rotation frame assets var rotationFrames = ['runnerRotation_01', 'runnerRotation_02', 'runnerRotation_03']; var rotationAssets = []; // Hide all frames first for (var i = 0; i < self.frameAssets.length; i++) { self.frameAssets[i].alpha = 0; } for (var i = 0; i < self.idleFrameAssets.length; i++) { self.idleFrameAssets[i].alpha = 0; } // Create and show rotation frames for (var i = 0; i < rotationFrames.length; i++) { var asset = self.attachAsset(rotationFrames[i], { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF, alpha: 0 }); rotationAssets.push(asset); } // Animate through rotation frames var frameIndex = 0; var frameInterval = 100; // ms per frame function showNextFrame() { if (frameIndex < rotationAssets.length) { // Hide previous frame if (frameIndex > 0) { rotationAssets[frameIndex - 1].alpha = 0; } // Show current frame rotationAssets[frameIndex].alpha = 1; frameIndex++; LK.setTimeout(showNextFrame, frameInterval); } else { // Animation complete, hide last frame and clean up rotationAssets[rotationAssets.length - 1].alpha = 0; // Destroy rotation assets for (var i = 0; i < rotationAssets.length; i++) { rotationAssets[i].alpha = 0; rotationAssets[i].destroy(); } for (var i = 0; i < self.idleFrameAssets.length; i++) { self.idleFrameAssets[i].alpha = 0; } // Show first idle frame to continue with idle animation if (self.idleFrameAssets.length > 0) { //self.idleFrameAssets[0].alpha = 1; } // Now start idle animation after rotation completes self.idleAnim(); } } // Start animation showNextFrame(); }; self.startIdleSequence = function () { // Hide all running frames for (var i = 0; i < self.frameAssets.length; i++) { self.frameAssets[i].alpha = 0; } // Start with rotation animation self.rotationAnim(); }; self.idleAnim = function () { if (self.isPlayingIdleAnim) { return; // Already playing idle animation } self.isPlayingIdleAnim = true; currentIdleFrameIndex = 0; lastIdleFrameTime = Date.now(); // Hide all running frames for (var i = 0; i < self.frameAssets.length; i++) { self.frameAssets[i].alpha = 0; } // Show first idle frame if (self.idleFrameAssets.length > 0) { self.idleFrameAssets[0].alpha = 1; } // Call teleportAnim after 2 seconds LK.setTimeout(function () { if (self.isPlayingIdleAnim) { // Only if still in idle animation self.teleportAnim(); } }, 2000); }; self.update = function () { // Handle transition from running to idle when returning to initial position if (self.isReturningToInitial) { // Keep running animation during return journey // Hide all idle frames for (var i = 0; i < self.idleFrameAssets.length; i++) { self.idleFrameAssets[i].alpha = 0; } // Show current running frame to ensure visibility if (self.frameAssets.length > 0) { // Make sure at least one frame is visible if (self.frameAssets[currentFrameIndex].alpha === 0) { self.frameAssets[currentFrameIndex].alpha = 1; } } // Continue with normal running animation var now = Date.now(); if (now - lastFrameTime >= animationInterval) { // Hide current frame self.frameAssets[currentFrameIndex].alpha = 0; // Move to next frame currentFrameIndex = (currentFrameIndex + 1) % self.frameAssets.length; // Show next frame self.frameAssets[currentFrameIndex].alpha = 1; lastFrameTime = now; } // Update rotation based on position var angle = Math.atan2(self.y - centerY, self.x - centerX); self.rotation = angle - Math.PI * 0.5; return; } if (!songStarted) { if (!self.isPlayingIdleAnim && !self.isReturningToInitial) { // Hide all running frames when song is not started and not returning for (var i = 0; i < self.frameAssets.length; i++) { self.frameAssets[i].alpha = 0; } } // Handle idle animation when song is not started if (self.isPlayingIdleAnim) { var now = Date.now(); if (now - lastIdleFrameTime >= idleAnimationInterval) { // Hide current idle frame self.idleFrameAssets[currentIdleFrameIndex].alpha = 0; // Move to next idle frame currentIdleFrameIndex = (currentIdleFrameIndex + 1) % self.idleFrameAssets.length; // Show next idle frame self.idleFrameAssets[currentIdleFrameIndex].alpha = 1; lastIdleFrameTime = now; } } return; } // Reset idle animation when song starts if (self.isPlayingIdleAnim) { self.isPlayingIdleAnim = false; // Hide all idle frames for (var i = 0; i < self.idleFrameAssets.length; i++) { self.idleFrameAssets[i].alpha = 0; } } // Update rotation based on position var angle = Math.atan2(self.y - centerY, self.x - centerX); self.rotation = angle - Math.PI * 0.5; // Animate frames var now = Date.now(); if (now - lastFrameTime >= animationInterval) { // Hide current frame self.frameAssets[currentFrameIndex].alpha = 0; // Move to next frame currentFrameIndex = (currentFrameIndex + 1) % self.frameAssets.length; // Show next frame self.frameAssets[currentFrameIndex].alpha = 1; lastFrameTime = now; } // self.tickCounter++; // if (self.tickCounter >= 5) { // self.scaleX *= -1; // self.tickCounter = 0; // } }; return self; }); var ScoreLabel = Container.expand(function () { var self = Container.call(this); self.scoreText = new Text2('0', { size: 160, fill: 0xFFFFFF }); self.scoreText.anchor.set(0.5, 0.5); self.addChild(self.scoreText); // Add penalty text self.penaltyText = new Text2('-2', { size: 120, fill: 0xFF0000 }); self.penaltyText.anchor.set(-0.5, 0.5); self.penaltyText.y = 100; // Position below score self.penaltyText.alpha = 0; // Start hidden self.addChild(self.penaltyText); self.updateScore = function (newScore) { self.scoreText.setText(newScore.toString()); // Animate score with scale effect tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeIn }); } }); }; self.showPenalty = function (penaltyValue) { penaltyValue = penaltyValue || -2; // Update penalty text with current value self.penaltyText.setText(penaltyValue.toString()); // Reset any ongoing animations tween.stop(self.penaltyText, { alpha: true, y: true }); // Reset position and alpha self.penaltyText.y = 150; self.penaltyText.alpha = 1; // Set random anchor X between -0.5 and 1.5 self.penaltyText.anchor.x = -0.5 + Math.random() * 2.0; // Animate penalty text - fade out and move up tween(self.penaltyText, { alpha: 0, y: 50 }, { duration: 1000, easing: tween.easeOut }); }; return self; }); var SparkAnim = Container.expand(function () { var self = Container.call(this); // Randomly select between note and note2 var assetType = Math.random() > 0.5 ? 'note' : 'note2'; var glowGraphics = self.attachAsset(assetType, { anchorX: 0.5, anchorY: 0.5, alpha: 1.0, scaleX: 1, scaleY: 1, tint: 0x32cbec }); self.lifetime = 1500; self.spawnTime = Date.now(); // Animate the glow with vertical movement, acceleration and alpha var initialVelocity = -200; // Start moving upward var acceleration = -2000; // Accelerate downward var deltaTime = 16; // 60fps frame time in ms var velocity = initialVelocity; // Create update function for physics movement self.update = function () { velocity += acceleration * (deltaTime / 1000); // Apply acceleration glowGraphics.y += velocity * (deltaTime / 1000); // Update position // Check if animation is complete var elapsed = Date.now() - self.spawnTime; if (elapsed >= self.lifetime) { self.destroy(); } }; // Animate alpha fade out tween(glowGraphics, { alpha: 0 }, { duration: self.lifetime, easing: tween.easeOut }); return self; }); var Speaker = Container.expand(function () { var self = Container.call(this); var speakerGraphics = self.attachAsset('speaker', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); self.volume = 1.0; self.isPlaying = false; self.setVolume = function (vol) { self.volume = Math.max(0, Math.min(1, vol)); }; self.toggleState = function () { self.isPlaying = !self.isPlaying; speakerGraphics.alpha = self.isPlaying ? 1.0 : 0.5; }; return self; }); var SpeakerManager = Container.expand(function () { var self = Container.call(this); self.speakers = []; self.lastBeatTime = 0; self.beatCooldown = 200; self.speakerSongData = speakersBeat[0]; self.currentBeatIndex = 0; self.songStartTime = 0; // Define speakerPositions in class scope so it's accessible in update method var speakerPositions = [{ x: 1024 - 500, y: 512 }, { x: 1024, y: 512 }, { x: 1024 + 500, y: 512 }]; self.initializeSpeakers = function () { for (var i = 0; i < 3; i++) { var speaker = new Speaker(); var finalX = speakerPositions[i].x; var finalY = speakerPositions[i].y; // Set initial positions for entrance animation if (i === 0) { // Left speaker - comes from left speaker.x = finalX - 800; speaker.y = finalY; } else if (i === 1) { // Center speaker - comes from top speaker.x = finalX; speaker.y = finalY - 800; } else { // Right speaker - comes from right speaker.x = finalX + 800; speaker.y = finalY; } speaker.scaleX = 0.8; speaker.scaleY = 0.8; speaker.isBigBumping = false; self.speakers.push(speaker); self.addChild(speaker); // Set delay for entrance order: left & right first, then center var delay; if (i === 0 || i === 2) { // Left and right speakers - no delay delay = 0; } else { // Center speaker - delay after left and right delay = 300; } LK.setTimeout(function (spkr, targetX, targetY) { return function () { tween(spkr, { x: targetX, y: targetY }, { duration: 800, easing: tween.easeOut }); }; }(speaker, finalX, finalY), delay); } }; self.onBeat = function (beatValue) { var now = Date.now(); if (now - self.lastBeatTime >= self.beatCooldown) { var speakerIndex = -1; if (beatValue === "1") { speakerIndex = 1; } else if (beatValue === "2") { speakerIndex = 2; } else { speakerIndex = 0; } if (speakerIndex >= 0 && speakerIndex < self.speakers.length) { var mainSpeaker = self.speakers[speakerIndex]; mainSpeaker.isBigBumping = true; self.spawnNoteSparks(mainSpeaker); tween(mainSpeaker, { scaleX: 1.2, scaleY: 1.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(mainSpeaker, { scaleX: 0.8, scaleY: 0.8 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { mainSpeaker.isBigBumping = false; } }); } }); } self.lastBeatTime = now; } }; self.update = function () { if (songStarted) { // Initialize speakers only once when song starts if (self.speakers.length === 0) { self.initializeSpeakers(); } for (var i = 0; i < self.speakers.length; i++) { var speaker = self.speakers[i]; var time = Date.now() * 0.003; var twistAngle = Math.sin(time + i * 0.5) * 0.15; speaker.rotation = twistAngle; if (!speaker.isBigBumping) { var scaleValue = 0.8 + Math.sin(time * 2 + i * 0.3) * 0.05; speaker.scaleX = scaleValue; speaker.scaleY = scaleValue; // Add dancing up/down movement var dancingOffset = Math.sin(time * 3 + i * 0.7) * 10; speaker.y = speakerPositions[i].y + dancingOffset; } } } if (!songStarted) { // Don't clear speakers array immediately to allow exit animation // The array will be cleared after the animation completes return; } var now = Date.now(); var songElapsed = now - self.songStartTime; if (self.currentBeatIndex < self.speakerSongData.songBeats.length) { var nextBeat = self.speakerSongData.songBeats[self.currentBeatIndex]; if (songElapsed >= nextBeat.time) { self.onBeat(nextBeat.beat); self.currentBeatIndex++; } } else { var lastBeatTime = self.speakerSongData.songBeats[self.speakerSongData.songBeats.length - 1].time; if (songElapsed > lastBeatTime + 5000) { self.songStartTime = Date.now(); self.currentBeatIndex = 0; } } }; self.spawnNoteSparks = function (speaker) { var noteCount = 3 + Math.floor(Math.random() * 3); for (var i = 0; i < noteCount; i++) { var note = new Note(); var angle = Math.random() * Math.PI * 2; var distance = 50 + Math.random() * 100; note.x = speaker.x + Math.cos(angle) * distance; note.y = speaker.y + Math.sin(angle) * distance; var speed = 3 + Math.random() * 5; note.setVelocity(Math.cos(angle) * speed, Math.sin(angle) * speed - 2); note.setNoteType(Math.random() > 0.5 ? 'note' : 'note2'); var futuristicColors = [0x32cbec]; var color = futuristicColors[Math.floor(Math.random() * futuristicColors.length)]; note.setColor(color); note.rotation = (Math.random() - 0.5) * 0.5; note.scaleX = 0.5; note.scaleY = 0.5; if (noteSparks) { noteSparks.notes.push(note); noteSparks.addChild(note); } } }; return self; }); /* var testGate = new Gate(); var newScale = 1; testGate.scaleX = newScale; testGate.scaleY = newScale; testGate.gateAsset.scaleX = newScale; testGate.gateAsset.scaleY = newScale; testGate.boundingBox.scaleX = newScale; testGate.boundingBox.scaleY = newScale; testGate.boundingBox.alpha = 0.3; game.addChild(testGate); */ var StartButton = Container.expand(function () { var self = Container.call(this); self.buttonBg = self.attachAsset('start', { anchorX: 0.5, anchorY: 0.5 }); self.x = centerX; self.y = centerY; self.down = function () { if (songStarted) { return; } songStarted = true; if (isDebug) { LK.playMusic('track_test'); } else { LK.playMusic('track_01'); } if (gateManager) { gateManager.songStartTime = Date.now(); gateManager.currentNoteIndex = 0; } if (speakerManager) { speakerManager.songStartTime = Date.now(); speakerManager.currentBeatIndex = 0; } if (noteSparks) {} // Show score label when game starts // Show score label when game starts if (scoreLabel) { scoreLabel.visible = true; } // Show progress bar when game starts if (progressBar) { progressBar.visible = true; progressBar.startProgressAnimation(); } tween(self, { alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); var WorldManager = Container.expand(function () { var self = Container.call(this); var assetWidth = 2732; var screenWidth = 2048; var totalContentWidth = assetWidth * 2; self.x_center_view = -(totalContentWidth / 2 - screenWidth / 2); self.shiftAmplitude = 1024; self.shiftDurationOneWay = 15000; self._isShifting = false; self._animateToRandomTarget = function () { if (!songStarted || !self._isShifting) { self._isShifting = false; tween.stop(self, { x: true }); return; } var minTargetX = self.x_center_view - self.shiftAmplitude; var maxTargetX = self.x_center_view + self.shiftAmplitude; var randomTargetX = minTargetX + Math.random() * (maxTargetX - minTargetX); var currentX = self.x; var distanceToTravel = Math.abs(currentX - randomTargetX); if (distanceToTravel < 50) { LK.setTimeout(self._animateToRandomTarget, 0); return; } var speed = self.shiftAmplitude / self.shiftDurationOneWay; if (speed <= 0) { speed = (self.shiftAmplitude > 0 ? self.shiftAmplitude : 1024) / 15000; if (speed <= 0) { speed = 0.05; } } var dynamicDuration = distanceToTravel / speed; dynamicDuration = Math.max(500, Math.min(dynamicDuration, self.shiftDurationOneWay * 2)); tween(self, { x: randomTargetX }, { duration: dynamicDuration, easing: tween.easeInOut, onFinish: self._animateToRandomTarget }); }; self._initiateShift = function () { if (self._isShifting) { return; } self._isShifting = true; self._animateToRandomTarget(); }; self.update = function () { if (songStarted && !self._isShifting) { self._initiateShift(); } else if (!songStarted && self._isShifting) { self._isShifting = false; tween.stop(self, { x: true }); tween(self, { x: self.x_center_view }, { duration: 1000, easing: tween.easeOut }); } }; self.x = self.x_center_view; self.y = 0; self.bgLeft = self.attachAsset('world01', { anchorX: 0.5, anchorY: 0.5, x: assetWidth / 2, y: centerY, scaleX: 1.0, scaleY: 1.0 }); self.bgRight = self.attachAsset('world01', { anchorX: 0.5, anchorY: 0.5, x: assetWidth / 2 + assetWidth, y: centerY, scaleX: -1.0, scaleY: 1.0 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000c33 }); /**** * Game Code ****/ var centerX = 1024; var centerY = 1366; var neonColors = [0x39FF14, 0xFF073A, 0x00FFFF, 0xF3F315, 0xFF61F6, 0xFF9900]; var keyColorMap = { 'Key0': 0x39FF14, 'Key1': 0xFF073A, 'Key2': 0x00FFFF, 'Key3': 0xF3F315, 'Key4': 0xFF61F6, 'Key5': 0xFF9900, 'Key6': 0x39FF14, 'Key7': 0xFF073A, 'Key8': 0x00FFFF, 'Key9': 0xF3F315, 'Key10': 0xFF61F6, 'Key11': 0xFF9900, 'Key12': 0x39FF14, 'Key13': 0xFF073A, 'Key14': 0x00FFFF }; var currentColor = neonColors[Math.floor(Math.random() * neonColors.length)]; function drawPolygon(coordinates, tint) { log("drawPolygon ", coordinates); var lines = []; for (var i = 0; i < coordinates.length; i++) { var startPoint = coordinates[i]; var endPoint = coordinates[(i + 1) % coordinates.length]; var line = drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, tint); lines.push(line); } return lines; } function updatePolygon(lines, newCoordinates, scale) { log("updatePolygon ", lines, scale); if (lines.length !== newCoordinates.length) { error("updatePolygon error: lines and newCoordinates length mismatch"); return lines; } for (var i = 0; i < lines.length; i++) { var startPoint = newCoordinates[i]; var endPoint = newCoordinates[(i + 1) % newCoordinates.length]; updateLine(lines[i], startPoint.x, startPoint.y, endPoint.x, endPoint.y, scale); } return lines; } function drawLine(x1, y1, x2, y2, tint) { log("drawLine ", x1, y1); var line = LK.getAsset('line', { anchorX: 0.0, anchorY: 0.0, x: x1, y: y1, tint: tint }); line.startX = x1; line.startY = y1; line.endX = x2; line.endY = y2; var distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); line.width = distance; var angle = Math.atan2(y2 - y1, x2 - x1); line.rotation = angle; return line; } function updateLine(line, newX1, newY1, newX2, newY2, scale) { log("updateLine ", line); scale = scale === undefined ? 1 : scale; var midX = (newX1 + newX2) / 2; var midY = (newY1 + newY2) / 2; newX1 = midX + (newX1 - midX) * scale; newY1 = midY + (newY1 - midY) * scale; newX2 = midX + (newX2 - midX) * scale; newY2 = midY + (newY2 - midY) * scale; line.x = newX1; line.y = newY1; line.startX = newX1; line.startY = newY1; line.endX = newX2; line.endY = newY2; var distance = Math.sqrt(Math.pow(newX2 - newX1, 2) + Math.pow(newY2 - newY1, 2)); line.width = distance; var angle = Math.atan2(newY2 - newY1, newX2 - newX1); line.rotation = angle; return line; } function log() { if (isDebug) { console.log(arguments); } } var songListV3 = [{ "name": "Words Fly Fast", "duration": 156000, // Real 157240, "songBeats": [{ "time": 651, "beat": "1" }, { "time": 1256, "beat": "1" }, { "time": 1800, "beat": "1" }, { "time": 2364, "beat": "1" }, { "time": 2828, "beat": "1" }, { "time": 3324, "beat": "1" }, { "time": 3708, "beat": "1" }, { "time": 4192, "beat": "2" }, { "time": 4804, "beat": "2" }, { "time": 5320, "beat": "2" }, { "time": 5796, "beat": "2" }, { "time": 6240, "beat": "2" }, { "time": 6692, "beat": "2" }, { "time": 7176, "beat": "2" }, { "time": 7640, "beat": "2" }, { "time": 8092, "beat": "1" }, { "time": 8576, "beat": "2" }, { "time": 9124, "beat": "1" }, { "time": 9580, "beat": "2" }, { "time": 10084, "beat": "1" }, { "time": 10548, "beat": "2" }, { "time": 11072, "beat": "1" }, { "time": 11556, "beat": "2" }, { "time": 12092, "beat": "1" }, { "time": 12564, "beat": "2" }, { "time": 13008, "beat": "1" }, { "time": 13400, "beat": "2" }, { "time": 13916, "beat": "1" }, { "time": 14460, "beat": "2" }, { "time": 14944, "beat": "1" }, { "time": 15360, "beat": "2" }, { "time": 17340, "beat": "1" }, { "time": 18260, "beat": "2" }, { "time": 19196, "beat": "1" }, { "time": 20064, "beat": "2" }, { "time": 21092, "beat": "1" }, { "time": 22072, "beat": "2" }, { "time": 23100, "beat": "1" }, { "time": 24040, "beat": "2" }, { "time": 24988, "beat": "1" }, { "time": 25884, "beat": "2" }, { "time": 26876, "beat": "1" }, { "time": 27892, "beat": "2" }, { "time": 28820, "beat": "1" }, { "time": 29688, "beat": "2" }, { "time": 30728, "beat": "1" }, { "time": 31696, "beat": "2" }, { "time": 32656, "beat": "1" }, { "time": 33624, "beat": "2" }, { "time": 34673, "beat": "1" }, { "time": 35692, "beat": "2" }, { "time": 36628, "beat": "1" }, { "time": 37536, "beat": "2" }, { "time": 38516, "beat": "1" }, { "time": 39372, "beat": "2" }, { "time": 40524, "beat": "1" }, { "time": 41028, "beat": "1" }, { "time": 43080, "beat": "2" }, { "time": 43564, "beat": "2" }, { "time": 44400, "beat": "1" }, { "time": 44948, "beat": "1" }, { "time": 46888, "beat": "2" }, { "time": 47412, "beat": "2" }, { "time": 48260, "beat": "1" }, { "time": 48818, "beat": "1" }, { "time": 50816, "beat": "2" }, { "time": 51524, "beat": "2" }, { "time": 52168, "beat": "1" }, { "time": 52684, "beat": "1" }, { "time": 54540, "beat": "3" }, { "time": 55488, "beat": "3" }, { "time": 56448, "beat": "3" }, { "time": 57436, "beat": "3" }, { "time": 58412, "beat": "1" }, { "time": 59240, "beat": "2" }, { "time": 59988, "beat": "1" }, { "time": 60808, "beat": "2" }, { "time": 61636, "beat": "1" }, { "time": 63800, "beat": "1" }, { "time": 64688, "beat": "2" }, { "time": 65656, "beat": "1" }, { "time": 66544, "beat": "2" }, { "time": 67492, "beat": "1" }, { "time": 68432, "beat": "2" }, { "time": 69369, "beat": "1" }, { "time": 70336, "beat": "2" }, { "time": 71416, "beat": "1" }, { "time": 72324, "beat": "2" }, { "time": 73408, "beat": "1" }, { "time": 74316, "beat": "2" }, { "time": 75276, "beat": "1" }, { "time": 76204, "beat": "2" }, { "time": 77248, "beat": "2" }, { "time": 78232, "beat": "1" }, { "time": 79168, "beat": "2" }, { "time": 81048, "beat": "1" }, { "time": 81996, "beat": "2" }, { "time": 83096, "beat": "1" }, { "time": 84064, "beat": "2" }, { "time": 85040, "beat": "1" }, { "time": 86008, "beat": "2" }, { "time": 86956, "beat": "1" }, { "time": 87976, "beat": "2" }, { "time": 88832, "beat": "1" }, { "time": 89844, "beat": "2" }, { "time": 90832, "beat": "1" }, { "time": 92672, "beat": "3" }, { "time": 93156, "beat": "3" }, { "time": 93720, "beat": "3" }, { "time": 94329, "beat": "3" }, { "time": 94812, "beat": "3" }, { "time": 95256, "beat": "3" }, { "time": 95720, "beat": "1" }, { "time": 96496, "beat": "2" }, { "time": 97556, "beat": "3" }, { "time": 98112, "beat": "3" }, { "time": 98624, "beat": "3" }, { "time": 99100, "beat": "3" }, { "time": 99604, "beat": "1" }, { "time": 100440, "beat": "2" }, { "time": 101420, "beat": "1" }, { "time": 102388, "beat": "2" }, { "time": 103336, "beat": "1" }, { "time": 104324, "beat": "2" }, { "time": 105172, "beat": "1" }, { "time": 106260, "beat": "3" }, { "time": 106836, "beat": "3" }, { "time": 107392, "beat": "3" }, { "time": 108028, "beat": "2" }, { "time": 108692, "beat": "1" }, { "time": 109540, "beat": "2" }, { "time": 110488, "beat": "1" }, { "time": 111932, "beat": "2" }, { "time": 112888, "beat": "1" }, { "time": 113796, "beat": "2" }, { "time": 114864, "beat": "1" }, { "time": 115904, "beat": "2" }, { "time": 116864, "beat": "2" }, { "time": 117792, "beat": "1" }, { "time": 119184, "beat": "2" }, { "time": 120244, "beat": "1" }, { "time": 121112, "beat": "2" }, { "time": 122121, "beat": "3" }, { "time": 122744, "beat": "3" }, { "time": 123260, "beat": "3" }, { "time": 123784, "beat": "3" }, { "time": 124217, "beat": "3" }, { "time": 125620, "beat": "1" }, { "time": 126668, "beat": "2" }, { "time": 127788, "beat": "1" }, { "time": 128796, "beat": "2" }, { "time": 129716, "beat": "1" }, { "time": 130884, "beat": "2" }, { "time": 131936, "beat": "1" }, { "time": 132932, "beat": "2" }, { "time": 134092, "beat": "1" }, { "time": 135124, "beat": "2" }, { "time": 136160, "beat": "1" }, { "time": 137128, "beat": "2" }, { "time": 139693, "beat": "3" }, { "time": 140208, "beat": "3" }, { "time": 140712, "beat": "3" }, { "time": 141216, "beat": "3" }, { "time": 141700, "beat": "3" }, { "time": 142164, "beat": "3" }, { "time": 142668, "beat": "3" }, { "time": 143164, "beat": "3" }, { "time": 143668, "beat": "1" }, { "time": 144484, "beat": "2" }, { "time": 145412, "beat": "1" }, { "time": 146340, "beat": "2" }, { "time": 147708, "beat": "3" }, { "time": 148304, "beat": "3" }, { "time": 148820, "beat": "3" }, { "time": 149312, "beat": "3" }, { "time": 149908, "beat": "1" }, { "time": 150804, "beat": "2" }, { "time": 151784, "beat": "3" }, { "time": 152328, "beat": "3" }, { "time": 152832, "beat": "3" }, { "time": 153236, "beat": "3" }, { "time": 153680, "beat": "1" }, { "time": 154518, "beat": "2" }] }]; var speakersBeat = [{ "name": "Words Fly Fast", "songBeats": [{ "time": 128, "beat": "1" }, { "time": 443, "beat": "1" }, { "time": 747, "beat": "1" }, { "time": 1232, "beat": "1" }, { "time": 1579, "beat": "1" }, { "time": 1893, "beat": "1" }, { "time": 2224, "beat": "1" }, { "time": 2549, "beat": "1" }, { "time": 2853, "beat": "1" }, { "time": 3269, "beat": "1" }, { "time": 3712, "beat": "1" }, { "time": 4037, "beat": "1" }, { "time": 4352, "beat": "1" }, { "time": 4661, "beat": "1" }, { "time": 5072, "beat": "1" }, { "time": 5392, "beat": "1" }, { "time": 5728, "beat": "1" }, { "time": 6176, "beat": "1" }, { "time": 6587, "beat": "1" }, { "time": 7141, "beat": "1" }, { "time": 7541, "beat": "1" }, { "time": 7856, "beat": "1" }, { "time": 8171, "beat": "3" }, { "time": 8501, "beat": "2" }, { "time": 8816, "beat": "2" }, { "time": 9120, "beat": "3" }, { "time": 9424, "beat": "2" }, { "time": 9728, "beat": "2" }, { "time": 10032, "beat": "3" }, { "time": 10347, "beat": "2" }, { "time": 10651, "beat": "1" }, { "time": 10971, "beat": "2" }, { "time": 11275, "beat": "2" }, { "time": 11600, "beat": "2" }, { "time": 11915, "beat": "1" }, { "time": 12240, "beat": "2" }, { "time": 12560, "beat": "3" }, { "time": 12875, "beat": "2" }, { "time": 13184, "beat": "3" }, { "time": 13493, "beat": "2" }, { "time": 13813, "beat": "3" }, { "time": 14176, "beat": "3" }, { "time": 14517, "beat": "1" }, { "time": 14843, "beat": "2" }, { "time": 15147, "beat": "2" }, { "time": 15472, "beat": "3" }, { "time": 15781, "beat": "2" }, { "time": 16112, "beat": "2" }, { "time": 16432, "beat": "2" }, { "time": 16741, "beat": "2" }, { "time": 17056, "beat": "3" }, { "time": 17360, "beat": "3" }, { "time": 17685, "beat": "2" }, { "time": 17995, "beat": "3" }, { "time": 18299, "beat": "3" }, { "time": 18608, "beat": "3" }, { "time": 18917, "beat": "3" }, { "time": 19232, "beat": "1" }, { "time": 19547, "beat": "2" }, { "time": 19851, "beat": "3" }, { "time": 20171, "beat": "1" }, { "time": 20475, "beat": "3" }, { "time": 20805, "beat": "3" }, { "time": 21120, "beat": "1" }, { "time": 21435, "beat": "2" }, { "time": 21749, "beat": "2" }, { "time": 22059, "beat": "2" }, { "time": 22373, "beat": "2" }, { "time": 22699, "beat": "2" }, { "time": 23019, "beat": "1" }, { "time": 23323, "beat": "3" }, { "time": 23627, "beat": "3" }, { "time": 23931, "beat": "2" }, { "time": 24240, "beat": "2" }, { "time": 24549, "beat": "2" }, { "time": 24869, "beat": "2" }, { "time": 25189, "beat": "3" }, { "time": 25493, "beat": "2" }, { "time": 25819, "beat": "2" }, { "time": 26133, "beat": "1" }, { "time": 26437, "beat": "2" }, { "time": 26757, "beat": "2" }, { "time": 27061, "beat": "2" }, { "time": 27365, "beat": "2" }, { "time": 27669, "beat": "3" }, { "time": 27973, "beat": "3" }, { "time": 28277, "beat": "3" }, { "time": 28581, "beat": "3" }, { "time": 28885, "beat": "3" }, { "time": 29221, "beat": "2" }, { "time": 29557, "beat": "3" }, { "time": 29861, "beat": "2" }, { "time": 30197, "beat": "2" }, { "time": 30507, "beat": "2" }, { "time": 30827, "beat": "2" }, { "time": 31141, "beat": "2" }, { "time": 31483, "beat": "2" }, { "time": 31787, "beat": "2" }, { "time": 32091, "beat": "3" }, { "time": 32395, "beat": "3" }, { "time": 32731, "beat": "1" }, { "time": 33045, "beat": "2" }, { "time": 33349, "beat": "3" }, { "time": 33653, "beat": "2" }, { "time": 33957, "beat": "3" }, { "time": 34261, "beat": "2" }, { "time": 34576, "beat": "2" }, { "time": 34901, "beat": "2" }, { "time": 35211, "beat": "3" }, { "time": 35520, "beat": "2" }, { "time": 35829, "beat": "3" }, { "time": 36149, "beat": "3" }, { "time": 36464, "beat": "2" }, { "time": 36779, "beat": "3" }, { "time": 37083, "beat": "2" }, { "time": 37403, "beat": "2" }, { "time": 37707, "beat": "2" }, { "time": 38037, "beat": "2" }, { "time": 38341, "beat": "3" }, { "time": 38661, "beat": "2" }, { "time": 38976, "beat": "1" }, { "time": 39301, "beat": "1" }, { "time": 39611, "beat": "2" }, { "time": 39941, "beat": "2" }, { "time": 40256, "beat": "1" }, { "time": 40565, "beat": "2" }, { "time": 40885, "beat": "1" }, { "time": 41189, "beat": "1" }, { "time": 41499, "beat": "1" }, { "time": 41851, "beat": "1" }, { "time": 42155, "beat": "1" }, { "time": 42459, "beat": "1" }, { "time": 42976, "beat": "1" }, { "time": 43429, "beat": "1" }, { "time": 43733, "beat": "1" }, { "time": 44043, "beat": "1" }, { "time": 44357, "beat": "2" }, { "time": 44672, "beat": "2" }, { "time": 44987, "beat": "1" }, { "time": 45312, "beat": "1" }, { "time": 45744, "beat": "1" }, { "time": 46059, "beat": "1" }, { "time": 46373, "beat": "1" }, { "time": 46683, "beat": "2" }, { "time": 46992, "beat": "2" }, { "time": 47301, "beat": "1" }, { "time": 47605, "beat": "2" }, { "time": 47920, "beat": "2" }, { "time": 48229, "beat": "1" }, { "time": 48544, "beat": "2" }, { "time": 48859, "beat": "1" }, { "time": 49168, "beat": "1" }, { "time": 49477, "beat": "2" }, { "time": 49845, "beat": "1" }, { "time": 50160, "beat": "1" }, { "time": 50496, "beat": "2" }, { "time": 50805, "beat": "1" }, { "time": 51173, "beat": "1" }, { "time": 51477, "beat": "2" }, { "time": 51792, "beat": "2" }, { "time": 52107, "beat": "2" }, { "time": 52421, "beat": "1" }, { "time": 52869, "beat": "1" }, { "time": 53189, "beat": "1" }, { "time": 53595, "beat": "1" }, { "time": 53979, "beat": "1" }, { "time": 54288, "beat": "1" }, { "time": 54597, "beat": "3" }, { "time": 54907, "beat": "2" }, { "time": 55227, "beat": "3" }, { "time": 55531, "beat": "3" }, { "time": 55851, "beat": "2" }, { "time": 56165, "beat": "3" }, { "time": 56475, "beat": "3" }, { "time": 56789, "beat": "2" }, { "time": 57104, "beat": "2" }, { "time": 57408, "beat": "1" }, { "time": 57728, "beat": "3" }, { "time": 58053, "beat": "2" }, { "time": 58363, "beat": "1" }, { "time": 58667, "beat": "3" }, { "time": 58976, "beat": "3" }, { "time": 59307, "beat": "1" }, { "time": 59621, "beat": "3" }, { "time": 59947, "beat": "3" }, { "time": 60304, "beat": "2" }, { "time": 60608, "beat": "3" }, { "time": 60971, "beat": "1" }, { "time": 61339, "beat": "2" }, { "time": 61701, "beat": "1" }, { "time": 62032, "beat": "1" }, { "time": 62336, "beat": "3" }, { "time": 62640, "beat": "3" }, { "time": 62955, "beat": "3" }, { "time": 63269, "beat": "3" }, { "time": 63584, "beat": "2" }, { "time": 63904, "beat": "3" }, { "time": 64213, "beat": "3" }, { "time": 64555, "beat": "2" }, { "time": 64864, "beat": "3" }, { "time": 65179, "beat": "2" }, { "time": 65499, "beat": "2" }, { "time": 65824, "beat": "3" }, { "time": 66144, "beat": "2" }, { "time": 66464, "beat": "2" }, { "time": 66768, "beat": "3" }, { "time": 67093, "beat": "1" }, { "time": 67403, "beat": "3" }, { "time": 67707, "beat": "3" }, { "time": 68053, "beat": "2" }, { "time": 68368, "beat": "2" }, { "time": 68709, "beat": "1" }, { "time": 69024, "beat": "1" }, { "time": 69333, "beat": "2" }, { "time": 69648, "beat": "3" }, { "time": 69968, "beat": "2" }, { "time": 70283, "beat": "2" }, { "time": 70587, "beat": "3" }, { "time": 70896, "beat": "3" }, { "time": 71205, "beat": "3" }, { "time": 71525, "beat": "3" }, { "time": 71835, "beat": "3" }, { "time": 72139, "beat": "3" }, { "time": 72448, "beat": "3" }, { "time": 72779, "beat": "3" }, { "time": 73083, "beat": "2" }, { "time": 73387, "beat": "3" }, { "time": 73691, "beat": "1" }, { "time": 74016, "beat": "3" }, { "time": 74336, "beat": "2" }, { "time": 74667, "beat": "3" }, { "time": 74987, "beat": "3" }, { "time": 75296, "beat": "1" }, { "time": 75605, "beat": "3" }, { "time": 75915, "beat": "3" }, { "time": 76224, "beat": "3" }, { "time": 76549, "beat": "3" }, { "time": 76853, "beat": "3" }, { "time": 77157, "beat": "3" }, { "time": 77461, "beat": "3" }, { "time": 77776, "beat": "1" }, { "time": 78107, "beat": "2" }, { "time": 78421, "beat": "2" }, { "time": 78731, "beat": "2" }, { "time": 79045, "beat": "2" }, { "time": 79365, "beat": "2" }, { "time": 79669, "beat": "1" }, { "time": 79995, "beat": "1" }, { "time": 80309, "beat": "1" }, { "time": 80640, "beat": "1" }, { "time": 80965, "beat": "1" }, { "time": 81296, "beat": "1" }, { "time": 81856, "beat": "1" }, { "time": 82165, "beat": "2" }, { "time": 82491, "beat": "2" }, { "time": 82827, "beat": "2" }, { "time": 83136, "beat": "2" }, { "time": 83451, "beat": "2" }, { "time": 83765, "beat": "1" }, { "time": 84080, "beat": "1" }, { "time": 84389, "beat": "1" }, { "time": 84704, "beat": "1" }, { "time": 85040, "beat": "1" }, { "time": 85392, "beat": "2" }, { "time": 85696, "beat": "1" }, { "time": 86016, "beat": "1" }, { "time": 86325, "beat": "1" }, { "time": 86688, "beat": "1" }, { "time": 87019, "beat": "2" }, { "time": 87323, "beat": "2" }, { "time": 87643, "beat": "1" }, { "time": 87947, "beat": "1" }, { "time": 88272, "beat": "1" }, { "time": 88587, "beat": "1" }, { "time": 88901, "beat": "1" }, { "time": 89216, "beat": "1" }, { "time": 89520, "beat": "1" }, { "time": 89872, "beat": "1" }, { "time": 90176, "beat": "2" }, { "time": 90485, "beat": "2" }, { "time": 90800, "beat": "2" }, { "time": 91115, "beat": "1" }, { "time": 91424, "beat": "1" }, { "time": 91819, "beat": "1" }, { "time": 92304, "beat": "1" }, { "time": 92667, "beat": "1" }, { "time": 92992, "beat": "2" }, { "time": 93301, "beat": "3" }, { "time": 93659, "beat": "1" }, { "time": 93968, "beat": "3" }, { "time": 94272, "beat": "3" }, { "time": 94581, "beat": "2" }, { "time": 94885, "beat": "3" }, { "time": 95205, "beat": "3" }, { "time": 95525, "beat": "2" }, { "time": 95845, "beat": "3" }, { "time": 96155, "beat": "1" }, { "time": 96485, "beat": "2" }, { "time": 96811, "beat": "3" }, { "time": 97125, "beat": "3" }, { "time": 97451, "beat": "2" }, { "time": 97755, "beat": "3" }, { "time": 98069, "beat": "3" }, { "time": 98411, "beat": "2" }, { "time": 98725, "beat": "3" }, { "time": 99035, "beat": "3" }, { "time": 99349, "beat": "3" }, { "time": 99680, "beat": "1" }, { "time": 100000, "beat": "2" }, { "time": 100304, "beat": "3" }, { "time": 100624, "beat": "3" }, { "time": 100928, "beat": "3" }, { "time": 101232, "beat": "3" }, { "time": 101557, "beat": "3" }, { "time": 101888, "beat": "2" }, { "time": 102192, "beat": "3" }, { "time": 102507, "beat": "3" }, { "time": 102853, "beat": "3" }, { "time": 103157, "beat": "3" }, { "time": 103461, "beat": "3" }, { "time": 103765, "beat": "2" }, { "time": 104085, "beat": "1" }, { "time": 104395, "beat": "1" }, { "time": 104709, "beat": "2" }, { "time": 105013, "beat": "3" }, { "time": 105317, "beat": "2" }, { "time": 105627, "beat": "1" }, { "time": 105931, "beat": "3" }, { "time": 106240, "beat": "2" }, { "time": 106555, "beat": "3" }, { "time": 106864, "beat": "3" }, { "time": 107168, "beat": "3" }, { "time": 107472, "beat": "1" }, { "time": 107781, "beat": "2" }, { "time": 108091, "beat": "3" }, { "time": 108416, "beat": "2" }, { "time": 108731, "beat": "2" }, { "time": 109045, "beat": "2" }, { "time": 109349, "beat": "3" }, { "time": 109669, "beat": "2" }, { "time": 109979, "beat": "2" }, { "time": 110293, "beat": "3" }, { "time": 110597, "beat": "3" }, { "time": 110917, "beat": "3" }, { "time": 111221, "beat": "3" }, { "time": 111525, "beat": "3" }, { "time": 111840, "beat": "2" }, { "time": 112144, "beat": "3" }, { "time": 112459, "beat": "3" }, { "time": 112773, "beat": "3" }, { "time": 113093, "beat": "3" }, { "time": 113419, "beat": "3" }, { "time": 113723, "beat": "3" }, { "time": 114032, "beat": "2" }, { "time": 114336, "beat": "2" }, { "time": 114651, "beat": "3" }, { "time": 114965, "beat": "1" }, { "time": 115280, "beat": "2" }, { "time": 115584, "beat": "3" }, { "time": 115888, "beat": "3" }, { "time": 116208, "beat": "2" }, { "time": 116523, "beat": "3" }, { "time": 116837, "beat": "2" }, { "time": 117147, "beat": "3" }, { "time": 117451, "beat": "3" }, { "time": 117787, "beat": "3" }, { "time": 118101, "beat": "3" }, { "time": 118405, "beat": "3" }, { "time": 118741, "beat": "2" }, { "time": 119051, "beat": "2" }, { "time": 119360, "beat": "1" }, { "time": 119664, "beat": "2" }, { "time": 119973, "beat": "3" }, { "time": 120283, "beat": "2" }, { "time": 120603, "beat": "3" }, { "time": 120912, "beat": "3" }, { "time": 121216, "beat": "3" }, { "time": 121525, "beat": "3" }, { "time": 121829, "beat": "3" }, { "time": 122293, "beat": "1" }, { "time": 122779, "beat": "1" }, { "time": 123099, "beat": "1" }, { "time": 123504, "beat": "1" }, { "time": 123845, "beat": "1" }, { "time": 124352, "beat": "1" }, { "time": 124699, "beat": "1" }, { "time": 125024, "beat": "1" }, { "time": 125333, "beat": "1" }, { "time": 125648, "beat": "1" }, { "time": 125979, "beat": "1" }, { "time": 126325, "beat": "1" }, { "time": 126635, "beat": "1" }, { "time": 126960, "beat": "1" }, { "time": 127275, "beat": "1" }, { "time": 127589, "beat": "1" }, { "time": 128059, "beat": "1" }, { "time": 128523, "beat": "1" }, { "time": 128837, "beat": "2" }, { "time": 129173, "beat": "1" }, { "time": 129483, "beat": "2" }, { "time": 129813, "beat": "2" }, { "time": 130133, "beat": "1" }, { "time": 130437, "beat": "1" }, { "time": 130741, "beat": "1" }, { "time": 131109, "beat": "1" }, { "time": 131413, "beat": "1" }, { "time": 131739, "beat": "2" }, { "time": 132080, "beat": "2" }, { "time": 132384, "beat": "2" }, { "time": 132784, "beat": "1" }, { "time": 133093, "beat": "1" }, { "time": 133408, "beat": "2" }, { "time": 133739, "beat": "1" }, { "time": 134069, "beat": "1" }, { "time": 134389, "beat": "1" }, { "time": 134709, "beat": "1" }, { "time": 135019, "beat": "1" }, { "time": 135355, "beat": "1" }, { "time": 135733, "beat": "1" }, { "time": 136064, "beat": "2" }, { "time": 136384, "beat": "3" }, { "time": 136693, "beat": "1" }, { "time": 137024, "beat": "2" }, { "time": 137339, "beat": "2" }, { "time": 137776, "beat": "1" }, { "time": 138261, "beat": "1" }, { "time": 138741, "beat": "1" }, { "time": 139109, "beat": "1" }, { "time": 139435, "beat": "1" }, { "time": 139744, "beat": "2" }, { "time": 140048, "beat": "2" }, { "time": 140352, "beat": "3" }, { "time": 140656, "beat": "3" }, { "time": 140987, "beat": "2" }, { "time": 141291, "beat": "3" }, { "time": 141605, "beat": "3" }, { "time": 141909, "beat": "3" }, { "time": 142251, "beat": "1" }, { "time": 142555, "beat": "1" }, { "time": 142859, "beat": "3" }, { "time": 143184, "beat": "3" }, { "time": 143504, "beat": "3" }, { "time": 143813, "beat": "2" }, { "time": 144123, "beat": "3" }, { "time": 144427, "beat": "2" }, { "time": 144741, "beat": "3" }, { "time": 145061, "beat": "3" }, { "time": 145365, "beat": "3" }, { "time": 145685, "beat": "3" }, { "time": 146000, "beat": "3" }, { "time": 146309, "beat": "2" }, { "time": 146624, "beat": "3" }, { "time": 146928, "beat": "2" }, { "time": 147237, "beat": "2" }, { "time": 147547, "beat": "3" }, { "time": 147851, "beat": "2" }, { "time": 148165, "beat": "3" }, { "time": 148480, "beat": "3" }, { "time": 148784, "beat": "2" }, { "time": 149104, "beat": "3" }, { "time": 149413, "beat": "3" }, { "time": 149717, "beat": "3" }, { "time": 150032, "beat": "2" }, { "time": 150336, "beat": "2" }, { "time": 150651, "beat": "2" }, { "time": 150971, "beat": "3" }, { "time": 151285, "beat": "2" }, { "time": 151600, "beat": "3" }, { "time": 151904, "beat": "3" }, { "time": 152208, "beat": "3" }, { "time": 152517, "beat": "3" }, { "time": 152821, "beat": "3" }, { "time": 153248, "beat": "1" }, { "time": 153728, "beat": "1" }, { "time": 154208, "beat": "1" }, { "time": 154576, "beat": "1" }] }]; var isDebug = true; var globalSpeed = 20; var currentRotationAngle = 0; var fullLog = []; var fpsText; var lastTick; var frameCount; var debugText; var worldManager; var backgroundManager; var gateManager; var targetManager; var ball; var runner; var speakerManager; var noteSparks; var scoreLabel; var progressBar; var orbManager; var minGateDetectionScale = 0.4; var maxGateDetectionScale = 0.6; var minOrbDetectionScale = 0.3; var maxOrbDetectionScale = 0.8; var borderLimitAngle = Math.PI * 0.08; var gateLimitAngle = Math.PI * 0.2; var gateUniqueId = 0; var songStarted = false; var leftAngle = -Math.PI * 0.5 + gateLimitAngle; var centerAngle = -Math.PI * 0.5 + Math.PI / 2; var rightAngle = -Math.PI * 0.5 + Math.PI - gateLimitAngle; function getNextGateId() { return gateUniqueId++; } var lastHitSoundTime = 0; var hitSoundCooldown = 100; var skipBeatDelay = 900; var lastBeatTime = 0; var lastGateHitTime = 0; var gatePenaltyValue = -2; if (isDebug) { songListV3 = [{ "name": "Words Fly Fast", "duration": 5000, // Real 157240, "songBeats": [{ "time": 651, "beat": "1" }, { "time": 1256, "beat": "1" }, { "time": 1800, "beat": "1" }, { "time": 2364, "beat": "1" }, { "time": 2828, "beat": "1" }, { "time": 3324, "beat": "1" }, { "time": 3708, "beat": "1" }, { "time": 4192, "beat": "2" }, { "time": 4804, "beat": "2" }] }]; speakersBeat = [{ "name": "Words Fly Fast", "songBeats": [{ "time": 128, "beat": "1" }, { "time": 443, "beat": "1" }, { "time": 747, "beat": "1" }, { "time": 1232, "beat": "1" }, { "time": 1579, "beat": "1" }, { "time": 1893, "beat": "1" }, { "time": 2224, "beat": "1" }, { "time": 2549, "beat": "1" }, { "time": 2853, "beat": "1" }, { "time": 3269, "beat": "1" }, { "time": 3712, "beat": "1" }, { "time": 4037, "beat": "1" }, { "time": 4352, "beat": "1" }, { "time": 4661, "beat": "1" }] }]; } function playHitSound() { var now = Date.now(); if (now - lastHitSoundTime >= hitSoundCooldown) { LK.getSound('hit').play(); lastHitSoundTime = now; } } function gameInitialize() { worldManager = new WorldManager(); game.addChild(worldManager); backgroundManager = new BackgroundManager(); game.addChild(backgroundManager); gateManager = new GateManager(); game.addChild(gateManager); speakerManager = new SpeakerManager(); game.addChild(speakerManager); noteSparks = new NoteSparks(); game.addChild(noteSparks); orbManager = new OrbManager(); game.addChild(orbManager); ball = new Ball(); ball.x = 1024; ball.y = 2000; ball.alpha = isDebug ? 1 : 0; game.addChild(ball); runner = new Runner(); runner.x = 1024; runner.y = 2000; game.addChild(runner); // Add score display scoreLabel = new ScoreLabel(); scoreLabel.y = 80; scoreLabel.visible = false; LK.gui.top.addChild(scoreLabel); // Add progress bar progressBar = new ProgressBar(); progressBar.x = 0; progressBar.y = 10; progressBar.visible = false; game.addChild(progressBar); // Update score display function game.updateScore = function () { scoreLabel.updateScore(LK.getScore()); }; if (!songStarted) { var startButton = new StartButton(); game.addChild(startButton); } if (isDebug) { var debugMarker = LK.getAsset('debugMarker', { anchorX: 0.5, anchorY: 0.5, x: 2048 * 0.5, y: 2732 / 2 }); game.addChild(debugMarker); fpsText = new Text2('FPS: 0', { size: 50, fill: 0xFFFFFF }); fpsText.anchor.set(1, 1); LK.gui.bottomRight.addChild(fpsText); lastTick = Date.now(); frameCount = 0; debugText = new Text2('Debug Info', { size: 50, fill: 0xFFFFFF }); debugText.anchor.set(0.5, 0); LK.gui.top.addChild(debugText); var soundTestButton = new Container(); var buttonBg = LK.getAsset('line', { anchorX: 0.5, anchorY: 0.5, scaleX: 50, scaleY: 15, tint: 0x333333 }); soundTestButton.addChild(buttonBg); var buttonText = new Text2('SOUND TEST', { size: 40, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); soundTestButton.addChild(buttonText); soundTestButton.x = -100; soundTestButton.y = 50; LK.gui.topRight.addChild(soundTestButton); soundTestButton.down = function () { for (var i = 0; i <= 14; i++) { (function (index) { LK.setTimeout(function () { LK.getSound('key' + index).play(); }, index * 600); })(i); } }; } } game.update = function () { // Update progress bar if (progressBar && progressBar.update) { progressBar.update(); } if (isDebug) { var now = Date.now(); frameCount++; if (now - lastTick >= 1000) { fpsText.setText('FPS: ' + frameCount); frameCount = 0; lastTick = now; } } }; var snapPositions = { left: 0, center: 1, right: 2 }; var currentSnapPosition = snapPositions.center; var lastMouseZone = 1; function updateSnapPosition(snapPos) { currentSnapPosition = snapPos; var targetAngle = centerAngle; if (snapPos === snapPositions.left) { targetAngle = leftAngle; } else if (snapPos === snapPositions.center) { targetAngle = centerAngle; } else if (snapPos === snapPositions.right) { targetAngle = rightAngle; } var radiusX = 924; var radiusY = 634; runner.x = centerX + radiusX * Math.cos(targetAngle + Math.PI * 0.5); runner.y = centerY + radiusY * Math.sin(targetAngle + Math.PI * 0.5); var rotationMap = { 0: -0.5, 1: 0, 2: 0.5 }; currentRotationAngle = rotationMap[snapPos] * Math.PI * 0.5; } function animateToSnapPosition(snapPos, jump) { var needsIntermediateStep = false; if (currentSnapPosition === snapPositions.left && snapPos === snapPositions.right || currentSnapPosition === snapPositions.right && snapPos === snapPositions.left) { needsIntermediateStep = true; } if (needsIntermediateStep && !jump) { var radiusX = 924; var radiusY = 634; var centerPosX = centerX + radiusX * Math.cos(centerAngle + Math.PI * 0.5); var centerPosY = centerY + radiusY * Math.sin(centerAngle + Math.PI * 0.5); tween(runner, { x: centerPosX, y: centerPosY }, { duration: 100, easing: tween.easeInOut, onFinish: function onFinish() { performSnapAnimation(snapPos, jump); } }); currentRotationAngle = 0; } else { performSnapAnimation(snapPos, jump); } } function performSnapAnimation(snapPos, jump) { currentSnapPosition = snapPos; var targetAngle = centerAngle; if (snapPos === snapPositions.left) { targetAngle = rightAngle; } else if (snapPos === snapPositions.center) { targetAngle = centerAngle; } else if (snapPos === snapPositions.right) { targetAngle = leftAngle; } var radiusX = 924; var radiusY = 634; var targetX = centerX + radiusX * Math.cos(targetAngle + Math.PI * 0.5); var targetY = centerY + radiusY * Math.sin(targetAngle + Math.PI * 0.5); var rotationMap = { 0: -0.5, 1: 0, 2: 0.5 }; var targetRotation = rotationMap[snapPos] * Math.PI * 0.5; if (jump) { tween(runner, { y: 1200 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(runner, { x: targetX, y: targetY }, { duration: 200, easing: tween.easeIn }); } }); } else { tween(runner, { x: targetX, y: targetY }, { duration: 300, easing: tween.easeInOut }); } currentRotationAngle = targetRotation; } game.down = function (x, y, obj) { if (!songStarted) { return; } var screenWidth = 2048; var thirdWidth = screenWidth / 3; var tapZone; if (x < thirdWidth) { tapZone = 0; } else if (x < thirdWidth * 2) { tapZone = 1; } else { tapZone = 2; } if (tapZone === 0) { animateToSnapPosition(snapPositions.left); } else if (tapZone === 1) { animateToSnapPosition(snapPositions.center); } else { animateToSnapPosition(snapPositions.right); } lastMouseZone = tapZone; }; game.move = function (x, y, obj) { if (!songStarted) { return; } var screenWidth = 2048; var thirdWidth = screenWidth / 3; var currentZone; if (x < thirdWidth) { currentZone = 0; } else if (x < thirdWidth * 2) { currentZone = 1; } else { currentZone = 2; } if (currentZone !== lastMouseZone) { if (currentZone === 0) { animateToSnapPosition(snapPositions.left); } else if (currentZone === 1) { animateToSnapPosition(snapPositions.center); } else { animateToSnapPosition(snapPositions.right); } lastMouseZone = currentZone; } }; game.up = function (x, y, obj) {}; gameInitialize();
===================================================================
--- original.js
+++ change.js
@@ -488,9 +488,9 @@
easing: tween.easeOut,
onFinish: function onFinish() {
runner.isReturningToInitial = false;
runner.shouldStartIdleAfterReturn = false;
- runner.idleAnim();
+ runner.startIdleSequence();
}
});
}
if (ball) {
@@ -1069,17 +1069,30 @@
for (var i = 0; i < rotationAssets.length; i++) {
rotationAssets[i].alpha = 0;
rotationAssets[i].destroy();
}
+ for (var i = 0; i < self.idleFrameAssets.length; i++) {
+ self.idleFrameAssets[i].alpha = 0;
+ }
// Show first idle frame to continue with idle animation
if (self.idleFrameAssets.length > 0) {
- self.idleFrameAssets[0].alpha = 1;
+ //self.idleFrameAssets[0].alpha = 1;
}
+ // Now start idle animation after rotation completes
+ self.idleAnim();
}
}
// Start animation
showNextFrame();
};
+ self.startIdleSequence = function () {
+ // Hide all running frames
+ for (var i = 0; i < self.frameAssets.length; i++) {
+ self.frameAssets[i].alpha = 0;
+ }
+ // Start with rotation animation
+ self.rotationAnim();
+ };
self.idleAnim = function () {
if (self.isPlayingIdleAnim) {
return; // Already playing idle animation
}
@@ -1089,17 +1102,19 @@
// Hide all running frames
for (var i = 0; i < self.frameAssets.length; i++) {
self.frameAssets[i].alpha = 0;
}
- // Call rotationAnim at the start of idleAnim
- self.rotationAnim();
+ // Show first idle frame
+ if (self.idleFrameAssets.length > 0) {
+ self.idleFrameAssets[0].alpha = 1;
+ }
// Call teleportAnim after 2 seconds
LK.setTimeout(function () {
if (self.isPlayingIdleAnim) {
// Only if still in idle animation
self.teleportAnim();
}
- }, 1300);
+ }, 2000);
};
self.update = function () {
// Handle transition from running to idle when returning to initial position
if (self.isReturningToInitial) {
remove background
remove background
Futuristic speaker in the shape of a white orb. Face view
white video camera icon
landscape of a furturistic world by night
a white music note
white sparkles emiting from the center. back background
clean red-violet beam from above
button in the shape of a protorealistic holographic futuristc Rectangle . Front view.
above the clouds by a bright night, no visible moon Photorealistic
White Clef de sol
A 20 nodes straight metalic lock chain. High definition. In-Game asset. 2d. High contrast. No shadows
a closed metalic padlock. No visible key hole.
white menu icon
in white