User prompt
black circle appear like blackhole slowly
User prompt
just move like spiral dont vibrate sprite ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fix the vibration when ufo pulling into ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a black circle back to blackhole layer
User prompt
fix vibration when spiral tween and tween start at same position not right there ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pull ufo with spiral shape and fix position at the center ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
wait game over screen 1 more second and change pull type like a spiral whirlpool ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fix pull after fall ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
stop shake ufo after die
User prompt
dont shake ufo just pull spiral like into center of black hole
User prompt
shake very slowly ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
shake slowly and reduce time 2 to 1 second ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
wait game over screen 2 sec more and shake ufo in blackhole ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
delete when dying red dead effect
User prompt
black hole appear slowly and pull ufo slowly ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
blackhole layer is under the bird layer
User prompt
when dying move bird slowly to black hole and until wait play again screen ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when dying create blackhole image center of the screen
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'Cubic')' in or related to this line: 'tween.to(blackHole, {' Line Number: 492
User prompt
Please fix the bug: 'TypeError: tween.to is not a function' in or related to this line: 'tween.to(blackHole, {' Line Number: 492
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'Cubic')' in or related to this line: 'tween.to(blackHole, {' Line Number: 492
User prompt
when dying open black hole asset on the screen center and bird pull into black hole effect
User prompt
change game name font size bigger x2
User prompt
move up game name 1000 px above tap to start text
User prompt
move up game name 800 px up
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); // Attach bird asset (ellipse, yellow) var birdAsset = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Physics properties self.velocityY = 0; self.gravity = 0.5; // Lower gravity per frame for slower fall self.flapStrength = -20; // Lower flap strength for gentler jump // Bird size for collision self.radius = birdAsset.width * 0.45; // Flap method self.flap = function () { self.velocityY = self.flapStrength; }; // Update method (called every tick) self.update = function () { // Only apply gravity and velocity if gameStarted is true if (typeof gameStarted !== "undefined" && gameStarted) { self.velocityY += self.gravity; self.y += self.velocityY; } // Clamp rotation for visual feedback (optional) var maxAngle = Math.PI / 4; var minAngle = -Math.PI / 6; var angle = self.velocityY / 40 * maxAngle; if (angle > maxAngle) { angle = maxAngle; } if (angle < minAngle) { angle = minAngle; } birdAsset.rotation = angle; }; return self; }); // PipePair class (top and bottom pipes as a pair) var PipePair = Container.expand(function () { var self = Container.call(this); // Pipe properties self.pipeWidth = 80; // Start very thin, will be set wider on spawn self.gapHeight = 520; // Will be randomized a bit self.speed = 12; // Speed at which pipes move left // Top pipe (cloud) self.topPipe = self.attachAsset('cloud', { anchorX: 0, anchorY: 1, width: self.pipeWidth, height: 300, // cloud height y: 0, x: 0 }); // Bottom pipe (mountain) self.bottomPipe = self.attachAsset('mountain', { anchorX: 0, anchorY: 0, width: self.pipeWidth, height: 600, // mountain height y: 0, x: 0 }); // Used to track if score was already given for this pipe self.passed = false; // Set pipes' vertical positions self.setGap = function (gapY, gapHeight) { self.gapHeight = gapHeight; // Top cloud: position at gapY, stretch to fill from top to gapY self.topPipe.y = gapY; self.topPipe.height = Math.max(1, gapY); // cloud height = gapY, min 1 self.topPipe.width = self.pipeWidth; // Bottom mountain: position at gapY+gapHeight, stretch to fill to bottom self.bottomPipe.y = gapY + gapHeight; self.bottomPipe.height = Math.max(1, 2732 - (gapY + gapHeight)); // mountain height self.bottomPipe.width = self.pipeWidth; }; // Update method self.update = function () { self.x -= self.speed; }; // Collision check with bird self.collidesWith = function (bird) { // Bird's bounding circle var bx = bird.x; var by = bird.y; var r = bird.radius; // Top pipe rectangle var topRect = { x: self.x, y: 0, w: self.pipeWidth, h: self.topPipe.y }; // Bottom pipe rectangle var bottomRect = { x: self.x, y: self.bottomPipe.y, w: self.pipeWidth, h: 2732 - self.bottomPipe.y }; // Helper: circle-rect collision function circleRectCollide(cx, cy, cr, rx, ry, rw, rh) { var closestX = Math.max(rx, Math.min(cx, rx + rw)); var closestY = Math.max(ry, Math.min(cy, ry + rh)); var dx = cx - closestX; var dy = cy - closestY; return dx * dx + dy * dy < cr * cr; } if (circleRectCollide(bx, by, r, topRect.x, topRect.y, topRect.w, topRect.h)) { return true; } if (circleRectCollide(bx, by, r, bottomRect.x, bottomRect.y, bottomRect.w, bottomRect.h)) { return true; } return false; }; // Has bird passed this pipe? (for scoring) self.isPassedBy = function (bird) { return !self.passed && self.x + self.pipeWidth < bird.x - bird.radius; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- No dynamic ground/upground height/width/distance here; handled in update below -- var background = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(background); // --- Cloud (top pipe) - white, wide, ellipse // Mountain (bottom pipe) - green, wide, triangle-like // --- Game Variables --- // Tween plugin for animations (not strictly needed for MVP, but included for future use) // --- Asset Initialization (shapes) --- var bird; var pipes = []; var pipeSpawnTimer = 0; var pipeInterval = 90; // Frames between pipes (1.5s at 60fps) var score = 0; var scoreTxt; var ground; var gameStarted = false; var gameOver = false; // --- Tap to Start Overlay --- var tapToStartTxt = new Text2('Tap to Start', { size: 140, fill: 0xffffff }); tapToStartTxt.anchor.set(0.5, 1); // anchor bottom center tapToStartTxt.x = 2048 / 2; // Move down so the layer sits on the ground, with a gap above ground var tapToStartGroundGap = 60; // distance above ground var tapToStartMaxY = 2732 - 920 - tapToStartGroundGap; // 120 is base ground height tapToStartTxt.y = tapToStartMaxY; tapToStartTxt.visible = false; // Add "How to play" instructions below the Tap to Start text var howToPlayTxt = new Text2('Tap to power up and guide your UFO through doors.\nAvoid galactic doors and see how far you can go!', { size: 70, fill: 0xffffff }); howToPlayTxt.anchor.set(0.5, 0); // anchor top center howToPlayTxt.x = 2048 / 2; howToPlayTxt.y = tapToStartTxt.y + 40; // 40px below tapToStartTxt // Remove from game if already added, then add to top if (tapToStartTxt.parent) { tapToStartTxt.parent.removeChild(tapToStartTxt); } game.addChild(tapToStartTxt); game.setChildIndex(tapToStartTxt, game.children.length - 1); // Always on top if (howToPlayTxt.parent) { howToPlayTxt.parent.removeChild(howToPlayTxt); } game.addChild(howToPlayTxt); game.setChildIndex(howToPlayTxt, game.children.length - 1); // --- GUI Score Display --- if (typeof scoreTxt !== "undefined" && scoreTxt && scoreTxt.parent) { scoreTxt.parent.removeChild(scoreTxt); scoreTxt.destroy(); } if (typeof scoreCircleBg !== "undefined" && scoreCircleBg && scoreCircleBg.parent) { scoreCircleBg.parent.removeChild(scoreCircleBg); scoreCircleBg.destroy(); } // Create a perfect circle background for the score and center it scoreCircleBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: LK.gui.width / 2, y: 80 + 45, // 45 is half of 90 (score text size), so circle is centered behind text scaleX: 0.8, scaleY: 0.8 }); LK.gui.addChild(scoreCircleBg); scoreTxt = new Text2('0', { size: 90, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0.5); // Center score horizontally at the top, vertically centered in the circle scoreTxt.x = LK.gui.width / 2; scoreTxt.y = 80 + 45; LK.gui.addChild(scoreTxt); // Add game name text under the score in big font, but on overlay layer (with tapToStartTxt) var gameNameTxt = new Text2('Galactic Doors', { size: 220, fill: 0xffffff, font: "'Orbitron', 'Audiowide', 'Space Mono', 'GillSans-Bold', Impact, 'Arial Black', Tahoma" }); gameNameTxt.anchor.set(0.5, 0); // Place it under the score circle, with a gap, but on overlay gameNameTxt.x = 2048 / 2; gameNameTxt.y = tapToStartTxt.y - 1000; // 1000px above tapToStartTxt (visually grouped) gameNameTxt.visible = false; // Remove from game if already added, then add to top if (gameNameTxt.parent) { gameNameTxt.parent.removeChild(gameNameTxt); } game.addChild(gameNameTxt); game.setChildIndex(gameNameTxt, game.children.length - 1); // Move howToPlayTxt to overlay and hide initially howToPlayTxt.x = 2048 / 2; howToPlayTxt.y = tapToStartTxt.y + 40; howToPlayTxt.visible = false; if (howToPlayTxt.parent) { howToPlayTxt.parent.removeChild(howToPlayTxt); } game.addChild(howToPlayTxt); game.setChildIndex(howToPlayTxt, game.children.length - 1); // --- Ground (for collision) --- ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: 2732 - 120 }); game.addChild(ground); // --- Mirrored ground at top (now called upground) --- var upground = LK.getAsset('ground', { anchorX: 0, anchorY: 1, x: 0, y: 0, scaleY: -1 }); game.addChild(upground); // --- Minimum ground width (never narrower than mountain/cloud asset) --- var minGroundWidth = 800; // same as mountain/cloud asset width var maxGroundWidth = 2048; // full width // --- Bird --- bird = new Bird(); game.addChild(bird); // Start position: horizontally 30% from left, vertically centered bird.x = 2048 * 0.3; bird.y = 2732 / 2; // --- Reset function --- function resetGame() { // Remove pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Ensure background is always at the back if (background && background.parent) { background.parent.setChildIndex(background, 0); } // Reset bird bird.x = 2048 * 0.3; bird.y = 2732 / 2; bird.velocityY = 0; // Reset score score = 0; scoreTxt.setText(score); // Reset timers pipeSpawnTimer = 0; gameStarted = false; gameOver = false; if (tapToStartTxt) { tapToStartTxt.visible = true; // Remove and re-add to ensure it's on top if (tapToStartTxt.parent) { tapToStartTxt.parent.removeChild(tapToStartTxt); } game.addChild(tapToStartTxt); game.setChildIndex(tapToStartTxt, game.children.length - 1); } if (gameNameTxt) { gameNameTxt.visible = true; if (gameNameTxt.parent) { gameNameTxt.parent.removeChild(gameNameTxt); } game.addChild(gameNameTxt); game.setChildIndex(gameNameTxt, game.children.length - 1); } if (howToPlayTxt) { howToPlayTxt.visible = true; if (howToPlayTxt.parent) { howToPlayTxt.parent.removeChild(howToPlayTxt); } game.addChild(howToPlayTxt); game.setChildIndex(howToPlayTxt, game.children.length - 1); } } // --- Start game on first tap --- game.down = function (x, y, obj) { if (gameOver) { return; } if (!gameStarted) { gameStarted = true; if (tapToStartTxt) { tapToStartTxt.visible = false; } if (gameNameTxt) { gameNameTxt.visible = false; } if (howToPlayTxt) { howToPlayTxt.visible = false; } bird.flap(); return; } bird.flap(); }; // --- Main update loop --- game.update = function () { if (gameOver) { return; } // Bird physics if (gameStarted) { bird.update(); } // Clamp bird to top of screen if (bird.y - bird.radius < 0) { bird.y = bird.radius; bird.velocityY = 0; } // Pipe spawning if (gameStarted) { pipeSpawnTimer++; if (pipeSpawnTimer >= pipeInterval) { pipeSpawnTimer = 0; // Mountain-like curve for gapY using a sine wave var minGapY = 350; var maxGapY = 2732 - 120 - 350 - 700; var t = (score + pipes.length) * 0.5; // t increases as more pipes spawn var amplitude = (maxGapY - minGapY) / 2; var centerY = minGapY + amplitude; var gapY = centerY + Math.sin(t) * amplitude; gapY = Math.max(minGapY, Math.min(maxGapY, gapY)); var gapHeight = 650 + Math.floor(Math.random() * 120); // 650-770 px (increased gap) // Calculate pipe width based on score: start thin, widen much more slowly var minPipeWidth = 80; var maxPipeWidth = 880; // Use a slower growth curve (e.g. score/120 instead of score/40) var pipeWidth = minPipeWidth + Math.floor((maxPipeWidth - minPipeWidth) * Math.min(1, score / 120)); // Clamp to max if (pipeWidth > maxPipeWidth) { pipeWidth = maxPipeWidth; } if (pipeWidth < minPipeWidth) { pipeWidth = minPipeWidth; } var pipePair = new PipePair(); pipePair.pipeWidth = pipeWidth; pipePair.topPipe.width = pipeWidth; pipePair.bottomPipe.width = pipeWidth; pipePair.x = 2048; pipePair.setGap(gapY, gapHeight); pipes.push(pipePair); game.addChild(pipePair); } } // Update pipes, check for collisions and scoring for (var i = pipes.length - 1; i >= 0; i--) { var pipe = pipes[i]; if (gameStarted) { pipe.update(); } // Remove pipes that are off screen if (pipe.x + pipe.pipeWidth < 0) { pipe.destroy(); pipes.splice(i, 1); continue; } // Collision if (gameStarted && pipe.collidesWith(bird)) { endGame(); return; } // Scoring if (gameStarted && pipe.isPassedBy(bird)) { score += 1; scoreTxt.setText(score); LK.getSound('score').play(); pipe.passed = true; } } // --- Move upground to upper edge and ground to lower edge, fixed positions --- if (ground && upground) { // Increase ground height as score increases, but clamp to a max (e.g. 600) var baseGroundHeight = 120; var maxGroundHeight = 600; // For every 5 points, increase by 12px (tune as needed) var groundHeight = baseGroundHeight + Math.floor(score / 5) * 12; if (groundHeight > maxGroundHeight) { groundHeight = maxGroundHeight; } // Always full width, always at x=0 ground.x = 0; upground.x = 0; ground.width = 2048; upground.width = 2048; ground.height = groundHeight; upground.height = groundHeight; // upground at very top edge upground.y = 0; // ground at very bottom edge ground.y = 2732 - groundHeight; } // Ground collision if (gameStarted && bird.y + bird.radius >= ground.y) { bird.y = ground.y - bird.radius; endGame(); return; } // Upground (top ground) collision if (gameStarted && bird.y - bird.radius <= upground.y + upground.height) { bird.y = upground.y + upground.height + bird.radius; endGame(); return; } }; // --- End game --- function endGame() { if (gameOver) { return; } gameOver = true; bird.velocityY = 0; // Stop bird movement after death // Add a black circle under the blackhole layer on death, fade in like a blackhole var blackCircle = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.5, scaleY: 2.5, tint: 0x000000 }); blackCircle.alpha = 0; var birdIndex = game.children.indexOf(bird); if (birdIndex > -1) { game.addChildAt(blackCircle, birdIndex); } else { game.addChild(blackCircle); } // Fade in the black circle slowly (like a blackhole) tween(blackCircle, { alpha: 1 }, { duration: 900, easing: tween.cubicInOut }); // Show blackhole image at center of screen, under the bird layer var blackhole = LK.getAsset('blackhole', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); blackhole.alpha = 0; // Start invisible var blackholeIndex = game.children.indexOf(bird); if (blackholeIndex > -1) { game.addChildAt(blackhole, blackholeIndex); } else { game.addChild(blackhole); } // Removed red flash effect on death // Fade in blackhole slowly, then spiral-pull bird to center and fix position tween(blackhole, { alpha: 1 }, { duration: 900, easing: tween.cubicInOut, onFinish: function onFinish() { // Spiral parameters var spiralSteps = 60; // 60 frames for spiral var spiralDuration = 1200; // ms // Capture bird's position at spiral start to avoid vibration var spiralStartX = bird.x; var spiralStartY = bird.y; var centerX = 2048 / 2; var centerY = 2732 / 2; var startAngle = Math.atan2(spiralStartY - centerY, spiralStartX - centerX); var radius = Math.sqrt((spiralStartX - centerX) * (spiralStartX - centerX) + (spiralStartY - centerY) * (spiralStartY - centerY)); var spiralTick = 0; // Stop any previous tweens on bird tween.stop(bird); // Spiral animation using manual tweening (only update position, do not tween other sprite properties) function spiralStep() { // Use t in [0,1] var t = spiralTick / spiralSteps; // Easing for spiral progress var easeT = tween.cubicInOut(t); // Spiral angle increases as t increases, start from startAngle var spiralAngle = startAngle + 4 * Math.PI * easeT; // 2 full turns // Radius shrinks to 0 var r = radius * (1 - easeT); // Calculate new position along spiral var x = centerX + r * Math.cos(spiralAngle); var y = centerY + r * Math.sin(spiralAngle); // Only update position, do not tween scale/rotation/etc bird.x = x; bird.y = y; spiralTick++; if (spiralTick <= spiralSteps) { LK.setTimeout(spiralStep, spiralDuration / spiralSteps); } else { // Snap to exact center bird.x = centerX; bird.y = centerY; LK.showGameOver(); } } spiralStep(); } }); } // --- Reset on game over (handled by LK) --- LK.on('gameover', function () { resetGame(); }); // --- Initial reset --- resetGame(); // --- Pause Button --- // Place pause button at right, same vertical as scoreTxt var pauseBtn = new Text2('II', { size: 120, fill: 0xffffff }); pauseBtn.anchor.set(1, 0); // Place at top right, just below top edge (keep 80px from top for visibility) pauseBtn.x = 2048 - 60; // 60px from right edge pauseBtn.y = 80; LK.gui.addChild(pauseBtn); // Pause event (optional: you may want to hook this up to LK.pauseGame if available) // pauseBtn.down = function(x, y, obj) { // LK.pauseGame(); // };
===================================================================
--- original.js
+++ change.js
@@ -464,9 +464,9 @@
return;
}
gameOver = true;
bird.velocityY = 0; // Stop bird movement after death
- // Add a black circle under the blackhole layer on death
+ // Add a black circle under the blackhole layer on death, fade in like a blackhole
var blackCircle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
@@ -474,15 +474,22 @@
scaleX: 2.5,
scaleY: 2.5,
tint: 0x000000
});
- blackCircle.alpha = 1;
+ blackCircle.alpha = 0;
var birdIndex = game.children.indexOf(bird);
if (birdIndex > -1) {
game.addChildAt(blackCircle, birdIndex);
} else {
game.addChild(blackCircle);
}
+ // Fade in the black circle slowly (like a blackhole)
+ tween(blackCircle, {
+ alpha: 1
+ }, {
+ duration: 900,
+ easing: tween.cubicInOut
+ });
// Show blackhole image at center of screen, under the bird layer
var blackhole = LK.getAsset('blackhole', {
anchorX: 0.5,
anchorY: 0.5,
galaxy theme background. In-Game asset. 2d. High contrast. No shadows
only black hole simple no background. In-Game asset. 2d. High contrast. No shadows
galactic portals looks like a black hole. In-Game asset. 2d. High contrast. No shadows
galactic portals looks like a long straight pillar . In-Game asset. 2d. High contrast. No shadows
create an ufo without legs only frizby shape. In-Game asset. 2d. High contrast. No shadows