User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;' Line Number: 359
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (18 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ggame is not defined' in or related to this line: 'ggame.update = function () {' Line Number: 1468
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'height')' in or related to this line: 'LK.gui.top.add(new Text2('SONG ENDED', {' Line Number: 920
Code edit (11 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'height')' in or related to this line: 'playerHpBarContainer.y = LK.data.height - 80; // Pozycja Y na dole (LK.data.height to wysokość ekranu)' Line Number: 698
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'stringify')' in or related to this line: 'console.log("Swipe BBox:", JSON.stringify(swipeBoundingBox));' Line Number: 497
Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'stringify')' in or related to this line: 'console.log("Swipe BBox:", JSON.stringify(swipeBoundingBox));' Line Number: 497
Code edit (1 edits merged)
Please save this source code
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Graphics is not a constructor' in or related to this line: 'var hitZoneLine = new Graphics();' Line Number: 242
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: LK.getTime is not a function' in or related to this line: 'var now = LK.getTime();' Line Number: 535
User prompt
Please fix the bug: 'LK.getTime is not a function' in or related to this line: 'gameStartTime = LK.getTime();' Line Number: 549
Code edit (1 edits merged)
Please save this source code
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Note = Container.expand(function (noteType, swipeDir, targetHitTimeFull) {
var self = Container.call(this);
self.noteType = noteType || 'tap';
self.swipeDir = swipeDir || null;
self.targetHitTime = targetHitTimeFull;
self.visualSpawnTime = self.targetHitTime - noteTravelTime;
self.hit = false;
self.judged = false;
self.scaleStart = 0.3;
self.scaleEnd = 1.2;
self.centerX = 2048 / 2;
self.centerY = 1800;
self.startY = 600;
self.noteAsset = null;
if (self.noteType === 'tap') {
self.noteAsset = self.attachAsset('tapNote', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.noteType === 'swipe') {
self.noteAsset = self.attachAsset('swipeNote', {
// Will use the square definition
anchorX: 0.5,
anchorY: 0.5
});
if (self.swipeDir) {
var arrow = new Text2('', {
size: 80,
// Arrow size
fill: 0xFFFFFF
});
arrow.anchor.set(0.5, 0.5);
if (self.swipeDir === 'left') {
arrow.setText('←');
} else if (self.swipeDir === 'right') {
arrow.setText('→');
} else if (self.swipeDir === 'up') {
arrow.setText('↑');
} else if (self.swipeDir === 'down') {
arrow.setText('↓');
}
self.addChild(arrow);
self.arrow = arrow;
}
} else if (self.noteType === 'trap') {
self.noteAsset = self.attachAsset('trapNote', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.alpha = 0;
self.showHitFeedback = function (result) {
var feedback = LK.getAsset('hitFeedback', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.7
});
if (result === 'perfect') {
feedback.tint = 0xffff00;
} else if (result === 'good') {
feedback.tint = 0x00ff00;
} else {
feedback.tint = 0xff0000;
}
self.addChild(feedback);
tween(feedback, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
if (feedback.parent) {
feedback.destroy();
}
}
});
};
self.update = function () {
var now = Date.now();
if (now < self.visualSpawnTime) {
self.alpha = 0;
return;
}
if (self.alpha === 0 && !self.judged) {
self.alpha = 1;
}
var elapsedTimeSinceSpawn = now - self.visualSpawnTime;
var progress = elapsedTimeSinceSpawn / noteTravelTime;
if (progress < 0) {
progress = 0;
}
if (progress > 1) {
progress = 1;
}
var scale = self.scaleStart + (self.scaleEnd - self.scaleStart) * progress;
self.scale.x = scale;
self.scale.y = scale;
self.x = self.centerX;
self.y = self.startY + (self.centerY - self.startY) * progress;
if (!self.judged && now > self.targetHitTime + hitWindowGood) {
self.judged = true;
if (self.noteType !== 'trap') {
game.onNoteMiss(self);
}
}
};
self.isInHitWindow = function () {
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
return dt <= hitWindowGood;
};
self.getHitAccuracy = function () {
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
if (dt <= hitWindowPerfect) {
return 'perfect';
}
if (dt <= hitWindowGood) {
return 'good';
}
return 'miss';
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181828
});
/****
* Game Code
****/
// Changed to square
var rhythmMap = [{
time: 1000,
type: 'tap'
}, {
time: 1800,
type: 'tap'
}, {
time: 2600,
type: 'swipe',
swipeDir: 'left'
}, {
time: 3400,
type: 'tap'
}, {
time: 4200,
type: 'swipe',
swipeDir: 'right'
}, {
time: 5000,
type: 'trap'
}, {
time: 5800,
type: 'tap'
}, {
time: 6600,
type: 'swipe',
swipeDir: 'up'
}, {
time: 7400,
type: 'tap'
}, {
time: 8200,
type: 'trap'
}, {
time: 9000,
type: 'swipe',
swipeDir: 'down'
}, {
time: 9800,
type: 'tap'
}, {
time: 10600,
type: 'tap'
}, {
time: 11400,
type: 'swipe',
swipeDir: 'left'
}, {
time: 12200,
type: 'trap'
}, {
time: 13000,
type: 'tap'
}];
var noteTravelTime = 1200;
var hitWindowPerfect = 120;
var hitWindowGood = 260;
var MIN_SWIPE_DISTANCE = 60; // Minimum distance for a swipe to be registered
var notes = [];
var nextNoteIdx = 0;
var gameStartTime = 0;
var score = 0;
var combo = 0;
var maxCombo = 0;
var swipeStart = null;
var inputLocked = false;
var scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.x = 2048 / 2;
scoreTxt.y = 20;
LK.gui.top.addChild(scoreTxt);
var comboTxt = new Text2('Combo: 0', {
size: 80,
fill: 0xFFFF00
});
comboTxt.anchor.set(0.5, 0);
comboTxt.x = 2048 / 2;
comboTxt.y = 130;
LK.gui.top.addChild(comboTxt);
var hitZoneY = 1800; // Matches Note's centerY
// Use a Container and a rectangle asset to visualize the hit zone line
var hitZoneWidth = 400; // Visual width of the hit zone line
var hitZoneLine = new Container();
var hitZoneRect = LK.getAsset('hitZoneRect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
hitZoneLine.addChild(hitZoneRect);
hitZoneLine.x = 2048 / 2;
hitZoneLine.y = hitZoneY;
game.addChild(hitZoneLine);
function rectsIntersect(r1, r2) {
return !(r2.x > r1.x + r1.width || r2.x + r2.width < r1.x || r2.y > r1.y + r1.height || r2.y + r2.height < r1.y);
}
function resetGameState() {
notes.forEach(function (n) {
if (n && n.parent) n.destroy();
});
notes = [];
nextNoteIdx = 0;
score = 0;
combo = 0;
maxCombo = 0;
swipeStart = null;
inputLocked = false;
scoreTxt.setText('Score: 0');
comboTxt.setText('Combo: 0');
}
function spawnNotes() {
var now = Date.now();
while (nextNoteIdx < rhythmMap.length) {
var noteData = rhythmMap[nextNoteIdx];
var noteTargetHitTime = gameStartTime + noteData.time;
var noteVisualSpawnTime = noteTargetHitTime - noteTravelTime;
if (noteVisualSpawnTime <= now) {
var n = new Note(noteData.type, noteData.swipeDir, noteTargetHitTime);
n.x = n.centerX;
n.y = n.startY;
n.scale.x = n.scaleStart;
n.scale.y = n.scaleStart;
n.alpha = 0;
notes.push(n);
game.addChild(n);
nextNoteIdx++;
} else {
break;
}
}
}
function removeOldNotes() {
var now = Date.now();
for (var i = notes.length - 1; i >= 0; i--) {
var n = notes[i];
if (n.judged && now > n.targetHitTime + hitWindowGood + 400) {
if (n.parent) {
n.destroy();
}
notes.splice(i, 1);
} else if (!n.judged && now > n.targetHitTime + noteTravelTime + 500) {
if (n.parent) {
n.destroy();
}
notes.splice(i, 1);
}
}
}
function findNoteAt(x, y, typeToFind) {
var now = Date.now();
var bestNote = null;
var smallestTimeDiff = hitWindowGood + 1;
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
if (n.judged || n.noteType !== typeToFind) {
continue;
}
var timeDiff = Math.abs(now - n.targetHitTime);
if (timeDiff > hitWindowGood) {
continue;
}
var currentNoteWidth = n.noteAsset.width * n.scale.x;
var currentNoteHeight = n.noteAsset.height * n.scale.y;
var dx = x - n.x; // Distance from input to note's center
var dy = y - n.y;
// Check for point within note's bounding box
if (Math.abs(dx) <= currentNoteWidth / 2 && Math.abs(dy) <= currentNoteHeight / 2) {
if (timeDiff < smallestTimeDiff) {
bestNote = n;
smallestTimeDiff = timeDiff;
}
}
}
return bestNote;
}
function addScore(result) {
if (result === 'perfect') {
score += 100;
} else if (result === 'good') {
score += 50;
}
scoreTxt.setText('Score: ' + score);
}
function addCombo() {
combo += 1;
if (combo > maxCombo) {
maxCombo = combo;
}
comboTxt.setText('Combo: ' + combo);
}
function resetCombo() {
combo = 0;
comboTxt.setText('Combo: ' + combo);
}
function checkGameEnd() {
if (nextNoteIdx >= rhythmMap.length && notes.length === 0) {
LK.setTimeout(function () {
if (nextNoteIdx >= rhythmMap.length && notes.length === 0) {
LK.showYouWin();
}
}, 1000);
}
}
game.onNoteMiss = function (note) {
if (!note || note.judged) return;
note.judged = true;
note.showHitFeedback('miss');
resetCombo();
if (note.parent) {
// Check if note still exists before flashing
LK.effects.flashObject(note, 0xff0000, 300);
}
};
game.down = function (x, y, obj) {
if (inputLocked) {
return;
}
swipeStart = {
x: x,
y: y,
time: Date.now()
};
var trap = findNoteAt(x, y, 'trap');
if (trap && !trap.judged && trap.isInHitWindow()) {
trap.judged = true;
trap.showHitFeedback('miss');
resetCombo();
LK.effects.flashScreen(0xff0000, 400);
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 200);
return;
}
var tap = findNoteAt(x, y, 'tap');
if (tap && !tap.judged && tap.isInHitWindow()) {
var result = tap.getHitAccuracy();
tap.judged = true;
tap.showHitFeedback(result);
if (result !== 'miss') {
addScore(result);
addCombo();
} else {
resetCombo();
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 120);
return;
}
};
game.up = function (x, y, obj) {
if (inputLocked || !swipeStart) {
swipeStart = null;
return;
}
var swipeEndX = x;
var swipeEndY = y;
var swipeEndTime = Date.now();
var dx = swipeEndX - swipeStart.x;
var dy = swipeEndY - swipeStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var potentialSwipe = dist >= MIN_SWIPE_DISTANCE;
var swipedNoteSuccessfully = false;
if (potentialSwipe) {
var detectedDir = null;
if (Math.abs(dx) > Math.abs(dy)) {
detectedDir = dx > 0 ? 'right' : 'left';
} else {
detectedDir = dy > 0 ? 'down' : 'up';
}
var swipeBoundingBox = {
x: Math.min(swipeStart.x, swipeEndX),
y: Math.min(swipeStart.y, swipeEndY),
width: Math.abs(dx),
height: Math.abs(dy)
};
var bestSwipedNote = null;
var bestSwipedNoteTimeDiff = hitWindowGood + 1;
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
if (n.judged || n.noteType !== 'swipe') {
continue;
}
// Check if the swipe *action time* is within the note's hit window
var timeDiffWithSwipeEnd = Math.abs(swipeEndTime - n.targetHitTime);
if (timeDiffWithSwipeEnd > hitWindowGood) {
// Check also with swipe start time for very fast notes / slow swipes
var timeDiffWithSwipeStart = Math.abs(swipeStart.time - n.targetHitTime);
if (timeDiffWithSwipeStart > hitWindowGood && (swipeStart.time > n.targetHitTime + hitWindowGood || swipeEndTime < n.targetHitTime - hitWindowGood)) {
continue;
}
}
// Check if the note itself is visually near the hit line at the moment of swipe evaluation
// This can be tricky because the note is moving. We rely more on its targetHitTime.
// However, we should only consider notes that are "active" (alpha=1)
if (n.alpha === 0) continue;
var noteCurrentWidth = n.noteAsset.width * n.scale.x;
var noteCurrentHeight = n.noteAsset.height * n.scale.y;
var noteBoundingBox = {
x: n.x - noteCurrentWidth / 2,
y: n.y - noteCurrentHeight / 2,
width: noteCurrentWidth,
height: noteCurrentHeight
};
if (rectsIntersect(swipeBoundingBox, noteBoundingBox)) {
if (detectedDir === n.swipeDir) {
// If multiple notes intersect, prefer the one closest to its targetHitTime
var currentNoteTimeDiff = Math.abs(swipeEndTime - n.targetHitTime); // Or average swipe time
if (bestSwipedNote === null || currentNoteTimeDiff < bestSwipedNoteTimeDiff) {
bestSwipedNote = n;
bestSwipedNoteTimeDiff = currentNoteTimeDiff;
}
}
}
}
if (bestSwipedNote) {
var noteToJudge = bestSwipedNote;
var result = noteToJudge.getHitAccuracy(); // Uses note's targetHitTime vs now (swipeEndTime)
noteToJudge.judged = true;
noteToJudge.showHitFeedback(result);
if (result !== 'miss') {
addScore(result);
addCombo();
} else {
resetCombo();
}
swipedNoteSuccessfully = true;
}
}
if (potentialSwipe && !swipedNoteSuccessfully) {
// Optional: If it was a swipe but didn't hit anything relevant,
// one might still want to reset combo if that's the desired game feel.
// For now, only a judged miss on a note resets combo.
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 120); // Short lock to prevent accidental double inputs from one action
swipeStart = null;
};
game.move = function (x, y, obj) {
// Not used for now
};
game.update = function () {
spawnNotes();
for (var i = 0; i < notes.length; i++) {
if (notes[i] && notes[i].update) {
notes[i].update();
}
}
removeOldNotes();
checkGameEnd();
};
resetGameState();
gameStartTime = Date.now(); ===================================================================
--- original.js
+++ change.js
@@ -26,14 +26,16 @@
anchorY: 0.5
});
} else if (self.noteType === 'swipe') {
self.noteAsset = self.attachAsset('swipeNote', {
+ // Will use the square definition
anchorX: 0.5,
anchorY: 0.5
});
if (self.swipeDir) {
var arrow = new Text2('', {
size: 80,
+ // Arrow size
fill: 0xFFFFFF
});
arrow.anchor.set(0.5, 0.5);
if (self.swipeDir === 'left') {
@@ -53,9 +55,9 @@
anchorX: 0.5,
anchorY: 0.5
});
}
- self.alpha = 0; // Initially invisible, will become visible when it's time
+ self.alpha = 0;
self.showHitFeedback = function (result) {
var feedback = LK.getAsset('hitFeedback', {
anchorX: 0.5,
anchorY: 0.5,
@@ -89,13 +91,12 @@
};
self.update = function () {
var now = Date.now();
if (now < self.visualSpawnTime) {
- self.alpha = 0; // Ensure it's invisible before visual spawn time
+ self.alpha = 0;
return;
}
- if (self.alpha === 0) {
- // First time it becomes visible
+ if (self.alpha === 0 && !self.judged) {
self.alpha = 1;
}
var elapsedTimeSinceSpawn = now - self.visualSpawnTime;
var progress = elapsedTimeSinceSpawn / noteTravelTime;
@@ -113,10 +114,8 @@
if (!self.judged && now > self.targetHitTime + hitWindowGood) {
self.judged = true;
if (self.noteType !== 'trap') {
game.onNoteMiss(self);
- } else {
- // Trap notes just disappear if not hit, no miss penalty unless clicked
}
}
};
self.isInHitWindow = function () {
@@ -147,8 +146,9 @@
/****
* Game Code
****/
+// Changed to square
var rhythmMap = [{
time: 1000,
type: 'tap'
}, {
@@ -204,8 +204,9 @@
}];
var noteTravelTime = 1200;
var hitWindowPerfect = 120;
var hitWindowGood = 260;
+var MIN_SWIPE_DISTANCE = 60; // Minimum distance for a swipe to be registered
var notes = [];
var nextNoteIdx = 0;
var gameStartTime = 0;
var score = 0;
@@ -228,8 +229,24 @@
comboTxt.anchor.set(0.5, 0);
comboTxt.x = 2048 / 2;
comboTxt.y = 130;
LK.gui.top.addChild(comboTxt);
+var hitZoneY = 1800; // Matches Note's centerY
+// Use a Container and a rectangle asset to visualize the hit zone line
+var hitZoneWidth = 400; // Visual width of the hit zone line
+var hitZoneLine = new Container();
+var hitZoneRect = LK.getAsset('hitZoneRect', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+});
+hitZoneLine.addChild(hitZoneRect);
+hitZoneLine.x = 2048 / 2;
+hitZoneLine.y = hitZoneY;
+game.addChild(hitZoneLine);
+function rectsIntersect(r1, r2) {
+ return !(r2.x > r1.x + r1.width || r2.x + r2.width < r1.x || r2.y > r1.y + r1.height || r2.y + r2.height < r1.y);
+}
function resetGameState() {
notes.forEach(function (n) {
if (n && n.parent) n.destroy();
});
@@ -254,9 +271,9 @@
n.x = n.centerX;
n.y = n.startY;
n.scale.x = n.scaleStart;
n.scale.y = n.scaleStart;
- n.alpha = 0; // Will be set to 1 in its own update when it's time
+ n.alpha = 0;
notes.push(n);
game.addChild(n);
nextNoteIdx++;
} else {
@@ -273,9 +290,8 @@
n.destroy();
}
notes.splice(i, 1);
} else if (!n.judged && now > n.targetHitTime + noteTravelTime + 500) {
- // Failsafe for notes that somehow weren't judged
if (n.parent) {
n.destroy();
}
notes.splice(i, 1);
@@ -294,27 +310,18 @@
var timeDiff = Math.abs(now - n.targetHitTime);
if (timeDiff > hitWindowGood) {
continue;
}
- var dx = x - n.x;
+ var currentNoteWidth = n.noteAsset.width * n.scale.x;
+ var currentNoteHeight = n.noteAsset.height * n.scale.y;
+ var dx = x - n.x; // Distance from input to note's center
var dy = y - n.y;
- var noteRadiusOrWidth = n.noteAsset.width * n.scale.x / 2;
- var noteHeight = n.noteAsset.height * n.scale.y / 2;
- if (typeToFind === 'swipe') {
- if (dx >= -noteRadiusOrWidth && dx <= noteRadiusOrWidth && dy >= -noteHeight && dy <= noteHeight) {
- if (timeDiff < smallestTimeDiff) {
- bestNote = n;
- smallestTimeDiff = timeDiff;
- }
+ // Check for point within note's bounding box
+ if (Math.abs(dx) <= currentNoteWidth / 2 && Math.abs(dy) <= currentNoteHeight / 2) {
+ if (timeDiff < smallestTimeDiff) {
+ bestNote = n;
+ smallestTimeDiff = timeDiff;
}
- } else {
- // tap or trap
- if (dx * dx + dy * dy <= noteRadiusOrWidth * noteRadiusOrWidth) {
- if (timeDiff < smallestTimeDiff) {
- bestNote = n;
- smallestTimeDiff = timeDiff;
- }
- }
}
}
return bestNote;
}
@@ -334,37 +341,37 @@
comboTxt.setText('Combo: ' + combo);
}
function resetCombo() {
combo = 0;
- comboTxt.setText('Combo: 0');
+ comboTxt.setText('Combo: ' + combo);
}
function checkGameEnd() {
if (nextNoteIdx >= rhythmMap.length && notes.length === 0) {
- // A small delay before showing "You Win" to let last feedback animations play
LK.setTimeout(function () {
if (nextNoteIdx >= rhythmMap.length && notes.length === 0) {
- // Double check in case of quick restart
LK.showYouWin();
}
}, 1000);
}
}
game.onNoteMiss = function (note) {
- if (note.judged) return; // Already handled
+ if (!note || note.judged) return;
note.judged = true;
note.showHitFeedback('miss');
resetCombo();
- LK.effects.flashObject(note, 0xff0000, 300);
+ if (note.parent) {
+ // Check if note still exists before flashing
+ LK.effects.flashObject(note, 0xff0000, 300);
+ }
};
game.down = function (x, y, obj) {
if (inputLocked) {
return;
}
swipeStart = {
x: x,
y: y,
- time: Date.now(),
- note: null
+ time: Date.now()
};
var trap = findNoteAt(x, y, 'trap');
if (trap && !trap.judged && trap.isInHitWindow()) {
trap.judged = true;
@@ -393,74 +400,106 @@
inputLocked = false;
}, 120);
return;
}
- // For swipe, we only record the start here if it's over a swipe note.
- // The actual swipe action is judged on game.up
- var swipeNoteUnderCursor = findNoteAt(x, y, 'swipe');
- if (swipeNoteUnderCursor && !swipeNoteUnderCursor.judged && swipeNoteUnderCursor.isInHitWindow()) {
- swipeStart.note = swipeNoteUnderCursor;
- }
};
game.up = function (x, y, obj) {
if (inputLocked || !swipeStart) {
swipeStart = null;
return;
}
- var noteToJudge = swipeStart.note;
- if (!noteToJudge || noteToJudge.judged || noteToJudge.noteType !== 'swipe') {
- swipeStart = null;
- return;
- }
- // Only judge if the swipe ended within a reasonable time window of the note's target time
- if (!noteToJudge.isInHitWindow()) {
- // swipeStart = null; // Optional: could also mark as miss if swipe was too late/early
- return;
- }
- var dx = x - swipeStart.x;
- var dy = y - swipeStart.y;
+ var swipeEndX = x;
+ var swipeEndY = y;
+ var swipeEndTime = Date.now();
+ var dx = swipeEndX - swipeStart.x;
+ var dy = swipeEndY - swipeStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
- if (dist < 80) {
- swipeStart = null;
- return;
- }
- var detectedDir = null;
- if (Math.abs(dx) > Math.abs(dy)) {
- detectedDir = dx > 0 ? 'right' : 'left';
- } else {
- detectedDir = dy > 0 ? 'down' : 'up';
- }
- if (detectedDir === noteToJudge.swipeDir) {
- var result = noteToJudge.getHitAccuracy();
- noteToJudge.judged = true;
- noteToJudge.showHitFeedback(result);
- if (result !== 'miss') {
- addScore(result);
- addCombo();
+ var potentialSwipe = dist >= MIN_SWIPE_DISTANCE;
+ var swipedNoteSuccessfully = false;
+ if (potentialSwipe) {
+ var detectedDir = null;
+ if (Math.abs(dx) > Math.abs(dy)) {
+ detectedDir = dx > 0 ? 'right' : 'left';
} else {
- resetCombo();
+ detectedDir = dy > 0 ? 'down' : 'up';
}
- } else {
- noteToJudge.judged = true;
- noteToJudge.showHitFeedback('miss');
- resetCombo();
- LK.effects.flashObject(noteToJudge, 0xff0000, 300);
+ var swipeBoundingBox = {
+ x: Math.min(swipeStart.x, swipeEndX),
+ y: Math.min(swipeStart.y, swipeEndY),
+ width: Math.abs(dx),
+ height: Math.abs(dy)
+ };
+ var bestSwipedNote = null;
+ var bestSwipedNoteTimeDiff = hitWindowGood + 1;
+ for (var i = 0; i < notes.length; i++) {
+ var n = notes[i];
+ if (n.judged || n.noteType !== 'swipe') {
+ continue;
+ }
+ // Check if the swipe *action time* is within the note's hit window
+ var timeDiffWithSwipeEnd = Math.abs(swipeEndTime - n.targetHitTime);
+ if (timeDiffWithSwipeEnd > hitWindowGood) {
+ // Check also with swipe start time for very fast notes / slow swipes
+ var timeDiffWithSwipeStart = Math.abs(swipeStart.time - n.targetHitTime);
+ if (timeDiffWithSwipeStart > hitWindowGood && (swipeStart.time > n.targetHitTime + hitWindowGood || swipeEndTime < n.targetHitTime - hitWindowGood)) {
+ continue;
+ }
+ }
+ // Check if the note itself is visually near the hit line at the moment of swipe evaluation
+ // This can be tricky because the note is moving. We rely more on its targetHitTime.
+ // However, we should only consider notes that are "active" (alpha=1)
+ if (n.alpha === 0) continue;
+ var noteCurrentWidth = n.noteAsset.width * n.scale.x;
+ var noteCurrentHeight = n.noteAsset.height * n.scale.y;
+ var noteBoundingBox = {
+ x: n.x - noteCurrentWidth / 2,
+ y: n.y - noteCurrentHeight / 2,
+ width: noteCurrentWidth,
+ height: noteCurrentHeight
+ };
+ if (rectsIntersect(swipeBoundingBox, noteBoundingBox)) {
+ if (detectedDir === n.swipeDir) {
+ // If multiple notes intersect, prefer the one closest to its targetHitTime
+ var currentNoteTimeDiff = Math.abs(swipeEndTime - n.targetHitTime); // Or average swipe time
+ if (bestSwipedNote === null || currentNoteTimeDiff < bestSwipedNoteTimeDiff) {
+ bestSwipedNote = n;
+ bestSwipedNoteTimeDiff = currentNoteTimeDiff;
+ }
+ }
+ }
+ }
+ if (bestSwipedNote) {
+ var noteToJudge = bestSwipedNote;
+ var result = noteToJudge.getHitAccuracy(); // Uses note's targetHitTime vs now (swipeEndTime)
+ noteToJudge.judged = true;
+ noteToJudge.showHitFeedback(result);
+ if (result !== 'miss') {
+ addScore(result);
+ addCombo();
+ } else {
+ resetCombo();
+ }
+ swipedNoteSuccessfully = true;
+ }
}
+ if (potentialSwipe && !swipedNoteSuccessfully) {
+ // Optional: If it was a swipe but didn't hit anything relevant,
+ // one might still want to reset combo if that's the desired game feel.
+ // For now, only a judged miss on a note resets combo.
+ }
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
- }, 120);
+ }, 120); // Short lock to prevent accidental double inputs from one action
swipeStart = null;
};
game.move = function (x, y, obj) {
- // Potential drag handling for future, or for a different type of note
+ // Not used for now
};
game.update = function () {
- var now = Date.now();
spawnNotes();
for (var i = 0; i < notes.length; i++) {
- if (notes[i]) {
- // Check if note still exists
+ if (notes[i] && notes[i].update) {
notes[i].update();
}
}
removeOldNotes();