User prompt
roket ekranın alt kısmında yer alır, roket ucar gibi gözüküyor ama aslında arka plan aşağıya doğru kayacak
Code edit (1 edits merged)
Please save this source code
User prompt
Rocket Fuel Rush
Initial prompt
bir oyun yapmak istiyorum, bir roket var, yukarı doğru uçuyor, ama uçmak için, roketin yakıta ihtiyacı var, roket önüne gelen yakıtları alamazsa, düşer ve oyun biter, yakıtları toplaması gerekiyor, ama tabi yukarıya çıkarken, bazı engeller karşısına çıkacak, ve engelle çarparsa, oyun yine biter. roketin kaç metere yukarıya çıktığını bilmek için bir metre sayacı olması lazım, best score ekranda kalacak, sayaç her düştüğünde sıfırlanacak, roketi sağ sola kaydırmak için rokete basılı tutup sağ sola kaydırmak gerekir
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { best: 0 }); /**** * Classes ****/ // Fuel class var Fuel = Container.expand(function () { var self = Container.call(this); var fuelGfx = self.attachAsset('fuel', { anchorX: 0.5, anchorY: 0.5 }); self.width = fuelGfx.width; self.height = fuelGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Obstacle1 class (obstacle1 asset, for 10000-19999m) var Obstacle1 = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle1', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Obstacle2 class (different look/behavior for >20000m) var Obstacle2 = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle2', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Obstacle3 class (for >20000m, new look/behavior) var Obstacle3 = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle3', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Obstacle4 class (for >40000m, new look/behavior) var Obstacle4 = Container.expand(function () { var self = Container.call(this); var obsGfx = self.attachAsset('obstacle4', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsGfx.width; self.height = obsGfx.height; self.update = function () { // Movement handled in game.update }; return self; }); // Rocket (player) class var Rocket = Container.expand(function () { var self = Container.call(this); // Attach rocket asset, centered var rocketGfx = self.attachAsset('rocket', { anchorX: 0.5, anchorY: 0.5 }); self.width = rocketGfx.width; self.height = rocketGfx.height; // Rocket state self.fuel = 100; self.alive = true; // No per-frame update needed (movement handled in game.update) self.update = function () {}; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Biome/level state --- var currentBiome = 1; var biomeTransitioning = false; var biomeTransitionDistance = 10000; // --- Biome scaling --- // At biome 1: scale = 1.0, biome 2: 0.8, biome 3: 0.65, biome 4: 0.55, biome 5+: 0.45 (minimum) function getBiomeScale(biome) { // Every 10000m, scale decreases by 5% (0.95x), looping every 40000m // biome: 1,2,3,4,5... (biome 1 = 0-9999m, biome 2 = 10000-19999m, etc) // At biome 1: 1.0, biome 2: 0.95, biome 3: 0.9025, biome 4: 0.857375, biome 5: 0.81450625, then repeat var biomeIndex = (biome - 1) % 4; // 0,1,2,3,0,1,2,3... var scale = 1.0; for (var i = 0; i < biomeIndex; ++i) { scale *= 0.95; } return scale; } var currentBiomeScale = 1.0; // Explosion effect (for flash) // Obstacle // Fuel // Rocket (player) // --- Global variables --- var rocket; var fuels = []; var obstacles = []; var dragStartX = null; var dragRocketStartX = null; var isDragging = false; var fuelTimer = 0; var obstacleTimer = 0; var distance = 0; // var best = typeof storage.best === "number" && storage.best > 0 ? storage.best : 0; var fuelDepleteRate = 0.18; // per tick var rocketSpeed = 8; // px per tick (vertical) var fuelSpawnInterval = 90; // ticks var obstacleSpawnInterval = 110; // ticks var minX = 100, maxX = 2048 - 100; var minY = 200, maxY = 2732 - 200; var fuelMax = 100; var fuelAmount = fuelMax * 0.2; // Yakıt toplandığında %20 doldurur var gameStarted = false; // --- UI --- var distanceTxt = new Text2('0 m', { size: 90, fill: 0xFFFFFF }); distanceTxt.anchor.set(0.5, 0); LK.gui.top.addChild(distanceTxt); // Best score UI (bottom left) var bestScore = typeof storage.best === "number" && storage.best > 0 ? storage.best : 0; var bestTxt = new Text2('best: ' + Math.floor(bestScore) + ' m', { size: 70, fill: 0xffffff, fontWeight: 'bold' }); bestTxt.anchor.set(0, 1); // bottom left LK.gui.bottomLeft.addChild(bestTxt); bestTxt.x = 20; bestTxt.y = -20; // Last score UI (bottom left, below best) var lastScore = 0; var lastTxt = new Text2('last: 0 m', { size: 60, fill: 0xffffff }); lastTxt.anchor.set(0, 1); LK.gui.bottomLeft.addChild(lastTxt); lastTxt.x = 20; lastTxt.y = bestTxt.y + bestTxt.height + 10; // Fuel bar (simple text) var fuelTxt = new Text2('Yakıt: 100%', { size: 60, fill: 0xff2222 }); fuelTxt.anchor.set(0.5, 0); // Place fuelTxt below distanceTxt (metre göstergesinin altında) LK.gui.top.addChild(fuelTxt); fuelTxt.y = distanceTxt.height + 10; // --- Fuel Bar UI --- // Black border (slightly bigger than background) var fuelBarBorder = LK.getAsset('backgroundImage', { width: 68, height: 408, x: 0, y: 0, anchorX: 0.5, anchorY: 0.0 }); fuelBarBorder.tint = 0x000000; fuelBarBorder.alpha = 1.0; // Bar background (light gray, inside border) var fuelBarBg = LK.getAsset('backgroundImage', { width: 60, height: 400, x: 0, y: 4, anchorX: 0.5, anchorY: 0.0 }); fuelBarBg.tint = 0xeeeeee; fuelBarBg.alpha = 1.0; // Bar fill (will be resized from top down) var fuelBarFill = LK.getAsset('backgroundImage', { width: 44, height: 392, x: 0, y: 8, anchorX: 0.5, anchorY: 0.0 }); fuelBarFill.tint = 0x00ff00; // Start as vivid green fuelBarFill.alpha = 1.0; // Container for bar var fuelBarContainer = new Container(); fuelBarContainer.addChild(fuelBarBorder); fuelBarContainer.addChild(fuelBarBg); fuelBarContainer.addChild(fuelBarFill); // Position bar at top right, with margin from top and right fuelBarContainer.x = 2048 - 80; fuelBarContainer.y = 100; // Add to game (not GUI, so it scales with gameplay) game.addChild(fuelBarContainer); // (bestTxt positioning removed) // --- Helper functions --- function resetGame() { // Remove old objects if (rocket) rocket.destroy(); for (var i = 0; i < fuels.length; ++i) fuels[i].destroy(); for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy(); fuels = []; obstacles = []; // Reset variables distance = 0; fuelTimer = 0; obstacleTimer = 0; currentBiome = 1; biomeTransitioning = false; // background and biome2Background removed // (best score logic removed) // Create rocket rocket = new Rocket(); rocket.x = 2048 / 2; rocket.y = 2732 - 350; rocket.scaleX = currentBiomeScale; rocket.scaleY = currentBiomeScale; if (rocket.children && rocket.children.length > 0) { rocket.children[0].scaleX = currentBiomeScale; rocket.children[0].scaleY = currentBiomeScale; } game.addChild(rocket); rocket.fuel = 100; rocket.alive = true; gameStarted = true; updateUI(); } function updateUI() { distanceTxt.setText(Math.floor(distance) + ' m'); fuelTxt.setText('Fuel: ' + Math.max(0, Math.floor(rocket ? rocket.fuel : 0)) + '%'); // Update fuel bar fill if (typeof fuelBarFill !== "undefined" && rocket) { // Height: 392px max, min 0 (depletes from top to bottom) var pct = Math.max(0, Math.min(1, rocket.fuel / fuelMax)); fuelBarFill.height = 392 * pct; // Always keep the top of the fill at the same y (so it shrinks from top) fuelBarFill.y = 8 + 392 * (1 - pct); // Vivid color gradient: green > yellow > orange > red var color; if (pct > 0.5) { // Interpolate green (0x00ff00) to yellow (0xffff00) var t = (pct - 0.5) * 2; // 1 at full, 0 at 0.5 var r = Math.floor(0x00 + (0xff - 0x00) * (1 - t)); var g = 0xff; var b = 0x00; color = r << 16 | g << 8 | b; } else if (pct > 0.2) { // Interpolate yellow (0xffff00) to orange (0xff8800) var t = (pct - 0.2) / 0.3; // 1 at 0.5, 0 at 0.2 var r = 0xff; var g = Math.floor(0x88 + (0xff - 0x88) * t); var b = 0x00; color = r << 16 | g << 8 | b; } else { // Interpolate orange (0xff8800) to red (0xff0000) var t = pct / 0.2; // 1 at 0.2, 0 at 0 var r = 0xff; var g = Math.floor(0x00 + (0x88 - 0x00) * t); var b = 0x00; color = r << 16 | g << 8 | b; } fuelBarFill.tint = color; } } // --- Input (drag to move rocket) --- game.down = function (x, y, obj) { if (!rocket || !rocket.alive) return; isDragging = true; dragStartX = x; dragRocketStartX = rocket.x; }; game.move = function (x, y, obj) { if (!rocket || !rocket.alive) return; if (isDragging) { var dx = x - dragStartX; rocket.x = Math.max(minX, Math.min(maxX, dragRocketStartX + dx)); } }; game.up = function (x, y, obj) { isDragging = false; }; // --- Main game loop --- game.update = function () { if (!rocket || !rocket.alive) return; // Move rocket up (rocket stays at same y, background moves down) // (Handled by moving all objects up, not down!) // Distance increases as if rocket is moving up distance += rocketSpeed / 6; // scale to meters // Speed up every 200 meters if (!rocket.lastSpeedupDistance) rocket.lastSpeedupDistance = 0; if (Math.floor(distance / 200) > Math.floor(rocket.lastSpeedupDistance / 200)) { rocketSpeed += 1.5; rocket.lastSpeedupDistance = distance; } // --- Biome/level transition every 10000m --- // --- Background color logic by distance --- // Smooth biome background color transitions using tweening if (typeof game._bgColor === "undefined") game._bgColor = 0x75d1ff; if (typeof game._bgColorTarget === "undefined") game._bgColorTarget = 0x75d1ff; if (typeof game._bgColorTweening === "undefined") game._bgColorTweening = false; function getBiomeBgColor(distance) { if (distance < 10000) { return 0x75d1ff; // açık mavi } else if (distance < 20000) { return 0x1e90ff; // mavi } else if (distance < 30000) { return 0x003366; // koyu mavi } else if (distance < 40000) { return 0x22232a; // koyu gri } else if (distance < 50000) { return 0x000000; // siyah } else { // 50000'den sonra arka plan sürekli renk değiştirsin // Renk döngüsü: HSV renk çarkı üzerinde döner var t = (distance - 50000) / 400; var h = t % 1 * 6; var c = 1, x = 1 - Math.abs(h % 2 - 1); var r = 0, g = 0, b = 0; if (h < 1) { r = c; g = x; b = 0; } else if (h < 2) { r = x; g = c; b = 0; } else if (h < 3) { r = 0; g = c; b = x; } else if (h < 4) { r = 0; g = x; b = c; } else if (h < 5) { r = x; g = 0; b = c; } else { r = c; g = 0; b = x; } var m = 0.25; r = Math.floor((r + m) / (1 + m) * 255); g = Math.floor((g + m) / (1 + m) * 255); b = Math.floor((b + m) / (1 + m) * 255); return r << 16 | g << 8 | b; } } // Determine which biome we're in var biomeIdx = Math.floor(distance / 10000); var nextBiomeColor = getBiomeBgColor(distance); // If biome color target changed, tween to new color if (game._bgColorTarget !== nextBiomeColor && distance < 50000) { // Only tween for biome transitions below 50000m, above that we cycle colors if (!game._bgColorTweening) { var fromColor = game._bgColor; var toColor = nextBiomeColor; // Decompose colors var fromR = fromColor >> 16 & 0xff, fromG = fromColor >> 8 & 0xff, fromB = fromColor & 0xff; var toR = toColor >> 16 & 0xff, toG = toColor >> 8 & 0xff, toB = toColor & 0xff; var colorObj = { r: fromR, g: fromG, b: fromB }; game._bgColorTweening = true; game._bgColorTarget = nextBiomeColor; tween(colorObj, { r: toR, g: toG, b: toB }, { duration: 1200, easing: tween.cubicInOut, onUpdate: function onUpdate(obj) { var c = Math.round(obj.r) << 16 | Math.round(obj.g) << 8 | Math.round(obj.b); game._bgColor = c; game.setBackgroundColor(c); }, onFinish: function onFinish() { game._bgColor = nextBiomeColor; game.setBackgroundColor(nextBiomeColor); game._bgColorTweening = false; } }); } } else if (distance < 50000) { // Not transitioning, just set color if (!game._bgColorTweening) { game._bgColor = nextBiomeColor; game._bgColorTarget = nextBiomeColor; game.setBackgroundColor(nextBiomeColor); } } else { // 50000m+ : color cycles, no tween, set instantly var cycleColor = getBiomeBgColor(distance); game._bgColor = cycleColor; game._bgColorTarget = cycleColor; game.setBackgroundColor(cycleColor); } if (!biomeTransitioning && Math.floor(distance / biomeTransitionDistance) + 1 !== currentBiome) { biomeTransitioning = true; var nextBiome = Math.floor(distance / biomeTransitionDistance) + 1; // Slow rocket var oldSpeed = rocketSpeed; tween({ v: oldSpeed }, { v: 6 }, { duration: 1200, easing: tween.cubicOut, onUpdate: function onUpdate(obj) { rocketSpeed = obj.v; }, onFinish: function onFinish() { rocketSpeed = 6; currentBiome = nextBiome; biomeTransitioning = false; // --- Scale down rocket, fuels, and obstacles for new biome --- var newScale = getBiomeScale(currentBiome); if (Math.abs(currentBiomeScale - newScale) > 0.01) { currentBiomeScale = newScale; // Tween rocket scale if (rocket) { tween(rocket, { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); // Also scale attached asset if needed if (rocket.children && rocket.children.length > 0) { tween(rocket.children[0], { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); } } // Tween all fuels for (var i = 0; i < fuels.length; ++i) { tween(fuels[i], { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); if (fuels[i].children && fuels[i].children.length > 0) { tween(fuels[i].children[0], { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); } } // Tween all obstacles for (var i = 0; i < obstacles.length; ++i) { tween(obstacles[i], { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); if (obstacles[i].children && obstacles[i].children.length > 0) { tween(obstacles[i].children[0], { scaleX: newScale, scaleY: newScale }, { duration: 600, easing: tween.cubicInOut }); } } } } }); // background fade logic removed } updateUI(); // Deplete fuel rocket.fuel -= fuelDepleteRate; if (rocket.fuel <= 0) { rocket.fuel = 0; rocket.alive = false; LK.effects.flashScreen(0xff0000, 800); // Update last score and best score if needed lastScore = Math.floor(distance); lastTxt.setText('last: ' + lastScore + ' m'); if (lastScore > bestScore) { bestScore = lastScore; bestTxt.setText('best: ' + bestScore + ' m'); storage.best = bestScore; } // Show "your score is: X m" message in the center of the screen for 5 seconds, then show game over popup var scoreMsg = new Text2('your score is: ' + Math.floor(distance) + ' m', { size: 120, fill: 0xffff00, align: 'center', fontWeight: 'bold' }); scoreMsg.anchor.set(0.5, 0.5); scoreMsg.x = 2048 / 2; scoreMsg.y = 2732 / 2; game.addChild(scoreMsg); LK.setTimeout(function () { if (scoreMsg && scoreMsg.parent) scoreMsg.parent.removeChild(scoreMsg); LK.showGameOver(); }, 5000); return; } // Move fuels and check collision for (var i = fuels.length - 1; i >= 0; --i) { var f = fuels[i]; f.y += rocketSpeed; // move up relative to rocket (background moves down) if (f.y > maxY + 200) { f.destroy(); fuels.splice(i, 1); continue; } if (rocket.intersects(f)) { rocket.fuel = Math.min(fuelMax, rocket.fuel + fuelAmount); f.destroy(); fuels.splice(i, 1); // Small flash effect LK.effects.flashObject(rocket, 0x44ddee, 300); updateUI(); } } // Move obstacles and check collision for (var i = obstacles.length - 1; i >= 0; --i) { var o = obstacles[i]; o.y += rocketSpeed; // move up relative to rocket (background moves down) // Move Obstacle1, Obstacle2, Obstacle3, and Obstacle4 from right to left or left to right randomly, keep Obstacle stationary if (o.constructor && (o.constructor === Obstacle1 || o.constructor === Obstacle2 || o.constructor === Obstacle3 || o.constructor === Obstacle4) || typeof o.children !== "undefined" && o.children.length > 0 && o.children[0].assetId && (o.children[0].assetId === "obstacle1" || o.children[0].assetId === "obstacle2" || o.children[0].assetId === "obstacle3" || o.children[0].assetId === "obstacle4")) { // Assign direction and speed if not set if (typeof o.moveDir === "undefined") { // 0: right-to-left, 1: left-to-right o.moveDir = Math.random() < 0.5 ? 0 : 1; o.moveSpeed = 6 + Math.random() * 3; } if (typeof o.lastX === "undefined") o.lastX = o.x; if (o.moveDir === 0) { o.x -= o.moveSpeed; // Bounce off left edge if (o.lastX >= minX + o.width / 2 && o.x < minX + o.width / 2) { o.x = minX + o.width / 2; o.moveDir = 1; // Change direction to right } } else { o.x += o.moveSpeed; // Bounce off right edge if (o.lastX <= maxX - o.width / 2 && o.x > maxX - o.width / 2) { o.x = maxX - o.width / 2; o.moveDir = 0; // Change direction to left } } o.lastX = o.x; } // --- Biome 2: obstacles move horizontally --- // (removed old biome2Dir logic) if (o.y > maxY + 200) { o.destroy(); obstacles.splice(i, 1); continue; } if (rocket.intersects(o)) { // Only lose 10% fuel, don't die instantly var lostFuel = fuelMax * 0.10; rocket.fuel = Math.max(0, rocket.fuel - lostFuel); LK.effects.flashObject(rocket, 0xff4444, 400); // --- Rocket collision animation: shake horizontally --- // Stop any previous tweens on rocket.x tween.stop(rocket, { x: true }); var originalX = rocket.x; // Animate shake: left, right, center tween(rocket, { x: originalX - 40 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(rocket, { x: originalX + 40 }, { duration: 90, easing: tween.cubicInOut, onFinish: function onFinish() { tween(rocket, { x: originalX }, { duration: 70, easing: tween.cubicIn }); } }); } }); // --- End rocket collision animation --- obstacles.splice(i, 1); o.destroy(); updateUI(); // If fuel is now 0, trigger game over as normal if (rocket.fuel <= 0) { rocket.fuel = 0; rocket.alive = false; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } continue; } } // Spawn fuel fuelTimer++; if (fuelTimer >= fuelSpawnInterval) { fuelTimer = 0; var f = new Fuel(); f.x = Math.floor(minX + Math.random() * (maxX - minX)); // Spawn above the visible screen, so they fall into view from the top f.y = rocket.y - 2732 / 2 - 200 - Math.random() * 300; f.scaleX = currentBiomeScale; f.scaleY = currentBiomeScale; if (f.children && f.children.length > 0) { f.children[0].scaleX = currentBiomeScale; f.children[0].scaleY = currentBiomeScale; } game.addChild(f); fuels.push(f); } // Spawn obstacle obstacleTimer++; if (obstacleTimer >= obstacleSpawnInterval) { obstacleTimer = 0; var o; if (distance >= 50000) { // After 50000m, spawn a random mix of all obstacle types var obstacleTypes = [Obstacle, Obstacle1, Obstacle2, Obstacle3, Obstacle4]; var idx = Math.floor(Math.random() * obstacleTypes.length); o = new obstacleTypes[idx](); } else if (distance >= 40000) { o = new Obstacle4(); } else if (distance >= 30000 && distance < 40000) { o = new Obstacle3(); } else if (distance >= 20000 && distance < 30000) { o = new Obstacle2(); } else if (distance >= 10000 && distance < 20000) { o = new Obstacle1(); } else { o = new Obstacle(); } o.x = Math.floor(minX + Math.random() * (maxX - minX)); // Spawn above the visible screen, so they fall into view from the top o.y = rocket.y - 2732 / 2 - 400 - Math.random() * 400; o.scaleX = currentBiomeScale; o.scaleY = currentBiomeScale; if (o.children && o.children.length > 0) { o.children[0].scaleX = currentBiomeScale; o.children[0].scaleY = currentBiomeScale; } game.addChild(o); obstacles.push(o); } }; // --- Game over / win handling --- LK.on('gameover', function () { gameStarted = false; updateUI(); }); // --- Start game --- resetGame(); if (obstacleTimer >= obstacleSpawnInterval) { obstacleTimer = 0; var o; if (distance >= 20000) { o = new Obstacle3(); } else if (distance >= 10000) { o = new Obstacle2(); } else { o = new Obstacle(); } o.x = Math.floor(minX + Math.random() * (maxX - minX)); // Spawn above the visible screen, so they fall into view from the top o.y = rocket.y - 2732 / 2 - 400 - Math.random() * 400; o.scaleX = currentBiomeScale; o.scaleY = currentBiomeScale; if (o.children && o.children.length > 0) { o.children[0].scaleX = currentBiomeScale; o.children[0].scaleY = currentBiomeScale; } game.addChild(o); obstacles.push(o); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
best: 0
});
/****
* Classes
****/
// Fuel class
var Fuel = Container.expand(function () {
var self = Container.call(this);
var fuelGfx = self.attachAsset('fuel', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = fuelGfx.width;
self.height = fuelGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Obstacle class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Obstacle1 class (obstacle1 asset, for 10000-19999m)
var Obstacle1 = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle1', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Obstacle2 class (different look/behavior for >20000m)
var Obstacle2 = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle2', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Obstacle3 class (for >20000m, new look/behavior)
var Obstacle3 = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle3', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Obstacle4 class (for >40000m, new look/behavior)
var Obstacle4 = Container.expand(function () {
var self = Container.call(this);
var obsGfx = self.attachAsset('obstacle4', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsGfx.width;
self.height = obsGfx.height;
self.update = function () {
// Movement handled in game.update
};
return self;
});
// Rocket (player) class
var Rocket = Container.expand(function () {
var self = Container.call(this);
// Attach rocket asset, centered
var rocketGfx = self.attachAsset('rocket', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rocketGfx.width;
self.height = rocketGfx.height;
// Rocket state
self.fuel = 100;
self.alive = true;
// No per-frame update needed (movement handled in game.update)
self.update = function () {};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- Biome/level state ---
var currentBiome = 1;
var biomeTransitioning = false;
var biomeTransitionDistance = 10000;
// --- Biome scaling ---
// At biome 1: scale = 1.0, biome 2: 0.8, biome 3: 0.65, biome 4: 0.55, biome 5+: 0.45 (minimum)
function getBiomeScale(biome) {
// Every 10000m, scale decreases by 5% (0.95x), looping every 40000m
// biome: 1,2,3,4,5... (biome 1 = 0-9999m, biome 2 = 10000-19999m, etc)
// At biome 1: 1.0, biome 2: 0.95, biome 3: 0.9025, biome 4: 0.857375, biome 5: 0.81450625, then repeat
var biomeIndex = (biome - 1) % 4; // 0,1,2,3,0,1,2,3...
var scale = 1.0;
for (var i = 0; i < biomeIndex; ++i) {
scale *= 0.95;
}
return scale;
}
var currentBiomeScale = 1.0;
// Explosion effect (for flash)
// Obstacle
// Fuel
// Rocket (player)
// --- Global variables ---
var rocket;
var fuels = [];
var obstacles = [];
var dragStartX = null;
var dragRocketStartX = null;
var isDragging = false;
var fuelTimer = 0;
var obstacleTimer = 0;
var distance = 0;
// var best = typeof storage.best === "number" && storage.best > 0 ? storage.best : 0;
var fuelDepleteRate = 0.18; // per tick
var rocketSpeed = 8; // px per tick (vertical)
var fuelSpawnInterval = 90; // ticks
var obstacleSpawnInterval = 110; // ticks
var minX = 100,
maxX = 2048 - 100;
var minY = 200,
maxY = 2732 - 200;
var fuelMax = 100;
var fuelAmount = fuelMax * 0.2; // Yakıt toplandığında %20 doldurur
var gameStarted = false;
// --- UI ---
var distanceTxt = new Text2('0 m', {
size: 90,
fill: 0xFFFFFF
});
distanceTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(distanceTxt);
// Best score UI (bottom left)
var bestScore = typeof storage.best === "number" && storage.best > 0 ? storage.best : 0;
var bestTxt = new Text2('best: ' + Math.floor(bestScore) + ' m', {
size: 70,
fill: 0xffffff,
fontWeight: 'bold'
});
bestTxt.anchor.set(0, 1); // bottom left
LK.gui.bottomLeft.addChild(bestTxt);
bestTxt.x = 20;
bestTxt.y = -20;
// Last score UI (bottom left, below best)
var lastScore = 0;
var lastTxt = new Text2('last: 0 m', {
size: 60,
fill: 0xffffff
});
lastTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(lastTxt);
lastTxt.x = 20;
lastTxt.y = bestTxt.y + bestTxt.height + 10;
// Fuel bar (simple text)
var fuelTxt = new Text2('Yakıt: 100%', {
size: 60,
fill: 0xff2222
});
fuelTxt.anchor.set(0.5, 0);
// Place fuelTxt below distanceTxt (metre göstergesinin altında)
LK.gui.top.addChild(fuelTxt);
fuelTxt.y = distanceTxt.height + 10;
// --- Fuel Bar UI ---
// Black border (slightly bigger than background)
var fuelBarBorder = LK.getAsset('backgroundImage', {
width: 68,
height: 408,
x: 0,
y: 0,
anchorX: 0.5,
anchorY: 0.0
});
fuelBarBorder.tint = 0x000000;
fuelBarBorder.alpha = 1.0;
// Bar background (light gray, inside border)
var fuelBarBg = LK.getAsset('backgroundImage', {
width: 60,
height: 400,
x: 0,
y: 4,
anchorX: 0.5,
anchorY: 0.0
});
fuelBarBg.tint = 0xeeeeee;
fuelBarBg.alpha = 1.0;
// Bar fill (will be resized from top down)
var fuelBarFill = LK.getAsset('backgroundImage', {
width: 44,
height: 392,
x: 0,
y: 8,
anchorX: 0.5,
anchorY: 0.0
});
fuelBarFill.tint = 0x00ff00; // Start as vivid green
fuelBarFill.alpha = 1.0;
// Container for bar
var fuelBarContainer = new Container();
fuelBarContainer.addChild(fuelBarBorder);
fuelBarContainer.addChild(fuelBarBg);
fuelBarContainer.addChild(fuelBarFill);
// Position bar at top right, with margin from top and right
fuelBarContainer.x = 2048 - 80;
fuelBarContainer.y = 100;
// Add to game (not GUI, so it scales with gameplay)
game.addChild(fuelBarContainer);
// (bestTxt positioning removed)
// --- Helper functions ---
function resetGame() {
// Remove old objects
if (rocket) rocket.destroy();
for (var i = 0; i < fuels.length; ++i) fuels[i].destroy();
for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy();
fuels = [];
obstacles = [];
// Reset variables
distance = 0;
fuelTimer = 0;
obstacleTimer = 0;
currentBiome = 1;
biomeTransitioning = false;
// background and biome2Background removed
// (best score logic removed)
// Create rocket
rocket = new Rocket();
rocket.x = 2048 / 2;
rocket.y = 2732 - 350;
rocket.scaleX = currentBiomeScale;
rocket.scaleY = currentBiomeScale;
if (rocket.children && rocket.children.length > 0) {
rocket.children[0].scaleX = currentBiomeScale;
rocket.children[0].scaleY = currentBiomeScale;
}
game.addChild(rocket);
rocket.fuel = 100;
rocket.alive = true;
gameStarted = true;
updateUI();
}
function updateUI() {
distanceTxt.setText(Math.floor(distance) + ' m');
fuelTxt.setText('Fuel: ' + Math.max(0, Math.floor(rocket ? rocket.fuel : 0)) + '%');
// Update fuel bar fill
if (typeof fuelBarFill !== "undefined" && rocket) {
// Height: 392px max, min 0 (depletes from top to bottom)
var pct = Math.max(0, Math.min(1, rocket.fuel / fuelMax));
fuelBarFill.height = 392 * pct;
// Always keep the top of the fill at the same y (so it shrinks from top)
fuelBarFill.y = 8 + 392 * (1 - pct);
// Vivid color gradient: green > yellow > orange > red
var color;
if (pct > 0.5) {
// Interpolate green (0x00ff00) to yellow (0xffff00)
var t = (pct - 0.5) * 2; // 1 at full, 0 at 0.5
var r = Math.floor(0x00 + (0xff - 0x00) * (1 - t));
var g = 0xff;
var b = 0x00;
color = r << 16 | g << 8 | b;
} else if (pct > 0.2) {
// Interpolate yellow (0xffff00) to orange (0xff8800)
var t = (pct - 0.2) / 0.3; // 1 at 0.5, 0 at 0.2
var r = 0xff;
var g = Math.floor(0x88 + (0xff - 0x88) * t);
var b = 0x00;
color = r << 16 | g << 8 | b;
} else {
// Interpolate orange (0xff8800) to red (0xff0000)
var t = pct / 0.2; // 1 at 0.2, 0 at 0
var r = 0xff;
var g = Math.floor(0x00 + (0x88 - 0x00) * t);
var b = 0x00;
color = r << 16 | g << 8 | b;
}
fuelBarFill.tint = color;
}
}
// --- Input (drag to move rocket) ---
game.down = function (x, y, obj) {
if (!rocket || !rocket.alive) return;
isDragging = true;
dragStartX = x;
dragRocketStartX = rocket.x;
};
game.move = function (x, y, obj) {
if (!rocket || !rocket.alive) return;
if (isDragging) {
var dx = x - dragStartX;
rocket.x = Math.max(minX, Math.min(maxX, dragRocketStartX + dx));
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// --- Main game loop ---
game.update = function () {
if (!rocket || !rocket.alive) return;
// Move rocket up (rocket stays at same y, background moves down)
// (Handled by moving all objects up, not down!)
// Distance increases as if rocket is moving up
distance += rocketSpeed / 6; // scale to meters
// Speed up every 200 meters
if (!rocket.lastSpeedupDistance) rocket.lastSpeedupDistance = 0;
if (Math.floor(distance / 200) > Math.floor(rocket.lastSpeedupDistance / 200)) {
rocketSpeed += 1.5;
rocket.lastSpeedupDistance = distance;
}
// --- Biome/level transition every 10000m ---
// --- Background color logic by distance ---
// Smooth biome background color transitions using tweening
if (typeof game._bgColor === "undefined") game._bgColor = 0x75d1ff;
if (typeof game._bgColorTarget === "undefined") game._bgColorTarget = 0x75d1ff;
if (typeof game._bgColorTweening === "undefined") game._bgColorTweening = false;
function getBiomeBgColor(distance) {
if (distance < 10000) {
return 0x75d1ff; // açık mavi
} else if (distance < 20000) {
return 0x1e90ff; // mavi
} else if (distance < 30000) {
return 0x003366; // koyu mavi
} else if (distance < 40000) {
return 0x22232a; // koyu gri
} else if (distance < 50000) {
return 0x000000; // siyah
} else {
// 50000'den sonra arka plan sürekli renk değiştirsin
// Renk döngüsü: HSV renk çarkı üzerinde döner
var t = (distance - 50000) / 400;
var h = t % 1 * 6;
var c = 1,
x = 1 - Math.abs(h % 2 - 1);
var r = 0,
g = 0,
b = 0;
if (h < 1) {
r = c;
g = x;
b = 0;
} else if (h < 2) {
r = x;
g = c;
b = 0;
} else if (h < 3) {
r = 0;
g = c;
b = x;
} else if (h < 4) {
r = 0;
g = x;
b = c;
} else if (h < 5) {
r = x;
g = 0;
b = c;
} else {
r = c;
g = 0;
b = x;
}
var m = 0.25;
r = Math.floor((r + m) / (1 + m) * 255);
g = Math.floor((g + m) / (1 + m) * 255);
b = Math.floor((b + m) / (1 + m) * 255);
return r << 16 | g << 8 | b;
}
}
// Determine which biome we're in
var biomeIdx = Math.floor(distance / 10000);
var nextBiomeColor = getBiomeBgColor(distance);
// If biome color target changed, tween to new color
if (game._bgColorTarget !== nextBiomeColor && distance < 50000) {
// Only tween for biome transitions below 50000m, above that we cycle colors
if (!game._bgColorTweening) {
var fromColor = game._bgColor;
var toColor = nextBiomeColor;
// Decompose colors
var fromR = fromColor >> 16 & 0xff,
fromG = fromColor >> 8 & 0xff,
fromB = fromColor & 0xff;
var toR = toColor >> 16 & 0xff,
toG = toColor >> 8 & 0xff,
toB = toColor & 0xff;
var colorObj = {
r: fromR,
g: fromG,
b: fromB
};
game._bgColorTweening = true;
game._bgColorTarget = nextBiomeColor;
tween(colorObj, {
r: toR,
g: toG,
b: toB
}, {
duration: 1200,
easing: tween.cubicInOut,
onUpdate: function onUpdate(obj) {
var c = Math.round(obj.r) << 16 | Math.round(obj.g) << 8 | Math.round(obj.b);
game._bgColor = c;
game.setBackgroundColor(c);
},
onFinish: function onFinish() {
game._bgColor = nextBiomeColor;
game.setBackgroundColor(nextBiomeColor);
game._bgColorTweening = false;
}
});
}
} else if (distance < 50000) {
// Not transitioning, just set color
if (!game._bgColorTweening) {
game._bgColor = nextBiomeColor;
game._bgColorTarget = nextBiomeColor;
game.setBackgroundColor(nextBiomeColor);
}
} else {
// 50000m+ : color cycles, no tween, set instantly
var cycleColor = getBiomeBgColor(distance);
game._bgColor = cycleColor;
game._bgColorTarget = cycleColor;
game.setBackgroundColor(cycleColor);
}
if (!biomeTransitioning && Math.floor(distance / biomeTransitionDistance) + 1 !== currentBiome) {
biomeTransitioning = true;
var nextBiome = Math.floor(distance / biomeTransitionDistance) + 1;
// Slow rocket
var oldSpeed = rocketSpeed;
tween({
v: oldSpeed
}, {
v: 6
}, {
duration: 1200,
easing: tween.cubicOut,
onUpdate: function onUpdate(obj) {
rocketSpeed = obj.v;
},
onFinish: function onFinish() {
rocketSpeed = 6;
currentBiome = nextBiome;
biomeTransitioning = false;
// --- Scale down rocket, fuels, and obstacles for new biome ---
var newScale = getBiomeScale(currentBiome);
if (Math.abs(currentBiomeScale - newScale) > 0.01) {
currentBiomeScale = newScale;
// Tween rocket scale
if (rocket) {
tween(rocket, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
// Also scale attached asset if needed
if (rocket.children && rocket.children.length > 0) {
tween(rocket.children[0], {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
}
}
// Tween all fuels
for (var i = 0; i < fuels.length; ++i) {
tween(fuels[i], {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
if (fuels[i].children && fuels[i].children.length > 0) {
tween(fuels[i].children[0], {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
}
}
// Tween all obstacles
for (var i = 0; i < obstacles.length; ++i) {
tween(obstacles[i], {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
if (obstacles[i].children && obstacles[i].children.length > 0) {
tween(obstacles[i].children[0], {
scaleX: newScale,
scaleY: newScale
}, {
duration: 600,
easing: tween.cubicInOut
});
}
}
}
}
});
// background fade logic removed
}
updateUI();
// Deplete fuel
rocket.fuel -= fuelDepleteRate;
if (rocket.fuel <= 0) {
rocket.fuel = 0;
rocket.alive = false;
LK.effects.flashScreen(0xff0000, 800);
// Update last score and best score if needed
lastScore = Math.floor(distance);
lastTxt.setText('last: ' + lastScore + ' m');
if (lastScore > bestScore) {
bestScore = lastScore;
bestTxt.setText('best: ' + bestScore + ' m');
storage.best = bestScore;
}
// Show "your score is: X m" message in the center of the screen for 5 seconds, then show game over popup
var scoreMsg = new Text2('your score is: ' + Math.floor(distance) + ' m', {
size: 120,
fill: 0xffff00,
align: 'center',
fontWeight: 'bold'
});
scoreMsg.anchor.set(0.5, 0.5);
scoreMsg.x = 2048 / 2;
scoreMsg.y = 2732 / 2;
game.addChild(scoreMsg);
LK.setTimeout(function () {
if (scoreMsg && scoreMsg.parent) scoreMsg.parent.removeChild(scoreMsg);
LK.showGameOver();
}, 5000);
return;
}
// Move fuels and check collision
for (var i = fuels.length - 1; i >= 0; --i) {
var f = fuels[i];
f.y += rocketSpeed; // move up relative to rocket (background moves down)
if (f.y > maxY + 200) {
f.destroy();
fuels.splice(i, 1);
continue;
}
if (rocket.intersects(f)) {
rocket.fuel = Math.min(fuelMax, rocket.fuel + fuelAmount);
f.destroy();
fuels.splice(i, 1);
// Small flash effect
LK.effects.flashObject(rocket, 0x44ddee, 300);
updateUI();
}
}
// Move obstacles and check collision
for (var i = obstacles.length - 1; i >= 0; --i) {
var o = obstacles[i];
o.y += rocketSpeed; // move up relative to rocket (background moves down)
// Move Obstacle1, Obstacle2, Obstacle3, and Obstacle4 from right to left or left to right randomly, keep Obstacle stationary
if (o.constructor && (o.constructor === Obstacle1 || o.constructor === Obstacle2 || o.constructor === Obstacle3 || o.constructor === Obstacle4) || typeof o.children !== "undefined" && o.children.length > 0 && o.children[0].assetId && (o.children[0].assetId === "obstacle1" || o.children[0].assetId === "obstacle2" || o.children[0].assetId === "obstacle3" || o.children[0].assetId === "obstacle4")) {
// Assign direction and speed if not set
if (typeof o.moveDir === "undefined") {
// 0: right-to-left, 1: left-to-right
o.moveDir = Math.random() < 0.5 ? 0 : 1;
o.moveSpeed = 6 + Math.random() * 3;
}
if (typeof o.lastX === "undefined") o.lastX = o.x;
if (o.moveDir === 0) {
o.x -= o.moveSpeed;
// Bounce off left edge
if (o.lastX >= minX + o.width / 2 && o.x < minX + o.width / 2) {
o.x = minX + o.width / 2;
o.moveDir = 1; // Change direction to right
}
} else {
o.x += o.moveSpeed;
// Bounce off right edge
if (o.lastX <= maxX - o.width / 2 && o.x > maxX - o.width / 2) {
o.x = maxX - o.width / 2;
o.moveDir = 0; // Change direction to left
}
}
o.lastX = o.x;
}
// --- Biome 2: obstacles move horizontally ---
// (removed old biome2Dir logic)
if (o.y > maxY + 200) {
o.destroy();
obstacles.splice(i, 1);
continue;
}
if (rocket.intersects(o)) {
// Only lose 10% fuel, don't die instantly
var lostFuel = fuelMax * 0.10;
rocket.fuel = Math.max(0, rocket.fuel - lostFuel);
LK.effects.flashObject(rocket, 0xff4444, 400);
// --- Rocket collision animation: shake horizontally ---
// Stop any previous tweens on rocket.x
tween.stop(rocket, {
x: true
});
var originalX = rocket.x;
// Animate shake: left, right, center
tween(rocket, {
x: originalX - 40
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(rocket, {
x: originalX + 40
}, {
duration: 90,
easing: tween.cubicInOut,
onFinish: function onFinish() {
tween(rocket, {
x: originalX
}, {
duration: 70,
easing: tween.cubicIn
});
}
});
}
});
// --- End rocket collision animation ---
obstacles.splice(i, 1);
o.destroy();
updateUI();
// If fuel is now 0, trigger game over as normal
if (rocket.fuel <= 0) {
rocket.fuel = 0;
rocket.alive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
continue;
}
}
// Spawn fuel
fuelTimer++;
if (fuelTimer >= fuelSpawnInterval) {
fuelTimer = 0;
var f = new Fuel();
f.x = Math.floor(minX + Math.random() * (maxX - minX));
// Spawn above the visible screen, so they fall into view from the top
f.y = rocket.y - 2732 / 2 - 200 - Math.random() * 300;
f.scaleX = currentBiomeScale;
f.scaleY = currentBiomeScale;
if (f.children && f.children.length > 0) {
f.children[0].scaleX = currentBiomeScale;
f.children[0].scaleY = currentBiomeScale;
}
game.addChild(f);
fuels.push(f);
}
// Spawn obstacle
obstacleTimer++;
if (obstacleTimer >= obstacleSpawnInterval) {
obstacleTimer = 0;
var o;
if (distance >= 50000) {
// After 50000m, spawn a random mix of all obstacle types
var obstacleTypes = [Obstacle, Obstacle1, Obstacle2, Obstacle3, Obstacle4];
var idx = Math.floor(Math.random() * obstacleTypes.length);
o = new obstacleTypes[idx]();
} else if (distance >= 40000) {
o = new Obstacle4();
} else if (distance >= 30000 && distance < 40000) {
o = new Obstacle3();
} else if (distance >= 20000 && distance < 30000) {
o = new Obstacle2();
} else if (distance >= 10000 && distance < 20000) {
o = new Obstacle1();
} else {
o = new Obstacle();
}
o.x = Math.floor(minX + Math.random() * (maxX - minX));
// Spawn above the visible screen, so they fall into view from the top
o.y = rocket.y - 2732 / 2 - 400 - Math.random() * 400;
o.scaleX = currentBiomeScale;
o.scaleY = currentBiomeScale;
if (o.children && o.children.length > 0) {
o.children[0].scaleX = currentBiomeScale;
o.children[0].scaleY = currentBiomeScale;
}
game.addChild(o);
obstacles.push(o);
}
};
// --- Game over / win handling ---
LK.on('gameover', function () {
gameStarted = false;
updateUI();
});
// --- Start game ---
resetGame();
if (obstacleTimer >= obstacleSpawnInterval) {
obstacleTimer = 0;
var o;
if (distance >= 20000) {
o = new Obstacle3();
} else if (distance >= 10000) {
o = new Obstacle2();
} else {
o = new Obstacle();
}
o.x = Math.floor(minX + Math.random() * (maxX - minX));
// Spawn above the visible screen, so they fall into view from the top
o.y = rocket.y - 2732 / 2 - 400 - Math.random() * 400;
o.scaleX = currentBiomeScale;
o.scaleY = currentBiomeScale;
if (o.children && o.children.length > 0) {
o.children[0].scaleX = currentBiomeScale;
o.children[0].scaleY = currentBiomeScale;
}
game.addChild(o);
obstacles.push(o);
}