User prompt
Can we make it infinite and have different speeds so 0.5x 1x and 2x
User prompt
Get rid of the color thing make it so you don’t need to change color
User prompt
Can we make it so we tap on one of the rectangles where the circles come down and you move to that one
User prompt
I don’t see any buttons so plz fix
Code edit (1 edits merged)
Please save this source code
User prompt
Cat Rhythm Color Dash
Initial prompt
A 2D rhythm game with cats featuring color matching. Also add 4 buttons for forward backward left right with arrows as an icon and you use those for movement. Also make sure that the buttons are visible.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Arrow Button class var ArrowButton = Container.expand(function () { var self = Container.call(this); self.direction = 'left'; // 'left', 'right', 'up', 'down' self.arrowAsset = null; self.setDirection = function (dir) { self.direction = dir; if (self.arrowAsset) { self.removeChild(self.arrowAsset); } var assetId = 'arrow_' + dir; self.arrowAsset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Add a simple arrow "icon" using Text2 var arrowChar = { 'left': '←', 'right': '→', 'up': '↑', 'down': '↓' }[dir]; if (self.arrowText) { self.removeChild(self.arrowText); } self.arrowText = new Text2(arrowChar, { size: 120, fill: 0x222222 }); self.arrowText.anchor.set(0.5, 0.5); self.addChild(self.arrowText); }; return self; }); // Cat class var Cat = Container.expand(function () { var self = Container.call(this); self.lane = 1; // start in lane 1 (from 0-3) self.catAsset = self.attachAsset('cat', { anchorX: 0.5, anchorY: 0.5 }); self.setLane = function (lane) { self.lane = lane; self.x = laneCenters[lane]; }; return self; }); // Note class var Note = Container.expand(function () { var self = Container.call(this); self.color = 'red'; // default, will be set on spawn self.lane = 0; // 0-3 self.hit = false; self.setColor = function (color) { self.color = color; if (self.noteAsset) { self.removeChild(self.noteAsset); } var assetId = 'note_' + color; self.noteAsset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; self.update = function () { self.y += noteSpeed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Music (looping, for rhythm) // Sound effects // Arrow buttons // Lane backgrounds (for visual feedback) // Note shapes: four colors // Cat character: cute box, default color yellow // Lane setup var laneCount = 4; var laneWidth = 400; var laneSpacing = 32; var laneColors = ['red', 'blue', 'green', 'yellow']; var laneCenters = []; var laneLeft = (2048 - (laneCount * laneWidth + (laneCount - 1) * laneSpacing)) / 2; for (var i = 0; i < laneCount; i++) { laneCenters[i] = laneLeft + i * (laneWidth + laneSpacing) + laneWidth / 2; } // Lane backgrounds var laneBGs = []; for (var i = 0; i < laneCount; i++) { var assetId = 'lane_' + laneColors[i]; var laneBG = LK.getAsset(assetId, { anchorX: 0.5, anchorY: 0, x: laneCenters[i], y: 0, width: laneWidth, height: 2732 }); laneBG.interactive = true; laneBG.buttonMode = true; laneBG.laneIndex = i; laneBG.down = function (x, y, obj) { // Move cat to this lane if not already there if (cat.lane !== this.laneIndex) { cat.setLane(this.laneIndex); } }; game.addChild(laneBG); laneBGs.push(laneBG); } // Cat setup var cat = new Cat(); cat.setLane(1); cat.y = 2732 - 350; game.addChild(cat); // Arrow buttons (bottom of screen, left/right/up/down) var arrowButtons = []; var arrowButtonSize = 180; var arrowButtonY = 2732 - 120; var arrowButtonSpacing = 220; var arrowButtonXStart = 2048 / 2 - arrowButtonSpacing * 1.5; var arrowDirs = ['left', 'right', 'up', 'down']; for (var i = 0; i < 4; i++) { var btn = new ArrowButton(); btn.setDirection(arrowDirs[i]); btn.x = arrowButtonXStart + i * arrowButtonSpacing; btn.y = arrowButtonY; btn.direction = arrowDirs[i]; btn.interactive = true; btn.buttonMode = true; game.addChild(btn); // Place arrow buttons in the main game area so they are always visible arrowButtons.push(btn); } // Color change buttons removed (no longer needed) // Score display var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Combo display var comboTxt = new Text2('', { size: 80, fill: 0xFFE066 }); comboTxt.anchor.set(0.5, 0); comboTxt.y = 130; LK.gui.top.addChild(comboTxt); // Speed selection buttons var speedOptions = [{ label: "0.5x", speed: 0.5, interval: 72 }, { label: "1x", speed: 1, interval: 36 }, { label: "2x", speed: 2, interval: 18 }]; var speedBtnY = 320; var speedBtnSpacing = 320; var speedBtnXStart = 2048 / 2 - speedBtnSpacing; var speedBtns = []; var selectedSpeedIdx = 1; // default 1x function setGameSpeed(idx) { selectedSpeedIdx = idx; for (var i = 0; i < speedBtns.length; i++) { speedBtns[i].alpha = i === idx ? 1 : 0.5; } noteSpeed = 18 * speedOptions[idx].speed; noteSpawnInterval = speedOptions[idx].interval; } for (var i = 0; i < speedOptions.length; i++) { var btn = new Container(); var bg = LK.getAsset('arrow_up', { anchorX: 0.5, anchorY: 0.5 }); bg.width = 220; bg.height = 120; btn.addChild(bg); var txt = new Text2(speedOptions[i].label, { size: 60, fill: "#222" }); txt.anchor.set(0.5, 0.5); btn.addChild(txt); btn.x = speedBtnXStart + i * speedBtnSpacing; btn.y = speedBtnY; btn.interactive = true; btn.buttonMode = true; (function (idx) { btn.down = function (x, y, obj) { setGameSpeed(idx); }; })(i); btn.alpha = i === selectedSpeedIdx ? 1 : 0.5; game.addChild(btn); speedBtns.push(btn); } setGameSpeed(selectedSpeedIdx); // Notes array var notes = []; var noteSpeed = 18; // will be set by speed selection var noteSpawnInterval = 36; // will be set by speed selection var noteTimer = 0; var noteColors = ['red', 'blue', 'green', 'yellow']; // Rhythm pattern (random for now, can be improved) function spawnNote() { var lane = Math.floor(Math.random() * 4); var color = noteColors[Math.floor(Math.random() * 4)]; var note = new Note(); note.setColor(color); note.lane = lane; note.x = laneCenters[lane]; note.y = -100; notes.push(note); game.addChild(note); } // Hit window (distance from cat.y to note.y for a "hit") var hitWindow = 120; // Score/combo var score = 0; var combo = 0; var maxCombo = 0; // Input handling function handleArrowButton(dir) { var newLane = cat.lane; if (dir === 'left') { newLane = Math.max(0, cat.lane - 1); } else if (dir === 'right') { newLane = Math.min(laneCount - 1, cat.lane + 1); } else if (dir === 'up') { // No vertical movement, but can add jump effect tween(cat, { y: cat.y - 60 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(cat, { y: 2732 - 350 }, { duration: 120, easing: tween.easeIn }); } }); return; } else if (dir === 'down') { // No vertical movement, but can add crouch effect tween(cat, { y: cat.y + 40 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(cat, { y: 2732 - 350 }, { duration: 120, easing: tween.easeIn }); } }); return; } if (newLane !== cat.lane) { cat.setLane(newLane); } } // Color change input handler and event attachment removed (no longer needed) for (var i = 0; i < arrowButtons.length; i++) { (function (btn) { btn.down = function (x, y, obj) { handleArrowButton(btn.direction); }; })(arrowButtons[i]); } // Attach input events to color buttons // Touch input: allow swipe left/right to move cat, tap on color buttons to change color var touchStartX = null; var touchStartY = null; game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; }; game.up = function (x, y, obj) { if (touchStartX !== null && Math.abs(x - touchStartX) > 80 && Math.abs(x - touchStartX) > Math.abs(y - touchStartY)) { // Horizontal swipe if (x < touchStartX) { handleArrowButton('left'); } else { handleArrowButton('right'); } } touchStartX = null; touchStartY = null; }; // Main update loop game.update = function () { // Spawn notes if (LK.ticks % noteSpawnInterval === 0) { spawnNote(); } // Update notes for (var i = notes.length - 1; i >= 0; i--) { var note = notes[i]; note.update(); // Check for hit if (!note.hit && Math.abs(note.y - cat.y) < hitWindow && note.lane === cat.lane) { // Hit! note.hit = true; score += 1; combo += 1; if (combo > maxCombo) maxCombo = combo; scoreTxt.setText(score); comboTxt.setText(combo > 1 ? combo + ' combo!' : ''); LK.getSound('note_hit').play(); LK.effects.flashObject(cat, 0xffffff, 120); // Animate note tween(note, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 180, onFinish: function onFinish() { note.destroy(); } }); notes.splice(i, 1); continue; } // Missed note (passed cat) if (!note.hit && note.y > cat.y + hitWindow) { note.hit = true; combo = 0; comboTxt.setText(''); LK.getSound('note_miss').play(); LK.effects.flashScreen(0xff4b4b, 200); // Animate note tween(note, { alpha: 0 }, { duration: 120, onFinish: function onFinish() { note.destroy(); } }); notes.splice(i, 1); continue; } // Remove notes off screen if (note.y > 2732 + 200) { note.destroy(); notes.splice(i, 1); } } // Infinite mode: no win condition }; // Start music LK.playMusic('bgmusic', { fade: { start: 0, end: 0.7, duration: 1200 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Arrow Button class
var ArrowButton = Container.expand(function () {
var self = Container.call(this);
self.direction = 'left'; // 'left', 'right', 'up', 'down'
self.arrowAsset = null;
self.setDirection = function (dir) {
self.direction = dir;
if (self.arrowAsset) {
self.removeChild(self.arrowAsset);
}
var assetId = 'arrow_' + dir;
self.arrowAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add a simple arrow "icon" using Text2
var arrowChar = {
'left': '←',
'right': '→',
'up': '↑',
'down': '↓'
}[dir];
if (self.arrowText) {
self.removeChild(self.arrowText);
}
self.arrowText = new Text2(arrowChar, {
size: 120,
fill: 0x222222
});
self.arrowText.anchor.set(0.5, 0.5);
self.addChild(self.arrowText);
};
return self;
});
// Cat class
var Cat = Container.expand(function () {
var self = Container.call(this);
self.lane = 1; // start in lane 1 (from 0-3)
self.catAsset = self.attachAsset('cat', {
anchorX: 0.5,
anchorY: 0.5
});
self.setLane = function (lane) {
self.lane = lane;
self.x = laneCenters[lane];
};
return self;
});
// Note class
var Note = Container.expand(function () {
var self = Container.call(this);
self.color = 'red'; // default, will be set on spawn
self.lane = 0; // 0-3
self.hit = false;
self.setColor = function (color) {
self.color = color;
if (self.noteAsset) {
self.removeChild(self.noteAsset);
}
var assetId = 'note_' + color;
self.noteAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
self.y += noteSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Music (looping, for rhythm)
// Sound effects
// Arrow buttons
// Lane backgrounds (for visual feedback)
// Note shapes: four colors
// Cat character: cute box, default color yellow
// Lane setup
var laneCount = 4;
var laneWidth = 400;
var laneSpacing = 32;
var laneColors = ['red', 'blue', 'green', 'yellow'];
var laneCenters = [];
var laneLeft = (2048 - (laneCount * laneWidth + (laneCount - 1) * laneSpacing)) / 2;
for (var i = 0; i < laneCount; i++) {
laneCenters[i] = laneLeft + i * (laneWidth + laneSpacing) + laneWidth / 2;
}
// Lane backgrounds
var laneBGs = [];
for (var i = 0; i < laneCount; i++) {
var assetId = 'lane_' + laneColors[i];
var laneBG = LK.getAsset(assetId, {
anchorX: 0.5,
anchorY: 0,
x: laneCenters[i],
y: 0,
width: laneWidth,
height: 2732
});
laneBG.interactive = true;
laneBG.buttonMode = true;
laneBG.laneIndex = i;
laneBG.down = function (x, y, obj) {
// Move cat to this lane if not already there
if (cat.lane !== this.laneIndex) {
cat.setLane(this.laneIndex);
}
};
game.addChild(laneBG);
laneBGs.push(laneBG);
}
// Cat setup
var cat = new Cat();
cat.setLane(1);
cat.y = 2732 - 350;
game.addChild(cat);
// Arrow buttons (bottom of screen, left/right/up/down)
var arrowButtons = [];
var arrowButtonSize = 180;
var arrowButtonY = 2732 - 120;
var arrowButtonSpacing = 220;
var arrowButtonXStart = 2048 / 2 - arrowButtonSpacing * 1.5;
var arrowDirs = ['left', 'right', 'up', 'down'];
for (var i = 0; i < 4; i++) {
var btn = new ArrowButton();
btn.setDirection(arrowDirs[i]);
btn.x = arrowButtonXStart + i * arrowButtonSpacing;
btn.y = arrowButtonY;
btn.direction = arrowDirs[i];
btn.interactive = true;
btn.buttonMode = true;
game.addChild(btn); // Place arrow buttons in the main game area so they are always visible
arrowButtons.push(btn);
}
// Color change buttons removed (no longer needed)
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Combo display
var comboTxt = new Text2('', {
size: 80,
fill: 0xFFE066
});
comboTxt.anchor.set(0.5, 0);
comboTxt.y = 130;
LK.gui.top.addChild(comboTxt);
// Speed selection buttons
var speedOptions = [{
label: "0.5x",
speed: 0.5,
interval: 72
}, {
label: "1x",
speed: 1,
interval: 36
}, {
label: "2x",
speed: 2,
interval: 18
}];
var speedBtnY = 320;
var speedBtnSpacing = 320;
var speedBtnXStart = 2048 / 2 - speedBtnSpacing;
var speedBtns = [];
var selectedSpeedIdx = 1; // default 1x
function setGameSpeed(idx) {
selectedSpeedIdx = idx;
for (var i = 0; i < speedBtns.length; i++) {
speedBtns[i].alpha = i === idx ? 1 : 0.5;
}
noteSpeed = 18 * speedOptions[idx].speed;
noteSpawnInterval = speedOptions[idx].interval;
}
for (var i = 0; i < speedOptions.length; i++) {
var btn = new Container();
var bg = LK.getAsset('arrow_up', {
anchorX: 0.5,
anchorY: 0.5
});
bg.width = 220;
bg.height = 120;
btn.addChild(bg);
var txt = new Text2(speedOptions[i].label, {
size: 60,
fill: "#222"
});
txt.anchor.set(0.5, 0.5);
btn.addChild(txt);
btn.x = speedBtnXStart + i * speedBtnSpacing;
btn.y = speedBtnY;
btn.interactive = true;
btn.buttonMode = true;
(function (idx) {
btn.down = function (x, y, obj) {
setGameSpeed(idx);
};
})(i);
btn.alpha = i === selectedSpeedIdx ? 1 : 0.5;
game.addChild(btn);
speedBtns.push(btn);
}
setGameSpeed(selectedSpeedIdx);
// Notes array
var notes = [];
var noteSpeed = 18; // will be set by speed selection
var noteSpawnInterval = 36; // will be set by speed selection
var noteTimer = 0;
var noteColors = ['red', 'blue', 'green', 'yellow'];
// Rhythm pattern (random for now, can be improved)
function spawnNote() {
var lane = Math.floor(Math.random() * 4);
var color = noteColors[Math.floor(Math.random() * 4)];
var note = new Note();
note.setColor(color);
note.lane = lane;
note.x = laneCenters[lane];
note.y = -100;
notes.push(note);
game.addChild(note);
}
// Hit window (distance from cat.y to note.y for a "hit")
var hitWindow = 120;
// Score/combo
var score = 0;
var combo = 0;
var maxCombo = 0;
// Input handling
function handleArrowButton(dir) {
var newLane = cat.lane;
if (dir === 'left') {
newLane = Math.max(0, cat.lane - 1);
} else if (dir === 'right') {
newLane = Math.min(laneCount - 1, cat.lane + 1);
} else if (dir === 'up') {
// No vertical movement, but can add jump effect
tween(cat, {
y: cat.y - 60
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(cat, {
y: 2732 - 350
}, {
duration: 120,
easing: tween.easeIn
});
}
});
return;
} else if (dir === 'down') {
// No vertical movement, but can add crouch effect
tween(cat, {
y: cat.y + 40
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(cat, {
y: 2732 - 350
}, {
duration: 120,
easing: tween.easeIn
});
}
});
return;
}
if (newLane !== cat.lane) {
cat.setLane(newLane);
}
}
// Color change input handler and event attachment removed (no longer needed)
for (var i = 0; i < arrowButtons.length; i++) {
(function (btn) {
btn.down = function (x, y, obj) {
handleArrowButton(btn.direction);
};
})(arrowButtons[i]);
}
// Attach input events to color buttons
// Touch input: allow swipe left/right to move cat, tap on color buttons to change color
var touchStartX = null;
var touchStartY = null;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
if (touchStartX !== null && Math.abs(x - touchStartX) > 80 && Math.abs(x - touchStartX) > Math.abs(y - touchStartY)) {
// Horizontal swipe
if (x < touchStartX) {
handleArrowButton('left');
} else {
handleArrowButton('right');
}
}
touchStartX = null;
touchStartY = null;
};
// Main update loop
game.update = function () {
// Spawn notes
if (LK.ticks % noteSpawnInterval === 0) {
spawnNote();
}
// Update notes
for (var i = notes.length - 1; i >= 0; i--) {
var note = notes[i];
note.update();
// Check for hit
if (!note.hit && Math.abs(note.y - cat.y) < hitWindow && note.lane === cat.lane) {
// Hit!
note.hit = true;
score += 1;
combo += 1;
if (combo > maxCombo) maxCombo = combo;
scoreTxt.setText(score);
comboTxt.setText(combo > 1 ? combo + ' combo!' : '');
LK.getSound('note_hit').play();
LK.effects.flashObject(cat, 0xffffff, 120);
// Animate note
tween(note, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 180,
onFinish: function onFinish() {
note.destroy();
}
});
notes.splice(i, 1);
continue;
}
// Missed note (passed cat)
if (!note.hit && note.y > cat.y + hitWindow) {
note.hit = true;
combo = 0;
comboTxt.setText('');
LK.getSound('note_miss').play();
LK.effects.flashScreen(0xff4b4b, 200);
// Animate note
tween(note, {
alpha: 0
}, {
duration: 120,
onFinish: function onFinish() {
note.destroy();
}
});
notes.splice(i, 1);
continue;
}
// Remove notes off screen
if (note.y > 2732 + 200) {
note.destroy();
notes.splice(i, 1);
}
}
// Infinite mode: no win condition
};
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.7,
duration: 1200
}
});