User prompt
Make the Bird Game controls easier
User prompt
No the breaks between the pipe next to the next time
User prompt
Make the Gaps between the pipes bigger
User prompt
Make the Bird Stativ in the start screen so its not falling down
User prompt
Make the Bird moving slower. Add an start screen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ok
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: OBSTACLE_WIDTH' in or related to this line: 'if (obstacle.x + OBSTACLE_WIDTH / 2 < 0) {' Line Number: 239
User prompt
Fix Bugs of the pipes
Code edit (1 edits merged)
Please save this source code
User prompt
Trippy Flap Odyssey
Initial prompt
Ich hätte gern ein Flappy Bird Game im LSD Style mit wilden Animationen und krassen Farben.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class representing the player character
var Bird = Container.expand(function () {
var self = Container.call(this);
// Constants for physics
var GRAVITY = 1.5;
var FLAP_STRENGTH = -25; // Negative value for upward movement
var MAX_ROTATION = Math.PI / 4; // Max tilt angle (45 degrees)
var MIN_ROTATION = -Math.PI / 6; // Min tilt angle (-30 degrees)
// Bird's vertical velocity
self.velocityY = 0;
// Attach the bird graphic asset
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Public method for flapping
self.flap = function () {
self.velocityY = FLAP_STRENGTH;
LK.getSound('flapSound').play(); // Play flap sound
// Optional: Add a quick visual feedback tween on flap
tween.stop(birdGraphics); // Stop previous scale tweens
birdGraphics.scale.set(1.1, 1.1);
tween(birdGraphics.scale, {
x: 1,
y: 1
}, {
duration: 100
});
};
// Update method called every frame by the engine
self.update = function () {
// Only apply gravity if the game has started
if (gameStarted) {
// Apply gravity
self.velocityY += GRAVITY;
self.y += self.velocityY;
// Clamp position to screen bounds (leaving some margin)
if (self.y < birdGraphics.height / 2) {
self.y = birdGraphics.height / 2;
self.velocityY = 0; // Stop moving up if hitting the ceiling
}
// Note: Ground collision is handled in the main game update loop
// Apply rotation based on velocity
var targetRotation = 0;
if (self.velocityY < 0) {
// Moving up
targetRotation = MIN_ROTATION; // Tilt slightly up
} else if (self.velocityY > 10) {
// Moving down fast
// Gradually tilt down based on velocity, capped at MAX_ROTATION
targetRotation = Math.min(MAX_ROTATION, self.velocityY / 50 * MAX_ROTATION);
}
// Smoothly rotate towards the target rotation
birdGraphics.rotation += (targetRotation - birdGraphics.rotation) * 0.1;
}
};
return self;
});
// ObstaclePair class representing a top and bottom obstacle
var ObstaclePair = Container.expand(function () {
var self = Container.call(this);
// Constants for obstacles
var GAP_HEIGHT = 800; // Space between top and bottom obstacles (increased from 550)
var OBSTACLE_WIDTH = 200; // Keep consistent with asset init
// Create top and bottom obstacles
self.topObstacle = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0 // Anchor at the bottom-center
});
self.bottomObstacle = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.0 // Anchor at the top-center
});
// Property to track if score has been awarded for this pair
self.scored = false;
// Method to set the position and gap
self.setup = function (xPos, gapCenterY) {
self.x = xPos;
// Position obstacles relative to the container's position
self.topObstacle.y = gapCenterY - GAP_HEIGHT / 2;
self.bottomObstacle.y = gapCenterY + GAP_HEIGHT / 2;
// Randomize color for psychedelic effect
var randomColor = Math.random() * 0xFFFFFF;
self.topObstacle.tint = randomColor;
self.bottomObstacle.tint = randomColor;
};
// Method to check collision with the bird using built-in intersects
self.collidesWith = function (bird) {
// Check intersection between the bird container and the top/bottom obstacle assets.
// The intersects() method compares the bounding boxes of the display objects.
if (bird.intersects(self.topObstacle) || bird.intersects(self.bottomObstacle)) {
return true;
}
return false;
};
// Update method for movement
self.update = function (speed) {
self.x -= speed;
};
return self;
});
// StartScreen class to show the intro screen
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create title text
var titleText = new Text2('TRIPPY FLAP', {
size: 200,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -300;
self.addChild(titleText);
// Create instruction text
var instructionText = new Text2('Tap to Start', {
size: 120,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.y = 100;
self.addChild(instructionText);
// Create a sample bird to show on start screen
var sampleBird = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scale: 1.5
});
self.addChild(sampleBird);
// Psychedelic color and animation effects
var colorPhase = 0;
var floatPhase = 0;
self.update = function () {
// Floating animation
floatPhase += 0.05;
sampleBird.y = -100 + Math.sin(floatPhase) * 30;
// Color cycling
colorPhase += 0.02;
var r = Math.sin(colorPhase) * 127 + 128;
var g = Math.sin(colorPhase + 2) * 127 + 128;
var b = Math.sin(colorPhase + 4) * 127 + 128;
var titleColor = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
// Apply cycling colors to text
titleText.fill = titleColor;
// Pulse the instruction text
instructionText.scale.x = 1 + Math.sin(floatPhase * 2) * 0.1;
instructionText.scale.y = 1 + Math.sin(floatPhase * 2) * 0.1;
// Apply trippy effect to sample bird
sampleBird.rotation = Math.sin(floatPhase) * 0.2;
sampleBird.tint = Math.floor(255 - r) << 16 | Math.floor(255 - g) << 8 | Math.floor(255 - b);
};
return self;
});
// TrailEffect class to create psychedelic trailing effect behind objects
var TrailEffect = Container.expand(function () {
var self = Container.call(this);
// Trail properties
self.maxTrails = 10; // Maximum number of trail elements
self.fadeSpeed = 0.1; // How quickly trails fade out
self.trailElements = []; // Array to store trail elements
self.target = null; // The object to trail
self.trailSpacing = 3; // Frames between trail elements
self.frameCount = 0; // Counter for spacing
// Initialize the trail effect for a target
self.init = function (target, assetId) {
self.target = target;
self.assetId = assetId;
// Clear any existing trails
self.clearTrails();
};
// Clear all trail elements
self.clearTrails = function () {
for (var i = 0; i < self.trailElements.length; i++) {
if (self.trailElements[i].parent) {
self.trailElements[i].parent.removeChild(self.trailElements[i]);
}
}
self.trailElements = [];
};
// Update the trail effect
self.update = function () {
if (!self.target) {
return;
}
self.frameCount++;
// Add new trail element at intervals
if (self.frameCount >= self.trailSpacing) {
self.frameCount = 0;
// Create new trail element
var trail = LK.getAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5,
x: self.target.x,
y: self.target.y,
rotation: self.target.rotation,
alpha: 0.6
});
// Apply random psychedelic color
trail.tint = Math.random() * 0xFFFFFF;
// Add to game and track
game.addChild(trail);
self.trailElements.push(trail);
// Remove oldest trail if we exceed max
if (self.trailElements.length > self.maxTrails) {
var oldest = self.trailElements.shift();
if (oldest.parent) {
oldest.parent.removeChild(oldest);
}
}
}
// Fade out all trail elements
for (var i = 0; i < self.trailElements.length; i++) {
self.trailElements[i].alpha -= self.fadeSpeed;
self.trailElements[i].scale.x += 0.03;
self.trailElements[i].scale.y += 0.03;
// Remove if fully faded
if (self.trailElements[i].alpha <= 0) {
if (self.trailElements[i].parent) {
self.trailElements[i].parent.removeChild(self.trailElements[i]);
}
self.trailElements.splice(i, 1);
i--;
}
}
};
return self;
});
// WaveEffect class to create psychedelic visual distortions
var WaveEffect = Container.expand(function () {
var self = Container.call(this);
// Effect properties
self.amplitude = 20; // Wave height
self.frequency = 0.005; // Wave frequency
self.speed = 0.05; // Wave speed
self.colorSpeed = 0.01; // Color change speed
self.phase = 0; // Current phase of the wave
self.colorPhase = 0; // Current phase of the color cycle
// Apply wave distortion to a target object
self.applyDistortion = function (target) {
if (!target) {
return;
}
// Update phases
self.phase += self.speed;
self.colorPhase += self.colorSpeed;
// Apply wave effect to scale/rotation
target.scale.x = 1 + Math.sin(self.phase) * 0.1;
target.scale.y = 1 + Math.cos(self.phase * 1.3) * 0.1;
target.rotation = Math.sin(self.phase * 0.7) * 0.1;
// Apply trippy color effect
var r = Math.sin(self.colorPhase) * 127 + 128;
var g = Math.sin(self.colorPhase + 2) * 127 + 128;
var b = Math.sin(self.colorPhase + 4) * 127 + 128;
var color = r << 16 | g << 8 | b;
target.tint = color;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a001a // Start with a dark purple background
});
/****
* Game Code
****/
// Game constants
// Define assets for the game. These will be created automatically by the engine.
// Bird asset
// Obstacle asset (will be tinted/resized later)
// Sound for flapping (optional, but good practice)
// Sound for passing obstacle (optional)
// Sound for collision (optional)
// Include the tween plugin for animations and effects
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var OBSTACLE_SPEED = 5; // Reduced from 8 to make the bird appear to move slower
var OBSTACLE_SPAWN_RATE = 180; // Ticks between spawns (approx 3 seconds at 60fps)
var OBSTACLE_START_X = GAME_WIDTH + 150; // Start spawning off-screen right
var OBSTACLE_MIN_Y = 600; // Min center Y for the gap
var OBSTACLE_MAX_Y = GAME_HEIGHT - 600; // Max center Y for the gap
// Game variables
var bird;
var obstacles = [];
var spawnTimer = 0;
var isGameOver = false;
var gameStarted = false; // New variable to track if game has started
var backgroundChangeTimer = 0;
var backgroundTween = null; // To manage background color tween
var startScreen; // Variable to hold the start screen
// Psychedelic effect variables
var waveEffect;
var birdTrail;
var globalDistortionPhase = 0;
var screenShakeIntensity = 0;
// Score display with psychedelic styling
var scoreTxt = new Text2('0', {
size: 180,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Position score text slightly down from the top center, avoiding top-left corner
scoreTxt.y = 100;
// Setup score text color animation
LK.setInterval(function () {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var randomColor = r << 16 | g << 8 | b;
// Animate score text color change
tween(scoreTxt, {
fill: randomColor
}, {
duration: 500,
easing: tween.easeInOut
});
// Add pulsating scale effect
tween(scoreTxt.scale, {
x: 1.2,
y: 1.2
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt.scale, {
x: 1.0,
y: 1.0
}, {
duration: 250,
easing: tween.easeIn
});
}
});
}, 1000);
// Initialize bird
bird = new Bird();
bird.x = GAME_WIDTH / 4; // Start position
bird.y = GAME_HEIGHT / 2;
game.addChild(bird);
// Initialize psychedelic effects
waveEffect = new WaveEffect();
birdTrail = new TrailEffect();
birdTrail.init(bird, 'bird');
// Handle player input (flap)
game.down = function (x, y, obj) {
if (!gameStarted) {
// Start the game on first tap
gameStarted = true;
// Remove start screen with a fade out effect
tween(startScreen, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
game.removeChild(startScreen);
}
});
// Reset score
LK.setScore(0);
scoreTxt.setText('0');
// Start game with a small delay to allow fade transition
LK.setTimeout(function () {
// Show score text
scoreTxt.alpha = 1;
}, 500);
} else if (!isGameOver) {
bird.flap();
// Add extra psychedelic effects on flap
screenShakeIntensity = 10; // Start screen shake
// Flash screen with random color
var flashColor = Math.random() * 0xFFFFFF;
LK.effects.flashScreen(flashColor, 100);
}
};
// Function to spawn a new obstacle pair
function spawnObstacle() {
var newObstacle = new ObstaclePair();
var gapCenterY = Math.random() * (OBSTACLE_MAX_Y - OBSTACLE_MIN_Y) + OBSTACLE_MIN_Y;
newObstacle.setup(OBSTACLE_START_X, gapCenterY);
obstacles.push(newObstacle);
game.addChild(newObstacle);
}
// Function for psychedelic background effect
function changeBackgroundColor() {
if (backgroundTween) {
tween.stop(game); // Stop existing background tween if any
}
// Generate vivid psychedelic colors - using high saturation/values
var h = Math.random();
var s = 0.8 + Math.random() * 0.2; // High saturation (0.8-1.0)
var v = 0.8 + Math.random() * 0.2; // High value (0.8-1.0)
// HSV to RGB conversion for more vibrant colors
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
var r, g, b;
switch (i % 6) {
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
}
var nextColor = Math.floor(r * 255) << 16 | Math.floor(g * 255) << 8 | Math.floor(b * 255);
backgroundTween = tween(game, {
backgroundColor: nextColor
}, {
duration: 800,
// Faster transitions for more trippy effect
easing: tween.easeInOut,
onFinish: function onFinish() {
backgroundTween = null;
} // Clear the tween reference on finish
});
}
// Game update loop
game.update = function () {
if (!gameStarted) {
// Only update start screen when game hasn't started
startScreen.update();
return;
}
if (isGameOver) {
return;
} // Stop updates if game over
// Update global distortion phase
globalDistortionPhase += 0.02;
// Apply screen shake effect (gradually reduces intensity)
if (screenShakeIntensity > 0) {
game.x = (Math.random() * 2 - 1) * screenShakeIntensity;
game.y = (Math.random() * 2 - 1) * screenShakeIntensity;
screenShakeIntensity *= 0.9;
if (screenShakeIntensity < 0.5) {
screenShakeIntensity = 0;
game.x = 0;
game.y = 0;
}
}
// Update bird and psychedelic effects
bird.update(); // Calls bird's internal update for physics
waveEffect.applyDistortion(bird.children[0]);
birdTrail.update();
// Check ground collision
if (bird.y >= GAME_HEIGHT - bird.children[0].height / 2) {
LK.getSound('hitSound').play();
LK.effects.flashScreen(0xFF0000, 300); // Flash red on hit
isGameOver = true;
LK.showGameOver();
return; // Stop further processing this frame
}
// Update obstacles
spawnTimer++;
if (spawnTimer >= OBSTACLE_SPAWN_RATE) {
spawnObstacle();
spawnTimer = 0;
}
// Move and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.update(OBSTACLE_SPEED); // Move obstacle left
// Check for collision with bird
if (obstacle.collidesWith(bird)) {
LK.getSound('hitSound').play();
LK.effects.flashObject(bird, 0xFF0000, 300); // Flash bird red
isGameOver = true;
LK.showGameOver();
return; // Stop further processing this frame
}
// Check for scoring
if (!obstacle.scored && obstacle.x + obstacle.topObstacle.width / 2 < bird.x) {
obstacle.scored = true;
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
LK.getSound('scoreSound').play();
// Optional: Flash score text or screen briefly on score
LK.effects.flashObject(scoreTxt, 0x00FF00, 150);
}
// Remove obstacles that are off-screen left
// Obstacle pair's x is its center. Remove when its right edge (x + width/2) is less than 0.
// Use the actual width of the obstacle graphic instance.
if (obstacle.x + obstacle.topObstacle.width / 2 < 0) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Psychedelic background effect timer
backgroundChangeTimer++;
if (backgroundChangeTimer >= 60) {
// Change color every second (approx)
changeBackgroundColor();
backgroundChangeTimer = 0;
}
// Apply intense psychedelic effects to obstacles
obstacles.forEach(function (obs, index) {
// More intense distortion effects
var individualPhase = globalDistortionPhase + index * 0.2;
// Wild scaling with different frequencies for each obstacle
var pulseScaleX = 1 + Math.sin(individualPhase * 1.1) * 0.1;
var pulseScaleY = 1 + Math.cos(individualPhase * 0.9) * 0.15;
// Apply to top obstacle
obs.topObstacle.scale.x = pulseScaleX;
obs.topObstacle.scale.y = pulseScaleY;
obs.topObstacle.rotation = Math.sin(individualPhase * 0.7) * 0.1;
// Apply to bottom obstacle with slight phase difference
obs.bottomObstacle.scale.x = pulseScaleX;
obs.bottomObstacle.scale.y = pulseScaleY;
obs.bottomObstacle.rotation = Math.cos(individualPhase * 0.7) * 0.1;
// Cycle colors rapidly based on time and position
var r = Math.sin(individualPhase) * 127 + 128;
var g = Math.sin(individualPhase + 2) * 127 + 128;
var b = Math.sin(individualPhase + 4) * 127 + 128;
var topColor = r << 16 | g << 8 | b;
var bottomColor = 255 - r << 16 | 255 - g << 8 | 255 - b;
obs.topObstacle.tint = topColor;
obs.bottomObstacle.tint = bottomColor;
});
};
// Start the first background color change
changeBackgroundColor();
// Initialize start screen
startScreen = new StartScreen();
startScreen.x = GAME_WIDTH / 2;
startScreen.y = GAME_HEIGHT / 2;
game.addChild(startScreen);
// Hide score text initially
scoreTxt.alpha = 0; ===================================================================
--- original.js
+++ change.js
@@ -285,9 +285,9 @@
// Include the tween plugin for animations and effects
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var OBSTACLE_SPEED = 5; // Reduced from 8 to make the bird appear to move slower
-var OBSTACLE_SPAWN_RATE = 120; // Ticks between spawns (approx 2 seconds at 60fps)
+var OBSTACLE_SPAWN_RATE = 180; // Ticks between spawns (approx 3 seconds at 60fps)
var OBSTACLE_START_X = GAME_WIDTH + 150; // Start spawning off-screen right
var OBSTACLE_MIN_Y = 600; // Min center Y for the gap
var OBSTACLE_MAX_Y = GAME_HEIGHT - 600; // Max center Y for the gap
// Game variables