User prompt
arabanın tekerleklerini yapma. zaten asset olarak arabanın tekerlekleri bulunmakta. onun yerine sadece canları yap
User prompt
Karakter bir engele çarptığında 2 saniyeliğine yavaşlasın
User prompt
eğer tüm canları doluysa bile bir can daha eklesin. Ama en fazla can alma sayısı 9 olsun
User prompt
yol üzerinde toplanabilir canlar olsun. Bu canları aldığımızda canımız artsın
User prompt
can gittikten sonra ekranda kırmızı ışık yanmasın. Oyuncunun engelleri görmesini çok zorlaştırıyor
User prompt
canların yerini değiştir. sol alt köşeye koy
User prompt
oyuna can ekle. 3 tane olsun. canlar bittiğinde oyun bitsin
User prompt
yaptığımız en yüksek skoru kaydetsin ve en yüksek skor kısmında o yazsın ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
En yüksek skor tablosunun aşağısında yaptığımız en yüksek skor bulunsun
User prompt
oyunda en son yaptığımız skoru görebilelim
User prompt
engellerin arasını biraz daha aç
User prompt
bazı engellerin arasını biraz daha aç, bazıları ise böyle kalsın.
User prompt
Please fix the bug: 'TypeError: LK.submitScore is not a function' in or related to this line: 'LK.submitScore(score); // Submit score to leaderboard' Line Number: 189
User prompt
oyuna skor tablosu ekle
User prompt
engellerim arasını biraz daha aç
User prompt
oyunu yavaş başlatıp daha sonra hızlanmasını sağla
User prompt
zıplamıyor
Code edit (1 edits merged)
Please save this source code
User prompt
Jumping Car: Endless Road
Initial prompt
düz sonsuz platformda engellerden zıplayan bir araba oyunu
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highestScore: 0 }); /**** * Classes ****/ // Bulut (Cloud) background object class var Bulut = Container.expand(function () { var self = Container.call(this); var bulutImg = self.attachAsset('bulut', { anchorX: 0.5, anchorY: 0.5 }); self.width = bulutImg.width; self.height = bulutImg.height; // Set a random speed for parallax effect self.speed = 2 + Math.random() * 2; self.update = function () { self.x -= self.speed; }; return self; }); // Car class var Car = Container.expand(function () { var self = Container.call(this); // Car body var carBody = self.attachAsset('car', { anchorX: 0.5, anchorY: 1 }); // Physics self.vy = 0; // vertical velocity self.isJumping = false; // Car size for collision self.bodyWidth = carBody.width; self.bodyHeight = carBody.height; // Update method self.update = function () { // Gravity and jump physics self.y += self.vy; if (self.y < groundY) { self.vy += gravity; if (self.y > groundY) { self.y = groundY; self.vy = 0; self.isJumping = false; } } else if (self.y > groundY) { self.y = groundY; self.vy = 0; self.isJumping = false; } }; // Jump method self.jump = function () { if (!self.isJumping && self.y >= groundY) { self.vy = jumpVelocity; self.isJumping = true; LK.getSound('jump').play(); // Tilt the car slightly when jumping, then return to normal after 300ms if (typeof tween !== "undefined" && typeof tween.create === "function") { // Animate tilt to -0.25 var tiltTween = tween.create(carBody, { rotation: -0.25 }, 120, { easing: "easeOutCubic" }); tiltTween.then(function () { // Animate back to 0 var resetTween = tween.create(carBody, { rotation: 0 }, 180, { easing: "easeInCubic" }); // No need to do anything after reset }); } else { carBody.rotation = -0.25; // Fallback: reset after 300ms LK.setTimeout(function () { carBody.rotation = 0; }, 300); } } }; return self; }); // Coin collectible class var CoinCollectible = Container.expand(function () { var self = Container.call(this); // Use a yellow coin emoji for collectible var coinTxt = new Text2('🪙', { size: 110, fill: 0xffe066 // gold/yellow }); coinTxt.anchor.set(0.5, 1); self.addChild(coinTxt); self.width = coinTxt.width; self.height = coinTxt.height; // For collision self.bodyWidth = coinTxt.width; self.bodyHeight = coinTxt.height; self.update = function () { var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed; self.x -= speed; }; return self; }); // Gold heart collectible class var GoldHeartCollectible = Container.expand(function () { var self = Container.call(this); // Use a text heart for collectible, gold color var goldHeartTxt = new Text2('❤', { size: 120, fill: 0xffd700 // gold }); goldHeartTxt.anchor.set(0.5, 1); self.addChild(goldHeartTxt); self.width = goldHeartTxt.width; self.height = goldHeartTxt.height; // For collision self.bodyWidth = goldHeartTxt.width; self.bodyHeight = goldHeartTxt.height; self.update = function () { var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed; self.x -= speed; }; return self; }); // Heart collectible class var HeartCollectible = Container.expand(function () { var self = Container.call(this); // Use a text heart for collectible var heartTxt = new Text2('❤', { size: 92, fill: 0xff69b4 }); heartTxt.anchor.set(0.5, 1); self.addChild(heartTxt); self.width = heartTxt.width; self.height = heartTxt.height; // For collision self.bodyWidth = heartTxt.width; self.bodyHeight = heartTxt.height; // Update method self.update = function () { // Use effectiveGameSpeed if defined, else fallback to gameSpeed var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed; self.x -= speed; }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obs = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1 }); self.width = obs.width; self.height = obs.height; // For collision self.bodyWidth = obs.width; self.bodyHeight = obs.height; // Update method self.update = function () { // Use effectiveGameSpeed if defined, else fallback to gameSpeed var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed; self.x -= speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // sky blue }); /**** * Game Code ****/ // Jump sound // Road: dark gray box // Obstacle: red box // Wheel: black ellipse // Car: blue box // Constants // Left-right moving obstacle asset var groundY = 2200; // y position of the road top var gravity = 4.5; var jumpVelocity = -80; var initialGameSpeed = 24; var maxGameSpeed = 60; var gameSpeed = initialGameSpeed; var obstacleMinGap = 500; var obstacleMaxGap = 1100; var obstacleMinY = groundY; var obstacleMaxY = groundY; var minObstacleHeight = 120; var maxObstacleHeight = 220; // Road var road = LK.getAsset('road', { anchorX: 0, anchorY: 0, x: 0, y: groundY }); game.addChild(road); // Car var car = new Car(); car.x = 400; // Move the car visually closer to the road (simulate being on the road, not floating above) car.y = groundY + 20; // 20px below the road top, adjust as needed for best look game.addChild(car); // --- Slow effect state --- var carIsSlowed = false; var carSlowTicks = 0; var carSlowDuration = 120; // 2 seconds at 60fps var carSlowSpeedFactor = 0.45; // 45% speed when slowed // Obstacles var obstacles = []; var nextObstacleX = 2048 + 400; // Heart collectibles var heartCollectibles = []; var nextHeartX = 2048 + 1200; // Start further out // Gold heart collectibles var goldHeartCollectibles = []; var goldHeartActive = false; var goldHeartTimer = 0; var goldHeartDuration = 8 * 60; // 8 seconds at 60fps var goldHeartDisplay = null; var goldHeartDisplayLives = 0; // --- Coin system --- // Persistent coin count (load from storage, default 0) var coins = typeof storage.coins === "number" ? storage.coins : 0; // Coin collectibles var coinCollectibles = []; // Coin display var coinTxt = new Text2('', { size: 90, fill: 0xffe066 }); coinTxt.anchor.set(1, 1); coinTxt.x = -40; coinTxt.y = -40; LK.gui.bottomRight.addChild(coinTxt); function updateCoinDisplay() { coinTxt.setText("Jeton: " + coins); } updateCoinDisplay(); // Score var score = 0; var lastScore = 0; var lives = 3; // Start with 3 lives var maxLives = 3; // This can grow up to 9 as hearts are collected var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives display var livesTxt = null; var goldHeartDisplay = null; function updateLivesDisplay() { if (!gameStarted) { // Hide lives display on start screen if (livesTxt) livesTxt.setText(""); if (goldHeartDisplay) goldHeartDisplay.setText(""); return; } if (!livesTxt) { livesTxt = new Text2('', { size: 90, fill: 0xff4444 }); livesTxt.anchor.set(0, 1); // Shift a bit more left to avoid coin overlap livesTxt.x = 10; livesTxt.y = -40; LK.gui.bottomLeft.addChild(livesTxt); } if (goldHeartActive) { // Hide normal lives, show gold hearts if (!goldHeartDisplay) { goldHeartDisplay = new Text2('', { size: 76, fill: 0xffd700 }); goldHeartDisplay.anchor.set(0, 1); goldHeartDisplay.x = 18; goldHeartDisplay.y = -40; LK.gui.bottomLeft.addChild(goldHeartDisplay); } var hearts = ''; // Always cap display to 9 hearts maximum to prevent overflow var displayMax = maxLives > 9 ? 9 : maxLives; var displayLives = goldHeartDisplayLives > 9 ? 9 : goldHeartDisplayLives; for (var i = 0; i < displayLives; i++) hearts += '❤ '; for (var i = displayLives; i < displayMax; i++) hearts += '♡ '; goldHeartDisplay.setText("Altın Can: " + hearts.trim()); livesTxt.setText(""); // Hide normal } else { // Show normal lives, hide gold if (goldHeartDisplay) goldHeartDisplay.setText(""); var hearts = ''; var displayMax = maxLives > 9 ? 9 : maxLives; for (var i = 0; i < lives && i < 9; i++) hearts += '❤ '; for (var i = lives; i < displayMax; i++) hearts += '♡ '; livesTxt.setText("Can: " + hearts.trim()); } } updateLivesDisplay(); // Last score display var lastScoreTxt = new Text2('', { size: 70, fill: 0xFFD700 }); lastScoreTxt.anchor.set(0.5, 0); lastScoreTxt.y = scoreTxt.height + 10; LK.gui.top.addChild(lastScoreTxt); // Highest score display (below leaderboard) var highestScore = storage.highestScore || 0; var highestScoreTxt = new Text2('', { size: 70, fill: 0x00ffcc }); highestScoreTxt.anchor.set(0.5, 0); highestScoreTxt.y = lastScoreTxt.y + lastScoreTxt.height + 10; LK.gui.top.addChild(highestScoreTxt); // Difficulty var ticksSinceStart = 0; // --- Start Screen Overlay --- var gameStarted = false; var startOverlay = new Container(); var startBg = LK.getAsset('road', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); startBg.alpha = 0.82; startOverlay.addChild(startBg); // Add a visual image to the start overlay var startVisual = LK.getAsset('car', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 700, scaleX: 2.2, scaleY: 2.2 }); startOverlay.addChild(startVisual); var startText = new Text2("Araba Koşusu", { size: 180, fill: 0xffffff }); startText.anchor.set(0.5, 0.5); startText.x = 2048 / 2; startText.y = 900; startOverlay.addChild(startText); var tapText = new Text2("Başlamak için ekrana dokun", { size: 90, fill: 0xffd700 }); tapText.anchor.set(0.5, 0.5); tapText.x = 2048 / 2; tapText.y = 1200; startOverlay.addChild(tapText); // --- Garage Button --- var garageBtn = new Text2("Garaj", { size: 100, fill: 0x00bfff }); garageBtn.anchor.set(0.5, 0.5); // Place below the start text, centered garageBtn.x = 2048 / 2; garageBtn.y = 1400; garageBtn.interactive = true; garageBtn.buttonMode = true; // --- Garage Overlay --- var garageOverlay = new Container(); garageOverlay.visible = false; // Add a semi-transparent background var garageBg = LK.getAsset('road', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); garageBg.alpha = 0.92; garageOverlay.addChild(garageBg); // Garage title var garageTitle = new Text2("Garaj", { size: 160, fill: 0xffffff }); garageTitle.anchor.set(0.5, 0.5); garageTitle.x = 2048 / 2; garageTitle.y = 400; garageOverlay.addChild(garageTitle); // --- Car selection state --- // Persistent unlock state for cars (all unlocked) var unlockedCars = { car: true, araba2: true, araba3: true }; var selectedCarId = storage.selectedCarId || 'car'; // Show araba (main car) character var araba1 = LK.getAsset('car', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 500, y: 1000, scaleX: 1.2, scaleY: 1.2 }); garageOverlay.addChild(araba1); // Show araba2 character var araba2 = LK.getAsset('araba2', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1000, scaleX: 1.2, scaleY: 1.2 }); garageOverlay.addChild(araba2); // Show araba3 character var araba3 = LK.getAsset('araba3', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 500, y: 1000, scaleX: 1.2, scaleY: 1.2 }); garageOverlay.addChild(araba3); // --- Car unlock/lock overlays and buy buttons --- var araba2LockTxt = null; var araba2BuyBtn = null; var araba3LockTxt = null; var araba3BuyBtn = null; function updateCarLockStates() { // All cars are unlocked, so remove any lock/buy overlays if present if (araba2LockTxt) { garageOverlay.removeChild(araba2LockTxt); araba2LockTxt = null; } if (araba2BuyBtn) { garageOverlay.removeChild(araba2BuyBtn); araba2BuyBtn = null; } if (araba3LockTxt) { garageOverlay.removeChild(araba3LockTxt); araba3LockTxt = null; } if (araba3BuyBtn) { garageOverlay.removeChild(araba3BuyBtn); araba3BuyBtn = null; } } updateCarLockStates(); // --- Car selection highlight --- var araba1Border = new Container(); var araba2Border = new Container(); var araba3Border = new Container(); function updateCarSelectionHighlight() { // Remove all children first araba1Border.removeChildren(); araba2Border.removeChildren(); araba3Border.removeChildren(); // Draw a simple border using a colored rectangle asset if (selectedCarId === 'car') { var border = LK.getAsset('road', { anchorX: 0.5, anchorY: 0.5, width: araba1.width + 30, height: araba1.height + 30, x: araba1.x, y: araba1.y }); border.alpha = 0.18; border.tint = 0x00ff00; araba1Border.addChild(border); } if (selectedCarId === 'araba2') { var border = LK.getAsset('road', { anchorX: 0.5, anchorY: 0.5, width: araba2.width + 30, height: araba2.height + 30, x: araba2.x, y: araba2.y }); border.alpha = 0.18; border.tint = 0x00ff00; araba2Border.addChild(border); } if (selectedCarId === 'araba3') { var border = LK.getAsset('road', { anchorX: 0.5, anchorY: 0.5, width: araba3.width + 30, height: araba3.height + 30, x: araba3.x, y: araba3.y }); border.alpha = 0.18; border.tint = 0x00ff00; araba3Border.addChild(border); } } araba1Border.x = 0; araba1Border.y = 0; araba2Border.x = 0; araba2Border.y = 0; araba3Border.x = 0; araba3Border.y = 0; garageOverlay.addChild(araba1Border); garageOverlay.addChild(araba2Border); garageOverlay.addChild(araba3Border); updateCarSelectionHighlight(); // --- Car selection interaction --- araba1.interactive = true; araba1.buttonMode = true; araba1.down = function (x, y, obj) { selectedCarId = 'car'; storage.selectedCarId = selectedCarId; updateCarSelectionHighlight(); }; araba2.interactive = true; araba2.buttonMode = true; araba2.down = function (x, y, obj) { if (unlockedCars.araba2) { selectedCarId = 'araba2'; storage.selectedCarId = selectedCarId; updateCarSelectionHighlight(); } }; araba3.interactive = true; araba3.buttonMode = true; araba3.down = function (x, y, obj) { if (unlockedCars.araba3) { selectedCarId = 'araba3'; storage.selectedCarId = selectedCarId; updateCarSelectionHighlight(); } }; // Add a close button to return to start screen var closeGarageBtn = new Text2("Kapat", { size: 90, fill: 0xff4444 }); closeGarageBtn.anchor.set(0.5, 0.5); closeGarageBtn.x = 2048 / 2; closeGarageBtn.y = 1800; closeGarageBtn.interactive = true; closeGarageBtn.buttonMode = true; closeGarageBtn.down = function (x, y, obj) { garageOverlay.visible = false; startOverlay.visible = true; }; garageOverlay.addChild(closeGarageBtn); game.addChild(garageOverlay); garageBtn.down = function (x, y, obj) { // Only allow navigation if still on start screen if (!gameStarted) { startOverlay.visible = false; garageOverlay.visible = true; } }; startOverlay.addChild(garageBtn); game.addChild(startOverlay); // Play 'arkaplan' music on the start screen overlay LK.playMusic('arkaplan'); // Touch handler: start game if on start screen and not tapping garage, otherwise jump game.down = function (x, y, obj) { if (!gameStarted) { // If garage overlay is visible, ignore all taps except closeGarageBtn (handled by its own .down) if (garageOverlay.visible) { return; } // If tap is on the garage button, let its own .down handle it // Use global coordinates for tap and garageBtn var btnGlobalX = garageBtn.x; var btnGlobalY = garageBtn.y; var btnBounds = { x: btnGlobalX - garageBtn.width * garageBtn.anchor.x, y: btnGlobalY - garageBtn.height * garageBtn.anchor.y, width: garageBtn.width, height: garageBtn.height }; if (x >= btnBounds.x && x <= btnBounds.x + btnBounds.width && y >= btnBounds.y && y <= btnBounds.y + btnBounds.height) { // Let garageBtn.down handle it, do NOT start the game return; } // Otherwise, start the game ONLY if not tapping garage button if (!garageOverlay.visible) { startOverlay.visible = false; gameStarted = true; // --- Set car asset based on selection --- if (selectedCarId === 'araba2' && unlockedCars.araba2) { // Remove old car asset if (car.children.length > 0) car.removeChild(car.children[0]); var carBody = car.attachAsset('araba2', { anchorX: 0.5, anchorY: 1 }); car.bodyWidth = carBody.width; car.bodyHeight = carBody.height; // Fix araba2 to be visually on top of the road car.y = groundY + 5; // Adjust as needed for best look } else if (selectedCarId === 'araba3' && unlockedCars.araba3) { // Remove old car asset if (car.children.length > 0) car.removeChild(car.children[0]); var carBody = car.attachAsset('araba3', { anchorX: 0.5, anchorY: 1 }); car.bodyWidth = carBody.width; car.bodyHeight = carBody.height; // Fix araba3 to be visually on top of the road car.y = groundY + 10; // Adjust as needed for best look } else { // Remove old car asset if (car.children.length > 0) car.removeChild(car.children[0]); var carBody = car.attachAsset('car', { anchorX: 0.5, anchorY: 1 }); car.bodyWidth = carBody.width; car.bodyHeight = carBody.height; } updateLivesDisplay(); // Stop menu music when game starts LK.stopMusic(); return; } } car.jump(); }; // --- Bulut (cloud) background logic --- // Only define bulutlar array here, spawn logic will be in game.update after gameStarted if (typeof bulutlar === "undefined") { var bulutlar = []; } // Main update loop game.update = function () { if (!gameStarted) return; // --- Bulut (cloud) background logic (spawn/update only after gameStarted) --- if (bulutlar.length === 0) { // Spawn initial clouds for (var i = 0; i < 4; i++) { var bulut = new Bulut(); bulut.x = 400 + i * 500 + Math.random() * 200; bulut.y = 400 + Math.random() * 600; bulut.speed = 1.2 + Math.random() * 1.8; game.addChild(bulut); bulutlar.push(bulut); } } for (var i = bulutlar.length - 1; i >= 0; i--) { var bulut = bulutlar[i]; bulut.update(); if (bulut.x < -bulut.width / 2) { bulut.destroy(); bulutlar.splice(i, 1); } } // Spawn new bulut if needed if (bulutlar.length < 4) { var bulut = new Bulut(); bulut.x = 2048 + bulut.width / 2 + Math.random() * 200; bulut.y = 300 + Math.random() * 800; bulut.speed = 1.2 + Math.random() * 1.8; game.addChild(bulut); bulutlar.push(bulut); } ticksSinceStart++; // Increase game speed smoothly over time for gradual acceleration if (gameSpeed < maxGameSpeed) { // Accelerate slowly at first, then faster as time goes on // The divisor controls how quickly speed ramps up (higher = slower ramp) var speedup = ticksSinceStart / 60 * 0.18; // 0.18 px/frame/sec, adjust for feel gameSpeed = initialGameSpeed + speedup; if (gameSpeed > maxGameSpeed) gameSpeed = maxGameSpeed; } // --- Car slow effect logic --- if (carIsSlowed) { carSlowTicks++; if (carSlowTicks >= carSlowDuration) { carIsSlowed = false; carSlowTicks = 0; } } var effectiveGameSpeed = carIsSlowed ? gameSpeed * carSlowSpeedFactor : gameSpeed; // Update car car.update(); // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; // If car is slowed, move obstacles at slowed speed for 2 seconds if (carIsSlowed) { var speed = gameSpeed * carSlowSpeedFactor; obs.x -= speed - (typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed); } obs.update(); // Remove if off screen if (obs.x < -200) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection (AABB) var carLeft = car.x - car.bodyWidth / 2 + 20; var carRight = car.x + car.bodyWidth / 2 - 20; var carTop = car.y - car.bodyHeight; var carBottom = car.y; var obsLeft = obs.x - obs.bodyWidth / 2; var obsRight = obs.x + obs.bodyWidth / 2; var obsTop = obs.y - obs.bodyHeight; var obsBottom = obs.y; var intersect = !(carRight < obsLeft || carLeft > obsRight || carBottom < obsTop + 10 || carTop > obsBottom - 10); if (intersect) { if (goldHeartActive) { // No damage, just animate obstacle tumble and remove after if (typeof tween !== "undefined" && typeof tween.create === "function") { // Animate: rotate 1.5 turns, fall down tween.create(obs, { rotation: obs.rotation + Math.PI * 3, y: obs.y + 400, alpha: 0.2 }, 700, { easing: "easeInCubic" }).then(function () { obs.destroy(); }); } else { obs.destroy(); } obstacles.splice(i, 1); continue; } // Play 'engellenmek' sound on collision LK.getSound('engellenmek').play(); // Removed LK.effects.flashScreen(0xff0000, 800); lives--; updateLivesDisplay(); // --- Trigger car slow effect for 2 seconds --- carIsSlowed = true; carSlowTicks = 0; if (lives <= 0) { // Stop car movement and animate tilt to indicate a crash car.vy = 0; car.isJumping = false; // Animate car tilt to crash angle (0.35 radians) smoothly if (typeof tween !== "undefined" && typeof tween.create === "function") { tween.create(car.children[0], { rotation: 0.35 }, 320, { easing: "easeOutCubic" }); } else { car.children[0].rotation = 0.35; } LK.setScore(score); // Ensure latest score is set lastScore = score; lastScoreTxt.setText("Son Skor: " + lastScore); // Update highest score if needed if (score > highestScore) { highestScore = score; storage.highestScore = highestScore; highestScoreTxt.setText("En Yüksek Skor: " + highestScore); } else { // Always show the stored value if not beaten highestScoreTxt.setText("En Yüksek Skor: " + (storage.highestScore || highestScore)); } LK.showGameOver(); return; } else { // Animate obstacle tumble and falling to ground, then remove after if (typeof tween !== "undefined" && typeof tween.create === "function") { tween.create(obs, { rotation: obs.rotation + Math.PI * 3, y: groundY + obs.height, alpha: 0.2 }, 700, { easing: "easeInCubic" }).then(function () { obs.destroy(); }); } else { obs.destroy(); } obstacles.splice(i, 1); continue; } } // Score: passed obstacle if (!obs.passed && obs.x + obs.bodyWidth / 2 < car.x - car.bodyWidth / 2) { obs.passed = true; score++; scoreTxt.setText(score); } } // --- Heart collectibles update and collision --- for (var i = heartCollectibles.length - 1; i >= 0; i--) { var heart = heartCollectibles[i]; // If car is slowed, move hearts at slowed speed for 2 seconds if (carIsSlowed) { var speed = gameSpeed * carSlowSpeedFactor; heart.x -= speed - (typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed); } heart.update(); // Remove if off screen if (heart.x < -200) { heart.destroy(); heartCollectibles.splice(i, 1); continue; } // Collision detection (AABB) var carLeft = car.x - car.bodyWidth / 2 + 20; var carRight = car.x + car.bodyWidth / 2 - 20; var carTop = car.y - car.bodyHeight; var carBottom = car.y; var heartLeft = heart.x - heart.bodyWidth / 2; var heartRight = heart.x + heart.bodyWidth / 2; var heartTop = heart.y - heart.bodyHeight; var heartBottom = heart.y; var intersect = !(carRight < heartLeft || carLeft > heartRight || carBottom < heartTop + 10 || carTop > heartBottom - 10); if (intersect) { if (!goldHeartActive) { // Always increase lives, up to a hard cap of 9 if (lives < 9) { lives++; // If we go above maxLives, update maxLives to match (so display shows more hearts) if (lives > maxLives) maxLives = lives; updateLivesDisplay(); } } // Remove the heart collectible heart.destroy(); heartCollectibles.splice(i, 1); continue; } } // --- Gold heart collectibles update and collision --- for (var i = goldHeartCollectibles.length - 1; i >= 0; i--) { var goldHeart = goldHeartCollectibles[i]; goldHeart.update(); if (goldHeart.x < -200) { goldHeart.destroy(); goldHeartCollectibles.splice(i, 1); continue; } // Collision detection (AABB) var carLeft = car.x - car.bodyWidth / 2 + 20; var carRight = car.x + car.bodyWidth / 2 - 20; var carTop = car.y - car.bodyHeight; var carBottom = car.y; var goldLeft = goldHeart.x - goldHeart.bodyWidth / 2; var goldRight = goldHeart.x + goldHeart.bodyWidth / 2; var goldTop = goldHeart.y - goldHeart.bodyHeight; var goldBottom = goldHeart.y; var intersect = !(carRight < goldLeft || carLeft > goldRight || carBottom < goldTop + 10 || carTop > goldBottom - 10); if (intersect) { // Activate gold heart mode goldHeartActive = true; goldHeartTimer = 0; // Fill lives to max when gold heart is collected lives = maxLives; // Cap goldHeartDisplayLives to 9 to prevent overflow goldHeartDisplayLives = lives > 9 ? 9 : lives; updateLivesDisplay(); // Remove the gold heart collectible goldHeart.destroy(); goldHeartCollectibles.splice(i, 1); continue; } } // --- Coin collectibles update and collision --- for (var i = coinCollectibles.length - 1; i >= 0; i--) { var coin = coinCollectibles[i]; coin.update(); if (coin.x < -200) { coin.destroy(); coinCollectibles.splice(i, 1); continue; } // Collision detection (AABB) var carLeft = car.x - car.bodyWidth / 2 + 20; var carRight = car.x + car.bodyWidth / 2 - 20; var carTop = car.y - car.bodyHeight; var carBottom = car.y; var coinLeft = coin.x - coin.bodyWidth / 2; var coinRight = coin.x + coin.bodyWidth / 2; var coinTop = coin.y - coin.bodyHeight; var coinBottom = coin.y; var intersect = !(carRight < coinLeft || carLeft > coinRight || carBottom < coinTop + 10 || carTop > coinBottom - 10); if (intersect) { // Add coin, persistently coins++; storage.coins = coins; updateCoinDisplay(); coin.destroy(); coinCollectibles.splice(i, 1); continue; } } // Gold heart timer logic if (goldHeartActive) { goldHeartTimer++; if (goldHeartTimer >= goldHeartDuration) { goldHeartActive = false; goldHeartTimer = 0; updateLivesDisplay(); } } // Spawn new obstacles if (obstacles.length === 0 || obstacles.length > 0 && obstacles[obstacles.length - 1].x < 2048 - getNextGap()) { var obs = new Obstacle(); obs.x = 2048 + 100; obs.y = groundY; game.addChild(obs); obstacles.push(obs); } // --- Spawn heart collectibles and coins occasionally --- if ((heartCollectibles.length === 0 || heartCollectibles.length > 0 && heartCollectibles[heartCollectibles.length - 1].x < 2048 - getNextHeartGap()) && goldHeartCollectibles.length === 0 // Only one gold heart at a time ) { var rand = Math.random(); if (rand < 0.02) { // 2% chance: spawn gold heart var goldHeart = new GoldHeartCollectible(); goldHeart.x = 2048 + 200 + Math.floor(Math.random() * 600); goldHeart.y = groundY - 180 - Math.floor(Math.random() * 200); game.addChild(goldHeart); goldHeartCollectibles.push(goldHeart); } else if (rand < 0.44) { // 39% chance: spawn normal heart (reduced by 1%) var heart = new HeartCollectible(); heart.x = 2048 + 200 + Math.floor(Math.random() * 600); heart.y = groundY - 180 - Math.floor(Math.random() * 200); game.addChild(heart); heartCollectibles.push(heart); } else if (rand < 1.00) { // 56% chance: spawn coin (increased by 15%) var coin = new CoinCollectible(); coin.x = 2048 + 200 + Math.floor(Math.random() * 600); coin.y = groundY - 180 - Math.floor(Math.random() * 200); game.addChild(coin); coinCollectibles.push(coin); } } }; // Helper: get next gap (randomized, gets smaller as speed increases) function getNextGap() { var minGap = obstacleMinGap + 400 - Math.floor((gameSpeed - initialGameSpeed) * 10); var maxGap = obstacleMaxGap + 600 - Math.floor((gameSpeed - initialGameSpeed) * 12); if (minGap < 720) minGap = 720; if (maxGap < 1000) maxGap = 1000; // 45% chance to make a much wider gap, otherwise normal if (Math.random() < 0.45) { // Extra wide gap (make even wider) var extraMin = maxGap + 700; var extraMax = maxGap + 1600; return extraMin + Math.floor(Math.random() * (extraMax - extraMin)); } else { // Normal gap return minGap + Math.floor(Math.random() * (maxGap - minGap)); } } // Helper: get next heart collectible gap (randomized, not too frequent) function getNextHeartGap() { // Hearts are less frequent than obstacles var minGap = 1200; var maxGap = 2200; return minGap + Math.floor(Math.random() * (maxGap - minGap)); } // Reset score and lives on game start LK.setScore(0); score = 0; // On game start, reset maxLives to 3, but if lives was higher, keep it (up to 9) if (lives > 3) { maxLives = lives > 9 ? 9 : lives; } else { maxLives = 3; } lives = maxLives; scoreTxt.setText(score); lastScoreTxt.setText(""); updateLivesDisplay(); heartCollectibles = []; goldHeartCollectibles = []; coinCollectibles = []; goldHeartActive = false; goldHeartTimer = 0; goldHeartDisplayLives = 0; updateCoinDisplay(); if ((storage.highestScore || highestScore) > 0) { highestScoreTxt.setText("En Yüksek Skor: " + (storage.highestScore || highestScore)); } else { highestScoreTxt.setText(""); } // Show leaderboard button in the top GUI, right side var leaderboardBtn = new Text2("🏆", { size: 110, fill: 0xffff00 }); leaderboardBtn.anchor.set(1, 0); // right-top leaderboardBtn.x = -40; // offset from right edge leaderboardBtn.y = 0; leaderboardBtn.interactive = true; leaderboardBtn.buttonMode = true; leaderboardBtn.down = function (x, y, obj) { LK.showLeaderboard(); }; LK.gui.topRight.addChild(leaderboardBtn);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highestScore: 0
});
/****
* Classes
****/
// Bulut (Cloud) background object class
var Bulut = Container.expand(function () {
var self = Container.call(this);
var bulutImg = self.attachAsset('bulut', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bulutImg.width;
self.height = bulutImg.height;
// Set a random speed for parallax effect
self.speed = 2 + Math.random() * 2;
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
// Car body
var carBody = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 1
});
// Physics
self.vy = 0; // vertical velocity
self.isJumping = false;
// Car size for collision
self.bodyWidth = carBody.width;
self.bodyHeight = carBody.height;
// Update method
self.update = function () {
// Gravity and jump physics
self.y += self.vy;
if (self.y < groundY) {
self.vy += gravity;
if (self.y > groundY) {
self.y = groundY;
self.vy = 0;
self.isJumping = false;
}
} else if (self.y > groundY) {
self.y = groundY;
self.vy = 0;
self.isJumping = false;
}
};
// Jump method
self.jump = function () {
if (!self.isJumping && self.y >= groundY) {
self.vy = jumpVelocity;
self.isJumping = true;
LK.getSound('jump').play();
// Tilt the car slightly when jumping, then return to normal after 300ms
if (typeof tween !== "undefined" && typeof tween.create === "function") {
// Animate tilt to -0.25
var tiltTween = tween.create(carBody, {
rotation: -0.25
}, 120, {
easing: "easeOutCubic"
});
tiltTween.then(function () {
// Animate back to 0
var resetTween = tween.create(carBody, {
rotation: 0
}, 180, {
easing: "easeInCubic"
});
// No need to do anything after reset
});
} else {
carBody.rotation = -0.25;
// Fallback: reset after 300ms
LK.setTimeout(function () {
carBody.rotation = 0;
}, 300);
}
}
};
return self;
});
// Coin collectible class
var CoinCollectible = Container.expand(function () {
var self = Container.call(this);
// Use a yellow coin emoji for collectible
var coinTxt = new Text2('🪙', {
size: 110,
fill: 0xffe066 // gold/yellow
});
coinTxt.anchor.set(0.5, 1);
self.addChild(coinTxt);
self.width = coinTxt.width;
self.height = coinTxt.height;
// For collision
self.bodyWidth = coinTxt.width;
self.bodyHeight = coinTxt.height;
self.update = function () {
var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed;
self.x -= speed;
};
return self;
});
// Gold heart collectible class
var GoldHeartCollectible = Container.expand(function () {
var self = Container.call(this);
// Use a text heart for collectible, gold color
var goldHeartTxt = new Text2('❤', {
size: 120,
fill: 0xffd700 // gold
});
goldHeartTxt.anchor.set(0.5, 1);
self.addChild(goldHeartTxt);
self.width = goldHeartTxt.width;
self.height = goldHeartTxt.height;
// For collision
self.bodyWidth = goldHeartTxt.width;
self.bodyHeight = goldHeartTxt.height;
self.update = function () {
var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed;
self.x -= speed;
};
return self;
});
// Heart collectible class
var HeartCollectible = Container.expand(function () {
var self = Container.call(this);
// Use a text heart for collectible
var heartTxt = new Text2('❤', {
size: 92,
fill: 0xff69b4
});
heartTxt.anchor.set(0.5, 1);
self.addChild(heartTxt);
self.width = heartTxt.width;
self.height = heartTxt.height;
// For collision
self.bodyWidth = heartTxt.width;
self.bodyHeight = heartTxt.height;
// Update method
self.update = function () {
// Use effectiveGameSpeed if defined, else fallback to gameSpeed
var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed;
self.x -= speed;
};
return self;
});
// Obstacle class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1
});
self.width = obs.width;
self.height = obs.height;
// For collision
self.bodyWidth = obs.width;
self.bodyHeight = obs.height;
// Update method
self.update = function () {
// Use effectiveGameSpeed if defined, else fallback to gameSpeed
var speed = typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed;
self.x -= speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // sky blue
});
/****
* Game Code
****/
// Jump sound
// Road: dark gray box
// Obstacle: red box
// Wheel: black ellipse
// Car: blue box
// Constants
// Left-right moving obstacle asset
var groundY = 2200; // y position of the road top
var gravity = 4.5;
var jumpVelocity = -80;
var initialGameSpeed = 24;
var maxGameSpeed = 60;
var gameSpeed = initialGameSpeed;
var obstacleMinGap = 500;
var obstacleMaxGap = 1100;
var obstacleMinY = groundY;
var obstacleMaxY = groundY;
var minObstacleHeight = 120;
var maxObstacleHeight = 220;
// Road
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
x: 0,
y: groundY
});
game.addChild(road);
// Car
var car = new Car();
car.x = 400;
// Move the car visually closer to the road (simulate being on the road, not floating above)
car.y = groundY + 20; // 20px below the road top, adjust as needed for best look
game.addChild(car);
// --- Slow effect state ---
var carIsSlowed = false;
var carSlowTicks = 0;
var carSlowDuration = 120; // 2 seconds at 60fps
var carSlowSpeedFactor = 0.45; // 45% speed when slowed
// Obstacles
var obstacles = [];
var nextObstacleX = 2048 + 400;
// Heart collectibles
var heartCollectibles = [];
var nextHeartX = 2048 + 1200; // Start further out
// Gold heart collectibles
var goldHeartCollectibles = [];
var goldHeartActive = false;
var goldHeartTimer = 0;
var goldHeartDuration = 8 * 60; // 8 seconds at 60fps
var goldHeartDisplay = null;
var goldHeartDisplayLives = 0;
// --- Coin system ---
// Persistent coin count (load from storage, default 0)
var coins = typeof storage.coins === "number" ? storage.coins : 0;
// Coin collectibles
var coinCollectibles = [];
// Coin display
var coinTxt = new Text2('', {
size: 90,
fill: 0xffe066
});
coinTxt.anchor.set(1, 1);
coinTxt.x = -40;
coinTxt.y = -40;
LK.gui.bottomRight.addChild(coinTxt);
function updateCoinDisplay() {
coinTxt.setText("Jeton: " + coins);
}
updateCoinDisplay();
// Score
var score = 0;
var lastScore = 0;
var lives = 3; // Start with 3 lives
var maxLives = 3; // This can grow up to 9 as hearts are collected
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var livesTxt = null;
var goldHeartDisplay = null;
function updateLivesDisplay() {
if (!gameStarted) {
// Hide lives display on start screen
if (livesTxt) livesTxt.setText("");
if (goldHeartDisplay) goldHeartDisplay.setText("");
return;
}
if (!livesTxt) {
livesTxt = new Text2('', {
size: 90,
fill: 0xff4444
});
livesTxt.anchor.set(0, 1);
// Shift a bit more left to avoid coin overlap
livesTxt.x = 10;
livesTxt.y = -40;
LK.gui.bottomLeft.addChild(livesTxt);
}
if (goldHeartActive) {
// Hide normal lives, show gold hearts
if (!goldHeartDisplay) {
goldHeartDisplay = new Text2('', {
size: 76,
fill: 0xffd700
});
goldHeartDisplay.anchor.set(0, 1);
goldHeartDisplay.x = 18;
goldHeartDisplay.y = -40;
LK.gui.bottomLeft.addChild(goldHeartDisplay);
}
var hearts = '';
// Always cap display to 9 hearts maximum to prevent overflow
var displayMax = maxLives > 9 ? 9 : maxLives;
var displayLives = goldHeartDisplayLives > 9 ? 9 : goldHeartDisplayLives;
for (var i = 0; i < displayLives; i++) hearts += '❤ ';
for (var i = displayLives; i < displayMax; i++) hearts += '♡ ';
goldHeartDisplay.setText("Altın Can: " + hearts.trim());
livesTxt.setText(""); // Hide normal
} else {
// Show normal lives, hide gold
if (goldHeartDisplay) goldHeartDisplay.setText("");
var hearts = '';
var displayMax = maxLives > 9 ? 9 : maxLives;
for (var i = 0; i < lives && i < 9; i++) hearts += '❤ ';
for (var i = lives; i < displayMax; i++) hearts += '♡ ';
livesTxt.setText("Can: " + hearts.trim());
}
}
updateLivesDisplay();
// Last score display
var lastScoreTxt = new Text2('', {
size: 70,
fill: 0xFFD700
});
lastScoreTxt.anchor.set(0.5, 0);
lastScoreTxt.y = scoreTxt.height + 10;
LK.gui.top.addChild(lastScoreTxt);
// Highest score display (below leaderboard)
var highestScore = storage.highestScore || 0;
var highestScoreTxt = new Text2('', {
size: 70,
fill: 0x00ffcc
});
highestScoreTxt.anchor.set(0.5, 0);
highestScoreTxt.y = lastScoreTxt.y + lastScoreTxt.height + 10;
LK.gui.top.addChild(highestScoreTxt);
// Difficulty
var ticksSinceStart = 0;
// --- Start Screen Overlay ---
var gameStarted = false;
var startOverlay = new Container();
var startBg = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
startBg.alpha = 0.82;
startOverlay.addChild(startBg);
// Add a visual image to the start overlay
var startVisual = LK.getAsset('car', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 700,
scaleX: 2.2,
scaleY: 2.2
});
startOverlay.addChild(startVisual);
var startText = new Text2("Araba Koşusu", {
size: 180,
fill: 0xffffff
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 900;
startOverlay.addChild(startText);
var tapText = new Text2("Başlamak için ekrana dokun", {
size: 90,
fill: 0xffd700
});
tapText.anchor.set(0.5, 0.5);
tapText.x = 2048 / 2;
tapText.y = 1200;
startOverlay.addChild(tapText);
// --- Garage Button ---
var garageBtn = new Text2("Garaj", {
size: 100,
fill: 0x00bfff
});
garageBtn.anchor.set(0.5, 0.5);
// Place below the start text, centered
garageBtn.x = 2048 / 2;
garageBtn.y = 1400;
garageBtn.interactive = true;
garageBtn.buttonMode = true;
// --- Garage Overlay ---
var garageOverlay = new Container();
garageOverlay.visible = false;
// Add a semi-transparent background
var garageBg = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
garageBg.alpha = 0.92;
garageOverlay.addChild(garageBg);
// Garage title
var garageTitle = new Text2("Garaj", {
size: 160,
fill: 0xffffff
});
garageTitle.anchor.set(0.5, 0.5);
garageTitle.x = 2048 / 2;
garageTitle.y = 400;
garageOverlay.addChild(garageTitle);
// --- Car selection state ---
// Persistent unlock state for cars (all unlocked)
var unlockedCars = {
car: true,
araba2: true,
araba3: true
};
var selectedCarId = storage.selectedCarId || 'car';
// Show araba (main car) character
var araba1 = LK.getAsset('car', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 500,
y: 1000,
scaleX: 1.2,
scaleY: 1.2
});
garageOverlay.addChild(araba1);
// Show araba2 character
var araba2 = LK.getAsset('araba2', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1000,
scaleX: 1.2,
scaleY: 1.2
});
garageOverlay.addChild(araba2);
// Show araba3 character
var araba3 = LK.getAsset('araba3', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 500,
y: 1000,
scaleX: 1.2,
scaleY: 1.2
});
garageOverlay.addChild(araba3);
// --- Car unlock/lock overlays and buy buttons ---
var araba2LockTxt = null;
var araba2BuyBtn = null;
var araba3LockTxt = null;
var araba3BuyBtn = null;
function updateCarLockStates() {
// All cars are unlocked, so remove any lock/buy overlays if present
if (araba2LockTxt) {
garageOverlay.removeChild(araba2LockTxt);
araba2LockTxt = null;
}
if (araba2BuyBtn) {
garageOverlay.removeChild(araba2BuyBtn);
araba2BuyBtn = null;
}
if (araba3LockTxt) {
garageOverlay.removeChild(araba3LockTxt);
araba3LockTxt = null;
}
if (araba3BuyBtn) {
garageOverlay.removeChild(araba3BuyBtn);
araba3BuyBtn = null;
}
}
updateCarLockStates();
// --- Car selection highlight ---
var araba1Border = new Container();
var araba2Border = new Container();
var araba3Border = new Container();
function updateCarSelectionHighlight() {
// Remove all children first
araba1Border.removeChildren();
araba2Border.removeChildren();
araba3Border.removeChildren();
// Draw a simple border using a colored rectangle asset
if (selectedCarId === 'car') {
var border = LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
width: araba1.width + 30,
height: araba1.height + 30,
x: araba1.x,
y: araba1.y
});
border.alpha = 0.18;
border.tint = 0x00ff00;
araba1Border.addChild(border);
}
if (selectedCarId === 'araba2') {
var border = LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
width: araba2.width + 30,
height: araba2.height + 30,
x: araba2.x,
y: araba2.y
});
border.alpha = 0.18;
border.tint = 0x00ff00;
araba2Border.addChild(border);
}
if (selectedCarId === 'araba3') {
var border = LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
width: araba3.width + 30,
height: araba3.height + 30,
x: araba3.x,
y: araba3.y
});
border.alpha = 0.18;
border.tint = 0x00ff00;
araba3Border.addChild(border);
}
}
araba1Border.x = 0;
araba1Border.y = 0;
araba2Border.x = 0;
araba2Border.y = 0;
araba3Border.x = 0;
araba3Border.y = 0;
garageOverlay.addChild(araba1Border);
garageOverlay.addChild(araba2Border);
garageOverlay.addChild(araba3Border);
updateCarSelectionHighlight();
// --- Car selection interaction ---
araba1.interactive = true;
araba1.buttonMode = true;
araba1.down = function (x, y, obj) {
selectedCarId = 'car';
storage.selectedCarId = selectedCarId;
updateCarSelectionHighlight();
};
araba2.interactive = true;
araba2.buttonMode = true;
araba2.down = function (x, y, obj) {
if (unlockedCars.araba2) {
selectedCarId = 'araba2';
storage.selectedCarId = selectedCarId;
updateCarSelectionHighlight();
}
};
araba3.interactive = true;
araba3.buttonMode = true;
araba3.down = function (x, y, obj) {
if (unlockedCars.araba3) {
selectedCarId = 'araba3';
storage.selectedCarId = selectedCarId;
updateCarSelectionHighlight();
}
};
// Add a close button to return to start screen
var closeGarageBtn = new Text2("Kapat", {
size: 90,
fill: 0xff4444
});
closeGarageBtn.anchor.set(0.5, 0.5);
closeGarageBtn.x = 2048 / 2;
closeGarageBtn.y = 1800;
closeGarageBtn.interactive = true;
closeGarageBtn.buttonMode = true;
closeGarageBtn.down = function (x, y, obj) {
garageOverlay.visible = false;
startOverlay.visible = true;
};
garageOverlay.addChild(closeGarageBtn);
game.addChild(garageOverlay);
garageBtn.down = function (x, y, obj) {
// Only allow navigation if still on start screen
if (!gameStarted) {
startOverlay.visible = false;
garageOverlay.visible = true;
}
};
startOverlay.addChild(garageBtn);
game.addChild(startOverlay);
// Play 'arkaplan' music on the start screen overlay
LK.playMusic('arkaplan');
// Touch handler: start game if on start screen and not tapping garage, otherwise jump
game.down = function (x, y, obj) {
if (!gameStarted) {
// If garage overlay is visible, ignore all taps except closeGarageBtn (handled by its own .down)
if (garageOverlay.visible) {
return;
}
// If tap is on the garage button, let its own .down handle it
// Use global coordinates for tap and garageBtn
var btnGlobalX = garageBtn.x;
var btnGlobalY = garageBtn.y;
var btnBounds = {
x: btnGlobalX - garageBtn.width * garageBtn.anchor.x,
y: btnGlobalY - garageBtn.height * garageBtn.anchor.y,
width: garageBtn.width,
height: garageBtn.height
};
if (x >= btnBounds.x && x <= btnBounds.x + btnBounds.width && y >= btnBounds.y && y <= btnBounds.y + btnBounds.height) {
// Let garageBtn.down handle it, do NOT start the game
return;
}
// Otherwise, start the game ONLY if not tapping garage button
if (!garageOverlay.visible) {
startOverlay.visible = false;
gameStarted = true;
// --- Set car asset based on selection ---
if (selectedCarId === 'araba2' && unlockedCars.araba2) {
// Remove old car asset
if (car.children.length > 0) car.removeChild(car.children[0]);
var carBody = car.attachAsset('araba2', {
anchorX: 0.5,
anchorY: 1
});
car.bodyWidth = carBody.width;
car.bodyHeight = carBody.height;
// Fix araba2 to be visually on top of the road
car.y = groundY + 5; // Adjust as needed for best look
} else if (selectedCarId === 'araba3' && unlockedCars.araba3) {
// Remove old car asset
if (car.children.length > 0) car.removeChild(car.children[0]);
var carBody = car.attachAsset('araba3', {
anchorX: 0.5,
anchorY: 1
});
car.bodyWidth = carBody.width;
car.bodyHeight = carBody.height;
// Fix araba3 to be visually on top of the road
car.y = groundY + 10; // Adjust as needed for best look
} else {
// Remove old car asset
if (car.children.length > 0) car.removeChild(car.children[0]);
var carBody = car.attachAsset('car', {
anchorX: 0.5,
anchorY: 1
});
car.bodyWidth = carBody.width;
car.bodyHeight = carBody.height;
}
updateLivesDisplay();
// Stop menu music when game starts
LK.stopMusic();
return;
}
}
car.jump();
};
// --- Bulut (cloud) background logic ---
// Only define bulutlar array here, spawn logic will be in game.update after gameStarted
if (typeof bulutlar === "undefined") {
var bulutlar = [];
}
// Main update loop
game.update = function () {
if (!gameStarted) return;
// --- Bulut (cloud) background logic (spawn/update only after gameStarted) ---
if (bulutlar.length === 0) {
// Spawn initial clouds
for (var i = 0; i < 4; i++) {
var bulut = new Bulut();
bulut.x = 400 + i * 500 + Math.random() * 200;
bulut.y = 400 + Math.random() * 600;
bulut.speed = 1.2 + Math.random() * 1.8;
game.addChild(bulut);
bulutlar.push(bulut);
}
}
for (var i = bulutlar.length - 1; i >= 0; i--) {
var bulut = bulutlar[i];
bulut.update();
if (bulut.x < -bulut.width / 2) {
bulut.destroy();
bulutlar.splice(i, 1);
}
}
// Spawn new bulut if needed
if (bulutlar.length < 4) {
var bulut = new Bulut();
bulut.x = 2048 + bulut.width / 2 + Math.random() * 200;
bulut.y = 300 + Math.random() * 800;
bulut.speed = 1.2 + Math.random() * 1.8;
game.addChild(bulut);
bulutlar.push(bulut);
}
ticksSinceStart++;
// Increase game speed smoothly over time for gradual acceleration
if (gameSpeed < maxGameSpeed) {
// Accelerate slowly at first, then faster as time goes on
// The divisor controls how quickly speed ramps up (higher = slower ramp)
var speedup = ticksSinceStart / 60 * 0.18; // 0.18 px/frame/sec, adjust for feel
gameSpeed = initialGameSpeed + speedup;
if (gameSpeed > maxGameSpeed) gameSpeed = maxGameSpeed;
}
// --- Car slow effect logic ---
if (carIsSlowed) {
carSlowTicks++;
if (carSlowTicks >= carSlowDuration) {
carIsSlowed = false;
carSlowTicks = 0;
}
}
var effectiveGameSpeed = carIsSlowed ? gameSpeed * carSlowSpeedFactor : gameSpeed;
// Update car
car.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
// If car is slowed, move obstacles at slowed speed for 2 seconds
if (carIsSlowed) {
var speed = gameSpeed * carSlowSpeedFactor;
obs.x -= speed - (typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed);
}
obs.update();
// Remove if off screen
if (obs.x < -200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection (AABB)
var carLeft = car.x - car.bodyWidth / 2 + 20;
var carRight = car.x + car.bodyWidth / 2 - 20;
var carTop = car.y - car.bodyHeight;
var carBottom = car.y;
var obsLeft = obs.x - obs.bodyWidth / 2;
var obsRight = obs.x + obs.bodyWidth / 2;
var obsTop = obs.y - obs.bodyHeight;
var obsBottom = obs.y;
var intersect = !(carRight < obsLeft || carLeft > obsRight || carBottom < obsTop + 10 || carTop > obsBottom - 10);
if (intersect) {
if (goldHeartActive) {
// No damage, just animate obstacle tumble and remove after
if (typeof tween !== "undefined" && typeof tween.create === "function") {
// Animate: rotate 1.5 turns, fall down
tween.create(obs, {
rotation: obs.rotation + Math.PI * 3,
y: obs.y + 400,
alpha: 0.2
}, 700, {
easing: "easeInCubic"
}).then(function () {
obs.destroy();
});
} else {
obs.destroy();
}
obstacles.splice(i, 1);
continue;
}
// Play 'engellenmek' sound on collision
LK.getSound('engellenmek').play();
// Removed LK.effects.flashScreen(0xff0000, 800);
lives--;
updateLivesDisplay();
// --- Trigger car slow effect for 2 seconds ---
carIsSlowed = true;
carSlowTicks = 0;
if (lives <= 0) {
// Stop car movement and animate tilt to indicate a crash
car.vy = 0;
car.isJumping = false;
// Animate car tilt to crash angle (0.35 radians) smoothly
if (typeof tween !== "undefined" && typeof tween.create === "function") {
tween.create(car.children[0], {
rotation: 0.35
}, 320, {
easing: "easeOutCubic"
});
} else {
car.children[0].rotation = 0.35;
}
LK.setScore(score); // Ensure latest score is set
lastScore = score;
lastScoreTxt.setText("Son Skor: " + lastScore);
// Update highest score if needed
if (score > highestScore) {
highestScore = score;
storage.highestScore = highestScore;
highestScoreTxt.setText("En Yüksek Skor: " + highestScore);
} else {
// Always show the stored value if not beaten
highestScoreTxt.setText("En Yüksek Skor: " + (storage.highestScore || highestScore));
}
LK.showGameOver();
return;
} else {
// Animate obstacle tumble and falling to ground, then remove after
if (typeof tween !== "undefined" && typeof tween.create === "function") {
tween.create(obs, {
rotation: obs.rotation + Math.PI * 3,
y: groundY + obs.height,
alpha: 0.2
}, 700, {
easing: "easeInCubic"
}).then(function () {
obs.destroy();
});
} else {
obs.destroy();
}
obstacles.splice(i, 1);
continue;
}
}
// Score: passed obstacle
if (!obs.passed && obs.x + obs.bodyWidth / 2 < car.x - car.bodyWidth / 2) {
obs.passed = true;
score++;
scoreTxt.setText(score);
}
}
// --- Heart collectibles update and collision ---
for (var i = heartCollectibles.length - 1; i >= 0; i--) {
var heart = heartCollectibles[i];
// If car is slowed, move hearts at slowed speed for 2 seconds
if (carIsSlowed) {
var speed = gameSpeed * carSlowSpeedFactor;
heart.x -= speed - (typeof effectiveGameSpeed !== "undefined" ? effectiveGameSpeed : gameSpeed);
}
heart.update();
// Remove if off screen
if (heart.x < -200) {
heart.destroy();
heartCollectibles.splice(i, 1);
continue;
}
// Collision detection (AABB)
var carLeft = car.x - car.bodyWidth / 2 + 20;
var carRight = car.x + car.bodyWidth / 2 - 20;
var carTop = car.y - car.bodyHeight;
var carBottom = car.y;
var heartLeft = heart.x - heart.bodyWidth / 2;
var heartRight = heart.x + heart.bodyWidth / 2;
var heartTop = heart.y - heart.bodyHeight;
var heartBottom = heart.y;
var intersect = !(carRight < heartLeft || carLeft > heartRight || carBottom < heartTop + 10 || carTop > heartBottom - 10);
if (intersect) {
if (!goldHeartActive) {
// Always increase lives, up to a hard cap of 9
if (lives < 9) {
lives++;
// If we go above maxLives, update maxLives to match (so display shows more hearts)
if (lives > maxLives) maxLives = lives;
updateLivesDisplay();
}
}
// Remove the heart collectible
heart.destroy();
heartCollectibles.splice(i, 1);
continue;
}
}
// --- Gold heart collectibles update and collision ---
for (var i = goldHeartCollectibles.length - 1; i >= 0; i--) {
var goldHeart = goldHeartCollectibles[i];
goldHeart.update();
if (goldHeart.x < -200) {
goldHeart.destroy();
goldHeartCollectibles.splice(i, 1);
continue;
}
// Collision detection (AABB)
var carLeft = car.x - car.bodyWidth / 2 + 20;
var carRight = car.x + car.bodyWidth / 2 - 20;
var carTop = car.y - car.bodyHeight;
var carBottom = car.y;
var goldLeft = goldHeart.x - goldHeart.bodyWidth / 2;
var goldRight = goldHeart.x + goldHeart.bodyWidth / 2;
var goldTop = goldHeart.y - goldHeart.bodyHeight;
var goldBottom = goldHeart.y;
var intersect = !(carRight < goldLeft || carLeft > goldRight || carBottom < goldTop + 10 || carTop > goldBottom - 10);
if (intersect) {
// Activate gold heart mode
goldHeartActive = true;
goldHeartTimer = 0;
// Fill lives to max when gold heart is collected
lives = maxLives;
// Cap goldHeartDisplayLives to 9 to prevent overflow
goldHeartDisplayLives = lives > 9 ? 9 : lives;
updateLivesDisplay();
// Remove the gold heart collectible
goldHeart.destroy();
goldHeartCollectibles.splice(i, 1);
continue;
}
}
// --- Coin collectibles update and collision ---
for (var i = coinCollectibles.length - 1; i >= 0; i--) {
var coin = coinCollectibles[i];
coin.update();
if (coin.x < -200) {
coin.destroy();
coinCollectibles.splice(i, 1);
continue;
}
// Collision detection (AABB)
var carLeft = car.x - car.bodyWidth / 2 + 20;
var carRight = car.x + car.bodyWidth / 2 - 20;
var carTop = car.y - car.bodyHeight;
var carBottom = car.y;
var coinLeft = coin.x - coin.bodyWidth / 2;
var coinRight = coin.x + coin.bodyWidth / 2;
var coinTop = coin.y - coin.bodyHeight;
var coinBottom = coin.y;
var intersect = !(carRight < coinLeft || carLeft > coinRight || carBottom < coinTop + 10 || carTop > coinBottom - 10);
if (intersect) {
// Add coin, persistently
coins++;
storage.coins = coins;
updateCoinDisplay();
coin.destroy();
coinCollectibles.splice(i, 1);
continue;
}
}
// Gold heart timer logic
if (goldHeartActive) {
goldHeartTimer++;
if (goldHeartTimer >= goldHeartDuration) {
goldHeartActive = false;
goldHeartTimer = 0;
updateLivesDisplay();
}
}
// Spawn new obstacles
if (obstacles.length === 0 || obstacles.length > 0 && obstacles[obstacles.length - 1].x < 2048 - getNextGap()) {
var obs = new Obstacle();
obs.x = 2048 + 100;
obs.y = groundY;
game.addChild(obs);
obstacles.push(obs);
}
// --- Spawn heart collectibles and coins occasionally ---
if ((heartCollectibles.length === 0 || heartCollectibles.length > 0 && heartCollectibles[heartCollectibles.length - 1].x < 2048 - getNextHeartGap()) && goldHeartCollectibles.length === 0 // Only one gold heart at a time
) {
var rand = Math.random();
if (rand < 0.02) {
// 2% chance: spawn gold heart
var goldHeart = new GoldHeartCollectible();
goldHeart.x = 2048 + 200 + Math.floor(Math.random() * 600);
goldHeart.y = groundY - 180 - Math.floor(Math.random() * 200);
game.addChild(goldHeart);
goldHeartCollectibles.push(goldHeart);
} else if (rand < 0.44) {
// 39% chance: spawn normal heart (reduced by 1%)
var heart = new HeartCollectible();
heart.x = 2048 + 200 + Math.floor(Math.random() * 600);
heart.y = groundY - 180 - Math.floor(Math.random() * 200);
game.addChild(heart);
heartCollectibles.push(heart);
} else if (rand < 1.00) {
// 56% chance: spawn coin (increased by 15%)
var coin = new CoinCollectible();
coin.x = 2048 + 200 + Math.floor(Math.random() * 600);
coin.y = groundY - 180 - Math.floor(Math.random() * 200);
game.addChild(coin);
coinCollectibles.push(coin);
}
}
};
// Helper: get next gap (randomized, gets smaller as speed increases)
function getNextGap() {
var minGap = obstacleMinGap + 400 - Math.floor((gameSpeed - initialGameSpeed) * 10);
var maxGap = obstacleMaxGap + 600 - Math.floor((gameSpeed - initialGameSpeed) * 12);
if (minGap < 720) minGap = 720;
if (maxGap < 1000) maxGap = 1000;
// 45% chance to make a much wider gap, otherwise normal
if (Math.random() < 0.45) {
// Extra wide gap (make even wider)
var extraMin = maxGap + 700;
var extraMax = maxGap + 1600;
return extraMin + Math.floor(Math.random() * (extraMax - extraMin));
} else {
// Normal gap
return minGap + Math.floor(Math.random() * (maxGap - minGap));
}
}
// Helper: get next heart collectible gap (randomized, not too frequent)
function getNextHeartGap() {
// Hearts are less frequent than obstacles
var minGap = 1200;
var maxGap = 2200;
return minGap + Math.floor(Math.random() * (maxGap - minGap));
}
// Reset score and lives on game start
LK.setScore(0);
score = 0;
// On game start, reset maxLives to 3, but if lives was higher, keep it (up to 9)
if (lives > 3) {
maxLives = lives > 9 ? 9 : lives;
} else {
maxLives = 3;
}
lives = maxLives;
scoreTxt.setText(score);
lastScoreTxt.setText("");
updateLivesDisplay();
heartCollectibles = [];
goldHeartCollectibles = [];
coinCollectibles = [];
goldHeartActive = false;
goldHeartTimer = 0;
goldHeartDisplayLives = 0;
updateCoinDisplay();
if ((storage.highestScore || highestScore) > 0) {
highestScoreTxt.setText("En Yüksek Skor: " + (storage.highestScore || highestScore));
} else {
highestScoreTxt.setText("");
}
// Show leaderboard button in the top GUI, right side
var leaderboardBtn = new Text2("🏆", {
size: 110,
fill: 0xffff00
});
leaderboardBtn.anchor.set(1, 0); // right-top
leaderboardBtn.x = -40; // offset from right edge
leaderboardBtn.y = 0;
leaderboardBtn.interactive = true;
leaderboardBtn.buttonMode = true;
leaderboardBtn.down = function (x, y, obj) {
LK.showLeaderboard();
};
LK.gui.topRight.addChild(leaderboardBtn);
red car and driver. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
sarı renkli "Stop" tabelası. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
a human. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
altın para, berrak. In-Game asset. 2d. High contrast. No shadows
pixelart, cloud. In-Game asset. 2d. High contrast. No shadows
dark green car and driver. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue car and driver. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat