User prompt
Add the floor back
User prompt
Stretch the floor to the bottom of the screen
User prompt
Add a scrolling backround
User prompt
Delete the doted line
User prompt
Make a dotted line between the two places you can tap
User prompt
Make it so that the longer you play for, the more enemies spawn
User prompt
Make it so that the more force you get the faster it goes
User prompt
Change the name of the shields counter to lives
User prompt
Move the force token counter to below the distance counter
User prompt
Add a force token counter
User prompt
Make the x wing’s lasers red and make the other lasers straight ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fix it
User prompt
Please fix the bug: 'TypeError: null is not an object (evaluating 'obstacle.graphic.height')' in or related to this line: 'obstacle.y = Math.random() < 0.5 ? game.trenchTop + obstacle.graphic.height / 2 : game.trenchBottom - obstacle.graphic.height / 2;' Line Number: 360
User prompt
Add the assets
User prompt
Add the assets
User prompt
Add the assets
User prompt
Implement the gameplay to the assets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Rebel Runner
Initial prompt
Star Wars game that only requires one input
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Collectible = Container.expand(function () {
var self = Container.call(this);
// Type determines appearance and effect
self.type = '';
self.speed = 0;
self.lastX = 0;
self.lastIsColliding = false;
self.graphic = null;
self.init = function (type, speed) {
self.type = type;
self.speed = speed;
// Create different visuals based on type
if (type === 'forceToken') {
self.graphic = self.attachAsset('forceToken', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'shield') {
self.graphic = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Record initial position
self.lastX = self.x;
};
// Float animation
self.update = function () {
// Save last position
self.lastX = self.x;
// Move left
self.x -= self.speed;
// Floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
self.graphic.rotation += 0.02;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Type determines appearance and behavior
self.type = '';
self.speed = 0;
self.lastX = 0;
self.lastY = 0;
self.lastIsColliding = false;
self.graphic = null;
self.init = function (type, speed) {
self.type = type;
self.speed = speed;
// Create different visuals based on type
if (type === 'wall') {
self.graphic = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'laser') {
self.graphic = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.graphic.rotation = Math.PI / 4; // 45 degrees
} else if (type === 'tieFighter') {
self.graphic = self.attachAsset('tieFighter', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Record initial position
self.lastX = self.x;
self.lastY = self.y;
};
// Move obstacle
self.update = function () {
// Save last position
self.lastX = self.x;
self.lastY = self.y;
// Move left
self.x -= self.speed;
// Special movement patterns based on type
if (self.type === 'tieFighter') {
// TIE fighters move in a slight wave pattern
self.y += Math.sin(self.x * 0.01) * 2;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Create X-wing graphic
var xwingGraphic = self.attachAsset('xwing', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.velocityY = 0;
self.gravity = 0.5;
self.jumpForce = -12;
self.maxVelocity = 15;
self.isJumping = false;
self.isShielded = false;
self.shieldTimer = 0;
// Track last position for collision detection
self.lastY = 0;
self.lastIsColliding = false;
// Shield visual effect
var shieldGraphic = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Apply physics and update position
self.update = function () {
// Save last position for collision detection
self.lastY = self.y;
// Apply gravity
self.velocityY += self.gravity;
// Cap terminal velocity
if (self.velocityY > self.maxVelocity) {
self.velocityY = self.maxVelocity;
}
// Update position
self.y += self.velocityY;
// Floor boundary
if (self.y > game.trenchBottom - xwingGraphic.height / 2) {
self.y = game.trenchBottom - xwingGraphic.height / 2;
self.velocityY = 0;
self.isJumping = false;
}
// Ceiling boundary
if (self.y < game.trenchTop + xwingGraphic.height / 2) {
self.y = game.trenchTop + xwingGraphic.height / 2;
self.velocityY = 1;
}
// Visual tilt based on velocity (diving down = nose down, rising up = nose up)
xwingGraphic.rotation = self.velocityY * 0.05;
// Create engine trail effect (every 5 frames)
if (LK.ticks % 5 === 0) {
var trail = LK.getAsset('engineTrail', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
trail.x = self.x - 60;
trail.y = self.y + 5;
game.addChild(trail);
// Animate the trail to fade out
tween(trail, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 500,
onComplete: function onComplete() {
trail.destroy();
}
});
}
// Shield timer
if (self.isShielded) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.isShielded = false;
shieldGraphic.alpha = 0;
}
}
};
// Jump method when screen is tapped
self.jump = function () {
self.velocityY = self.jumpForce;
self.isJumping = true;
LK.getSound('jump').play();
};
// Activate shield power-up
self.activateShield = function (duration) {
self.isShielded = true;
self.shieldTimer = duration;
shieldGraphic.alpha = 0.6;
};
return self;
});
var TrenchSegment = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.lastX = 0;
self.init = function (speed) {
self.speed = speed;
// Add walls
var topWall = self.attachAsset('trenchWall', {
anchorX: 0,
anchorY: 0
});
var bottomWall = self.attachAsset('trenchWall', {
anchorX: 0,
anchorY: 1
});
// Position walls
topWall.y = game.trenchTop;
bottomWall.y = game.trenchBottom;
self.lastX = self.x;
};
self.update = function () {
self.lastX = self.x;
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
// Game constants
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Background music
// Sounds
// Particle effects
// Collectibles
// Environment
// Obstacles
// Enemies
// Player ship
// Game constants
//Minimalistic tween library which should be used for animations over time
// Initialize game assets
var GAME_SPEED_INITIAL = 8;
var GAME_SPEED_INCREMENT = 0.001;
var OBSTACLE_SPAWN_RATE_INITIAL = 120; // frames
var COLLECTIBLE_SPAWN_RATE = 180; // frames
var TRENCH_WIDTH = 1600;
var TRENCH_HEIGHT = 1400;
// Game variables
var gameSpeed = GAME_SPEED_INITIAL;
var obstacleSpawnRate = OBSTACLE_SPAWN_RATE_INITIAL;
var obstacleTimer = 0;
var collectibleTimer = 0;
var distance = 0;
var lives = 3;
var trenchSegments = [];
var obstacles = [];
var collectibles = [];
var player = null;
var isGameActive = true;
// Set up trench boundaries
game.trenchTop = (2732 - TRENCH_HEIGHT) / 2;
game.trenchBottom = game.trenchTop + TRENCH_HEIGHT;
game.trenchLeft = (2048 - TRENCH_WIDTH) / 2;
game.trenchRight = game.trenchLeft + TRENCH_WIDTH;
// Initialize trench floor
var trenchFloor = LK.getAsset('trenchFloor', {
anchorX: 0.5,
anchorY: 0
});
trenchFloor.x = 2048 / 2;
trenchFloor.y = game.trenchBottom;
game.addChild(trenchFloor);
// Create GUI elements
var distanceText = new Text2('DISTANCE: 0', {
size: 70,
fill: 0xFFFFFF
});
distanceText.anchor.set(0, 0);
distanceText.x = 120;
distanceText.y = 50;
LK.gui.topLeft.addChild(distanceText);
var livesText = new Text2('SHIELDS: 3', {
size: 70,
fill: 0xFFFFFF
});
livesText.anchor.set(1, 0);
livesText.x = -120;
livesText.y = 50;
LK.gui.topRight.addChild(livesText);
// Create player (X-wing)
player = new Player();
player.x = 400;
player.y = (game.trenchTop + game.trenchBottom) / 2;
game.addChild(player);
// Start background music with fade in
LK.playMusic('starWarsTheme', {
fade: {
start: 0,
end: 0.4,
duration: 2000
}
});
// Initialize trench segments
function createInitialTrench() {
var segments = 3; // Number of initial trench segments
var segmentWidth = 2048; // Width of each segment
for (var i = 0; i < segments; i++) {
var segment = new TrenchSegment();
segment.x = i * segmentWidth;
segment.init(gameSpeed);
trenchSegments.push(segment);
game.addChild(segment);
}
}
// Create a new obstacle
function spawnObstacle() {
var obstacle = new Obstacle();
// Random obstacle type
var types = ['wall', 'laser', 'tieFighter'];
var type = types[Math.floor(Math.random() * types.length)];
// Position at right side of screen
obstacle.x = 2048 + 100;
// Random vertical position within trench
if (type === 'wall') {
// Walls randomly appear at top or bottom
obstacle.y = Math.random() < 0.5 ? game.trenchTop + obstacle.graphic.height / 2 : game.trenchBottom - obstacle.graphic.height / 2;
} else {
// Other obstacles can appear anywhere in trench
obstacle.y = game.trenchTop + 150 + Math.random() * (TRENCH_HEIGHT - 300);
}
obstacle.init(type, gameSpeed);
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Create a new collectible
function spawnCollectible() {
var collectible = new Collectible();
// Random collectible type (force tokens more common than shields)
var type = Math.random() < 0.8 ? 'forceToken' : 'shield';
// Position at right side of screen
collectible.x = 2048 + 100;
// Random vertical position within trench
collectible.y = game.trenchTop + 150 + Math.random() * (TRENCH_HEIGHT - 300);
collectible.init(type, gameSpeed);
collectibles.push(collectible);
game.addChild(collectible);
}
// Update score and distance display
function updateHUD() {
var distanceKm = Math.floor(distance / 100);
distanceText.setText('DISTANCE: ' + distanceKm + ' KM');
livesText.setText('SHIELDS: ' + lives);
}
// Handle player hit
function playerHit() {
if (player.isShielded) return; // Shield protects from damage
lives--;
livesText.setText('SHIELDS: ' + lives);
// Flash player to indicate damage
LK.effects.flashObject(player, 0xFF0000, 500);
if (lives <= 0) {
gameOver();
}
}
// Game over
function gameOver() {
isGameActive = false;
LK.setScore(Math.floor(distance / 10));
LK.showGameOver();
}
// Handle screen tap/click input
game.down = function (x, y, obj) {
if (isGameActive) {
player.jump();
}
};
// Main game update loop
createInitialTrench();
game.update = function () {
if (!isGameActive) return;
// Increase game speed over time
gameSpeed += GAME_SPEED_INCREMENT;
// Update distance traveled
distance += gameSpeed;
// Update player
player.update();
// Manage trench segments
for (var i = trenchSegments.length - 1; i >= 0; i--) {
var segment = trenchSegments[i];
segment.speed = gameSpeed;
segment.update();
// If segment moves off screen, remove and create new one at the end
if (segment.x + 2048 < 0) {
segment.destroy();
trenchSegments.splice(i, 1);
var newSegment = new TrenchSegment();
newSegment.x = trenchSegments[trenchSegments.length - 1].x + 2048;
newSegment.init(gameSpeed);
trenchSegments.push(newSegment);
game.addChild(newSegment);
}
}
// Manage obstacles
obstacleTimer++;
if (obstacleTimer >= obstacleSpawnRate) {
spawnObstacle();
obstacleTimer = 0;
// Gradually decrease spawn rate as game speed increases
obstacleSpawnRate = Math.max(60, OBSTACLE_SPAWN_RATE_INITIAL - Math.floor(distance / 1000));
}
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
obstacle.speed = gameSpeed;
obstacle.update();
// Check collision with player
var isCollidingNow = obstacle.intersects(player);
if (!obstacle.lastIsColliding && isCollidingNow) {
playerHit();
LK.getSound('explosion').play();
// Create explosion effect
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
x: obstacle.x,
y: obstacle.y
});
game.addChild(explosion);
// Animate explosion
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onComplete: function onComplete() {
explosion.destroy();
}
});
// Remove obstacle after collision
obstacle.destroy();
obstacles.splice(j, 1);
continue;
}
obstacle.lastIsColliding = isCollidingNow;
// Remove if off screen
if (obstacle.x + 100 < 0) {
obstacle.destroy();
obstacles.splice(j, 1);
}
}
// Manage collectibles
collectibleTimer++;
if (collectibleTimer >= COLLECTIBLE_SPAWN_RATE) {
spawnCollectible();
collectibleTimer = 0;
}
for (var k = collectibles.length - 1; k >= 0; k--) {
var collectible = collectibles[k];
collectible.speed = gameSpeed;
collectible.update();
// Check collision with player
var isCollectingNow = collectible.intersects(player);
if (!collectible.lastIsColliding && isCollectingNow) {
// Apply effect based on type
if (collectible.type === 'forceToken') {
// Increase score
LK.setScore(LK.getScore() + 10);
// Create floating score text
var scorePopup = new Text2('+10', {
size: 50,
fill: 0x00FFFF
});
scorePopup.anchor.set(0.5, 0.5);
scorePopup.x = collectible.x;
scorePopup.y = collectible.y - 30;
game.addChild(scorePopup);
// Animate score text
tween(scorePopup, {
y: scorePopup.y - 80,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
scorePopup.destroy();
}
});
tween(collectible.graphic, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300
});
LK.getSound('collect').play();
} else if (collectible.type === 'shield') {
// Activate shield
player.activateShield(600); // Shield lasts 10 seconds (600 frames)
tween(collectible.graphic, {
alpha: 0
}, {
duration: 300
});
LK.getSound('collect').play();
}
// Remove collectible
collectible.destroy();
collectibles.splice(k, 1);
continue;
}
collectible.lastIsColliding = isCollectingNow;
// Remove if off screen
if (collectible.x + 50 < 0) {
collectible.destroy();
collectibles.splice(k, 1);
}
}
// Update HUD
updateHUD();
}; ===================================================================
--- original.js
+++ change.js
@@ -141,8 +141,30 @@
self.velocityY = 1;
}
// Visual tilt based on velocity (diving down = nose down, rising up = nose up)
xwingGraphic.rotation = self.velocityY * 0.05;
+ // Create engine trail effect (every 5 frames)
+ if (LK.ticks % 5 === 0) {
+ var trail = LK.getAsset('engineTrail', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ });
+ trail.x = self.x - 60;
+ trail.y = self.y + 5;
+ game.addChild(trail);
+ // Animate the trail to fade out
+ tween(trail, {
+ alpha: 0,
+ scaleX: 0.5,
+ scaleY: 0.5
+ }, {
+ duration: 500,
+ onComplete: function onComplete() {
+ trail.destroy();
+ }
+ });
+ }
// Shield timer
if (self.isShielded) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
@@ -154,8 +176,9 @@
// Jump method when screen is tapped
self.jump = function () {
self.velocityY = self.jumpForce;
self.isJumping = true;
+ LK.getSound('jump').play();
};
// Activate shield power-up
self.activateShield = function (duration) {
self.isShielded = true;
@@ -201,22 +224,16 @@
/****
* Game Code
****/
-// Import tween library for smooth animations
-// Laser firing sound
-// Explosion sound for collisions
-// Collectible pickup sound
-// Initialize sound effects for the game
-// Player's X-wing fighter
-// Death Star trench walls
-// Death Star trench floor
-// Enemy TIE Fighter
-// Shield power-up and visual effect
-// Wall obstacle in Death Star trench
-// Red laser beam obstacle
-// Blue Force token collectible
-// Initialize visual assets with proper Star Wars themed appearance
+// Background music
+// Sounds
+// Particle effects
+// Collectibles
+// Environment
+// Obstacles
+// Enemies
+// Player ship
// Game constants
//Minimalistic tween library which should be used for animations over time
// Initialize game assets
var GAME_SPEED_INITIAL = 8;
@@ -271,8 +288,16 @@
player = new Player();
player.x = 400;
player.y = (game.trenchTop + game.trenchBottom) / 2;
game.addChild(player);
+// Start background music with fade in
+LK.playMusic('starWarsTheme', {
+ fade: {
+ start: 0,
+ end: 0.4,
+ duration: 2000
+ }
+});
// Initialize trench segments
function createInitialTrench() {
var segments = 3; // Number of initial trench segments
var segmentWidth = 2048; // Width of each segment
@@ -388,8 +413,27 @@
var isCollidingNow = obstacle.intersects(player);
if (!obstacle.lastIsColliding && isCollidingNow) {
playerHit();
LK.getSound('explosion').play();
+ // Create explosion effect
+ var explosion = LK.getAsset('explosion', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: obstacle.x,
+ y: obstacle.y
+ });
+ game.addChild(explosion);
+ // Animate explosion
+ tween(explosion, {
+ alpha: 0,
+ scaleX: 2,
+ scaleY: 2
+ }, {
+ duration: 500,
+ onComplete: function onComplete() {
+ explosion.destroy();
+ }
+ });
// Remove obstacle after collision
obstacle.destroy();
obstacles.splice(j, 1);
continue;
@@ -417,11 +461,32 @@
// Apply effect based on type
if (collectible.type === 'forceToken') {
// Increase score
LK.setScore(LK.getScore() + 10);
- tween(collectible.graphic, {
+ // Create floating score text
+ var scorePopup = new Text2('+10', {
+ size: 50,
+ fill: 0x00FFFF
+ });
+ scorePopup.anchor.set(0.5, 0.5);
+ scorePopup.x = collectible.x;
+ scorePopup.y = collectible.y - 30;
+ game.addChild(scorePopup);
+ // Animate score text
+ tween(scorePopup, {
+ y: scorePopup.y - 80,
alpha: 0
}, {
+ duration: 1000,
+ onComplete: function onComplete() {
+ scorePopup.destroy();
+ }
+ });
+ tween(collectible.graphic, {
+ alpha: 0,
+ scaleX: 1.5,
+ scaleY: 1.5
+ }, {
duration: 300
});
LK.getSound('collect').play();
} else if (collectible.type === 'shield') {
@@ -447,16 +512,5 @@
}
}
// Update HUD
updateHUD();
- // Start background music with fade in
- if (LK.ticks === 1) {
- // Add Star Wars themed background music that fades in
- LK.playMusic('musicId', {
- fade: {
- start: 0,
- end: 0.8,
- duration: 2000
- }
- });
- }
};
\ No newline at end of file