User prompt
Kafa karıştırıcı olmaması için kaybolan kalpler saydam degil yok olsun ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Notalar şarkı ritmime göre gelsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Şimdi onu turuncu yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Onun rengini etlileyen herşeyi kaldır
User prompt
Koyu turuncu yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Turuncu yap ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Turuncu tonlarında bir kahve yap
User prompt
Biraz daha koyu yap
User prompt
Koyu kahve yap
User prompt
Alt orta obje resim varlık rengi mavi fakat oyunda mor düzelt
User prompt
Alt merkez nesne için resim varlıkladını sil tekrar yarat
User prompt
Olmadı
User prompt
Olmadı
User prompt
Müzik ve nota dogurma ritmi düzelt
User prompt
Alttaki 3 nesne biraz büyült ve ara mesafelerini aç
User prompt
Orta ve sol not çizgilerini notlar ile birlikte hafif saga kaydır
User prompt
Keskinlik ekle
User prompt
Hala bulanık
User prompt
Hedef bölge resim barlıgı cok bulanık biraz belirginleştir
User prompt
Not kaçma sesi yanlış yerde devreye giriyor
User prompt
Oyunda sadece hedef bölgeden kaçan notlar can azaltabilir onun dısında hiç birley oyuncunun canını azaltamaz
User prompt
Sadece hedef bölgeden kaçan notalar can azaltır
User prompt
Nota şerit çizgileri hedef bölgede bitsin
User prompt
Aşagıdakı 3 nesne arası mesafeyi biraz aç
User prompt
Nota şeritleri arası mesafeyi daralt ve notalar şerit üzerinde hareket etsin
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Note = Container.expand(function (trackIndex, isPowerNote) {
var self = Container.call(this);
self.trackIndex = trackIndex;
self.isPowerNote = isPowerNote || false;
self.speed = 7;
self.hasBeenTapped = false;
self.hasReducedLife = false; // Flag to track if this note already caused life loss
self.lastY = 0;
var noteGraphics = self.attachAsset(self.isPowerNote ? 'powerNote' : 'note', {
anchorX: 0.5,
anchorY: 0.5
});
// Apply sharpness enhancement to note graphics
if (noteGraphics.filters) {
noteGraphics.filters = [];
} else {
noteGraphics.filters = [];
}
// Enhance contrast for sharper appearance
noteGraphics.alpha = 1.0;
if (self.isPowerNote) {
noteGraphics.tint = 0xFFD93D;
self.scale.set(1.2);
}
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
if (self.lastInTargetZone === undefined) self.lastInTargetZone = false;
// Check if note just entered target zone
var targetY = 1650; // unifiedTargetZone.y
var inTargetZone = Math.abs(self.y - targetY) <= 150; // Expanded target zone range
// Additional check: ensure no other note is currently in target zone
var otherNoteInZone = false;
for (var k = 0; k < notes.length; k++) {
var otherNote = notes[k];
if (otherNote !== self && !otherNote.hasBeenTapped && Math.abs(otherNote.y - targetY) <= 100) {
otherNoteInZone = true;
break;
}
}
if (!self.lastInTargetZone && inTargetZone && !self.hasBeenTapped && !otherNoteInZone) {
// Note just entered target zone and no other note is present - trigger explosion
self.triggerExplosion();
}
// Check if note passed bottom of target zone without being tapped (missed)
var targetZoneBottom = targetY + 150; // Bottom of target zone
if (self.lastY <= targetZoneBottom && self.y > targetZoneBottom && !self.hasBeenTapped && !self.hasReducedLife) {
// Note passed bottom of target zone - play miss sound and reduce lives only once
LK.getSound('miss').play();
updateLives(-1);
self.hasReducedLife = true; // Mark that this note has already caused life loss
}
self.lastY = self.y;
self.lastInTargetZone = inTargetZone;
self.y += self.speed;
};
self.checkTiming = function () {
var targetY = unifiedTargetZone.y;
var distance = Math.abs(self.y - targetY);
if (distance <= 45) {
// Expanded perfect range
return 'perfect';
} else if (distance <= 90) {
// Expanded good range
return 'good';
}
return 'miss';
};
self.triggerExplosion = function () {
if (self.hasBeenTapped) return;
var timing = self.checkTiming();
if (timing !== 'miss') {
self.hasBeenTapped = true;
var points = 0;
if (timing === 'perfect') {
points = 1;
LK.getSound('perfect').play();
createParticleEffect(self.x, self.y, self.isPowerNote ? 0xFFD93D : 0x00FF00);
} else if (timing === 'good') {
points = 1;
LK.getSound('tap').play();
createParticleEffect(self.x, self.y, 0x87CEEB);
}
updateScore(points);
unifiedTargetZone.flash();
// Trigger explosion animation on corresponding bottom object
var bottomObjects = [leftObject, centerObject, rightObject];
if (bottomObjects[self.trackIndex]) {
var targetObject = bottomObjects[self.trackIndex];
// Flash the bottom object
var originalAlpha = targetObject.alpha;
tween(targetObject, {
alpha: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
tween(targetObject, {
alpha: originalAlpha
}, {
duration: 200
});
}
});
// Scale pulse effect
var originalScale = targetObject.scaleX;
tween(targetObject, {
scaleX: originalScale * 1.1,
scaleY: originalScale * 1.1
}, {
duration: 150,
onFinish: function onFinish() {
tween(targetObject, {
scaleX: originalScale,
scaleY: originalScale
}, {
duration: 150
});
}
});
}
// Explode the note
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
for (var j = 0; j < notes.length; j++) {
if (notes[j] === self) {
notes.splice(j, 1);
break;
}
}
}
});
}
};
return self;
});
var TargetZone = Container.expand(function (trackIndex) {
var self = Container.call(this);
self.trackIndex = trackIndex;
var zoneGraphics = self.attachAsset('targetZone', {
anchorX: 0.5,
anchorY: 0.5
});
zoneGraphics.alpha = 1.0;
self.flash = function () {
zoneGraphics.alpha = 1.0;
// Remove fade animation to keep target zone fully visible
};
return self;
});
var Track = Container.expand(function (trackIndex) {
var self = Container.call(this);
self.trackIndex = trackIndex;
var trackGraphics = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0
});
trackGraphics.alpha = 0.1;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var notes = [];
var tracks = [];
var targetZones = [];
var numTracks = 3;
var trackWidth = 200; // Reduced from 300 to bring tracks closer
var gameWidth = 2048;
var score = 0;
var lives = 5; // Player starts with 5 lives
var noteSpawnTimer = 0;
var noteSpawnInterval = 90; // Faster baseline spawning
var gameSpeed = 1;
var difficultyTimer = 0;
// Note queue system to prevent simultaneous target zone entry
var noteQueue = [];
var lastTargetZoneEntry = 0;
var minTimeBetweenEntries = 60; // Reduced minimum frames for better rhythm flow
// Vertical spacing system to prevent notes from overlapping
var minVerticalSpacing = 200; // Reduced spacing for more dynamic gameplay
// Bottom objects for explosion effects
var leftObject, centerObject, rightObject;
// Strip line references for sway effects
var leftStripLine, centerStripLine, rightStripLine;
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120; // Position away from platform menu icon
scoreTxt.y = 220; // Move even further down from top
LK.gui.topLeft.addChild(scoreTxt);
// Create array to hold heart graphics for lives display
var heartsArray = [];
var heartsContainer = new Container();
heartsContainer.x = 120; // Same x as score
heartsContainer.y = 380; // Move hearts further down below score text
LK.gui.topLeft.addChild(heartsContainer);
// Initialize 5 hearts
for (var h = 0; h < 5; h++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = h * 60; // Space hearts 60 pixels apart
heart.y = 0;
heart.alpha = 1.0; // Start with full opacity
heartsArray.push(heart);
heartsContainer.addChild(heart);
}
// Add background image
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
background.x = 0;
background.y = 0;
background.tint = 0x000000;
game.addChild(background);
// Initialize tracks and unified target zone
var startX = (gameWidth - numTracks * trackWidth) / 2 + trackWidth / 2;
for (var i = 0; i < numTracks; i++) {
var track = new Track(i);
track.x = startX + i * trackWidth;
track.y = 0;
tracks.push(track);
game.addChild(track);
}
// Create single unified target zone covering all tracks
var unifiedTargetZone = new TargetZone(0);
unifiedTargetZone.x = gameWidth / 2; // Center of screen
unifiedTargetZone.y = 1650; // Move target zone slightly down
// Scale the target zone to cover all tracks
unifiedTargetZone.scale.x = numTracks * trackWidth / 350; // Scale to cover all track widths with new spacing
unifiedTargetZone.scale.y = 1.5; // Expand target zone height by 50%
// Add sharpness filter for better visual clarity
if (unifiedTargetZone.filters) {
unifiedTargetZone.filters = [];
} else {
unifiedTargetZone.filters = [];
}
// Apply contrast and brightness adjustments for sharper appearance
unifiedTargetZone.alpha = 1.0;
targetZones.push(unifiedTargetZone);
// Add unified background covering entire play area
var unifiedBg = LK.getAsset('unifiedBackground', {
anchorX: 0.5,
anchorY: 0
});
unifiedBg.x = gameWidth / 2; // Center horizontally
unifiedBg.y = 0; // Start from top of screen
// Crop background to fit exactly within game area without extending beyond screen
unifiedBg.width = gameWidth; // Fit exactly to game width (2048px)
unifiedBg.height = 2732; // Fit exactly to game height (2732px)
unifiedBg.alpha = 0.8; // Slightly transparent to show game elements clearly
game.addChild(unifiedBg);
// Re-add strip lines and unified target zone to foreground
for (var i = 0; i < numTracks; i++) {
// Add strip line for each track (moved to foreground) - end at target zone
var stripLine = LK.getAsset('stripLine', {
anchorX: 0.5,
anchorY: 0
});
stripLine.x = startX + i * trackWidth;
stripLine.y = 0;
// Set strip line height to end at target zone
stripLine.height = unifiedTargetZone.y + 200 * unifiedTargetZone.scale.y / 2; // End at bottom of target zone
stripLine.alpha = 1.0; // Increase alpha for sharper appearance
// Apply sharpness enhancement
if (stripLine.filters) {
stripLine.filters = [];
} else {
stripLine.filters = [];
}
// Store original position for vibration reset
stripLine.originalX = stripLine.x;
game.addChild(stripLine);
// Store references to strip lines
if (i === 0) leftStripLine = stripLine;else if (i === 1) centerStripLine = stripLine;else if (i === 2) rightStripLine = stripLine;
}
// Add unified target zone to foreground
game.addChild(unifiedTargetZone);
// Create rounded border around unified target zone
var borderThickness = 8;
var targetZoneWidth = 350 * unifiedTargetZone.scale.x;
var targetZoneHeight = 200 * unifiedTargetZone.scale.y; // Use scaled height
// Top border
var topBorder = LK.getAsset('stripLine', {
anchorX: 0.5,
anchorY: 0.5
});
topBorder.width = targetZoneWidth - borderThickness;
topBorder.height = borderThickness;
topBorder.x = unifiedTargetZone.x;
topBorder.y = unifiedTargetZone.y - targetZoneHeight / 2 - borderThickness / 2;
topBorder.alpha = 1.0;
game.addChild(topBorder);
// Bottom border
var bottomBorder = LK.getAsset('stripLine', {
anchorX: 0.5,
anchorY: 0.5
});
bottomBorder.width = targetZoneWidth - borderThickness;
bottomBorder.height = borderThickness;
bottomBorder.x = unifiedTargetZone.x;
bottomBorder.y = unifiedTargetZone.y + targetZoneHeight / 2 + borderThickness / 2;
bottomBorder.alpha = 1.0;
game.addChild(bottomBorder);
// Left border
var leftBorder = LK.getAsset('stripLine', {
anchorX: 0.5,
anchorY: 0.5
});
leftBorder.width = borderThickness;
leftBorder.height = targetZoneHeight - borderThickness;
leftBorder.x = unifiedTargetZone.x - targetZoneWidth / 2 - borderThickness / 2;
leftBorder.y = unifiedTargetZone.y;
leftBorder.alpha = 1.0;
game.addChild(leftBorder);
// Right border
var rightBorder = LK.getAsset('stripLine', {
anchorX: 0.5,
anchorY: 0.5
});
rightBorder.width = borderThickness;
rightBorder.height = targetZoneHeight - borderThickness;
rightBorder.x = unifiedTargetZone.x + targetZoneWidth / 2 + borderThickness / 2;
rightBorder.y = unifiedTargetZone.y;
rightBorder.alpha = 1.0;
game.addChild(rightBorder);
// Add rounded corners with ellipses
// Top-left corner
var topLeftCorner = LK.getAsset('cornerEllipse', {
anchorX: 0.5,
anchorY: 0.5
});
topLeftCorner.x = unifiedTargetZone.x - targetZoneWidth / 2;
topLeftCorner.y = unifiedTargetZone.y - targetZoneHeight / 2;
topLeftCorner.alpha = 1.0;
game.addChild(topLeftCorner);
// Top-right corner
var topRightCorner = LK.getAsset('cornerEllipse', {
anchorX: 0.5,
anchorY: 0.5
});
topRightCorner.x = unifiedTargetZone.x + targetZoneWidth / 2;
topRightCorner.y = unifiedTargetZone.y - targetZoneHeight / 2;
topRightCorner.alpha = 1.0;
game.addChild(topRightCorner);
// Bottom-left corner
var bottomLeftCorner = LK.getAsset('cornerEllipse', {
anchorX: 0.5,
anchorY: 0.5
});
bottomLeftCorner.x = unifiedTargetZone.x - targetZoneWidth / 2;
bottomLeftCorner.y = unifiedTargetZone.y + targetZoneHeight / 2;
bottomLeftCorner.alpha = 1.0;
game.addChild(bottomLeftCorner);
// Bottom-right corner
var bottomRightCorner = LK.getAsset('cornerEllipse', {
anchorX: 0.5,
anchorY: 0.5
});
bottomRightCorner.x = unifiedTargetZone.x + targetZoneWidth / 2;
bottomRightCorner.y = unifiedTargetZone.y + targetZoneHeight / 2;
bottomRightCorner.alpha = 1.0;
game.addChild(bottomRightCorner);
// Rhythm pattern system for music-synchronized note spawning
var rhythmPatterns = {
'bgmusic': [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
// Simple steady 4/4 pattern
'bgmusic2': [1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
// Upbeat syncopated rhythm
'bgmusic3': [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0],
// Fast-paced dense pattern
'bgmusic4': [1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0],
// Varied mixed pattern
'bgmusic5': [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0] // Moderate sparse pattern
};
// Enhanced rhythm synchronization system
var currentBeatIndex = -1;
var beatsPerMinute = {
'bgmusic': 140,
// Adjusted BPM values for better synchronization
'bgmusic2': 150,
'bgmusic3': 160,
'bgmusic4': 145,
'bgmusic5': 135
};
var musicStartFrame = 0;
var beatAccumulator = 0;
var lastSpawnTime = 0;
var framesPerBeat = 0;
var nextBeatFrame = 0;
var rhythmCalibration = {
'bgmusic': 15,
// Frame offset calibration for each track
'bgmusic2': 20,
'bgmusic3': 10,
'bgmusic4': 25,
'bgmusic5': 18
};
// Helper functions
function spawnNote() {
var trackIndex = Math.floor(Math.random() * numTracks);
var isPowerNote = Math.random() < 0.1;
// Add to queue instead of spawning directly
noteQueue.push({
trackIndex: trackIndex,
isPowerNote: isPowerNote,
readyTime: LK.ticks + Math.max(0, lastTargetZoneEntry + minTimeBetweenEntries - LK.ticks)
});
}
function spawnRhythmNote() {
// Only spawn notes if music is playing and we have a rhythm pattern
if (!musicStarted || !currentMusicTrack || !rhythmPatterns[currentMusicTrack]) {
return;
}
// Calculate precise beat timing based on music BPM and elapsed time
var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
framesPerBeat = Math.round(60 * 60 / currentBPM); // 60 FPS * 60 seconds / BPM
var musicElapsedFrames = LK.ticks - musicStartFrame;
var calibrationOffset = rhythmCalibration[currentMusicTrack] || 0;
var adjustedElapsed = musicElapsedFrames - calibrationOffset; // Subtract offset for proper sync
// Check if we've hit the next beat exactly
if (LK.ticks >= nextBeatFrame) {
currentBeatIndex++;
nextBeatFrame = musicStartFrame + Math.round(currentBeatIndex * framesPerBeat) - calibrationOffset;
var pattern = rhythmPatterns[currentMusicTrack];
var shouldSpawn = pattern[currentBeatIndex % pattern.length];
if (shouldSpawn === 1) {
// Better track distribution with more variation
var trackIndex;
if (currentBeatIndex % 4 === 0) {
trackIndex = 1; // Center track on strong beats
} else {
trackIndex = Math.floor(Math.random() * numTracks);
}
var isPowerNote = currentBeatIndex % 8 === 0 ? true : Math.random() < 0.08; // Power notes on measure starts
// Add to queue with precise timing
noteQueue.push({
trackIndex: trackIndex,
isPowerNote: isPowerNote,
readyTime: LK.ticks + Math.max(5, lastTargetZoneEntry + minTimeBetweenEntries - LK.ticks)
});
lastSpawnTime = LK.ticks;
}
}
}
function processNoteQueue() {
for (var i = noteQueue.length - 1; i >= 0; i--) {
var queuedNote = noteQueue[i];
if (LK.ticks >= queuedNote.readyTime) {
// Check if any note is currently in or approaching target zone
var canSpawn = true;
var targetY = 1650;
var spawnY = -50;
var targetZoneBuffer = 250; // Increased buffer zone for expanded target
for (var j = 0; j < notes.length; j++) {
var existingNote = notes[j];
// Check if note is in extended target zone area (larger buffer for safety)
if (Math.abs(existingNote.y - targetY) <= targetZoneBuffer) {
canSpawn = false;
break;
}
// Check if note will reach target zone soon (prediction based on speed)
var timeToTarget = (targetY - existingNote.y) / existingNote.speed;
if (timeToTarget > 0 && timeToTarget <= 50) {
// Within 50 frames of reaching target
canSpawn = false;
break;
}
// Check vertical spacing collision - prevent notes from being too close vertically
if (Math.abs(existingNote.y - spawnY) < minVerticalSpacing) {
canSpawn = false;
break;
}
}
if (canSpawn) {
// Spawn the note
var note = new Note(queuedNote.trackIndex, queuedNote.isPowerNote);
// Position notes exactly on track center lines
var noteX = startX + queuedNote.trackIndex * trackWidth;
note.x = noteX;
note.y = spawnY;
note.speed = 7; // Fixed speed constant - reduced to 7 for gameplay balance
notes.push(note);
game.addChild(note);
lastTargetZoneEntry = LK.ticks;
noteQueue.splice(i, 1);
} else {
// Delay this note by adding minimum time
queuedNote.readyTime = LK.ticks + minTimeBetweenEntries;
}
}
}
}
function updateScore(points) {
score += points;
scoreTxt.setText('Score: ' + score);
LK.setScore(score);
}
function updateLives(change) {
lives += change;
// Update heart display based on current lives
for (var h = 0; h < heartsArray.length; h++) {
if (h < lives) {
heartsArray[h].alpha = 1.0; // Show heart
} else {
heartsArray[h].alpha = 0.3; // Dim heart to show it's lost
}
}
if (lives <= 0) {
LK.showGameOver();
}
}
function createParticleEffect(x, y, color) {
// Create enhanced particle effects with increased count
var totalParticles = 80; // Significantly increased particle count
var primaryParticles = 35;
var secondaryParticles = 25;
var trailParticles = 20;
// Primary burst particles - fast moving with enhanced visuals
for (var i = 0; i < primaryParticles; i++) {
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = x;
particle.y = y;
// Enhanced color with gradient-like effect
var colorVariation = 0x303030 * Math.random();
particle.tint = (color || 0xFFD93D) + colorVariation;
particle.alpha = 0.95 + Math.random() * 0.05;
game.addChild(particle);
// Calculate random direction and speed for each particle
var angle = i / primaryParticles * Math.PI * 2 + (Math.random() - 0.5) * 2.2;
var speed = 800 + Math.random() * 700; // Significantly increased speed range
var targetX = x + Math.cos(angle) * speed;
var targetY = y + Math.sin(angle) * speed;
// Enhanced particle scaling with better proportions
particle.scaleX = 3.5 + Math.random() * 3.0; // Larger particle size for better impact
particle.scaleY = particle.scaleX + (Math.random() - 0.5) * 0.8; // More asymmetry for dynamic feel
// Animate particle flying outward with enhanced effects
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.05,
// Smoother scale transition
scaleY: 0.05,
rotation: (Math.random() - 0.5) * Math.PI * 16 // Increased rotation for more dynamic motion
}, {
duration: 1000 + Math.random() * 800,
// Longer duration for better visual impact
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Secondary slower particles for depth with improved visuals
for (var i = 0; i < secondaryParticles; i++) {
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = x + (Math.random() - 0.5) * 60; // Increased initial spread
particle.y = y + (Math.random() - 0.5) * 60;
// Enhanced secondary particle coloring
var secondaryColor = color || 0xFFD93D;
var brightness = 0.8 + Math.random() * 0.2;
particle.tint = secondaryColor * brightness;
particle.alpha = 0.85 + Math.random() * 0.15;
game.addChild(particle);
var angle = Math.random() * Math.PI * 2;
var speed = 450 + Math.random() * 350; // Increased secondary particle speed
var targetX = x + Math.cos(angle) * speed;
var targetY = y + Math.sin(angle) * speed;
// Enhanced secondary particle scaling
particle.scaleX = 2.5 + Math.random() * 2.0; // Larger secondary particles
particle.scaleY = particle.scaleX * (0.7 + Math.random() * 0.6); // More varied proportions
// Delayed animation for staggered effect with enhanced timing
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
// Smoother scale transition
scaleY: 0.1,
rotation: (Math.random() - 0.5) * Math.PI * 14 // Increased rotation
}, {
duration: 1200 + Math.random() * 1000,
// Longer duration for better visual flow
easing: tween.easeInOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
// Enhanced trail particles that move upward
for (var i = 0; i < trailParticles; i++) {
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = x + (Math.random() - 0.5) * 80; // Increased initial spread
particle.y = y;
// Enhanced trail particle coloring with stronger glow effect
var trailColor = color || 0xFFD93D;
var glowIntensity = 0.9 + Math.random() * 0.1;
particle.tint = trailColor * glowIntensity;
particle.alpha = 0.8 + Math.random() * 0.2;
game.addChild(particle);
// Enhanced trail particle scaling with larger proportions
particle.scaleX = 4.0 + Math.random() * 3.0; // Significantly larger trail particles
particle.scaleY = particle.scaleX * (0.5 + Math.random() * 1.0); // More dramatic shape variations
// Animate upward with enhanced gravity-like effect
tween(particle, {
x: particle.x + (Math.random() - 0.5) * 300,
// Increased horizontal spread
y: y - 500 - Math.random() * 350,
// Significantly enhanced upward movement
alpha: 0,
scaleX: 0.2,
// Smoother scale transition
scaleY: 0.2,
rotation: (Math.random() - 0.5) * Math.PI * 12 // Increased rotation for more dynamic motion
}, {
duration: 1500 + Math.random() * 1200,
// Longer duration for better visual impact
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
function checkNoteInTrack(trackIndex) {
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.trackIndex === trackIndex && !note.hasBeenTapped) {
var timing = note.checkTiming();
if (timing !== 'miss') {
note.hasBeenTapped = true;
var points = 0;
if (timing === 'perfect') {
points = 1;
LK.getSound('perfect').play();
createParticleEffect(note.x, note.y, note.isPowerNote ? 0xFFD93D : 0x00FF00);
} else if (timing === 'good') {
points = 1;
LK.getSound('tap').play();
createParticleEffect(note.x, note.y, 0x87CEEB);
}
updateScore(points);
// Start background music on first successful hit or after music ends
if (!musicStarted) {
currentMusicIndex = 0; // Start with first track for consistency
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStarted = true;
musicStartTime = LK.ticks;
musicStartFrame = LK.ticks; // Track actual start frame for rhythm sync
musicRepeatCount = 0;
// Reset rhythm timing for new music with proper initialization
currentBeatIndex = -1; // Start at -1 so first beat becomes 0
var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
framesPerBeat = Math.round(60 * 60 / currentBPM);
nextBeatFrame = musicStartFrame + framesPerBeat - (rhythmCalibration[currentMusicTrack] || 0);
beatAccumulator = 0; // Reset beat accumulator for precise timing
lastSpawnTime = 0; // Reset last spawn time
} else if (waitingForNoteAfterMusicEnd) {
// Start next music track after previous one ended
currentMusicIndex = (currentMusicIndex + 1) % musicTracks.length;
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStartTime = LK.ticks;
musicStartFrame = LK.ticks; // Track actual start frame for rhythm sync
musicFinished = false;
waitingForNoteAfterMusicEnd = false;
// Reset rhythm timing for new music with proper initialization
currentBeatIndex = -1; // Start at -1 so first beat becomes 0
var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
framesPerBeat = Math.round(60 * 60 / currentBPM);
nextBeatFrame = musicStartFrame + framesPerBeat - (rhythmCalibration[currentMusicTrack] || 0);
beatAccumulator = 0; // Reset beat accumulator for precise timing
lastSpawnTime = 0; // Reset last spawn time
}
unifiedTargetZone.flash();
note.destroy();
notes.splice(i, 1);
return true;
}
}
}
return false;
}
// Touch handlers
game.down = function (x, y, obj) {
for (var i = 0; i < numTracks; i++) {
var trackX = startX + i * trackWidth;
if (x >= trackX - trackWidth / 2 && x <= trackX + trackWidth / 2) {
if (!checkNoteInTrack(i)) {
// Removed miss sound and life reduction for missed taps - only notes escaping target zone should reduce lives and play miss sound
}
break;
}
}
};
// Main game loop
game.update = function () {
// Rhythm-based note spawning when music is playing
if (musicStarted && currentMusicTrack) {
// Use precise music synchronization for rhythm-based spawning
spawnRhythmNote();
} else {
// Fallback to timer-based spawning when no music is playing
noteSpawnTimer++;
if (noteSpawnTimer >= noteSpawnInterval) {
spawnNote();
noteSpawnTimer = 0;
}
}
// Process note queue to ensure no simultaneous target zone entries
processNoteQueue();
// Update difficulty
difficultyTimer++;
if (difficultyTimer >= 1800) {
// Every 30 seconds
gameSpeed += 0.2;
noteSpawnInterval = Math.max(20, noteSpawnInterval - 2);
difficultyTimer = 0;
}
// Update notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
// Check if note passed beyond target zone - let it pass slightly further before removing
var targetY = 1650; // unifiedTargetZone.y
var targetZoneBottom = targetY + 200 * 1.5 / 2; // Bottom of expanded target zone
var disappearY = targetZoneBottom + 100; // Allow note to pass 100px beyond target zone
if (!note.hasBeenTapped && note.lastY <= disappearY && note.y > disappearY) {
note.destroy();
notes.splice(i, 1);
continue;
}
// Remove notes that are off screen
if (note.y > 2800) {
note.destroy();
notes.splice(i, 1);
}
}
// Clean up off-screen particles
var allChildren = game.children.slice(); // Create a copy to avoid modification during iteration
for (var i = allChildren.length - 1; i >= 0; i--) {
var child = allChildren[i];
// Check if this is a particle (has particle-like properties)
if (child && child.x !== undefined && child.y !== undefined && child.width <= 10 && child.height <= 10) {
// Remove particles that are far off-screen or destroyed
if (child.x < -500 || child.x > 2548 || child.y < -500 || child.y > 3232 || child.destroyed) {
if (child.destroy) {
child.destroy();
} else {
game.removeChild(child);
}
}
}
}
// Create continuous particle effects around the three objects
enhanceObjectVisuals();
// Check for music track changes every 60 seconds (1 minute) with fade out
if (musicStarted && LK.ticks % 60 === 0) {
// Check every second
var timeElapsed = (LK.ticks - musicStartTime) / 60; // Convert to seconds since music started
var musicChangeInterval = 60; // 60 seconds (1 minute) per music change
// Start fade out 2 seconds before music ends
if (timeElapsed >= musicChangeInterval - 2 && timeElapsed < musicChangeInterval && !musicFinished) {
// Fade out over 2 seconds
LK.playMusic(currentMusicTrack, {
fade: {
start: 1,
end: 0,
duration: 2000
}
});
}
// Check if current music should have finished
if (timeElapsed >= musicChangeInterval && !musicFinished) {
musicFinished = true;
waitingForNoteAfterMusicEnd = true;
LK.stopMusic(); // Stop current music and wait for note hit
}
}
// Win condition
if (score >= 10000) {
LK.showYouWin();
}
};
// Add 3 objects at bottom of target zone (left, center, right)
var targetBottomY = unifiedTargetZone.y + targetZoneHeight / 2 + 520; // Move objects down very slightly
var objectSpacing = targetZoneWidth / 1.0; // Further increased spacing for better separation between objects
// Left object
leftObject = LK.getAsset('leftObjectAsset', {
anchorX: 0.5,
anchorY: 0.5
});
leftObject.x = unifiedTargetZone.x - objectSpacing;
leftObject.y = targetBottomY;
// Scale up the left object
leftObject.scaleX = 2.5;
leftObject.scaleY = 2.5;
// Animate color change for left object
tween(leftObject, {
tint: 0xFFD700 // Change to gold color
}, {
duration: 1500,
easing: tween.easeInOut
});
leftObject.alpha = 1.0; // Increase alpha for sharper appearance
// Apply sharpness enhancement to left object
if (leftObject.filters) {
leftObject.filters = [];
} else {
leftObject.filters = [];
}
game.addChild(leftObject);
// Center object
centerObject = LK.getAsset('centerObjectAsset', {
anchorX: 0.5,
anchorY: 0.5
});
centerObject.x = unifiedTargetZone.x;
centerObject.y = targetBottomY;
// Scale up the center object
centerObject.scaleX = 2.5;
centerObject.scaleY = 2.5;
// Animate color change for center object
tween(centerObject, {
tint: 0xFF1493 // Change to deep pink color
}, {
duration: 1500,
easing: tween.easeInOut
});
centerObject.alpha = 1.0; // Increase alpha for sharper appearance
// Apply sharpness enhancement to center object
if (centerObject.filters) {
centerObject.filters = [];
} else {
centerObject.filters = [];
}
game.addChild(centerObject);
// Right object
rightObject = LK.getAsset('rightObjectAsset', {
anchorX: 0.5,
anchorY: 0.5
});
rightObject.x = unifiedTargetZone.x + objectSpacing;
rightObject.y = targetBottomY;
// Scale up the right object
rightObject.scaleX = 2.5;
rightObject.scaleY = 2.5;
// Animate color change for right object
tween(rightObject, {
tint: 0x9370DB // Change to medium purple color
}, {
duration: 1500,
easing: tween.easeInOut
});
rightObject.alpha = 1.0; // Increase alpha for sharper appearance
// Apply sharpness enhancement to right object
if (rightObject.filters) {
rightObject.filters = [];
} else {
rightObject.filters = [];
}
game.addChild(rightObject);
// Objects are now properly sized - no extreme scaling needed
// Move objects to topmost layer for better visibility
game.removeChild(leftObject);
game.addChild(leftObject);
game.removeChild(centerObject);
game.addChild(centerObject);
game.removeChild(rightObject);
game.addChild(rightObject);
// Add touch handlers to the 3 bottom objects
leftObject.down = function (x, y, obj) {
// Add guitar string vibration effect to left track strip line
if (leftStripLine) {
// Use stored original position instead of current position
var originalX = leftStripLine.originalX;
var _vibrateString = function vibrateString() {
if (vibrationCount >= maxVibrations) {
// Reset to original position when vibration completes
tween(leftStripLine, {
x: originalX
}, {
duration: 100,
easing: tween.easeOut
});
return;
}
var amplitude = baseAmplitude * (1 - vibrationCount / maxVibrations);
var direction = vibrationCount % 2 === 0 ? 1 : -1;
tween(leftStripLine, {
x: originalX + amplitude * direction
}, {
duration: 40,
easing: tween.easeInOut,
onFinish: function onFinish() {
vibrationCount++;
_vibrateString();
}
});
};
// Guitar string effect - rapid horizontal vibrations that decay
var vibrationCount = 0;
var maxVibrations = 15;
var baseAmplitude = 25;
_vibrateString();
}
// Check for notes in left track (track 0) within target zone
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.trackIndex === 0 && !note.hasBeenTapped) {
var timing = note.checkTiming();
if (timing !== 'miss') {
// Explode the note
note.hasBeenTapped = true;
var points = 0;
if (timing === 'perfect') {
points = 1;
LK.getSound('perfect').play();
createParticleEffect(note.x, note.y, note.isPowerNote ? 0xFFD93D : 0x00FF00);
} else if (timing === 'good') {
points = 1;
LK.getSound('tap').play();
createParticleEffect(note.x, note.y, 0x87CEEB);
}
updateScore(points);
// Start background music on first successful hit or after music ends
if (!musicStarted) {
currentMusicIndex = Math.floor(Math.random() * musicTracks.length);
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStarted = true;
musicStartTime = LK.ticks;
musicRepeatCount = 0;
} else if (waitingForNoteAfterMusicEnd) {
// Start next music track after previous one ended
currentMusicIndex = (currentMusicIndex + 1) % musicTracks.length;
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStartTime = LK.ticks;
musicFinished = false;
waitingForNoteAfterMusicEnd = false;
}
unifiedTargetZone.flash();
// Scale animation for explosion effect
tween(note, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
note.destroy();
for (var j = 0; j < notes.length; j++) {
if (notes[j] === note) {
notes.splice(j, 1);
break;
}
}
}
});
break;
}
}
}
};
centerObject.down = function (x, y, obj) {
// Add guitar string vibration effect to center track strip line
if (centerStripLine) {
// Use stored original position instead of current position
var originalX = centerStripLine.originalX;
var _vibrateString2 = function vibrateString() {
if (vibrationCount >= maxVibrations) {
// Reset to original position when vibration completes
tween(centerStripLine, {
x: originalX
}, {
duration: 100,
easing: tween.easeOut
});
return;
}
var amplitude = baseAmplitude * (1 - vibrationCount / maxVibrations);
var direction = vibrationCount % 2 === 0 ? 1 : -1;
tween(centerStripLine, {
x: originalX + amplitude * direction
}, {
duration: 40,
easing: tween.easeInOut,
onFinish: function onFinish() {
vibrationCount++;
_vibrateString2();
}
});
};
// Guitar string effect - rapid horizontal vibrations that decay
var vibrationCount = 0;
var maxVibrations = 15;
var baseAmplitude = 25;
_vibrateString2();
}
// Check for notes in center track (track 1) within target zone
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.trackIndex === 1 && !note.hasBeenTapped) {
var timing = note.checkTiming();
if (timing !== 'miss') {
// Explode the note
note.hasBeenTapped = true;
var points = 0;
if (timing === 'perfect') {
points = 1;
LK.getSound('perfect').play();
createParticleEffect(note.x, note.y, note.isPowerNote ? 0xFFD93D : 0x00FF00);
} else if (timing === 'good') {
points = 1;
LK.getSound('tap').play();
createParticleEffect(note.x, note.y, 0x87CEEB);
}
updateScore(points);
// Start background music on first successful hit or after music ends
if (!musicStarted) {
currentMusicIndex = Math.floor(Math.random() * musicTracks.length);
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStarted = true;
musicStartTime = LK.ticks;
musicRepeatCount = 0;
} else if (waitingForNoteAfterMusicEnd) {
// Start next music track after previous one ended
currentMusicIndex = (currentMusicIndex + 1) % musicTracks.length;
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStartTime = LK.ticks;
musicFinished = false;
waitingForNoteAfterMusicEnd = false;
}
unifiedTargetZone.flash();
// Scale animation for explosion effect
tween(note, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
note.destroy();
for (var j = 0; j < notes.length; j++) {
if (notes[j] === note) {
notes.splice(j, 1);
break;
}
}
}
});
break;
}
}
}
};
rightObject.down = function (x, y, obj) {
// Add guitar string vibration effect to right track strip line
if (rightStripLine) {
// Use stored original position instead of current position
var originalX = rightStripLine.originalX;
var _vibrateString3 = function vibrateString() {
if (vibrationCount >= maxVibrations) {
// Reset to original position when vibration completes
tween(rightStripLine, {
x: originalX
}, {
duration: 100,
easing: tween.easeOut
});
return;
}
var amplitude = baseAmplitude * (1 - vibrationCount / maxVibrations);
var direction = vibrationCount % 2 === 0 ? 1 : -1;
tween(rightStripLine, {
x: originalX + amplitude * direction
}, {
duration: 40,
easing: tween.easeInOut,
onFinish: function onFinish() {
vibrationCount++;
_vibrateString3();
}
});
};
// Guitar string effect - rapid horizontal vibrations that decay
var vibrationCount = 0;
var maxVibrations = 15;
var baseAmplitude = 25;
_vibrateString3();
}
// Check for notes in right track (track 2) within target zone
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.trackIndex === 2 && !note.hasBeenTapped) {
var timing = note.checkTiming();
if (timing !== 'miss') {
// Explode the note
note.hasBeenTapped = true;
var points = 0;
if (timing === 'perfect') {
points = 1;
LK.getSound('perfect').play();
createParticleEffect(note.x, note.y, note.isPowerNote ? 0xFFD93D : 0x00FF00);
} else if (timing === 'good') {
points = 1;
LK.getSound('tap').play();
createParticleEffect(note.x, note.y, 0x87CEEB);
}
updateScore(points);
// Start background music on first successful hit or after music ends
if (!musicStarted) {
currentMusicIndex = Math.floor(Math.random() * musicTracks.length);
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStarted = true;
musicStartTime = LK.ticks;
musicRepeatCount = 0;
} else if (waitingForNoteAfterMusicEnd) {
// Start next music track after previous one ended
currentMusicIndex = (currentMusicIndex + 1) % musicTracks.length;
currentMusicTrack = musicTracks[currentMusicIndex];
LK.playMusic(currentMusicTrack);
musicStartTime = LK.ticks;
musicFinished = false;
waitingForNoteAfterMusicEnd = false;
}
unifiedTargetZone.flash();
// Scale animation for explosion effect
tween(note, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
note.destroy();
for (var j = 0; j < notes.length; j++) {
if (notes[j] === note) {
notes.splice(j, 1);
break;
}
}
}
});
break;
}
}
}
};
// Music will start when first note is hit
var musicStarted = false;
var musicTracks = ['bgmusic', 'bgmusic2', 'bgmusic3', 'bgmusic4', 'bgmusic5'];
var currentMusicTrack = null;
var musicRepeatCount = 0;
var targetRepeatCount = 3;
var musicStartTime = 0;
var currentMusicIndex = 0;
var musicFinished = false;
var waitingForNoteAfterMusicEnd = false;
// Orbital particle effects removed - variables no longer needed
// Optimized visual effects function
function enhanceObjectVisuals() {
// Orbital particle effects removed
} ===================================================================
--- original.js
+++ change.js
@@ -390,36 +390,39 @@
game.addChild(bottomRightCorner);
// Rhythm pattern system for music-synchronized note spawning
var rhythmPatterns = {
'bgmusic': [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
- // Simple 4/4 pattern
- 'bgmusic2': [1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0],
- // Syncopated rhythm
- 'bgmusic3': [1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1],
- // Dense pattern
- 'bgmusic4': [1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0],
- // Mixed pattern
- 'bgmusic5': [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0] // Sparse pattern
+ // Simple steady 4/4 pattern
+ 'bgmusic2': [1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
+ // Upbeat syncopated rhythm
+ 'bgmusic3': [1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0],
+ // Fast-paced dense pattern
+ 'bgmusic4': [1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0],
+ // Varied mixed pattern
+ 'bgmusic5': [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0] // Moderate sparse pattern
};
// Enhanced rhythm synchronization system
var currentBeatIndex = -1;
var beatsPerMinute = {
- 'bgmusic': 120,
- 'bgmusic2': 128,
- 'bgmusic3': 130,
- 'bgmusic4': 135,
- 'bgmusic5': 125
+ 'bgmusic': 140,
+ // Adjusted BPM values for better synchronization
+ 'bgmusic2': 150,
+ 'bgmusic3': 160,
+ 'bgmusic4': 145,
+ 'bgmusic5': 135
};
var musicStartFrame = 0;
var beatAccumulator = 0;
var lastSpawnTime = 0;
+var framesPerBeat = 0;
+var nextBeatFrame = 0;
var rhythmCalibration = {
- 'bgmusic': 0,
- // Synchronized offset for each track
- 'bgmusic2': 0,
- 'bgmusic3': 0,
- 'bgmusic4': 0,
- 'bgmusic5': 0
+ 'bgmusic': 15,
+ // Frame offset calibration for each track
+ 'bgmusic2': 20,
+ 'bgmusic3': 10,
+ 'bgmusic4': 25,
+ 'bgmusic5': 18
};
// Helper functions
function spawnNote() {
var trackIndex = Math.floor(Math.random() * numTracks);
@@ -436,28 +439,33 @@
if (!musicStarted || !currentMusicTrack || !rhythmPatterns[currentMusicTrack]) {
return;
}
// Calculate precise beat timing based on music BPM and elapsed time
- var currentBPM = beatsPerMinute[currentMusicTrack] || 120;
- var framesPerBeat = Math.round(60 * 60 / currentBPM); // 60 FPS * 60 seconds / BPM
+ var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
+ framesPerBeat = Math.round(60 * 60 / currentBPM); // 60 FPS * 60 seconds / BPM
var musicElapsedFrames = LK.ticks - musicStartFrame;
var calibrationOffset = rhythmCalibration[currentMusicTrack] || 0;
- var adjustedElapsed = musicElapsedFrames + calibrationOffset;
- var newBeatPosition = Math.floor(adjustedElapsed / framesPerBeat);
- // Only spawn if we've moved to a new beat position
- if (newBeatPosition !== currentBeatIndex && newBeatPosition >= 0) {
- currentBeatIndex = newBeatPosition;
+ var adjustedElapsed = musicElapsedFrames - calibrationOffset; // Subtract offset for proper sync
+ // Check if we've hit the next beat exactly
+ if (LK.ticks >= nextBeatFrame) {
+ currentBeatIndex++;
+ nextBeatFrame = musicStartFrame + Math.round(currentBeatIndex * framesPerBeat) - calibrationOffset;
var pattern = rhythmPatterns[currentMusicTrack];
var shouldSpawn = pattern[currentBeatIndex % pattern.length];
if (shouldSpawn === 1) {
- // Better track distribution - cycle through tracks more evenly
- var trackIndex = currentBeatIndex % numTracks;
- var isPowerNote = Math.random() < 0.12; // Balanced chance for power notes
- // Add to queue with better timing
+ // Better track distribution with more variation
+ var trackIndex;
+ if (currentBeatIndex % 4 === 0) {
+ trackIndex = 1; // Center track on strong beats
+ } else {
+ trackIndex = Math.floor(Math.random() * numTracks);
+ }
+ var isPowerNote = currentBeatIndex % 8 === 0 ? true : Math.random() < 0.08; // Power notes on measure starts
+ // Add to queue with precise timing
noteQueue.push({
trackIndex: trackIndex,
isPowerNote: isPowerNote,
- readyTime: LK.ticks + Math.max(10, lastTargetZoneEntry + minTimeBetweenEntries - LK.ticks)
+ readyTime: LK.ticks + Math.max(5, lastTargetZoneEntry + minTimeBetweenEntries - LK.ticks)
});
lastSpawnTime = LK.ticks;
}
}
@@ -677,10 +685,13 @@
musicStarted = true;
musicStartTime = LK.ticks;
musicStartFrame = LK.ticks; // Track actual start frame for rhythm sync
musicRepeatCount = 0;
- // Reset rhythm timing for new music
+ // Reset rhythm timing for new music with proper initialization
currentBeatIndex = -1; // Start at -1 so first beat becomes 0
+ var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
+ framesPerBeat = Math.round(60 * 60 / currentBPM);
+ nextBeatFrame = musicStartFrame + framesPerBeat - (rhythmCalibration[currentMusicTrack] || 0);
beatAccumulator = 0; // Reset beat accumulator for precise timing
lastSpawnTime = 0; // Reset last spawn time
} else if (waitingForNoteAfterMusicEnd) {
// Start next music track after previous one ended
@@ -690,10 +701,13 @@
musicStartTime = LK.ticks;
musicStartFrame = LK.ticks; // Track actual start frame for rhythm sync
musicFinished = false;
waitingForNoteAfterMusicEnd = false;
- // Reset rhythm timing for new music
+ // Reset rhythm timing for new music with proper initialization
currentBeatIndex = -1; // Start at -1 so first beat becomes 0
+ var currentBPM = beatsPerMinute[currentMusicTrack] || 140;
+ framesPerBeat = Math.round(60 * 60 / currentBPM);
+ nextBeatFrame = musicStartFrame + framesPerBeat - (rhythmCalibration[currentMusicTrack] || 0);
beatAccumulator = 0; // Reset beat accumulator for precise timing
lastSpawnTime = 0; // Reset last spawn time
}
unifiedTargetZone.flash();
Gitar gövde kısmı
Do müzik notası
Mavi pastel renkli daire. In-Game asset. 2d. High contrast. No shadows
Kalp. In-Game asset. 2d. High contrast. No shadows
Gitar aksesuarı turuncu pastel renk. In-Game asset. 2d. High contrast. No shadows
Kırmızı pastel renk gitar çalma aksesuarı. In-Game asset. 2d. High contrast. No shadows