Code edit (1 edits merged)
Please save this source code
User prompt
Rocket Runner: Fuel the Journey
Initial prompt
Objective: Create a one-tap endless runner where players guide a rocket through floating platforms, dodging obstacles and collecting fuel orbs to maximize score. Core Mechanics: Controls: Single tap (or click) to make the rocket jump/boost upward. No tap means the rocket falls due to gravity. Platforms: Randomly generated platforms move left at a constant speed. The rocket must land on them to avoid falling. Fuel Orbs: Collectible orbs appear above platforms, granting points when collected. Obstacles: Optionally add moving obstacles (e.g., comets) in later iterations for challenge. Scoring: 10 points per fuel orb; score increases as the player survives longer. Game Over: Rocket falls below the screen, triggering a restart option on tap. Visual Style: Theme: Retro-futuristic with a vibrant, starry background (#1a1a3d) and quirky rocket designs (e.g., cartoonish rockets with expressive faces). Assets: Simple 2D sprites for rocket (50x50px), platforms (100x20px), and fuel orbs (20x20px). Use Uplit’s sprite management for smooth rendering. Animations: Add subtle rocket tilt on jump and particle effects (via Uplit’s particle system) for orb collection and crashes. Uplit Implementation: Setup: Use Uplit’s Game class to initialize a 800x600 canvas with a dark background. Physics: Leverage Uplit’s lightweight physics for gravity (0.5) and jump force (-12). Use createSprite for rocket, platforms, and orbs. Random Generation: Spawn platforms at random y-positions (within 100-400px from bottom) every 200px along x-axis. Add 50% chance for fuel orbs. Collisions: Use game.collides to detect rocket-platform landings and rocket-orb collections. Input: Use onTouchStart for tap/click to trigger jumps or restart on game over. Performance: Uplit’s sprite culling ensures off-screen objects (platforms/orbs) are removed efficiently. Features: Random Levels: Platforms spawn with varied y-positions for endless variety. Rocket Designs: Unlockable skins (e.g., red rocket, UFO) via score milestones (not implemented in base code but extensible). Leaderboards: Use Uplit’s cloud integration (if available) to store high scores, or local storage for simplicity. Polish: Add sound effects for jumps (beep) and orb collection (sparkle) using Uplit’s audio system. Player Experience: Appeal: Quick, addictive sessions (1-2 minutes) for casual players. Collectibles and increasing difficulty keep players engaged. Difficulty Curve: Start with wider platforms, gradually increase moveSpeed or reduce platform size as score grows. Feedback: Visual feedback (orb sparkle, rocket shake on landing) and score display enhance satisfaction. Development Tips: Prototype Fast: Use Uplit’s hot-reload to tweak gravity, jump force, and platform spacing in real-time. Optimize: Keep sprite counts low (max 10 platforms/orbs) to ensure smooth performance on mobile. Test Inputs: Test tap responsiveness on touch devices to ensure precise jumps. Asset Creation: Create simple PNGs in tools like Aseprite for rocket, platforms, and orbs, or use placeholder shapes in Uplit for prototyping. Next Steps: Add obstacles (e.g., moving comets) with createSprite and collision checks. Implement rocket skins by swapping image property on score thresholds. Add a title screen with game.drawText and state management for start/restart.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var FuelOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('fuelOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.collected = false;
// Add floating animation
self.floatOffset = Math.random() * Math.PI * 2;
self.update = function () {
self.x += self.speed;
// Floating animation
orbGraphics.y = Math.sin(LK.ticks * 0.1 + self.floatOffset) * 5;
// Gentle rotation
orbGraphics.rotation += 0.02;
// Remove orb when it goes off screen
if (self.x < -50) {
self.shouldRemove = true;
}
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.hasFuelOrb = false;
self.update = function () {
self.x += self.speed;
// Remove platform when it goes off screen
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphics = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.5;
self.boostPower = -12;
self.maxVelocity = 15;
self.boost = function () {
self.velocityY = self.boostPower;
LK.getSound('boost').play();
// Tilt rocket upward when boosting
tween(rocketGraphics, {
rotation: -0.3
}, {
duration: 200
});
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Limit velocity
if (self.velocityY > self.maxVelocity) {
self.velocityY = self.maxVelocity;
}
// Update position
self.y += self.velocityY;
// Tilt rocket based on velocity
if (self.velocityY > 0) {
tween(rocketGraphics, {
rotation: 0.2
}, {
duration: 300
});
}
// Check if rocket fell below screen
if (self.y > 2732 + 100) {
gameOver = true;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1;
self.update = function () {
self.x += self.speed;
// Remove star when it goes off screen
if (self.x < -10) {
self.shouldRemove = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a2e
});
/****
* Game Code
****/
var rocket;
var platforms = [];
var fuelOrbs = [];
var stars = [];
var gameStarted = false;
var gameOver = false;
var platformSpawnTimer = 0;
var starSpawnTimer = 0;
var lastPlatformY = 2732 / 2;
var difficultyLevel = 1;
// Initialize rocket
rocket = game.addChild(new Rocket());
rocket.x = 300;
rocket.y = 2732 / 2;
// Create UI
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var instructionText = new Text2('TAP TO BOOST', {
size: 60,
fill: 0xFFEB3B
});
instructionText.anchor.set(0.5, 0.5);
game.addChild(instructionText);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2 + 200;
// Generate initial stars
function createStar() {
var star = game.addChild(new Star());
star.x = 2048 + Math.random() * 500;
star.y = Math.random() * 2732;
stars.push(star);
}
// Generate initial background stars
for (var i = 0; i < 50; i++) {
createStar();
}
function createPlatform() {
var platform = game.addChild(new Platform());
platform.x = 2048 + 100;
// Calculate next platform Y position with some randomness
var minY = Math.max(200, lastPlatformY - 150);
var maxY = Math.min(2532, lastPlatformY + 150);
platform.y = minY + Math.random() * (maxY - minY);
lastPlatformY = platform.y;
platforms.push(platform);
// 50% chance to spawn a fuel orb above this platform
if (Math.random() < 0.5) {
var orb = game.addChild(new FuelOrb());
orb.x = platform.x;
orb.y = platform.y - 80;
fuelOrbs.push(orb);
platform.hasFuelOrb = true;
}
}
function checkCollisions() {
// Check rocket collision with platforms (landing)
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (rocket.intersects(platform) && rocket.velocityY > 0) {
// Land on platform
rocket.y = platform.y - 20;
rocket.velocityY = 0;
}
}
// Check fuel orb collection
for (var j = 0; j < fuelOrbs.length; j++) {
var orb = fuelOrbs[j];
if (!orb.collected && rocket.intersects(orb)) {
orb.collected = true;
LK.setScore(LK.getScore() + 10);
scoreText.setText(LK.getScore());
LK.getSound('collect').play();
// Particle effect
LK.effects.flashObject(orb, 0xffeb3b, 300);
orb.shouldRemove = true;
}
}
}
function updateDifficulty() {
var score = LK.getScore();
difficultyLevel = Math.floor(score / 50) + 1;
// Increase platform and orb speed
var newSpeed = -4 - (difficultyLevel - 1) * 0.5;
platforms.forEach(function (platform) {
platform.speed = newSpeed;
});
fuelOrbs.forEach(function (orb) {
orb.speed = newSpeed;
});
}
// Game input handling
game.down = function (x, y, obj) {
if (gameOver) {
// Restart game
gameOver = false;
gameStarted = true;
LK.setScore(0);
scoreText.setText('0');
// Reset rocket
rocket.x = 300;
rocket.y = 2732 / 2;
rocket.velocityY = 0;
// Clear all platforms and orbs
platforms.forEach(function (platform) {
platform.destroy();
});
fuelOrbs.forEach(function (orb) {
orb.destroy();
});
platforms = [];
fuelOrbs = [];
lastPlatformY = 2732 / 2;
difficultyLevel = 1;
instructionText.visible = false;
return;
}
if (!gameStarted) {
gameStarted = true;
instructionText.visible = false;
}
rocket.boost();
};
game.update = function () {
if (!gameStarted || gameOver) {
if (gameOver) {
// Show game over
LK.showGameOver();
}
return;
}
// Spawn platforms
platformSpawnTimer++;
if (platformSpawnTimer >= 90) {
// Spawn every 1.5 seconds at 60fps
createPlatform();
platformSpawnTimer = 0;
}
// Spawn stars occasionally
starSpawnTimer++;
if (starSpawnTimer >= 120) {
createStar();
starSpawnTimer = 0;
}
// Update and cleanup platforms
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.shouldRemove) {
platform.destroy();
platforms.splice(i, 1);
}
}
// Update and cleanup fuel orbs
for (var j = fuelOrbs.length - 1; j >= 0; j--) {
var orb = fuelOrbs[j];
if (orb.shouldRemove) {
orb.destroy();
fuelOrbs.splice(j, 1);
}
}
// Update and cleanup stars
for (var k = stars.length - 1; k >= 0; k--) {
var star = stars[k];
if (star.shouldRemove) {
star.destroy();
stars.splice(k, 1);
}
}
// Check collisions
checkCollisions();
// Update difficulty
updateDifficulty();
// Add survival bonus points
if (LK.ticks % 180 === 0) {
// Every 3 seconds
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
};
// Start background music
LK.playMusic('backgroundMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var FuelOrb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('fuelOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.collected = false;
// Add floating animation
self.floatOffset = Math.random() * Math.PI * 2;
self.update = function () {
self.x += self.speed;
// Floating animation
orbGraphics.y = Math.sin(LK.ticks * 0.1 + self.floatOffset) * 5;
// Gentle rotation
orbGraphics.rotation += 0.02;
// Remove orb when it goes off screen
if (self.x < -50) {
self.shouldRemove = true;
}
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.hasFuelOrb = false;
self.update = function () {
self.x += self.speed;
// Remove platform when it goes off screen
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var Rocket = Container.expand(function () {
var self = Container.call(this);
var rocketGraphics = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.5;
self.boostPower = -12;
self.maxVelocity = 15;
self.boost = function () {
self.velocityY = self.boostPower;
LK.getSound('boost').play();
// Tilt rocket upward when boosting
tween(rocketGraphics, {
rotation: -0.3
}, {
duration: 200
});
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Limit velocity
if (self.velocityY > self.maxVelocity) {
self.velocityY = self.maxVelocity;
}
// Update position
self.y += self.velocityY;
// Tilt rocket based on velocity
if (self.velocityY > 0) {
tween(rocketGraphics, {
rotation: 0.2
}, {
duration: 300
});
}
// Check if rocket fell below screen
if (self.y > 2732 + 100) {
gameOver = true;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1;
self.update = function () {
self.x += self.speed;
// Remove star when it goes off screen
if (self.x < -10) {
self.shouldRemove = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a2e
});
/****
* Game Code
****/
var rocket;
var platforms = [];
var fuelOrbs = [];
var stars = [];
var gameStarted = false;
var gameOver = false;
var platformSpawnTimer = 0;
var starSpawnTimer = 0;
var lastPlatformY = 2732 / 2;
var difficultyLevel = 1;
// Initialize rocket
rocket = game.addChild(new Rocket());
rocket.x = 300;
rocket.y = 2732 / 2;
// Create UI
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var instructionText = new Text2('TAP TO BOOST', {
size: 60,
fill: 0xFFEB3B
});
instructionText.anchor.set(0.5, 0.5);
game.addChild(instructionText);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2 + 200;
// Generate initial stars
function createStar() {
var star = game.addChild(new Star());
star.x = 2048 + Math.random() * 500;
star.y = Math.random() * 2732;
stars.push(star);
}
// Generate initial background stars
for (var i = 0; i < 50; i++) {
createStar();
}
function createPlatform() {
var platform = game.addChild(new Platform());
platform.x = 2048 + 100;
// Calculate next platform Y position with some randomness
var minY = Math.max(200, lastPlatformY - 150);
var maxY = Math.min(2532, lastPlatformY + 150);
platform.y = minY + Math.random() * (maxY - minY);
lastPlatformY = platform.y;
platforms.push(platform);
// 50% chance to spawn a fuel orb above this platform
if (Math.random() < 0.5) {
var orb = game.addChild(new FuelOrb());
orb.x = platform.x;
orb.y = platform.y - 80;
fuelOrbs.push(orb);
platform.hasFuelOrb = true;
}
}
function checkCollisions() {
// Check rocket collision with platforms (landing)
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (rocket.intersects(platform) && rocket.velocityY > 0) {
// Land on platform
rocket.y = platform.y - 20;
rocket.velocityY = 0;
}
}
// Check fuel orb collection
for (var j = 0; j < fuelOrbs.length; j++) {
var orb = fuelOrbs[j];
if (!orb.collected && rocket.intersects(orb)) {
orb.collected = true;
LK.setScore(LK.getScore() + 10);
scoreText.setText(LK.getScore());
LK.getSound('collect').play();
// Particle effect
LK.effects.flashObject(orb, 0xffeb3b, 300);
orb.shouldRemove = true;
}
}
}
function updateDifficulty() {
var score = LK.getScore();
difficultyLevel = Math.floor(score / 50) + 1;
// Increase platform and orb speed
var newSpeed = -4 - (difficultyLevel - 1) * 0.5;
platforms.forEach(function (platform) {
platform.speed = newSpeed;
});
fuelOrbs.forEach(function (orb) {
orb.speed = newSpeed;
});
}
// Game input handling
game.down = function (x, y, obj) {
if (gameOver) {
// Restart game
gameOver = false;
gameStarted = true;
LK.setScore(0);
scoreText.setText('0');
// Reset rocket
rocket.x = 300;
rocket.y = 2732 / 2;
rocket.velocityY = 0;
// Clear all platforms and orbs
platforms.forEach(function (platform) {
platform.destroy();
});
fuelOrbs.forEach(function (orb) {
orb.destroy();
});
platforms = [];
fuelOrbs = [];
lastPlatformY = 2732 / 2;
difficultyLevel = 1;
instructionText.visible = false;
return;
}
if (!gameStarted) {
gameStarted = true;
instructionText.visible = false;
}
rocket.boost();
};
game.update = function () {
if (!gameStarted || gameOver) {
if (gameOver) {
// Show game over
LK.showGameOver();
}
return;
}
// Spawn platforms
platformSpawnTimer++;
if (platformSpawnTimer >= 90) {
// Spawn every 1.5 seconds at 60fps
createPlatform();
platformSpawnTimer = 0;
}
// Spawn stars occasionally
starSpawnTimer++;
if (starSpawnTimer >= 120) {
createStar();
starSpawnTimer = 0;
}
// Update and cleanup platforms
for (var i = platforms.length - 1; i >= 0; i--) {
var platform = platforms[i];
if (platform.shouldRemove) {
platform.destroy();
platforms.splice(i, 1);
}
}
// Update and cleanup fuel orbs
for (var j = fuelOrbs.length - 1; j >= 0; j--) {
var orb = fuelOrbs[j];
if (orb.shouldRemove) {
orb.destroy();
fuelOrbs.splice(j, 1);
}
}
// Update and cleanup stars
for (var k = stars.length - 1; k >= 0; k--) {
var star = stars[k];
if (star.shouldRemove) {
star.destroy();
stars.splice(k, 1);
}
}
// Check collisions
checkCollisions();
// Update difficulty
updateDifficulty();
// Add survival bonus points
if (LK.ticks % 180 === 0) {
// Every 3 seconds
LK.setScore(LK.getScore() + 1);
scoreText.setText(LK.getScore());
}
};
// Start background music
LK.playMusic('backgroundMusic');