Code edit (2 edits merged)
Please save this source code
User prompt
agrega a note un aro externo llamado hit zone separado a unos pixeles de el con una transparencia de 0.6
Code edit (1 edits merged)
Please save this source code
User prompt
agrega a note un aro externo llamado hit zone separado a unos pixeles de el con una transparencia de 0.6
Code edit (3 edits merged)
Please save this source code
User prompt
Crea un objeto llamado note que aparece en alguna posición aleatoria (x,y) de la pantalla
User prompt
Crea un objeto llamado note que aparece en alguna posición aleatoria (x,y) de la pantalla (No agrueges ningun script aun)
Code edit (1 edits merged)
Please save this source code
User prompt
Beat Tapper
Initial prompt
Music Game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Note: All note types use the same asset for now, but can be extended for different shapes/colors.
var Note = Container.expand(function () {
var self = Container.call(this);
// Attach note asset (ellipse shape, color varies by lane)
var noteGraphics = self.attachAsset('note', {
anchorX: 0.5,
anchorY: 0.5
});
// Lane index (0-3)
self.lane = 0;
// Whether this note has been hit or missed
self.hit = false;
// Time (in ticks) when the note should reach the hit zone
self.targetTick = 0;
// For animation (optional)
self.update = function () {
// Notes move down at a constant speed, calculated from their spawn time and target time
// y is updated in the main game loop for precise timing
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181830
});
/****
* Game Code
****/
// --- CONFIGURATION ---
// Number of lanes (columns)
var NUM_LANES = 4;
// Lane colors
var LANE_COLORS = [0xff4b4b, 0x4bafff, 0x4bff7a, 0xffe14b];
// Note color per lane
var NOTE_COLORS = [0xffb3b3, 0xb3d1ff, 0xb3ffd1, 0xfff3b3];
// Lane width (calculated)
var LANE_WIDTH = Math.floor(2048 / NUM_LANES);
// Hit zone Y position (from top)
var HIT_ZONE_Y = 2400;
// Hit window (in px)
var HIT_WINDOW = 120;
// Miss window (in px, below hit zone)
var MISS_WINDOW = 80;
// Note size
var NOTE_SIZE = 180;
// Timing
var TICKS_PER_SECOND = 60;
var SONG_BPM = 120; // beats per minute
var BEAT_INTERVAL = Math.floor(60 / SONG_BPM * TICKS_PER_SECOND); // ticks per beat
// Song length (in beats)
var SONG_BEATS = 64;
// --- ASSETS ---
// Lane backgrounds
for (var i = 0; i < NUM_LANES; i++) {}
// Generic note asset (for class)
// Hit zone
// --- GAME STATE ---
// Notes to be spawned (array of {lane, beat})
var noteChart = [];
// For MVP, generate a simple pattern: every beat, random lane
for (var b = 0; b < SONG_BEATS; b++) {
// For more challenge, sometimes spawn two notes at once
if (b % 8 === 4) {
// Double note
var l1 = Math.floor(Math.random() * NUM_LANES);
var l2 = (l1 + 1 + Math.floor(Math.random() * (NUM_LANES - 1))) % NUM_LANES;
noteChart.push({
lane: l1,
beat: b
});
noteChart.push({
lane: l2,
beat: b
});
} else {
noteChart.push({
lane: Math.floor(Math.random() * NUM_LANES),
beat: b
});
}
}
// Active notes in play
var notes = [];
// For each lane, track the last note hit (for combo)
var laneCombo = [0, 0, 0, 0];
// Score and combo
var score = 0;
var combo = 0;
var maxCombo = 0;
var misses = 0;
var MAX_MISSES = 10;
// --- UI ELEMENTS ---
// Lane backgrounds
var laneNodes = [];
for (var i = 0; i < NUM_LANES; i++) {
var laneNode = LK.getAsset('lane' + i, {
anchorX: 0,
anchorY: 0,
x: i * LANE_WIDTH + 4,
y: 0
});
game.addChild(laneNode);
laneNodes.push(laneNode);
}
// Hit zone (visual guide)
var hitZoneNode = LK.getAsset('hitZone', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: HIT_ZONE_Y
});
hitZoneNode.alpha = 0.08;
game.addChild(hitZoneNode);
// Score text
var scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Combo text
var comboTxt = new Text2('', {
size: 80,
fill: 0xFFE14B
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
// Misses text
var missTxt = new Text2('', {
size: 80,
fill: 0xFF4B4B
});
missTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missTxt);
// --- NOTE SPAWNING ---
// For each note, calculate when to spawn so it reaches hit zone at the right beat
// Notes fall from y = -NOTE_SIZE/2 to HIT_ZONE_Y
var NOTE_TRAVEL_DISTANCE = HIT_ZONE_Y + NOTE_SIZE / 2;
var NOTE_SPEED = 18; // px per tick (tune for feel)
var NOTE_TRAVEL_TICKS = Math.floor(NOTE_TRAVEL_DISTANCE / NOTE_SPEED);
// For each note in chart, add a spawnTick property
for (var i = 0; i < noteChart.length; i++) {
var n = noteChart[i];
n.targetTick = n.beat * BEAT_INTERVAL;
n.spawnTick = n.targetTick - NOTE_TRAVEL_TICKS;
}
// --- GAMEPLAY ---
var currentTick = 0;
var nextNoteIndex = 0;
var songEnded = false;
// --- INPUT HANDLING ---
// For touch, map x to lane
function getLaneFromX(x) {
var lane = Math.floor(x / LANE_WIDTH);
if (lane < 0) lane = 0;
if (lane >= NUM_LANES) lane = NUM_LANES - 1;
return lane;
}
// On tap/click/touch
game.down = function (x, y, obj) {
// Only allow input in the lower part of the screen (where hit zone is)
if (y < HIT_ZONE_Y - HIT_WINDOW * 2) return;
var lane = getLaneFromX(x);
// Find the closest note in this lane within the hit window
var bestNote = null;
var bestDist = HIT_WINDOW;
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
if (note.lane !== lane || note.hit) continue;
var dist = Math.abs(note.y - HIT_ZONE_Y);
if (dist < bestDist) {
bestDist = dist;
bestNote = note;
}
}
if (bestNote) {
// Hit!
bestNote.hit = true;
// Animate note (pop and fade)
tween(bestNote, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 180,
easing: tween.cubicOut,
onFinish: function onFinish() {
bestNote.destroy();
}
});
// Remove from notes array
for (var j = 0; j < notes.length; j++) {
if (notes[j] === bestNote) {
notes.splice(j, 1);
break;
}
}
// Scoring: closer = more points
var accuracy = Math.max(0, 1 - bestDist / HIT_WINDOW);
var points = 100 + Math.floor(accuracy * 100);
score += points;
combo += 1;
if (combo > maxCombo) maxCombo = combo;
scoreTxt.setText('Score: ' + score);
comboTxt.setText('Combo: ' + combo);
missTxt.setText('');
// Flash lane
LK.effects.flashObject(laneNodes[lane], 0xffffff, 120);
} else {
// Miss (tapped but no note)
combo = 0;
misses += 1;
comboTxt.setText('');
missTxt.setText('Miss!');
LK.effects.flashScreen(0xff4b4b, 200);
if (misses >= MAX_MISSES) {
LK.showGameOver();
}
}
};
// --- GAME LOOP ---
game.update = function () {
if (songEnded) return;
// Spawn notes at correct time
while (nextNoteIndex < noteChart.length && noteChart[nextNoteIndex].spawnTick <= currentTick) {
var n = noteChart[nextNoteIndex];
// Create note
var note = new Note();
note.lane = n.lane;
note.targetTick = n.targetTick;
// Use lane-specific color
var noteAsset = note.children[0];
noteAsset.tint = NOTE_COLORS[n.lane];
// Position at top of lane
note.x = n.lane * LANE_WIDTH + LANE_WIDTH / 2;
note.y = -NOTE_SIZE / 2;
note.scaleX = 1;
note.scaleY = 1;
note.alpha = 1;
notes.push(note);
game.addChild(note);
nextNoteIndex++;
}
// Move notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
if (note.hit) continue;
note.y += NOTE_SPEED;
// Check for miss (passed hit zone)
if (note.y > HIT_ZONE_Y + MISS_WINDOW) {
// Missed note
note.hit = true;
combo = 0;
misses += 1;
comboTxt.setText('');
missTxt.setText('Miss!');
LK.effects.flashObject(note, 0xff4b4b, 200);
// Animate fade out
tween(note, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
note.destroy();
}
});
notes.splice(i, 1);
if (misses >= MAX_MISSES) {
LK.showGameOver();
}
}
}
// End of song
if (currentTick > SONG_BEATS * BEAT_INTERVAL + 60 && !songEnded) {
songEnded = true;
// Show win if not too many misses
if (misses < MAX_MISSES) {
LK.setScore(score);
LK.showYouWin();
} else {
LK.showGameOver();
}
}
currentTick++;
};
// --- UI POSITIONING ---
// Position score at top center, combo below it, miss below combo
scoreTxt.x = LK.gui.top.width / 2;
scoreTxt.y = 10;
comboTxt.x = LK.gui.top.width / 2;
comboTxt.y = 120;
missTxt.x = LK.gui.top.width / 2;
missTxt.y = 200;
// --- MUSIC (optional, not implemented in MVP) ---
// (In future: LK.playMusic('song1');) ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,307 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Note: All note types use the same asset for now, but can be extended for different shapes/colors.
+var Note = Container.expand(function () {
+ var self = Container.call(this);
+ // Attach note asset (ellipse shape, color varies by lane)
+ var noteGraphics = self.attachAsset('note', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Lane index (0-3)
+ self.lane = 0;
+ // Whether this note has been hit or missed
+ self.hit = false;
+ // Time (in ticks) when the note should reach the hit zone
+ self.targetTick = 0;
+ // For animation (optional)
+ self.update = function () {
+ // Notes move down at a constant speed, calculated from their spawn time and target time
+ // y is updated in the main game loop for precise timing
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x181830
+});
+
+/****
+* Game Code
+****/
+// --- CONFIGURATION ---
+// Number of lanes (columns)
+var NUM_LANES = 4;
+// Lane colors
+var LANE_COLORS = [0xff4b4b, 0x4bafff, 0x4bff7a, 0xffe14b];
+// Note color per lane
+var NOTE_COLORS = [0xffb3b3, 0xb3d1ff, 0xb3ffd1, 0xfff3b3];
+// Lane width (calculated)
+var LANE_WIDTH = Math.floor(2048 / NUM_LANES);
+// Hit zone Y position (from top)
+var HIT_ZONE_Y = 2400;
+// Hit window (in px)
+var HIT_WINDOW = 120;
+// Miss window (in px, below hit zone)
+var MISS_WINDOW = 80;
+// Note size
+var NOTE_SIZE = 180;
+// Timing
+var TICKS_PER_SECOND = 60;
+var SONG_BPM = 120; // beats per minute
+var BEAT_INTERVAL = Math.floor(60 / SONG_BPM * TICKS_PER_SECOND); // ticks per beat
+// Song length (in beats)
+var SONG_BEATS = 64;
+// --- ASSETS ---
+// Lane backgrounds
+for (var i = 0; i < NUM_LANES; i++) {}
+// Generic note asset (for class)
+// Hit zone
+// --- GAME STATE ---
+// Notes to be spawned (array of {lane, beat})
+var noteChart = [];
+// For MVP, generate a simple pattern: every beat, random lane
+for (var b = 0; b < SONG_BEATS; b++) {
+ // For more challenge, sometimes spawn two notes at once
+ if (b % 8 === 4) {
+ // Double note
+ var l1 = Math.floor(Math.random() * NUM_LANES);
+ var l2 = (l1 + 1 + Math.floor(Math.random() * (NUM_LANES - 1))) % NUM_LANES;
+ noteChart.push({
+ lane: l1,
+ beat: b
+ });
+ noteChart.push({
+ lane: l2,
+ beat: b
+ });
+ } else {
+ noteChart.push({
+ lane: Math.floor(Math.random() * NUM_LANES),
+ beat: b
+ });
+ }
+}
+// Active notes in play
+var notes = [];
+// For each lane, track the last note hit (for combo)
+var laneCombo = [0, 0, 0, 0];
+// Score and combo
+var score = 0;
+var combo = 0;
+var maxCombo = 0;
+var misses = 0;
+var MAX_MISSES = 10;
+// --- UI ELEMENTS ---
+// Lane backgrounds
+var laneNodes = [];
+for (var i = 0; i < NUM_LANES; i++) {
+ var laneNode = LK.getAsset('lane' + i, {
+ anchorX: 0,
+ anchorY: 0,
+ x: i * LANE_WIDTH + 4,
+ y: 0
+ });
+ game.addChild(laneNode);
+ laneNodes.push(laneNode);
+}
+// Hit zone (visual guide)
+var hitZoneNode = LK.getAsset('hitZone', {
+ anchorX: 0,
+ anchorY: 0.5,
+ x: 0,
+ y: HIT_ZONE_Y
+});
+hitZoneNode.alpha = 0.08;
+game.addChild(hitZoneNode);
+// Score text
+var scoreTxt = new Text2('Score: 0', {
+ size: 100,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// Combo text
+var comboTxt = new Text2('', {
+ size: 80,
+ fill: 0xFFE14B
+});
+comboTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(comboTxt);
+// Misses text
+var missTxt = new Text2('', {
+ size: 80,
+ fill: 0xFF4B4B
+});
+missTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(missTxt);
+// --- NOTE SPAWNING ---
+// For each note, calculate when to spawn so it reaches hit zone at the right beat
+// Notes fall from y = -NOTE_SIZE/2 to HIT_ZONE_Y
+var NOTE_TRAVEL_DISTANCE = HIT_ZONE_Y + NOTE_SIZE / 2;
+var NOTE_SPEED = 18; // px per tick (tune for feel)
+var NOTE_TRAVEL_TICKS = Math.floor(NOTE_TRAVEL_DISTANCE / NOTE_SPEED);
+// For each note in chart, add a spawnTick property
+for (var i = 0; i < noteChart.length; i++) {
+ var n = noteChart[i];
+ n.targetTick = n.beat * BEAT_INTERVAL;
+ n.spawnTick = n.targetTick - NOTE_TRAVEL_TICKS;
+}
+// --- GAMEPLAY ---
+var currentTick = 0;
+var nextNoteIndex = 0;
+var songEnded = false;
+// --- INPUT HANDLING ---
+// For touch, map x to lane
+function getLaneFromX(x) {
+ var lane = Math.floor(x / LANE_WIDTH);
+ if (lane < 0) lane = 0;
+ if (lane >= NUM_LANES) lane = NUM_LANES - 1;
+ return lane;
+}
+// On tap/click/touch
+game.down = function (x, y, obj) {
+ // Only allow input in the lower part of the screen (where hit zone is)
+ if (y < HIT_ZONE_Y - HIT_WINDOW * 2) return;
+ var lane = getLaneFromX(x);
+ // Find the closest note in this lane within the hit window
+ var bestNote = null;
+ var bestDist = HIT_WINDOW;
+ for (var i = 0; i < notes.length; i++) {
+ var note = notes[i];
+ if (note.lane !== lane || note.hit) continue;
+ var dist = Math.abs(note.y - HIT_ZONE_Y);
+ if (dist < bestDist) {
+ bestDist = dist;
+ bestNote = note;
+ }
+ }
+ if (bestNote) {
+ // Hit!
+ bestNote.hit = true;
+ // Animate note (pop and fade)
+ tween(bestNote, {
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0
+ }, {
+ duration: 180,
+ easing: tween.cubicOut,
+ onFinish: function onFinish() {
+ bestNote.destroy();
+ }
+ });
+ // Remove from notes array
+ for (var j = 0; j < notes.length; j++) {
+ if (notes[j] === bestNote) {
+ notes.splice(j, 1);
+ break;
+ }
+ }
+ // Scoring: closer = more points
+ var accuracy = Math.max(0, 1 - bestDist / HIT_WINDOW);
+ var points = 100 + Math.floor(accuracy * 100);
+ score += points;
+ combo += 1;
+ if (combo > maxCombo) maxCombo = combo;
+ scoreTxt.setText('Score: ' + score);
+ comboTxt.setText('Combo: ' + combo);
+ missTxt.setText('');
+ // Flash lane
+ LK.effects.flashObject(laneNodes[lane], 0xffffff, 120);
+ } else {
+ // Miss (tapped but no note)
+ combo = 0;
+ misses += 1;
+ comboTxt.setText('');
+ missTxt.setText('Miss!');
+ LK.effects.flashScreen(0xff4b4b, 200);
+ if (misses >= MAX_MISSES) {
+ LK.showGameOver();
+ }
+ }
+};
+// --- GAME LOOP ---
+game.update = function () {
+ if (songEnded) return;
+ // Spawn notes at correct time
+ while (nextNoteIndex < noteChart.length && noteChart[nextNoteIndex].spawnTick <= currentTick) {
+ var n = noteChart[nextNoteIndex];
+ // Create note
+ var note = new Note();
+ note.lane = n.lane;
+ note.targetTick = n.targetTick;
+ // Use lane-specific color
+ var noteAsset = note.children[0];
+ noteAsset.tint = NOTE_COLORS[n.lane];
+ // Position at top of lane
+ note.x = n.lane * LANE_WIDTH + LANE_WIDTH / 2;
+ note.y = -NOTE_SIZE / 2;
+ note.scaleX = 1;
+ note.scaleY = 1;
+ note.alpha = 1;
+ notes.push(note);
+ game.addChild(note);
+ nextNoteIndex++;
+ }
+ // Move notes
+ for (var i = notes.length - 1; i >= 0; i--) {
+ var note = notes[i];
+ if (note.hit) continue;
+ note.y += NOTE_SPEED;
+ // Check for miss (passed hit zone)
+ if (note.y > HIT_ZONE_Y + MISS_WINDOW) {
+ // Missed note
+ note.hit = true;
+ combo = 0;
+ misses += 1;
+ comboTxt.setText('');
+ missTxt.setText('Miss!');
+ LK.effects.flashObject(note, 0xff4b4b, 200);
+ // Animate fade out
+ tween(note, {
+ alpha: 0
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ note.destroy();
+ }
+ });
+ notes.splice(i, 1);
+ if (misses >= MAX_MISSES) {
+ LK.showGameOver();
+ }
+ }
+ }
+ // End of song
+ if (currentTick > SONG_BEATS * BEAT_INTERVAL + 60 && !songEnded) {
+ songEnded = true;
+ // Show win if not too many misses
+ if (misses < MAX_MISSES) {
+ LK.setScore(score);
+ LK.showYouWin();
+ } else {
+ LK.showGameOver();
+ }
+ }
+ currentTick++;
+};
+// --- UI POSITIONING ---
+// Position score at top center, combo below it, miss below combo
+scoreTxt.x = LK.gui.top.width / 2;
+scoreTxt.y = 10;
+comboTxt.x = LK.gui.top.width / 2;
+comboTxt.y = 120;
+missTxt.x = LK.gui.top.width / 2;
+missTxt.y = 200;
+// --- MUSIC (optional, not implemented in MVP) ---
+// (In future: LK.playMusic('song1');)
\ No newline at end of file