User prompt
El frenini kaldır
User prompt
Düzeltir misin kontrol et
User prompt
El freni aktif gözükmüyor
User prompt
El freni imagesini bastığımda fren yapsın aktiflestir
User prompt
Fren durdurmuyor fazla oranını yükselt
User prompt
Eklediğimiz frenin imagesini el freni imagesini ekle
User prompt
Fren ekranda gözükmüyor
User prompt
Fren butonuyla yapılsın fren
User prompt
Fren ekleme özelliği getir break
User prompt
Araba seçim ekranında "music"müziği calmasin sadece Aeabasec soundu çalsın arabayı seciktikten sonra "music" müziği Çal
User prompt
Araba seçim ekranında backgorund müziği calmasin sadece Aeabasec soundu çalsın arabayı seciktikten sonra background müziği calabilir
User prompt
Aeabasec müziğini çal araba seçim ekranında.
User prompt
Motosikletin ismini lüks araba yap
User prompt
Mosiklet ile kamyonun isimlerini değiştir ters olmuş
User prompt
Araba seç ekranına background ekledim ekle
User prompt
Araba seçim ekranında ki sedan ve minibüs seçeneklerini kaldır ikisini
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'y')' in or related to this line: 'var wasFar = Math.abs(car.y - obs.lastYForSound) > closeRange;' Line Number: 754
User prompt
Araba seçme ekranına animasyon ekleyelim backgorund gibi ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Araba seçme ekranında bir tane araba var sadece başka arabalarında ekle
User prompt
Araba seçme ekranı güzel olurdu
User prompt
Polis arabası 10 saniye bir spawn olsun
User prompt
Polis arabasının yanından geçerken sesi çal polisosund
User prompt
Polisarabasini surekli ekleme 25 saniyede bir ekrana çıksın
User prompt
Gittiğim mesafeyi ölçerin yerini değiştir sayfanın en üstüne koy
User prompt
Arabalar 260x170 olsun
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Boost class var Boost = Container.expand(function () { var self = Container.call(this); var boostAsset = self.attachAsset('boost', { anchorX: 0.5, anchorY: 0.5 }); self.width = boostAsset.width; self.height = boostAsset.height; self.update = function () { self.y += roadSpeed; }; return self; }); // Car class var Car = Container.expand(function () { var self = Container.call(this); var carAsset = self.attachAsset('car', { anchorX: 0.5, anchorY: 0.5 }); // For collision, use the container itself self.width = carAsset.width; self.height = carAsset.height; // Car speed (pixels per tick) self.speed = 10; // Lateral speed (for smooth steering) self.lateralSpeed = 0; // Max lateral speed self.maxLateralSpeed = 32; // Steering target (x position) self.targetX = self.x; // Update method self.update = function () { // Smoothly move towards targetX var dx = self.targetX - self.x; if (Math.abs(dx) > 2) { self.lateralSpeed = Math.max(-self.maxLateralSpeed, Math.min(self.maxLateralSpeed, dx * 0.25)); self.x += self.lateralSpeed; } else { self.lateralSpeed = 0; self.x = self.targetX; } }; return self; }); // Lane marker class var Lane = Container.expand(function () { var self = Container.call(this); var laneAsset = self.attachAsset('lane', { anchorX: 0.5, anchorY: 0.5 }); self.width = laneAsset.width; self.height = laneAsset.height; self.update = function () { self.y += roadSpeed; }; return self; }); // Nitro class (collectible for nitro boost) var Nitro = Container.expand(function () { var self = Container.call(this); var nitroAsset = self.attachAsset('Nitro', { anchorX: 0.5, anchorY: 0.5 }); self.width = nitroAsset.width; self.height = nitroAsset.height; self.update = function () { self.y += roadSpeed; }; return self; }); // Obstacle class (default car) var Obstacle = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; // Update method: move down by road speed self.update = function () { // Track lastY for scoring if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; // No score for passing obstacles; scoring is handled by collecting boosts. self.lastY = self.y; }; return self; }); // Motorcycle obstacle var ObstacleMotorcycle = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle_motorcycle', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; self.lastY = self.y; }; return self; }); // Sports car obstacle var ObstacleSportsCar = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle_sportscar', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; self.lastY = self.y; }; return self; }); // Truck obstacle var ObstacleTruck = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle_truck', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; self.lastY = self.y; }; return self; }); // Van obstacle var ObstacleVan = Container.expand(function () { var self = Container.call(this); var obsAsset = self.attachAsset('obstacle_van', { anchorX: 0.5, anchorY: 0.5 }); self.width = obsAsset.width; self.height = obsAsset.height; self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; self.lastY = self.y; }; return self; }); // Police Car class var PolisCar = Container.expand(function () { var self = Container.call(this); var polisAsset = self.attachAsset('Polisecar', { anchorX: 0.5, anchorY: 0.5 }); self.width = polisAsset.width; self.height = polisAsset.height; // Police car speed (moves down the road) self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += roadSpeed; self.lastY = self.y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Lane marker // Road // Speed boost // Obstacle // Car (player) // Play start sound at the very beginning of the game LK.getSound('Arabasssw').play(); LK.playMusic('Music'); // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var ROAD_WIDTH = 900; var ROAD_X = (GAME_WIDTH - ROAD_WIDTH) / 2; var ROAD_Y = 0; var LANE_COUNT = 3; var LANE_WIDTH = ROAD_WIDTH / LANE_COUNT; var CAR_START_X = GAME_WIDTH / 2; var CAR_START_Y = GAME_HEIGHT - 500; var OBSTACLE_MIN_GAP = 600; var OBSTACLE_MAX_GAP = 1100; var BOOST_CHANCE = 0.25; // 25% chance to spawn a boost with an obstacle // Road speed (pixels per tick) var roadSpeed = 10; var roadSpeedBase = 10; var roadSpeedBoosted = 16; var boostDuration = 90; // ticks (1.5 seconds) var boostTicks = 0; // Score var score = 0; // Arrays for game objects var obstacles = []; var boosts = []; var lanes = []; var nitros = []; // Nitro collectibles // Nitro state var nitroCount = 0; var nitroActive = false; var nitroTicks = 0; var NITRO_DURATION = 240; // 4 seconds at 60fps // Road background var road = LK.getAsset('road', { anchorX: 0, anchorY: 0, x: ROAD_X, y: ROAD_Y }); // Score text var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Distance traveled (meters) var distanceTraveled = 0; // Distance text var distanceText = new Text2('0 m', { size: 80, fill: 0xFFD700 }); distanceText.anchor.set(0.5, 0); // Place at the very top center, with a small margin from the top distanceText.x = LK.gui.width / 2; distanceText.y = 0; // absolutely at the top LK.gui.top.addChild(distanceText); // Nitro GUI icon and counter (must be after scoreTxt is created) var nitroIcon = LK.getAsset('Nitro', { anchorX: 0, anchorY: 0, width: 90, height: 90 }); nitroIcon.x = LK.gui.width / 2 + scoreTxt.width / 2 + 350; nitroIcon.y = 10; LK.gui.top.addChild(nitroIcon); var nitroLabel = new Text2('x' + nitroCount, { size: 80, fill: 0x00EAFF }); nitroLabel.anchor.set(0, 0); nitroLabel.x = nitroIcon.x + nitroIcon.width + 10; nitroLabel.y = nitroIcon.y + 10; LK.gui.top.addChild(nitroLabel); function updateNitroLabel() { nitroLabel.setText('x' + nitroCount); } game.addChild(road); // Lane markers function spawnLaneMarkers() { // Remove old lanes for (var i = 0; i < lanes.length; i++) { lanes[i].destroy(); } lanes = []; // For each lane (except the leftmost), draw a marker for (var l = 1; l < LANE_COUNT; l++) { for (var y = -200; y < GAME_HEIGHT + 200; y += 400) { var lane = new Lane(); lane.x = ROAD_X + l * LANE_WIDTH; lane.y = y; lanes.push(lane); game.addChild(lane); } } } spawnLaneMarkers(); // Car (player) var car = new Car(); car.x = CAR_START_X; car.y = CAR_START_Y; car.targetX = car.x; game.addChild(car); // Score text var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives (hak) system var lives = 3; // Image-based lives display var livesImages = []; var LIVES_IMAGE_ID = 'car'; // Use car image for lives var LIVES_IMAGE_SIZE = 90; // px var LIVES_IMAGE_MARGIN = 20; // px between images // Positioning: Place lives images to the right of the score counter var LIVES_IMAGE_TOP_MARGIN = 10; // px from top of GUI var LIVES_IMAGE_LEFT_MARGIN = 40; // px from left of score counter function updateLivesImages() { // Remove old images for (var i = 0; i < livesImages.length; i++) { livesImages[i].destroy(); } livesImages = []; // Place lives images to the right of the score counter // Get scoreTxt position in GUI coordinates var scoreX = scoreTxt.x * LK.gui.width; var scoreY = scoreTxt.y * LK.gui.height; // But since anchor is (0.5, 0), scoreTxt.x is centered in GUI width var baseX = LK.gui.width / 2 + scoreTxt.width / 2 + LIVES_IMAGE_LEFT_MARGIN; var baseY = LIVES_IMAGE_TOP_MARGIN; for (var i = 0; i < lives; i++) { var img = LK.getAsset(LIVES_IMAGE_ID, { anchorX: 0, anchorY: 0, width: LIVES_IMAGE_SIZE, height: LIVES_IMAGE_SIZE }); // Position: right of score, stacked horizontally with margin img.x = baseX + i * (LIVES_IMAGE_SIZE + LIVES_IMAGE_MARGIN); img.y = baseY; LK.gui.top.addChild(img); livesImages.push(img); } } // Helper to update lives text (legacy, keep for compatibility) function updateLivesText() { updateLivesImages(); if (typeof livesLabel !== "undefined") { livesLabel.setText('Can: ' + lives); } } updateLivesImages(); // Add a text label to show remaining lives (can/hak) on the GUI, next to the last life image var livesLabel = new Text2('Can: ' + lives, { size: 80, fill: "#fff" }); livesLabel.anchor.set(0, 0); // left-top // Initial position: right of the last life image, will be updated on resize and updateLivesImages function updateLivesLabelPosition() { if (livesImages.length > 0) { var lastImg = livesImages[livesImages.length - 1]; livesLabel.x = lastImg.x + lastImg.width + 20; livesLabel.y = lastImg.y + 10; } else { // Fallback: right of score livesLabel.x = LK.gui.width / 2 + scoreTxt.width / 2 + LIVES_IMAGE_LEFT_MARGIN; livesLabel.y = LIVES_IMAGE_TOP_MARGIN + 10; } } LK.gui.top.addChild(livesLabel); updateLivesLabelPosition(); // Ensure lives images and label are always visible on resize LK.on('resize', function () { updateLivesImages(); updateLivesLabelPosition(); }); // Helper: get lane center x function getLaneCenter(laneIdx) { return ROAD_X + LANE_WIDTH * (laneIdx + 0.5); } // Helper: spawn an obstacle (and maybe a boost) function spawnObstacle() { // Random lane var laneIdx = Math.floor(Math.random() * LANE_COUNT); // Randomly select one of six obstacle types (including police car) var type = Math.floor(Math.random() * 6); var obs; if (type === 0) { obs = new Obstacle(); // default car } else if (type === 1) { obs = new ObstacleTruck(); } else if (type === 2) { obs = new ObstacleMotorcycle(); } else if (type === 3) { obs = new ObstacleSportsCar(); } else if (type === 4) { obs = new ObstacleVan(); } else { // type === 5 obs = new PolisCar(); } obs.x = getLaneCenter(laneIdx); obs.y = -obs.height / 2; obstacles.push(obs); game.addChild(obs); // Maybe spawn a boost in a different lane if (Math.random() < BOOST_CHANCE) { var boostLane = laneIdx; // Try to pick a different lane if (LANE_COUNT > 1) { while (boostLane === laneIdx) { boostLane = Math.floor(Math.random() * LANE_COUNT); } } var boost = new Boost(); boost.x = getLaneCenter(boostLane); boost.y = obs.y; boosts.push(boost); game.addChild(boost); } // Maybe spawn a nitro in a random lane (10% chance) if (Math.random() < 0.10) { var nitroLane = laneIdx; if (LANE_COUNT > 1) { while (nitroLane === laneIdx) { nitroLane = Math.floor(Math.random() * LANE_COUNT); } } var nitro = new Nitro(); nitro.x = getLaneCenter(nitroLane); nitro.y = obs.y; nitros.push(nitro); game.addChild(nitro); } } // Helper: spawn lane markers as they scroll function updateLaneMarkers() { for (var i = lanes.length - 1; i >= 0; i--) { var lane = lanes[i]; lane.update(); if (lane.y > GAME_HEIGHT + 200) { // Recycle to top lane.y -= GAME_HEIGHT + 400; } } } // Dragging var dragging = false; var dragOffsetX = 0; // Touch/mouse controls game.down = function (x, y, obj) { // Nitro activation: if touch is on nitro icon, activate nitro if available if (x >= nitroIcon.x && x <= nitroIcon.x + nitroIcon.width && y >= nitroIcon.y && y <= nitroIcon.y + nitroIcon.height) { if (nitroCount > 0 && !nitroActive) { nitroCount--; updateNitroLabel(); nitroActive = true; nitroTicks = NITRO_DURATION; roadSpeed = roadSpeedBoosted; LK.effects.flashObject(car, 0x00eaff, 800); // Optionally, flash screen blue for effect LK.effects.flashScreen(0x00eaff, 300); } return; } // Only allow drag if touch is on car or on road if (x > ROAD_X && x < ROAD_X + ROAD_WIDTH && y > 0 && y < GAME_HEIGHT) { dragging = true; dragOffsetX = x - car.x; // Set targetX immediately car.targetX = Math.max(ROAD_X + car.width / 2, Math.min(ROAD_X + ROAD_WIDTH - car.width / 2, x - dragOffsetX)); } }; game.up = function (x, y, obj) { dragging = false; }; game.move = function (x, y, obj) { if (dragging) { // Clamp to road var tx = Math.max(ROAD_X + car.width / 2, Math.min(ROAD_X + ROAD_WIDTH - car.width / 2, x - dragOffsetX)); car.targetX = tx; } }; // Game update var lastObstacleY = -OBSTACLE_MIN_GAP; game.update = function () { // Update car car.update(); // Update lane markers updateLaneMarkers(); // Update distance traveled (add roadSpeed per tick, convert to meters) distanceTraveled += roadSpeed; if (distanceText) { // Show as meters or km if (distanceTraveled < 1000) { distanceText.setText(Math.floor(distanceTraveled) + " m"); } else { distanceText.setText((distanceTraveled / 1000).toFixed(2) + " km"); } } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if off screen if (obs.y - obs.height / 2 > GAME_HEIGHT + 100) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision with car if (car.intersects(obs)) { // Play damage sound LK.getSound('Damage').play(); // Flash screen red LK.effects.flashScreen(0xff0000, 800); // Remove the obstacle so it doesn't trigger again obs.destroy(); obstacles.splice(i, 1); // Decrement lives lives--; updateLivesText(); if (lives <= 0) { LK.showGameOver(); return; } // If not game over, briefly flash car and continue LK.effects.flashObject(car, 0xff0000, 600); continue; } } // Update boosts for (var i = boosts.length - 1; i >= 0; i--) { var boost = boosts[i]; boost.update(); // Remove if off screen if (boost.y - boost.height / 2 > GAME_HEIGHT + 100) { boost.destroy(); boosts.splice(i, 1); continue; } // Collect boost if (car.intersects(boost)) { boost.destroy(); boosts.splice(i, 1); // Add score for collecting boost score += 100; scoreTxt.setText(score); // Play coin sound LK.getSound('Coinsound').play(); // Flash car yellow LK.effects.flashObject(car, 0xffeb3b, 400); } } // Update nitros for (var i = nitros.length - 1; i >= 0; i--) { var nitro = nitros[i]; nitro.update(); // Remove if off screen if (nitro.y - nitro.height / 2 > GAME_HEIGHT + 100) { nitro.destroy(); nitros.splice(i, 1); continue; } // Collect nitro if (car.intersects(nitro)) { nitro.destroy(); nitros.splice(i, 1); nitroCount++; updateNitroLabel(); // Play nitro sound LK.getSound('Nitrosound').play(); // Flash car cyan LK.effects.flashObject(car, 0x00eaff, 400); // Activate nitro immediately for 4 seconds (240 ticks at 60fps) nitroActive = true; nitroTicks = 240; roadSpeed = roadSpeedBoosted; } } // Handle boost timer if (boostTicks > 0) { boostTicks--; if (boostTicks === 0) { roadSpeed = roadSpeedBase; } } // Handle nitro timer if (nitroActive) { nitroTicks--; if (nitroTicks <= 0) { nitroActive = false; roadSpeed = roadSpeedBase; } } // Spawn new obstacles if (obstacles.length === 0 || obstacles[obstacles.length - 1].y > OBSTACLE_MIN_GAP + Math.random() * (OBSTACLE_MAX_GAP - OBSTACLE_MIN_GAP)) { spawnObstacle(); } // Score is only updated by collecting boosts. // Check if car is off the road if (car.x - car.width / 2 < ROAD_X || car.x + car.width / 2 > ROAD_X + ROAD_WIDTH) { // Play damage sound before game over LK.getSound('Damage').play(); LK.effects.flashScreen(0xff0000, 800); // Decrement lives lives--; updateLivesText(); if (lives <= 0) { // Delay game over slightly to ensure sound plays LK.setTimeout(function () { LK.showGameOver(); }, 100); return; } // If not game over, flash car and move car back to road center LK.effects.flashObject(car, 0xff0000, 600); car.x = CAR_START_X; car.targetX = car.x; // Don't return, let the game continue } }; // Reset game state on new game LK.on('gameStart', function () { // Play start sound LK.getSound('Arabasssw').play(); LK.playMusic('Music'); // Remove all obstacles and boosts for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy(); for (var i = 0; i < boosts.length; i++) boosts[i].destroy(); obstacles = []; boosts = []; // Reset car position car.x = CAR_START_X; car.y = CAR_START_Y; car.targetX = car.x; // Reset score and speed score = 0; scoreTxt.setText(score); roadSpeed = roadSpeedBase; boostTicks = 0; // Reset distance traveled distanceTraveled = 0; if (distanceText) { distanceText.setText("0 m"); } // Reset lane markers spawnLaneMarkers(); // Reset lives lives = 3; updateLivesText(); if (typeof livesLabel !== "undefined") { livesLabel.setText('Can: ' + lives); } // Reset nitro state nitroCount = 0; nitroActive = false; nitroTicks = 0; updateNitroLabel(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Boost class
var Boost = Container.expand(function () {
var self = Container.call(this);
var boostAsset = self.attachAsset('boost', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = boostAsset.width;
self.height = boostAsset.height;
self.update = function () {
self.y += roadSpeed;
};
return self;
});
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
var carAsset = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
// For collision, use the container itself
self.width = carAsset.width;
self.height = carAsset.height;
// Car speed (pixels per tick)
self.speed = 10;
// Lateral speed (for smooth steering)
self.lateralSpeed = 0;
// Max lateral speed
self.maxLateralSpeed = 32;
// Steering target (x position)
self.targetX = self.x;
// Update method
self.update = function () {
// Smoothly move towards targetX
var dx = self.targetX - self.x;
if (Math.abs(dx) > 2) {
self.lateralSpeed = Math.max(-self.maxLateralSpeed, Math.min(self.maxLateralSpeed, dx * 0.25));
self.x += self.lateralSpeed;
} else {
self.lateralSpeed = 0;
self.x = self.targetX;
}
};
return self;
});
// Lane marker class
var Lane = Container.expand(function () {
var self = Container.call(this);
var laneAsset = self.attachAsset('lane', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = laneAsset.width;
self.height = laneAsset.height;
self.update = function () {
self.y += roadSpeed;
};
return self;
});
// Nitro class (collectible for nitro boost)
var Nitro = Container.expand(function () {
var self = Container.call(this);
var nitroAsset = self.attachAsset('Nitro', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = nitroAsset.width;
self.height = nitroAsset.height;
self.update = function () {
self.y += roadSpeed;
};
return self;
});
// Obstacle class (default car)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsAsset.width;
self.height = obsAsset.height;
// Update method: move down by road speed
self.update = function () {
// Track lastY for scoring
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
// No score for passing obstacles; scoring is handled by collecting boosts.
self.lastY = self.y;
};
return self;
});
// Motorcycle obstacle
var ObstacleMotorcycle = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle_motorcycle', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsAsset.width;
self.height = obsAsset.height;
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
self.lastY = self.y;
};
return self;
});
// Sports car obstacle
var ObstacleSportsCar = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle_sportscar', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsAsset.width;
self.height = obsAsset.height;
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
self.lastY = self.y;
};
return self;
});
// Truck obstacle
var ObstacleTruck = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle_truck', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsAsset.width;
self.height = obsAsset.height;
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
self.lastY = self.y;
};
return self;
});
// Van obstacle
var ObstacleVan = Container.expand(function () {
var self = Container.call(this);
var obsAsset = self.attachAsset('obstacle_van', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = obsAsset.width;
self.height = obsAsset.height;
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
self.lastY = self.y;
};
return self;
});
// Police Car class
var PolisCar = Container.expand(function () {
var self = Container.call(this);
var polisAsset = self.attachAsset('Polisecar', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = polisAsset.width;
self.height = polisAsset.height;
// Police car speed (moves down the road)
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += roadSpeed;
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Lane marker
// Road
// Speed boost
// Obstacle
// Car (player)
// Play start sound at the very beginning of the game
LK.getSound('Arabasssw').play();
LK.playMusic('Music');
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var ROAD_WIDTH = 900;
var ROAD_X = (GAME_WIDTH - ROAD_WIDTH) / 2;
var ROAD_Y = 0;
var LANE_COUNT = 3;
var LANE_WIDTH = ROAD_WIDTH / LANE_COUNT;
var CAR_START_X = GAME_WIDTH / 2;
var CAR_START_Y = GAME_HEIGHT - 500;
var OBSTACLE_MIN_GAP = 600;
var OBSTACLE_MAX_GAP = 1100;
var BOOST_CHANCE = 0.25; // 25% chance to spawn a boost with an obstacle
// Road speed (pixels per tick)
var roadSpeed = 10;
var roadSpeedBase = 10;
var roadSpeedBoosted = 16;
var boostDuration = 90; // ticks (1.5 seconds)
var boostTicks = 0;
// Score
var score = 0;
// Arrays for game objects
var obstacles = [];
var boosts = [];
var lanes = [];
var nitros = []; // Nitro collectibles
// Nitro state
var nitroCount = 0;
var nitroActive = false;
var nitroTicks = 0;
var NITRO_DURATION = 240; // 4 seconds at 60fps
// Road background
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0,
x: ROAD_X,
y: ROAD_Y
});
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Distance traveled (meters)
var distanceTraveled = 0;
// Distance text
var distanceText = new Text2('0 m', {
size: 80,
fill: 0xFFD700
});
distanceText.anchor.set(0.5, 0);
// Place at the very top center, with a small margin from the top
distanceText.x = LK.gui.width / 2;
distanceText.y = 0; // absolutely at the top
LK.gui.top.addChild(distanceText);
// Nitro GUI icon and counter (must be after scoreTxt is created)
var nitroIcon = LK.getAsset('Nitro', {
anchorX: 0,
anchorY: 0,
width: 90,
height: 90
});
nitroIcon.x = LK.gui.width / 2 + scoreTxt.width / 2 + 350;
nitroIcon.y = 10;
LK.gui.top.addChild(nitroIcon);
var nitroLabel = new Text2('x' + nitroCount, {
size: 80,
fill: 0x00EAFF
});
nitroLabel.anchor.set(0, 0);
nitroLabel.x = nitroIcon.x + nitroIcon.width + 10;
nitroLabel.y = nitroIcon.y + 10;
LK.gui.top.addChild(nitroLabel);
function updateNitroLabel() {
nitroLabel.setText('x' + nitroCount);
}
game.addChild(road);
// Lane markers
function spawnLaneMarkers() {
// Remove old lanes
for (var i = 0; i < lanes.length; i++) {
lanes[i].destroy();
}
lanes = [];
// For each lane (except the leftmost), draw a marker
for (var l = 1; l < LANE_COUNT; l++) {
for (var y = -200; y < GAME_HEIGHT + 200; y += 400) {
var lane = new Lane();
lane.x = ROAD_X + l * LANE_WIDTH;
lane.y = y;
lanes.push(lane);
game.addChild(lane);
}
}
}
spawnLaneMarkers();
// Car (player)
var car = new Car();
car.x = CAR_START_X;
car.y = CAR_START_Y;
car.targetX = car.x;
game.addChild(car);
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives (hak) system
var lives = 3;
// Image-based lives display
var livesImages = [];
var LIVES_IMAGE_ID = 'car'; // Use car image for lives
var LIVES_IMAGE_SIZE = 90; // px
var LIVES_IMAGE_MARGIN = 20; // px between images
// Positioning: Place lives images to the right of the score counter
var LIVES_IMAGE_TOP_MARGIN = 10; // px from top of GUI
var LIVES_IMAGE_LEFT_MARGIN = 40; // px from left of score counter
function updateLivesImages() {
// Remove old images
for (var i = 0; i < livesImages.length; i++) {
livesImages[i].destroy();
}
livesImages = [];
// Place lives images to the right of the score counter
// Get scoreTxt position in GUI coordinates
var scoreX = scoreTxt.x * LK.gui.width;
var scoreY = scoreTxt.y * LK.gui.height;
// But since anchor is (0.5, 0), scoreTxt.x is centered in GUI width
var baseX = LK.gui.width / 2 + scoreTxt.width / 2 + LIVES_IMAGE_LEFT_MARGIN;
var baseY = LIVES_IMAGE_TOP_MARGIN;
for (var i = 0; i < lives; i++) {
var img = LK.getAsset(LIVES_IMAGE_ID, {
anchorX: 0,
anchorY: 0,
width: LIVES_IMAGE_SIZE,
height: LIVES_IMAGE_SIZE
});
// Position: right of score, stacked horizontally with margin
img.x = baseX + i * (LIVES_IMAGE_SIZE + LIVES_IMAGE_MARGIN);
img.y = baseY;
LK.gui.top.addChild(img);
livesImages.push(img);
}
}
// Helper to update lives text (legacy, keep for compatibility)
function updateLivesText() {
updateLivesImages();
if (typeof livesLabel !== "undefined") {
livesLabel.setText('Can: ' + lives);
}
}
updateLivesImages();
// Add a text label to show remaining lives (can/hak) on the GUI, next to the last life image
var livesLabel = new Text2('Can: ' + lives, {
size: 80,
fill: "#fff"
});
livesLabel.anchor.set(0, 0); // left-top
// Initial position: right of the last life image, will be updated on resize and updateLivesImages
function updateLivesLabelPosition() {
if (livesImages.length > 0) {
var lastImg = livesImages[livesImages.length - 1];
livesLabel.x = lastImg.x + lastImg.width + 20;
livesLabel.y = lastImg.y + 10;
} else {
// Fallback: right of score
livesLabel.x = LK.gui.width / 2 + scoreTxt.width / 2 + LIVES_IMAGE_LEFT_MARGIN;
livesLabel.y = LIVES_IMAGE_TOP_MARGIN + 10;
}
}
LK.gui.top.addChild(livesLabel);
updateLivesLabelPosition();
// Ensure lives images and label are always visible on resize
LK.on('resize', function () {
updateLivesImages();
updateLivesLabelPosition();
});
// Helper: get lane center x
function getLaneCenter(laneIdx) {
return ROAD_X + LANE_WIDTH * (laneIdx + 0.5);
}
// Helper: spawn an obstacle (and maybe a boost)
function spawnObstacle() {
// Random lane
var laneIdx = Math.floor(Math.random() * LANE_COUNT);
// Randomly select one of six obstacle types (including police car)
var type = Math.floor(Math.random() * 6);
var obs;
if (type === 0) {
obs = new Obstacle(); // default car
} else if (type === 1) {
obs = new ObstacleTruck();
} else if (type === 2) {
obs = new ObstacleMotorcycle();
} else if (type === 3) {
obs = new ObstacleSportsCar();
} else if (type === 4) {
obs = new ObstacleVan();
} else {
// type === 5
obs = new PolisCar();
}
obs.x = getLaneCenter(laneIdx);
obs.y = -obs.height / 2;
obstacles.push(obs);
game.addChild(obs);
// Maybe spawn a boost in a different lane
if (Math.random() < BOOST_CHANCE) {
var boostLane = laneIdx;
// Try to pick a different lane
if (LANE_COUNT > 1) {
while (boostLane === laneIdx) {
boostLane = Math.floor(Math.random() * LANE_COUNT);
}
}
var boost = new Boost();
boost.x = getLaneCenter(boostLane);
boost.y = obs.y;
boosts.push(boost);
game.addChild(boost);
}
// Maybe spawn a nitro in a random lane (10% chance)
if (Math.random() < 0.10) {
var nitroLane = laneIdx;
if (LANE_COUNT > 1) {
while (nitroLane === laneIdx) {
nitroLane = Math.floor(Math.random() * LANE_COUNT);
}
}
var nitro = new Nitro();
nitro.x = getLaneCenter(nitroLane);
nitro.y = obs.y;
nitros.push(nitro);
game.addChild(nitro);
}
}
// Helper: spawn lane markers as they scroll
function updateLaneMarkers() {
for (var i = lanes.length - 1; i >= 0; i--) {
var lane = lanes[i];
lane.update();
if (lane.y > GAME_HEIGHT + 200) {
// Recycle to top
lane.y -= GAME_HEIGHT + 400;
}
}
}
// Dragging
var dragging = false;
var dragOffsetX = 0;
// Touch/mouse controls
game.down = function (x, y, obj) {
// Nitro activation: if touch is on nitro icon, activate nitro if available
if (x >= nitroIcon.x && x <= nitroIcon.x + nitroIcon.width && y >= nitroIcon.y && y <= nitroIcon.y + nitroIcon.height) {
if (nitroCount > 0 && !nitroActive) {
nitroCount--;
updateNitroLabel();
nitroActive = true;
nitroTicks = NITRO_DURATION;
roadSpeed = roadSpeedBoosted;
LK.effects.flashObject(car, 0x00eaff, 800);
// Optionally, flash screen blue for effect
LK.effects.flashScreen(0x00eaff, 300);
}
return;
}
// Only allow drag if touch is on car or on road
if (x > ROAD_X && x < ROAD_X + ROAD_WIDTH && y > 0 && y < GAME_HEIGHT) {
dragging = true;
dragOffsetX = x - car.x;
// Set targetX immediately
car.targetX = Math.max(ROAD_X + car.width / 2, Math.min(ROAD_X + ROAD_WIDTH - car.width / 2, x - dragOffsetX));
}
};
game.up = function (x, y, obj) {
dragging = false;
};
game.move = function (x, y, obj) {
if (dragging) {
// Clamp to road
var tx = Math.max(ROAD_X + car.width / 2, Math.min(ROAD_X + ROAD_WIDTH - car.width / 2, x - dragOffsetX));
car.targetX = tx;
}
};
// Game update
var lastObstacleY = -OBSTACLE_MIN_GAP;
game.update = function () {
// Update car
car.update();
// Update lane markers
updateLaneMarkers();
// Update distance traveled (add roadSpeed per tick, convert to meters)
distanceTraveled += roadSpeed;
if (distanceText) {
// Show as meters or km
if (distanceTraveled < 1000) {
distanceText.setText(Math.floor(distanceTraveled) + " m");
} else {
distanceText.setText((distanceTraveled / 1000).toFixed(2) + " km");
}
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y - obs.height / 2 > GAME_HEIGHT + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with car
if (car.intersects(obs)) {
// Play damage sound
LK.getSound('Damage').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 800);
// Remove the obstacle so it doesn't trigger again
obs.destroy();
obstacles.splice(i, 1);
// Decrement lives
lives--;
updateLivesText();
if (lives <= 0) {
LK.showGameOver();
return;
}
// If not game over, briefly flash car and continue
LK.effects.flashObject(car, 0xff0000, 600);
continue;
}
}
// Update boosts
for (var i = boosts.length - 1; i >= 0; i--) {
var boost = boosts[i];
boost.update();
// Remove if off screen
if (boost.y - boost.height / 2 > GAME_HEIGHT + 100) {
boost.destroy();
boosts.splice(i, 1);
continue;
}
// Collect boost
if (car.intersects(boost)) {
boost.destroy();
boosts.splice(i, 1);
// Add score for collecting boost
score += 100;
scoreTxt.setText(score);
// Play coin sound
LK.getSound('Coinsound').play();
// Flash car yellow
LK.effects.flashObject(car, 0xffeb3b, 400);
}
}
// Update nitros
for (var i = nitros.length - 1; i >= 0; i--) {
var nitro = nitros[i];
nitro.update();
// Remove if off screen
if (nitro.y - nitro.height / 2 > GAME_HEIGHT + 100) {
nitro.destroy();
nitros.splice(i, 1);
continue;
}
// Collect nitro
if (car.intersects(nitro)) {
nitro.destroy();
nitros.splice(i, 1);
nitroCount++;
updateNitroLabel();
// Play nitro sound
LK.getSound('Nitrosound').play();
// Flash car cyan
LK.effects.flashObject(car, 0x00eaff, 400);
// Activate nitro immediately for 4 seconds (240 ticks at 60fps)
nitroActive = true;
nitroTicks = 240;
roadSpeed = roadSpeedBoosted;
}
}
// Handle boost timer
if (boostTicks > 0) {
boostTicks--;
if (boostTicks === 0) {
roadSpeed = roadSpeedBase;
}
}
// Handle nitro timer
if (nitroActive) {
nitroTicks--;
if (nitroTicks <= 0) {
nitroActive = false;
roadSpeed = roadSpeedBase;
}
}
// Spawn new obstacles
if (obstacles.length === 0 || obstacles[obstacles.length - 1].y > OBSTACLE_MIN_GAP + Math.random() * (OBSTACLE_MAX_GAP - OBSTACLE_MIN_GAP)) {
spawnObstacle();
}
// Score is only updated by collecting boosts.
// Check if car is off the road
if (car.x - car.width / 2 < ROAD_X || car.x + car.width / 2 > ROAD_X + ROAD_WIDTH) {
// Play damage sound before game over
LK.getSound('Damage').play();
LK.effects.flashScreen(0xff0000, 800);
// Decrement lives
lives--;
updateLivesText();
if (lives <= 0) {
// Delay game over slightly to ensure sound plays
LK.setTimeout(function () {
LK.showGameOver();
}, 100);
return;
}
// If not game over, flash car and move car back to road center
LK.effects.flashObject(car, 0xff0000, 600);
car.x = CAR_START_X;
car.targetX = car.x;
// Don't return, let the game continue
}
};
// Reset game state on new game
LK.on('gameStart', function () {
// Play start sound
LK.getSound('Arabasssw').play();
LK.playMusic('Music');
// Remove all obstacles and boosts
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var i = 0; i < boosts.length; i++) boosts[i].destroy();
obstacles = [];
boosts = [];
// Reset car position
car.x = CAR_START_X;
car.y = CAR_START_Y;
car.targetX = car.x;
// Reset score and speed
score = 0;
scoreTxt.setText(score);
roadSpeed = roadSpeedBase;
boostTicks = 0;
// Reset distance traveled
distanceTraveled = 0;
if (distanceText) {
distanceText.setText("0 m");
}
// Reset lane markers
spawnLaneMarkers();
// Reset lives
lives = 3;
updateLivesText();
if (typeof livesLabel !== "undefined") {
livesLabel.setText('Can: ' + lives);
}
// Reset nitro state
nitroCount = 0;
nitroActive = false;
nitroTicks = 0;
updateNitroLabel();
});