User prompt
“Tap to start” text white color
User prompt
Add an intro instruction screen that appears when the game starts. This screen should include: • A short message: “Tap when the beats reach the center circle!” “Time your taps to the rhythm.” “Earn combos and level up!” • A large “Tap to Start” button • When the player taps the button, hide the instruction screen and begin the game normally • Make sure this screen appears only at the beginning, not after game restarts Keep the design clean, with bold text and centered layout.
User prompt
Enlarge all visual elements slightly to improve mobile touch experience. • Increase the size of the center target circle by 40% • Increase incoming beat circles by 25% • Make lane visuals wider or bolder by 20% • Score, combo, and level indicators should be slightly larger and easier to read Ensure all enlarged elements stay within safe screen margins and do not overlap each other.
User prompt
Add a level progression system to the rhythm game: • Each level lasts 30 seconds. • When a level is completed, display “LEVEL UP!” and increase the beat frequency and circle spawn speed slightly. • Do not end the game immediately on a few misses. • Instead, reset the player’s combo, but let them continue. • End the game only if the player misses 10 times total or after reaching level 10. • Show current level and miss count at the top of the screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Animate the lane background to visually respond to the beat of the music. The lane should gently pulse or wave upward and downward in sync with the music rhythm. • Create a smooth wave or ripple effect across the lane line • The effect should match the bass or beat of the background music • Keep the animation subtle but noticeable, like an equalizer or audio-reactive wave • The lane should never block or overlap the beat indicators This adds a music-responsive visual layer to increase immersion. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Improve the rhythm game layout and timing: 1. Enlarge the target circle in the center of the screen by 30–50%. Make it easier to see and tap. 2. Spawn incoming circles farther away, so that they appear earlier and give the player more time to react. They should smoothly move toward the center in sync with the music. 3. Adjust the spawn timing so that each beat circle takes at least 1.2 seconds to reach the center after spawning. This gives players enough time to focus and tap accurately. Ensure the beat visuals remain satisfying and match the music tempo. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Tap the Beat
Initial prompt
Create a simple but addictive rhythm game called “Tap the Beat.” • Show a single circular lane in the center of the screen. • Display beat indicators (circles or rings) that approach the center in sync with background music. • The player must tap when a beat reaches the center. • Score based on accuracy: “Perfect”, “Good”, or “Miss” • Show combo counter and total score • Increase music intensity and visual feedback as combo increases • If the player misses, combo resets but the game continues • Make the game fast, responsive, and visually satisfying • Use an energetic loop music track Touch-optimized and ideal for portrait mode. Make it playable in quick 30–60 second sessions.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BeatCircle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('beatCircle', {
anchorX: 0.5,
anchorY: 0.5
});
self.startRadius = 450;
self.targetRadius = 100;
self.speed = 2.2;
self.isActive = true;
self.hasBeenTapped = false;
self.update = function () {
if (!self.isActive) return;
var centerX = 2048 / 2;
var centerY = 2732 / 2;
// Calculate current distance from center
var dx = self.x - centerX;
var dy = self.y - centerY;
var currentRadius = Math.sqrt(dx * dx + dy * dy);
// Move inward
currentRadius -= self.speed;
if (currentRadius <= 70) {
// Beat missed - too close to center
if (!self.hasBeenTapped) {
missedBeat();
}
self.isActive = false;
return;
}
// Update position
var angle = Math.atan2(dy, dx);
self.x = centerX + Math.cos(angle) * currentRadius;
self.y = centerY + Math.sin(angle) * currentRadius;
// Scale based on distance for visual feedback
var scale = 0.5 + currentRadius / self.startRadius * 0.5;
graphics.scaleX = scale;
graphics.scaleY = scale;
};
self.checkHit = function () {
if (!self.isActive || self.hasBeenTapped) return false;
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var dx = self.x - centerX;
var dy = self.y - centerY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance <= 168 && distance >= 112) {
// Perfect hit
self.hasBeenTapped = true;
self.isActive = false;
return 'perfect';
} else if (distance <= 210 && distance >= 84) {
// Good hit
self.hasBeenTapped = true;
self.isActive = false;
return 'good';
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var gameScore = 0;
var combo = 0;
var beats = [];
var spawnTimer = 0;
var spawnInterval = 50; // Spawn every 50 ticks (about 0.83 seconds at 60fps)
var currentLevel = 1;
var missCount = 0;
var maxMisses = 10;
var levelTimer = 0;
var levelDuration = 1800; // 30 seconds at 60fps
// Create lane background
var lane = game.addChild(LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
}));
lane.x = 2048 / 2;
lane.y = 2732 / 2;
// Lane animation variables
var laneWaveTimer = 0;
var laneBaseScale = 1.0;
var laneWaveIntensity = 0.08;
var laneWaveSpeed = 0.15;
// Create center target
var centerTarget = game.addChild(LK.getAsset('centerTarget', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.4
}));
centerTarget.x = 2048 / 2;
centerTarget.y = 2732 / 2;
// Score display
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
// Combo display
var comboText = new Text2('Combo: 0', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(0.5, 0);
LK.gui.top.addChild(comboText);
comboText.y = 200;
// Level display
var levelText = new Text2('Level: 1', {
size: 70,
fill: 0x00FFFF
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
levelText.x = 120;
levelText.y = 50;
// Miss count display
var missText = new Text2('Misses: 0/10', {
size: 50,
fill: 0xFF6666
});
missText.anchor.set(1, 0);
LK.gui.topRight.addChild(missText);
missText.x = -20;
missText.y = 50;
// Feedback text
var feedbackText = new Text2('', {
size: 100,
fill: 0x00FF00
});
feedbackText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(feedbackText);
feedbackText.alpha = 0;
function spawnBeat() {
var beat = new BeatCircle();
// Apply level-based speed increase
beat.speed = 2.2 + (currentLevel - 1) * 0.2;
// Random angle for spawn position
var angle = Math.random() * Math.PI * 2;
var centerX = 2048 / 2;
var centerY = 2732 / 2;
beat.x = centerX + Math.cos(angle) * beat.startRadius;
beat.y = centerY + Math.sin(angle) * beat.startRadius;
beats.push(beat);
game.addChild(beat);
}
function levelUp() {
currentLevel++;
levelTimer = 0;
// Show level up feedback
feedbackText.setText('LEVEL UP!');
feedbackText.tint = "#00FFFF";
feedbackText.alpha = 1;
tween(feedbackText, {
alpha: 0
}, {
duration: 1000
});
// Increase difficulty
spawnInterval = Math.max(25, spawnInterval - 3); // Faster spawning
var speedIncrease = 0.2;
for (var i = 0; i < beats.length; i++) {
beats[i].speed += speedIncrease;
}
// Update level display
levelText.setText('Level: ' + currentLevel);
// Flash screen for level up
LK.effects.flashScreen(0x00FFFF, 500);
}
function hitBeat(accuracy) {
var points = 0;
var feedbackColor = "#ffffff";
var feedbackMsg = "";
if (accuracy === 'perfect') {
points = 100 + combo * 10;
feedbackColor = "#00ff00";
feedbackMsg = "PERFECT!";
} else if (accuracy === 'good') {
points = 50 + combo * 5;
feedbackColor = "#ffff00";
feedbackMsg = "GOOD!";
}
gameScore += points;
combo++;
// Update displays
scoreText.setText('Score: ' + gameScore);
comboText.setText('Combo: ' + combo);
// Show feedback
feedbackText.setText(feedbackMsg);
feedbackText.tint = feedbackColor;
feedbackText.alpha = 1;
tween(feedbackText, {
alpha: 0
}, {
duration: 500
});
// Visual effects for combos
if (combo > 0 && combo % 5 === 0) {
LK.effects.flashScreen(0x00ff00, 200);
}
// Increase lane wave intensity with combo
laneWaveIntensity = 0.08 + combo * 0.002;
laneWaveSpeed = 0.15 + combo * 0.005;
// Add combo pulse effect to lane
tween(lane, {
scaleX: laneBaseScale + 0.15,
scaleY: laneBaseScale + 0.15
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(lane, {
scaleX: laneBaseScale,
scaleY: laneBaseScale
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Play hit sound
LK.getSound('hit').play();
// Update score for LK system
LK.setScore(gameScore);
}
function missedBeat() {
combo = 0;
missCount++;
comboText.setText('Combo: 0');
missText.setText('Misses: ' + missCount + '/' + maxMisses);
// Check for game over condition
if (missCount >= maxMisses) {
LK.showGameOver();
return;
}
// Reset lane wave intensity
laneWaveIntensity = 0.08;
laneWaveSpeed = 0.15;
// Show miss feedback
feedbackText.setText('MISS!');
feedbackText.tint = "#ff0000";
feedbackText.alpha = 1;
tween(feedbackText, {
alpha: 0
}, {
duration: 500
});
// Flash effect
LK.effects.flashScreen(0xff0000, 300);
// Play miss sound
LK.getSound('miss').play();
}
// Touch handler
game.down = function (x, y, obj) {
var hitDetected = false;
// Check all active beats for hits
for (var i = beats.length - 1; i >= 0; i--) {
var beat = beats[i];
if (!beat.isActive) continue;
var accuracy = beat.checkHit();
if (accuracy) {
hitBeat(accuracy);
hitDetected = true;
break; // Only hit one beat per tap
}
}
// If no beat was hit, it's a miss (but don't reset combo for tapping empty space)
};
game.update = function () {
// Animate lane wave effect
laneWaveTimer += laneWaveSpeed;
var waveScale = laneBaseScale + Math.sin(laneWaveTimer) * laneWaveIntensity;
lane.scaleX = waveScale;
lane.scaleY = waveScale;
// Add subtle rotation wave
lane.rotation = Math.sin(laneWaveTimer * 0.7) * 0.02;
// Spawn new beats
spawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnBeat();
spawnTimer = 0;
// Gradually increase difficulty by spawning beats more frequently
if (spawnInterval > 25) {
spawnInterval -= 0.1;
}
}
// Clean up inactive beats
for (var i = beats.length - 1; i >= 0; i--) {
var beat = beats[i];
if (!beat.isActive) {
beat.destroy();
beats.splice(i, 1);
}
}
// Level progression timer
levelTimer++;
if (levelTimer >= levelDuration) {
if (currentLevel >= 10) {
LK.showYouWin();
return;
}
levelUp();
}
// Win condition - reach level 10
if (currentLevel > 10) {
LK.showYouWin();
}
};
// Start background music
LK.playMusic('bgmusic'); ===================================================================
--- original.js
+++ change.js
@@ -81,8 +81,13 @@
var combo = 0;
var beats = [];
var spawnTimer = 0;
var spawnInterval = 50; // Spawn every 50 ticks (about 0.83 seconds at 60fps)
+var currentLevel = 1;
+var missCount = 0;
+var maxMisses = 10;
+var levelTimer = 0;
+var levelDuration = 1800; // 30 seconds at 60fps
// Create lane background
var lane = game.addChild(LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5,
@@ -119,8 +124,26 @@
});
comboText.anchor.set(0.5, 0);
LK.gui.top.addChild(comboText);
comboText.y = 200;
+// Level display
+var levelText = new Text2('Level: 1', {
+ size: 70,
+ fill: 0x00FFFF
+});
+levelText.anchor.set(0, 0);
+LK.gui.topLeft.addChild(levelText);
+levelText.x = 120;
+levelText.y = 50;
+// Miss count display
+var missText = new Text2('Misses: 0/10', {
+ size: 50,
+ fill: 0xFF6666
+});
+missText.anchor.set(1, 0);
+LK.gui.topRight.addChild(missText);
+missText.x = -20;
+missText.y = 50;
// Feedback text
var feedbackText = new Text2('', {
size: 100,
fill: 0x00FF00
@@ -129,8 +152,10 @@
LK.gui.center.addChild(feedbackText);
feedbackText.alpha = 0;
function spawnBeat() {
var beat = new BeatCircle();
+ // Apply level-based speed increase
+ beat.speed = 2.2 + (currentLevel - 1) * 0.2;
// Random angle for spawn position
var angle = Math.random() * Math.PI * 2;
var centerX = 2048 / 2;
var centerY = 2732 / 2;
@@ -138,8 +163,31 @@
beat.y = centerY + Math.sin(angle) * beat.startRadius;
beats.push(beat);
game.addChild(beat);
}
+function levelUp() {
+ currentLevel++;
+ levelTimer = 0;
+ // Show level up feedback
+ feedbackText.setText('LEVEL UP!');
+ feedbackText.tint = "#00FFFF";
+ feedbackText.alpha = 1;
+ tween(feedbackText, {
+ alpha: 0
+ }, {
+ duration: 1000
+ });
+ // Increase difficulty
+ spawnInterval = Math.max(25, spawnInterval - 3); // Faster spawning
+ var speedIncrease = 0.2;
+ for (var i = 0; i < beats.length; i++) {
+ beats[i].speed += speedIncrease;
+ }
+ // Update level display
+ levelText.setText('Level: ' + currentLevel);
+ // Flash screen for level up
+ LK.effects.flashScreen(0x00FFFF, 500);
+}
function hitBeat(accuracy) {
var points = 0;
var feedbackColor = "#ffffff";
var feedbackMsg = "";
@@ -196,9 +244,16 @@
LK.setScore(gameScore);
}
function missedBeat() {
combo = 0;
+ missCount++;
comboText.setText('Combo: 0');
+ missText.setText('Misses: ' + missCount + '/' + maxMisses);
+ // Check for game over condition
+ if (missCount >= maxMisses) {
+ LK.showGameOver();
+ return;
+ }
// Reset lane wave intensity
laneWaveIntensity = 0.08;
laneWaveSpeed = 0.15;
// Show miss feedback
@@ -256,10 +311,19 @@
beat.destroy();
beats.splice(i, 1);
}
}
- // Win condition - reach score of 5000
- if (gameScore >= 5000) {
+ // Level progression timer
+ levelTimer++;
+ if (levelTimer >= levelDuration) {
+ if (currentLevel >= 10) {
+ LK.showYouWin();
+ return;
+ }
+ levelUp();
+ }
+ // Win condition - reach level 10
+ if (currentLevel > 10) {
LK.showYouWin();
}
};
// Start background music