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 (7 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 (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
User prompt
Beat Swipe: Rhythm Saber
Initial prompt
Create a 2D rhythm game framework inspired by Beat Saber. Game mechanics: - Notes (circles or shapes) appear far away and grow in size as they "approach" the player, simulating a forward motion toward the screen. - There are 3 types of notes: 1. Tap notes — the player must click exactly when the note reaches maximum size. 2. Swipe notes — the player must perform a quick swipe with the mouse through the note in a given direction (left, right, up, down). 3. Trap notes — these must be avoided entirely. Clicking or swiping them results in a combo break. - Notes appear at specific times and types defined in an array. Controls: - Mouse only. Recognize: - Clicks (onMouseDown + release timing). - Swipes (track onMouseDown → onMouseUp direction and distance). Scoring: - Perfect timing (±0.1 sec) gives max points. - Good timing (±0.3 sec) gives half points. - Missed or incorrect interaction resets combo. - Trap interaction resets combo too. Other features: - Notes scale up as they approach to simulate perspective. - Show combo counter and score. - Simple placeholder graphics and dark background are fine. - Music and visuals will be added manually later. Code structure must clearly separate: - Note spawn logic. - Input detection (click + swipe). - Timing window checks. - Scoring and combo logic. Use simple assets for now (colored shapes). Add comments to explain functions.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Note = Container.expand(function (noteType, swipeDir, targetHitTimeFull, centerXVal) { 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 = centerXVal; 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', { anchorX: 0.5, anchorY: 0.5 }); if (self.swipeDir) { var arrow = new Text2('', { size: 80, 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 currentScale = self.scaleStart + (self.scaleEnd - self.scaleStart) * progress; self.scale.x = Math.max(0.01, currentScale); self.scale.y = Math.max(0.01, currentScale); 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 ****/ var gameScreenWidth = 2048; var playfieldWidth = 1408; // Narrower playfield var playfieldStartX = (gameScreenWidth - playfieldWidth) / 2; // 320 var NUM_COLUMNS = 4; var columnWidth = playfieldWidth / NUM_COLUMNS; // 352 var columnCenterXs = []; for (var i = 0; i < NUM_COLUMNS; i++) { columnCenterXs.push(playfieldStartX + i * columnWidth + columnWidth / 2); } // New columnCenterXs for playfieldWidth = 1408, starting at X = 320: // columnCenterXs[0] = 320 + 176 = 496 // columnCenterXs[1] = 496 + 352 = 848 // columnCenterXs[2] = 848 + 352 = 1200 // columnCenterXs[3] = 1200 + 352 = 1552 var SWIPE_NOTE_WIDTH = 160; var rhythmMap = [{ time: 1000, type: 'tap', columnIndex: 0 }, { time: 1800, type: 'tap', columnIndex: 1 }, { time: 2600, type: 'swipe', swipeDir: 'left', columnIndex: 2 }, { time: 3400, type: 'tap', columnIndex: 3 }, { time: 4200, type: 'swipe', swipeDir: 'right', columnIndex: 0 }, { time: 5000, type: 'trap', columnIndex: 1 }, { time: 5800, type: 'tap', columnIndex: 2 }, { // Wider swipe between new col 1 and col 2 (centers 848 and 1200) // Midpoint is (848 + 1200) / 2 = 1024 time: 6600, type: 'swipe', swipeDir: 'right', partOfWiderSwipe: 'leftHalf', widerSwipePairCenterX: (columnCenterXs[1] + columnCenterXs[2]) / 2 }, { time: 6600, type: 'swipe', swipeDir: 'right', partOfWiderSwipe: 'rightHalf', widerSwipePairCenterX: (columnCenterXs[1] + columnCenterXs[2]) / 2 }, { time: 7400, type: 'tap', columnIndex: 0 }, { time: 8200, type: 'trap', columnIndex: 3 }, { time: 9000, type: 'swipe', swipeDir: 'down', columnIndex: 1 }, { // Wider swipe between new col 0 and col 1 (centers 496 and 848) // Midpoint is (496 + 848) / 2 = 672 time: 9800, type: 'swipe', swipeDir: 'left', partOfWiderSwipe: 'leftHalf', widerSwipePairCenterX: (columnCenterXs[0] + columnCenterXs[1]) / 2 }, { time: 9800, type: 'swipe', swipeDir: 'left', partOfWiderSwipe: 'rightHalf', widerSwipePairCenterX: (columnCenterXs[0] + columnCenterXs[1]) / 2 }, { time: 10600, type: 'tap', columnIndex: 3 }, { time: 11400, type: 'swipe', swipeDir: 'up', columnIndex: 0 }, { time: 12200, type: 'trap', columnIndex: 1 }, { time: 13000, type: 'tap', columnIndex: 2 }]; var noteTravelTime = 1200; var hitWindowPerfect = 120; var hitWindowGood = 260; var MIN_SWIPE_DISTANCE = 60; 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 = gameScreenWidth / 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 = gameScreenWidth / 2; comboTxt.y = 130; LK.gui.top.addChild(comboTxt); var hitZoneY = 1800; var hitZoneVisualWidth = playfieldWidth; // Line width matches the new playfield width var hitZoneLine = LK.getAsset('lineAsset', { anchorX: 0.5, anchorY: 0.5, x: gameScreenWidth / 2, // Centered on the whole screen, but visual width is playfieldWidth y: hitZoneY, width: hitZoneVisualWidth, height: 4, alpha: 0.6 }); 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 targetCenterX; if (noteData.partOfWiderSwipe && noteData.widerSwipePairCenterX !== undefined) { // Ensure the noteAsset (specifically swipeNote) is defined for SWIPE_NOTE_WIDTH // For wider swipes, their visual representation is two standard swipe notes if (noteData.partOfWiderSwipe === 'leftHalf') { targetCenterX = noteData.widerSwipePairCenterX - SWIPE_NOTE_WIDTH / 2; } else if (noteData.partOfWiderSwipe === 'rightHalf') { targetCenterX = noteData.widerSwipePairCenterX + SWIPE_NOTE_WIDTH / 2; } else { targetCenterX = columnCenterXs[noteData.columnIndex !== undefined ? noteData.columnIndex : Math.floor(NUM_COLUMNS / 2)]; } } else if (noteData.columnIndex !== undefined && noteData.columnIndex >= 0 && noteData.columnIndex < NUM_COLUMNS) { targetCenterX = columnCenterXs[noteData.columnIndex]; } else { // Fallback for notes without proper column/widerSwipe info (e.g. old map format) // Place in the center of the new, narrower playfield targetCenterX = playfieldStartX + playfieldWidth / 2; } var n = new Note(noteData.type, noteData.swipeDir, noteTargetHitTime, targetCenterX); 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 currentNoteAsset = n.noteAsset; if (!currentNoteAsset) continue; // Should not happen if note is properly initialized var currentNoteWidth = currentNoteAsset.width * n.scale.x; var currentNoteHeight = currentNoteAsset.height * n.scale.y; // If swipeNote, use SWIPE_NOTE_WIDTH for consistency, as its asset is square if (n.noteType === 'swipe') { currentNoteWidth = SWIPE_NOTE_WIDTH * n.scale.x; currentNoteHeight = SWIPE_NOTE_WIDTH * n.scale.y; } var dx = x - n.x; var dy = y - n.y; 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: 0'); } 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) { LK.effects.flashObject(note, 0xff0000, 300); } }; game.down = function (x, y, obj) { if (inputLocked) { return; } swipeStart = { x: x, y: y, time: Date.now() }; var noteUnderCursor = findNoteAt(x, y, 'trap'); if (noteUnderCursor && !noteUnderCursor.judged && noteUnderCursor.isInHitWindow()) { noteUnderCursor.judged = true; noteUnderCursor.showHitFeedback('miss'); resetCombo(); LK.effects.flashScreen(0xff0000, 400); inputLocked = true; LK.setTimeout(function () { inputLocked = false; }, 200); return; } noteUnderCursor = findNoteAt(x, y, 'tap'); if (noteUnderCursor && !noteUnderCursor.judged && noteUnderCursor.isInHitWindow()) { var result = noteUnderCursor.getHitAccuracy(); noteUnderCursor.judged = true; noteUnderCursor.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 notesHitThisSwipe = []; for (var i = 0; i < notes.length; i++) { var n = notes[i]; if (n.judged || n.noteType !== 'swipe') { continue; } var overallSwipeTimeMatchesNote = false; if (n.targetHitTime >= swipeStart.time - hitWindowGood && n.targetHitTime <= swipeEndTime + hitWindowGood) { overallSwipeTimeMatchesNote = true; } if (!overallSwipeTimeMatchesNote) { continue; } if (n.alpha === 0) continue; var noteCurrentWidth = SWIPE_NOTE_WIDTH * n.scale.x; var noteCurrentHeight = SWIPE_NOTE_WIDTH * 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 (Math.abs(n.y - n.centerY) < noteCurrentHeight / 1.5) { notesHitThisSwipe.push(n); } } } } if (notesHitThisSwipe.length > 0) { notesHitThisSwipe.sort(function (a, b) { var da = Math.abs(swipeEndTime - a.targetHitTime); // Or use n.y proximity to centerY var db = Math.abs(swipeEndTime - b.targetHitTime); return da - db; }); var maxNotesToHitPerSwipe = notesHitThisSwipe.length > 1 && notesHitThisSwipe[0].widerSwipePairCenterX !== undefined ? 2 : 1; // If it's a wider swipe candidate, allow hitting up to 2, otherwise just 1. // This check is a bit simplistic, assumes wider swipe notes are sorted first if both are hit. // A more robust way would be to check if the hit notes form a valid wider swipe pair. var notesActuallyHitCount = 0; for (var k = 0; k < notesHitThisSwipe.length && notesActuallyHitCount < maxNotesToHitPerSwipe; k++) { var noteToJudge = notesHitThisSwipe[k]; if (noteToJudge.judged) continue; var result = noteToJudge.getHitAccuracy(); noteToJudge.judged = true; noteToJudge.showHitFeedback(result); if (result !== 'miss') { addScore(result); addCombo(); } else { resetCombo(); } swipedNoteSuccessfully = true; notesActuallyHitCount++; } } } inputLocked = true; LK.setTimeout(function () { inputLocked = false; }, 80); swipeStart = null; }; game.move = function (x, y, obj) {}; 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
@@ -5,9 +5,8 @@
/****
* Classes
****/
-// Visual width of swipeNote asset
var Note = Container.expand(function (noteType, swipeDir, targetHitTimeFull, centerXVal) {
var self = Container.call(this);
self.noteType = noteType || 'tap';
self.swipeDir = swipeDir || null;
@@ -72,9 +71,8 @@
feedback.tint = 0x00ff00;
} else {
feedback.tint = 0xff0000;
}
- // Ensure feedback is added to the note itself, so its position is relative
self.addChild(feedback);
tween(feedback, {
alpha: 0,
scaleX: 1.5,
@@ -106,9 +104,8 @@
if (progress > 1) {
progress = 1;
}
var currentScale = self.scaleStart + (self.scaleEnd - self.scaleStart) * progress;
- // Ensure scale doesn't go to 0 or negative if times are weird
self.scale.x = Math.max(0.01, currentScale);
self.scale.y = Math.max(0.01, currentScale);
self.x = self.centerX;
self.y = self.startY + (self.centerY - self.startY) * progress;
@@ -148,15 +145,21 @@
/****
* Game Code
****/
var gameScreenWidth = 2048;
+var playfieldWidth = 1408; // Narrower playfield
+var playfieldStartX = (gameScreenWidth - playfieldWidth) / 2; // 320
var NUM_COLUMNS = 4;
-var columnWidth = gameScreenWidth / NUM_COLUMNS; // 512
+var columnWidth = playfieldWidth / NUM_COLUMNS; // 352
var columnCenterXs = [];
for (var i = 0; i < NUM_COLUMNS; i++) {
- columnCenterXs.push(i * columnWidth + columnWidth / 2);
+ columnCenterXs.push(playfieldStartX + i * columnWidth + columnWidth / 2);
}
-// columnCenterXs will be [256, 768, 1280, 1792]
+// New columnCenterXs for playfieldWidth = 1408, starting at X = 320:
+// columnCenterXs[0] = 320 + 176 = 496
+// columnCenterXs[1] = 496 + 352 = 848
+// columnCenterXs[2] = 848 + 352 = 1200
+// columnCenterXs[3] = 1200 + 352 = 1552
var SWIPE_NOTE_WIDTH = 160;
var rhythmMap = [{
time: 1000,
type: 'tap',
@@ -187,9 +190,10 @@
time: 5800,
type: 'tap',
columnIndex: 2
}, {
- // Example of a "wider swipe" (horizontal right)
+ // Wider swipe between new col 1 and col 2 (centers 848 and 1200)
+ // Midpoint is (848 + 1200) / 2 = 1024
time: 6600,
type: 'swipe',
swipeDir: 'right',
partOfWiderSwipe: 'leftHalf',
@@ -213,9 +217,10 @@
type: 'swipe',
swipeDir: 'down',
columnIndex: 1
}, {
- // Example of another "wider swipe" (horizontal left)
+ // Wider swipe between new col 0 and col 1 (centers 496 and 848)
+ // Midpoint is (496 + 848) / 2 = 672
time: 9800,
type: 'swipe',
swipeDir: 'left',
partOfWiderSwipe: 'leftHalf',
@@ -272,15 +277,16 @@
comboTxt.x = gameScreenWidth / 2;
comboTxt.y = 130;
LK.gui.top.addChild(comboTxt);
var hitZoneY = 1800;
-var hitZoneWidth = gameScreenWidth * 0.95;
+var hitZoneVisualWidth = playfieldWidth; // Line width matches the new playfield width
var hitZoneLine = LK.getAsset('lineAsset', {
anchorX: 0.5,
anchorY: 0.5,
x: gameScreenWidth / 2,
+ // Centered on the whole screen, but visual width is playfieldWidth
y: hitZoneY,
- width: hitZoneWidth,
+ width: hitZoneVisualWidth,
height: 4,
alpha: 0.6
});
game.addChild(hitZoneLine);
@@ -288,11 +294,9 @@
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();
- }
+ if (n && n.parent) n.destroy();
});
notes = [];
nextNoteIdx = 0;
score = 0;
@@ -311,20 +315,23 @@
var noteVisualSpawnTime = noteTargetHitTime - noteTravelTime;
if (noteVisualSpawnTime <= now) {
var targetCenterX;
if (noteData.partOfWiderSwipe && noteData.widerSwipePairCenterX !== undefined) {
+ // Ensure the noteAsset (specifically swipeNote) is defined for SWIPE_NOTE_WIDTH
+ // For wider swipes, their visual representation is two standard swipe notes
if (noteData.partOfWiderSwipe === 'leftHalf') {
targetCenterX = noteData.widerSwipePairCenterX - SWIPE_NOTE_WIDTH / 2;
} else if (noteData.partOfWiderSwipe === 'rightHalf') {
targetCenterX = noteData.widerSwipePairCenterX + SWIPE_NOTE_WIDTH / 2;
} else {
- // Fallback if partOfWiderSwipe has unexpected value
targetCenterX = columnCenterXs[noteData.columnIndex !== undefined ? noteData.columnIndex : Math.floor(NUM_COLUMNS / 2)];
}
} else if (noteData.columnIndex !== undefined && noteData.columnIndex >= 0 && noteData.columnIndex < NUM_COLUMNS) {
targetCenterX = columnCenterXs[noteData.columnIndex];
} else {
- targetCenterX = gameScreenWidth / 2; // Fallback for notes without proper column/widerSwipe info
+ // Fallback for notes without proper column/widerSwipe info (e.g. old map format)
+ // Place in the center of the new, narrower playfield
+ targetCenterX = playfieldStartX + playfieldWidth / 2;
}
var n = new Note(noteData.type, noteData.swipeDir, noteTargetHitTime, targetCenterX);
n.alpha = 0;
notes.push(n);
@@ -364,10 +371,17 @@
var timeDiff = Math.abs(now - n.targetHitTime);
if (timeDiff > hitWindowGood) {
continue;
}
- var currentNoteWidth = (n.noteType === 'swipe' ? SWIPE_NOTE_WIDTH : n.noteAsset.width) * n.scale.x;
- var currentNoteHeight = (n.noteType === 'swipe' ? SWIPE_NOTE_WIDTH : n.noteAsset.height) * n.scale.y; // Assuming swipe notes are square
+ var currentNoteAsset = n.noteAsset;
+ if (!currentNoteAsset) continue; // Should not happen if note is properly initialized
+ var currentNoteWidth = currentNoteAsset.width * n.scale.x;
+ var currentNoteHeight = currentNoteAsset.height * n.scale.y;
+ // If swipeNote, use SWIPE_NOTE_WIDTH for consistency, as its asset is square
+ if (n.noteType === 'swipe') {
+ currentNoteWidth = SWIPE_NOTE_WIDTH * n.scale.x;
+ currentNoteHeight = SWIPE_NOTE_WIDTH * n.scale.y;
+ }
var dx = x - n.x;
var dy = y - n.y;
if (Math.abs(dx) <= currentNoteWidth / 2 && Math.abs(dy) <= currentNoteHeight / 2) {
if (timeDiff < smallestTimeDiff) {
@@ -394,9 +408,9 @@
comboTxt.setText('Combo: ' + combo);
}
function resetCombo() {
combo = 0;
- comboTxt.setText('Combo: ' + combo);
+ comboTxt.setText('Combo: 0');
}
function checkGameEnd() {
if (nextNoteIdx >= rhythmMap.length && notes.length === 0) {
LK.setTimeout(function () {
@@ -406,11 +420,9 @@
}, 1000);
}
}
game.onNoteMiss = function (note) {
- if (!note || note.judged) {
- return;
- }
+ if (!note || note.judged) return;
note.judged = true;
note.showHitFeedback('miss');
resetCombo();
if (note.parent) {
@@ -457,9 +469,8 @@
}
};
game.up = function (x, y, obj) {
if (inputLocked || !swipeStart) {
- console.log("Swipe Rejected: Input locked or no swipe start");
swipeStart = null;
return;
}
var swipeEndX = x;
@@ -467,9 +478,8 @@
var swipeEndTime = Date.now();
var dx = swipeEndX - swipeStart.x;
var dy = swipeEndY - swipeStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
- console.log("Swipe End: X=" + swipeEndX + " Y=" + swipeEndY + " Dist=" + dist);
var potentialSwipe = dist >= MIN_SWIPE_DISTANCE;
var swipedNoteSuccessfully = false;
if (potentialSwipe) {
var detectedDir = null;
@@ -477,89 +487,59 @@
detectedDir = dx > 0 ? 'right' : 'left';
} else {
detectedDir = dy > 0 ? 'down' : 'up';
}
- console.log("Potential Swipe Detected. Dir: " + detectedDir);
var swipeBoundingBox = {
x: Math.min(swipeStart.x, swipeEndX),
y: Math.min(swipeStart.y, swipeEndY),
width: Math.abs(dx),
height: Math.abs(dy)
};
- // Safer logging for swipeBoundingBox
- console.log("Swipe BBox: x=" + swipeBoundingBox.x + ", y=" + swipeBoundingBox.y + ", w=" + swipeBoundingBox.width + ", h=" + swipeBoundingBox.height);
var notesHitThisSwipe = [];
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
- // console.log("Checking Note " + i + ": Type=" + n.noteType + " Judged=" + n.judged + " TargetX=" + n.centerX + " TargetY=" + n.centerY + " CurrentY=" + n.y);
if (n.judged || n.noteType !== 'swipe') {
continue;
}
- // console.log("Note " + i + " is a potential swipe target.");
var overallSwipeTimeMatchesNote = false;
- if (swipeStart.time <= n.targetHitTime + hitWindowGood && swipeEndTime >= n.targetHitTime - hitWindowGood) {
+ if (n.targetHitTime >= swipeStart.time - hitWindowGood && n.targetHitTime <= swipeEndTime + hitWindowGood) {
overallSwipeTimeMatchesNote = true;
}
- // This secondary check is redundant if the first one is inclusive enough.
- // if (!overallSwipeTimeMatchesNote) {
- // if (swipeStart.time <= n.targetHitTime + hitWindowGood && swipeEndTime >= n.targetHitTime - hitWindowGood) {
- // overallSwipeTimeMatchesNote = true;
- // }
- // }
- // console.log("Note " + i + " - overallSwipeTimeMatchesNote: " + overallSwipeTimeMatchesNote + " (SwipeStart: " + swipeStart.time + ", SwipeEnd: " + swipeEndTime + ", NoteTarget: " + n.targetHitTime + ", Window: " + hitWindowGood + ")");
if (!overallSwipeTimeMatchesNote) {
- // console.log("Note " + i + " rejected: Swipe time does not match note time window.");
continue;
}
- if (n.alpha === 0) {
- // console.log("Note " + i + " rejected: Note alpha is 0 (not visible/active).");
- continue;
- }
+ if (n.alpha === 0) continue;
var noteCurrentWidth = SWIPE_NOTE_WIDTH * n.scale.x;
var noteCurrentHeight = SWIPE_NOTE_WIDTH * n.scale.y;
var noteBoundingBox = {
x: n.x - noteCurrentWidth / 2,
y: n.y - noteCurrentHeight / 2,
width: noteCurrentWidth,
height: noteCurrentHeight
};
- // console.log("Note " + i + " BBox: x=" + noteBoundingBox.x + ", y=" + noteBoundingBox.y + ", w=" + noteBoundingBox.width + ", h=" + noteBoundingBox.height);
if (rectsIntersect(swipeBoundingBox, noteBoundingBox)) {
- console.log("Note " + i + " INTERSECTS with swipe BBox.");
if (detectedDir === n.swipeDir) {
- console.log("Note " + i + " Direction MATCH. Detected: " + detectedDir + ", Expected: " + n.swipeDir);
- var verticalCheckTolerance = noteCurrentHeight / 1.5; // Height of note plus some tolerance
- // console.log("Note " + i + " Vertical Check: |" + n.y + " - " + n.centerY + "| < " + verticalCheckTolerance + " ? Result: " + (Math.abs(n.y - n.centerY) < verticalCheckTolerance));
- if (Math.abs(n.y - n.centerY) < verticalCheckTolerance) {
- console.log("Note " + i + " PASSED vertical proximity check. Adding to hits.");
+ if (Math.abs(n.y - n.centerY) < noteCurrentHeight / 1.5) {
notesHitThisSwipe.push(n);
- } else {
- // console.log("Note " + i + " FAILED vertical proximity check.");
}
- } else {
- // console.log("Note " + i + " Direction MISMATCH. Detected: " + detectedDir + ", Expected: " + n.swipeDir);
}
- } else {
- // console.log("Note " + i + " does NOT intersect with swipe BBox.");
}
}
if (notesHitThisSwipe.length > 0) {
- console.log("Processing " + notesHitThisSwipe.length + " notes hit by this swipe.");
notesHitThisSwipe.sort(function (a, b) {
- var da = Math.abs(swipeEndTime - a.targetHitTime);
+ var da = Math.abs(swipeEndTime - a.targetHitTime); // Or use n.y proximity to centerY
var db = Math.abs(swipeEndTime - b.targetHitTime);
return da - db;
});
- var maxNotesToHitPerSwipe = 2;
+ var maxNotesToHitPerSwipe = notesHitThisSwipe.length > 1 && notesHitThisSwipe[0].widerSwipePairCenterX !== undefined ? 2 : 1;
+ // If it's a wider swipe candidate, allow hitting up to 2, otherwise just 1.
+ // This check is a bit simplistic, assumes wider swipe notes are sorted first if both are hit.
+ // A more robust way would be to check if the hit notes form a valid wider swipe pair.
var notesActuallyHitCount = 0;
- for (var k = 0; k < notesHitThisSwipe.length && k < maxNotesToHitPerSwipe; k++) {
+ for (var k = 0; k < notesHitThisSwipe.length && notesActuallyHitCount < maxNotesToHitPerSwipe; k++) {
var noteToJudge = notesHitThisSwipe[k];
- if (noteToJudge.judged) {
- // console.log("Note (ID/Ref might be useful here) already judged, skipping.");
- continue;
- }
+ if (noteToJudge.judged) continue;
var result = noteToJudge.getHitAccuracy();
- console.log("Judging Note Hit! Result: " + result);
noteToJudge.judged = true;
noteToJudge.showHitFeedback(result);
if (result !== 'miss') {
addScore(result);
@@ -569,13 +549,9 @@
}
swipedNoteSuccessfully = true;
notesActuallyHitCount++;
}
- } else {
- console.log("No notes were successfully hit by this swipe action.");
}
- } else {
- console.log("Swipe too short or not considered potential.");
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;