User prompt
platforms should start from the bottom
Code edit (1 edits merged)
Please save this source code
User prompt
Color Bounce
Initial prompt
Build a complete, mobile-friendly rhythm-reaction game called **Color Bounce** with the following specifications: 🎮 Core Mechanics: 1. A ball automatically bounces downward onto colored platforms. 2. Each platform has one of 4 colors: red, blue, yellow and green. 3. The player must tap to **cycle the ball's color** in the order: red → blue → yellow → green → red... 4. When the ball lands on a platform: - ✅ If the color matches: it bounces again and the game continues. - ❌ If the color doesn't match: the game ends. 5. The ball falls faster as the game progresses — **increase tempo over time.** 🎯 Controls: - Single-tap input anywhere on screen = cycle ball color to next one. 🧠 Difficulty Progression: - Start with 4 colored platforms, slow tempo. - Every 10 bounces, increase fall speed slightly. - After 20 bounces, introduce *moving* platforms (horizontal slide). - After 40 bounces, introduce random gaps (platform missing). - Cap difficulty at 80 bounces for now. 🌈 Visual & Audio Feedback: - Each color has a **distinct glow and trail**. - Add a **particle burst** on successful bounce (small confetti or glow). - Add a **shake + screen flash** on failure. - Add SFX: - Bounce success = pitch-matched ping - Color switch = soft click - Fail = low thud + screen flash 🏆 Score & Game Flow: - Show **score as total successful bounces**. - At game over, show: - Final score - Best score - Retry button ✨ Cosmetic System: - Add **coin pickup items** that appear randomly on platforms (10% chance). - Player earns coins to unlock: - Ball skins (change ball appearance) - Trail styles (fire, smoke, sparkles) - Background themes (night, neon, pixel) - Add a basic **shop UI** with 6 total unlockable items (2 per category).
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { coins: 0, unlockedSkins: [], selectedSkin: 0 }); /**** * Classes ****/ // Ball class var Ball = Container.expand(function () { var self = Container.call(this); // Ball color index: 0=red, 1=blue, 2=green, 3=yellow self.colorIndex = 0; self.colors = ['red', 'blue', 'green', 'yellow']; self.asset = null; // Attach initial asset self.setColor = function (idx) { if (self.asset) { self.removeChild(self.asset); } self.colorIndex = idx; var colorName = self.colors[self.colorIndex]; self.asset = self.attachAsset('ball_' + colorName, { anchorX: 0.5, anchorY: 0.5 }); }; self.cycleColor = function () { var next = (self.colorIndex + 1) % self.colors.length; self.setColor(next); }; // For simple trail effect (MVP: just a quick flash) self.flash = function () { tween(self.asset, { alpha: 0.5 }, { duration: 60, easing: tween.linear, onFinish: function onFinish() { tween(self.asset, { alpha: 1 }, { duration: 80 }); } }); }; // Set initial color self.setColor(0); return self; }); // Coin class var Coin = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // MVP: no animation }; return self; }); // Platform class var Platform = Container.expand(function () { var self = Container.call(this); // Color index: 0=red, 1=blue, 2=green, 3=yellow self.colorIndex = 0; self.colors = ['red', 'blue', 'green', 'yellow']; self.asset = null; // For moving platforms (future) self.vx = 0; self.setColor = function (idx) { if (self.asset) { self.removeChild(self.asset); } self.colorIndex = idx; var colorName = self.colors[self.colorIndex]; self.asset = self.attachAsset('platform_' + colorName, { anchorX: 0.5, anchorY: 0.5 }); }; // For MVP, platforms are static self.update = function () { if (self.vx !== 0) { self.x += self.vx; // Bounce off edges if (self.x < self.asset.width / 2) { self.x = self.asset.width / 2; self.vx *= -1; } if (self.x > 2048 - self.asset.width / 2) { self.x = 2048 - self.asset.width / 2; self.vx *= -1; } } }; // Set initial color self.setColor(0); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c20 }); /**** * Game Code ****/ // Music (stub, not played in MVP) // SFX // Ball colors (platforms and ball) // --- Game variables --- var ball = null; var platforms = []; var coins = []; var score = 0; var coinCount = 0; var platformSpacing = 340; // vertical distance between platforms var platformSpeed = 12; // initial fall speed var gravity = 1.1; // increases as score increases var bounceVelocity = -38; // initial bounce velocity var ballVy = 0; var isFalling = true; var currentPlatformIdx = 0; var lastTapTick = 0; var gameStarted = false; var dragNode = null; // not used, but required by guidelines var lastIntersecting = false; var canTap = true; // prevent double tap in one frame // GUI var scoreTxt = new Text2('0', { size: 120, fill: '#fff' }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var coinTxt = new Text2('0', { size: 80, fill: '#ffd700' }); coinTxt.anchor.set(1, 0); coinTxt.x = -40; coinTxt.y = 20; LK.gui.topRight.addChild(coinTxt); // --- Helper functions --- function getRandomColorIdx() { // 0=red, 1=blue, 2=green, 3=yellow return Math.floor(Math.random() * 4); } function spawnPlatform(y, colorIdx) { var plat = new Platform(); plat.setColor(colorIdx); plat.x = 2048 / 2; plat.y = y; // MVP: no moving platforms platforms.push(plat); game.addChild(plat); return plat; } function spawnCoin(x, y) { var c = new Coin(); c.x = x; c.y = y - 60; coins.push(c); game.addChild(c); return c; } function resetGameVars() { score = 0; coinCount = 0; platformSpeed = 12; gravity = 1.1; bounceVelocity = -38; ballVy = 0; isFalling = true; currentPlatformIdx = 0; lastTapTick = 0; canTap = true; gameStarted = false; lastIntersecting = false; // Remove old platforms and coins for (var i = 0; i < platforms.length; ++i) platforms[i].destroy(); for (var i = 0; i < coins.length; ++i) coins[i].destroy(); platforms = []; coins = []; // Remove ball if (ball) { ball.destroy(); ball = null; } } // --- Game start --- function startGame() { resetGameVars(); // Ball ball = new Ball(); ball.x = 2048 / 2; ball.y = 600; game.addChild(ball); // Platforms: fill screen from the bottom up var y = 2732 - 120; // Start near the bottom of the screen for (var i = 0; i < 8; ++i) { var colorIdx = getRandomColorIdx(); var plat = spawnPlatform(y, colorIdx); // Place a coin on every 3rd platform if (i > 0 && i % 3 === 0) { spawnCoin(plat.x, plat.y); } y -= platformSpacing; } currentPlatformIdx = 0; isFalling = true; ballVy = 0; score = 0; coinCount = 0; scoreTxt.setText('0'); coinTxt.setText(storage.coins || 0); gameStarted = true; } // --- Input: tap to cycle color --- game.down = function (x, y, obj) { if (!gameStarted) { startGame(); return; } if (!canTap) return; canTap = false; if (ball) { ball.cycleColor(); ball.flash(); } lastTapTick = LK.ticks; }; game.up = function (x, y, obj) { canTap = true; }; // --- Main game loop --- game.update = function () { if (!gameStarted) return; // Ball physics if (isFalling) { ballVy += gravity; ball.y += ballVy; } // Move platforms upward to simulate ball falling var moveUp = platformSpeed; for (var i = 0; i < platforms.length; ++i) { platforms[i].y -= moveUp; platforms[i].update(); } for (var i = 0; i < coins.length; ++i) { coins[i].y -= moveUp; coins[i].update(); } // Remove platforms/coins that go off top for (var i = platforms.length - 1; i >= 0; --i) { if (platforms[i].y < -100) { platforms[i].destroy(); platforms.splice(i, 1); } } for (var i = coins.length - 1; i >= 0; --i) { if (coins[i].y < -100) { coins[i].destroy(); coins.splice(i, 1); } } // Spawn new platforms as needed var lastPlat = platforms[platforms.length - 1]; if (lastPlat && lastPlat.y < 2732 - platformSpacing) { var colorIdx = getRandomColorIdx(); var plat = spawnPlatform(lastPlat.y + platformSpacing, colorIdx); // Place a coin on every 3rd platform if ((score + platforms.length) % 3 === 0) { spawnCoin(plat.x, plat.y); } } // Ball collision with platform (only check nearest platform) var hit = false; for (var i = 0; i < platforms.length; ++i) { var plat = platforms[i]; // Only check platforms below ball if (plat.y > ball.y && plat.y - ball.y < 120) { // Check horizontal overlap var dx = Math.abs(ball.x - plat.x); if (dx < plat.asset.width / 2 - 30) { // Check vertical overlap var dy = Math.abs(ball.y - plat.y); if (dy < 90) { // Ball is landing on platform hit = true; // Only trigger bounce if falling if (ballVy > 0) { // Color match? if (ball.colorIndex === plat.colorIndex) { // Success! ballVy = bounceVelocity; isFalling = true; score += 1; scoreTxt.setText(score); LK.setScore(score); LK.getSound('bounce').play(); // Flash ball ball.flash(); // Increase difficulty if (score % 10 === 0) { platformSpeed += 1.5; gravity += 0.12; } } else { // Fail: wrong color LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 600); LK.showGameOver(); return; } } } } } } // Ball falls off bottom if (ball.y > 2732 + 100) { LK.getSound('fail').play(); LK.effects.flashScreen(0xff0000, 600); LK.showGameOver(); return; } // Coin collection for (var i = coins.length - 1; i >= 0; --i) { var c = coins[i]; var dx = Math.abs(ball.x - c.x); var dy = Math.abs(ball.y - c.y); if (dx < 90 && dy < 90) { // Collect coin LK.getSound('coin').play(); c.destroy(); coins.splice(i, 1); coinCount += 1; storage.coins = (storage.coins || 0) + 1; coinTxt.setText(storage.coins); // Simple coin pop // (future: animate) } } }; // --- Game over / win handling is automatic by LK --- // --- Start screen: tap to start --- startGame();
===================================================================
--- original.js
+++ change.js
@@ -206,18 +206,18 @@
ball = new Ball();
ball.x = 2048 / 2;
ball.y = 600;
game.addChild(ball);
- // Platforms: fill screen
- var y = 1000;
+ // Platforms: fill screen from the bottom up
+ var y = 2732 - 120; // Start near the bottom of the screen
for (var i = 0; i < 8; ++i) {
var colorIdx = getRandomColorIdx();
var plat = spawnPlatform(y, colorIdx);
// Place a coin on every 3rd platform
if (i > 0 && i % 3 === 0) {
spawnCoin(plat.x, plat.y);
}
- y += platformSpacing;
+ y -= platformSpacing;
}
currentPlatformIdx = 0;
isFalling = true;
ballVy = 0;
blue ball. In-Game asset. 2d. High contrast. No shadows
green ball. In-Game asset. 2d. High contrast. No shadows
red ball. In-Game asset. 2d. High contrast. No shadows
yellow ball. In-Game asset. 2d. High contrast. No shadows
coin. In-Game asset. 2d. High contrast. No shadows
blue platform. In-Game asset. 2d. High contrast. No shadows
green platform. In-Game asset. 2d. High contrast. No shadows
red platform. In-Game asset. 2d. High contrast. No shadows
yellow platform. In-Game asset. 2d. High contrast. No shadows
Create a vertical-scrolling, futuristic game background for a rhythm-based mobile game. The style should be vibrant and glowing, with a deep gradient from dark purple to electric blue. Include subtle abstract shapes like floating geometric particles, soft energy lines, and a faint digital grid. The mood should feel like you're inside a pulsing rhythm tunnel or neon cyber tower. No text, no characters — just atmospheric depth and motion-friendly layers. Must loop seamlessly for vertical scrolling. Style: sleek, minimal, energetic.. In-Game asset. 2d. High contrast. No shadows