User prompt
puan sayısının textini, metre barının texini, kapasite barının texinin fontunu değiştir
User prompt
shop menüsündeki capacity yazısını kaldır
User prompt
durakların shop menüsünün üstünde kalmasını düzelt
User prompt
hâlâ aldığımda kapasite doluluğunu göstermek için yol assetsi gözüküyor onu dark green assets ile değiştir
User prompt
add plus capacity assets and make dark green. Use that for showing get traveller in capacity
User prompt
change streetbg showing in meter bar
User prompt
add new assets for capacity bar bg and meter bar bg. Make capacity bar bg green meter bar orange
User prompt
change meter bar background and capacity background. Make meter bar bg yellow and capacity bar bg green
User prompt
Please fix the bug: 'undefined is not an object (evaluating 'musicToggleTxt.setText')' in or related to this line: 'musicToggleTxt.setText('Music: On');' Line Number: 130
User prompt
make setting button and make we can close/open music and sounds
User prompt
play baba music
User prompt
make sound lowest volune
User prompt
play cheer sound when take and drop traveller
User prompt
durakları yolun içine koydun düzelt
User prompt
durak konumlarını yolun boyutuna göre ayarla duraklar yolun içine girmesin tam kenarında olsın
User prompt
durağa bırakınca sadece erkek bırakmasını düzelt kaç kadın kaç erkek yolcu aldıysak o kadar erkek kadın bıraksın
User prompt
kadın yolcu spawn olmuyor duraklarda
User prompt
kadın yolcu assetsi ekle ve erkek kadın karışın spawn olmasını sağla
User prompt
yolcuları alınca değil bırakınca puan gelmesini sağla
User prompt
Please fix the bug: 'Can't find variable: shopBusCapacityText' in or related to this line: 'shopTitle.y = shopBusCapacityText.y + shopBusCapacityText.height + 8;' Line Number: 311
User prompt
shop butonundaki bus capacity i eski yerine barına koy
User prompt
upgrade mesajlarında açıklamaları kaldır sadece başlıklar fiyatları ve upgrade butonları kalsın
User prompt
upgrade mesajlarında taşanları alt satırlara geçirerek falan okunmasını sağla
User prompt
costları upgrade mesajlarının alt satırlarına yaz
User prompt
mesajları eski boyutuna getir upgrade butonlarını küçült
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bus (player) class var Bus = Container.expand(function () { var self = Container.call(this); var busAsset = self.attachAsset('bus', { anchorX: 0.5, anchorY: 1 }); // For touch drag self.dragging = false; self.dragOffsetY = 0; // Called every tick self.update = function () { // Clamp bus to road (vertical bounds) if (self.y < 400) self.y = 400; if (self.y > 2200) self.y = 2200; }; // Touch down on bus self.down = function (x, y, obj) { self.dragging = true; self.dragOffsetY = y - self.y; }; // Touch up on bus self.up = function (x, y, obj) { self.dragging = false; }; return self; }); // Bus Station class var BusStation = Container.expand(function () { var self = Container.call(this); // Use dropStation asset if isPickup is false, otherwise use station var assetId = typeof self.isPickup !== "undefined" && self.isPickup === false ? 'dropStation' : 'station'; var stationAsset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 1 }); // List of travelers at this station self.travelers = []; // Travelers are now spawned in spawnStation, not here // Remove traveler from this station self.removeTraveler = function (traveler) { for (var i = 0; i < self.travelers.length; i++) { if (self.travelers[i] === traveler) { self.travelers.splice(i, 1); break; } } }; // Called every tick self.update = function () { // No longer remove station when bus passes; stations persist }; return self; }); // Traveler class var Traveler = Container.expand(function () { var self = Container.call(this); var travelerAsset = self.attachAsset('traveler', { anchorX: 0.5, anchorY: 1 }); // Reference to the station this traveler belongs to self.station = null; // Whether this traveler is still waiting at the station self.waiting = true; // Track if this traveler was dropped (for possible future logic) self.dropped = false; // Time (in ticks) until this traveler leaves self.leaveTick = 0; // Called every tick self.update = function () { // If not waiting, do nothing if (!self.waiting) return; // Travelers no longer leave by themselves // Remove the leave-tick logic entirely }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // visually distinguish drop station (flipX as example) var streetBgWidth = 900; var streetBgHeight = 400; var streetBgY = 1500; var streetBgs = []; for (var i = 0; i < 3; i++) { var streetBg = LK.getAsset('streetBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + (i - 1) * streetBgWidth, y: streetBgY }); game.addChild(streetBg); streetBgs.push(streetBg); } // Traveler // Bus station // Bus (player vehicle) // Game world scroll variables var scrollX = 0; // How far the world has scrolled right var scrollSpeed = 10; // Pixels per tick // Bus (player) var bus = new Bus(); game.addChild(bus); bus.x = 400; bus.y = 1500; // List of stations in the world var stations = []; // Spawn fewer stations, with much greater spacing, and ensure max 2 stations visible on screen var lastStationX = 1200; var NUM_STATIONS = 6; // fewer stations for less crowding var minStationSpacing = 1200; // minimum distance between stations (at least 1 screen width) var maxStationSpacing = 1600; // maximum distance between stations var stationWidth = 400; for (var i = 0; i < NUM_STATIONS; i++) { var isPickup = i % 2 === 0; var tryCount = 0; var valid = false; var tryX = 0; while (!valid && tryCount < 100) { var spacing = minStationSpacing + Math.floor(Math.random() * (maxStationSpacing - minStationSpacing + 1)); if (i === 0) { tryX = 1200; } else { tryX = lastStationX + spacing; } // Check for overlap with all previous stations (ensure at least minStationSpacing between centers) valid = true; for (var j = 0; j < stations.length; j++) { var prev = stations[j]; if (Math.abs(tryX - prev.x) < minStationSpacing) { valid = false; break; } } tryCount++; } lastStationX = tryX; spawnStation(lastStationX, isPickup); } // GUI: Score (number of travelers picked up) var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Meter Bar UI --- var meterBarBg = LK.getAsset('streetBg', { anchorX: 0, anchorY: 0.5, x: 200, y: 120, width: 600, height: 40, color: 0x222222 }); var meterBarFill = LK.getAsset('streetBg', { anchorX: 0, anchorY: 0.5, x: 200, y: 120, width: 600, height: 40, color: 0x2d8cf0 }); meterBarFill.width = 0; LK.gui.top.addChild(meterBarBg); LK.gui.top.addChild(meterBarFill); // Add a text label to the meter bar showing the remaining distance in meters var meterBarText = new Text2('0m', { size: 60, fill: 0xffffff }); meterBarText.anchor.set(0.5, 0.5); meterBarText.x = 200 + 600 / 2; meterBarText.y = 120; LK.gui.top.addChild(meterBarText); // --- Bus Capacity Bar UI --- var busCapacityBarBg = LK.getAsset('streetBg', { anchorX: 0, anchorY: 0.5, x: 200, y: 200, width: 600, height: 32, color: 0x444444 }); var busCapacityBarFill = LK.getAsset('streetBg', { anchorX: 0, anchorY: 0.5, x: 200, y: 200, width: 600, height: 32, color: 0x83de44 }); busCapacityBarFill.width = 0; LK.gui.top.addChild(busCapacityBarBg); LK.gui.top.addChild(busCapacityBarFill); // (busCapacityBarText definition moved to after shopPanelBg is defined) // For dragging bus var dragBus = false; // --- Take Travelers Button --- var takeBtnBg = LK.getAsset('takeBtnBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 320, y: 2732 - 200 }); var takeBtnTxt = new Text2('Take Travelers', { size: 60, fill: 0xffffff }); takeBtnTxt.anchor.set(0.5, 0.5); takeBtnBg.addChild(takeBtnTxt); game.addChild(takeBtnBg); // --- Drop Travelers Button --- var dropBtnBg = LK.getAsset('takeBtnBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 320, y: 2732 - 200 }); var dropBtnTxt = new Text2('Drop Travelers', { size: 60, fill: 0xffffff }); dropBtnTxt.anchor.set(0.5, 0.5); dropBtnBg.addChild(dropBtnTxt); game.addChild(dropBtnBg); // --- Shop Button --- var shopBtnBg = LK.getAsset('takeBtnBg', { anchorX: 0.5, anchorY: 0.5, x: 320, // Move to left side of the screen, away from top left 100x100 area y: 2732 - 200 }); var shopBtnTxt = new Text2('Shop', { size: 60, fill: 0xffffff }); shopBtnTxt.anchor.set(0.5, 0.5); shopBtnBg.addChild(shopBtnTxt); game.addChild(shopBtnBg); // Shop UI elements (hidden by default) var shopPanelBg = LK.getAsset('whitePanel', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); shopPanelBg.visible = false; game.addChild(shopPanelBg); // Add text to capacity bar (above the bus capacity bar, in the main UI) // (Removed from main UI, now only in shop panel) // Add a bus capacity message to the shop panel, clearly inside and visually separated var shopBusCapacityText = new Text2('0/10', { size: 60, fill: 0x222222, fontWeight: "bold" }); shopBusCapacityText.anchor.set(0.5, 0); // Place at the top center of the white panel, with margin from the top shopBusCapacityText.x = 0; // Move the bus capacity message higher (closer to the top edge of the white panel) shopBusCapacityText.y = -340; shopPanelBg.addChild(shopBusCapacityText); // Shop title, below the capacity message, centered var shopTitle = new Text2('Shop', { size: 90, fill: 0x222222 }); shopTitle.anchor.set(0.5, 0); shopTitle.x = 0; // Move the shop title higher as well, just below the bus capacity message shopTitle.y = shopBusCapacityText.y + shopBusCapacityText.height + 8; shopPanelBg.addChild(shopTitle); // Shop upgrade buttons and texts var shopUpgradeBtns = []; var shopUpgradeTxts = []; var shopUpgradeCosts = [30, 30, 30]; // initial costs var shopUpgradeLevels = [0, 0, 0]; // [capacity, speed, money] var shopUpgradeMax = [10, 10, 10]; var shopUpgradeNames = ['Capacity', 'Speed', 'Money']; var shopUpgradeDesc = ['Increase bus capacity by 2', 'Increase speed by 2', 'Increase money per traveler by 1']; for (var i = 0; i < 3; i++) { // Create a container for each row var row = new Container(); // Vertically space rows within the white panel, below the title, with even spacing var rowHeight = 180; // Move the upgrade rows higher as well var panelContentTop = shopTitle.y + shopTitle.height + 16; row.y = panelContentTop + i * rowHeight; // Center row horizontally in the panel row.x = 0; // --- Lay out texts from left to right, all inside the white panel --- // Name var nameTxt = new Text2(shopUpgradeNames[i], { size: 56, fill: 0x222222 }); nameTxt.anchor.set(0, 0.5); nameTxt.x = -900 / 2 + 40; nameTxt.y = 0; // Level var levelTxt = new Text2('(Lv.0)', { size: 56, fill: 0x222222 }); levelTxt.anchor.set(0, 0.5); levelTxt.x = nameTxt.x + nameTxt.width + 24; levelTxt.y = 0; // Desc var descTxt = new Text2(shopUpgradeDesc[i], { size: 44, fill: 0x222222 }); descTxt.anchor.set(0, 0.5); descTxt.x = levelTxt.x + levelTxt.width + 24; descTxt.y = 0; // Cost var costTxt = new Text2('Cost: 30', { size: 56, fill: 0x222222 }); costTxt.anchor.set(0, 0.5); costTxt.x = descTxt.x + descTxt.width + 24; costTxt.y = 0; // Upgrade button (right side, inside panel, with margin) var btn = LK.getAsset('takeBtnBg', { anchorX: 0.5, anchorY: 0.5, x: 900 / 2 - 120, y: 0, width: 180, height: 70 }); btn.visible = true; // Button label var btnLabel = new Text2('Upgrade', { size: 32, fill: 0xffffff }); btnLabel.anchor.set(0.5, 0.5); btn.addChild(btnLabel); // Add all texts and button to row row.addChild(nameTxt); row.addChild(levelTxt); row.addChild(descTxt); row.addChild(costTxt); row.addChild(btn); // Add row to shop panel shopPanelBg.addChild(row); // Track for logic shopUpgradeBtns.push(btn); // Store all text objects for update logic shopUpgradeTxts.push({ name: nameTxt, level: levelTxt, desc: descTxt, cost: costTxt }); } shopPanelBg.visible = false; // Shop close button var shopCloseBtn = LK.getAsset('takeBtnBg', { anchorX: 0.5, anchorY: 0.5, x: 900 / 2, y: 820 }); var shopCloseTxt = new Text2('Close', { size: 48, fill: 0x222222 }); shopCloseTxt.anchor.set(0.5, 0.5); shopCloseBtn.addChild(shopCloseTxt); shopPanelBg.addChild(shopCloseBtn); // Track if take or drop or shop button is pressed this frame var takeBtnPressed = false; var dropBtnPressed = false; var shopBtnPressed = false; var shopUpgradePressed = [false, false, false]; var shopClosePressed = false; // Button press handlers takeBtnBg.down = function (x, y, obj) { if (takeBtnBg.interactive !== false && !shopPanelBg.visible) { takeBtnPressed = true; } }; dropBtnBg.down = function (x, y, obj) { if (dropBtnBg.interactive !== false && !shopPanelBg.visible) { dropBtnPressed = true; } }; // Shop button handler shopBtnBg.down = function (x, y, obj) { if (!shopPanelBg.visible) { shopBtnPressed = true; } }; // Shop upgrade button handlers for (var i = 0; i < 3; i++) { (function (idx) { shopUpgradeBtns[idx].down = function (x, y, obj) { if (shopPanelBg.visible) { shopUpgradePressed[idx] = true; } }; })(i); } // Shop close button handler shopCloseBtn.down = function (x, y, obj) { if (shopPanelBg.visible) { shopClosePressed = true; } }; // Generate a station at a given x, alternating pickup/drop and up/down function spawnStation(x, isPickup) { var station = new BusStation(); station.isPickup = !!isPickup; // Re-attach correct asset if drop station (for existing BusStation instances) if (!station.isPickup) { if (station.children.length > 0) { station.removeChild(station.children[0]); } station.attachAsset('dropStation', { anchorX: 0.5, anchorY: 1 }); } // Alternate up/down for each station var streetCenterY = streetBgY; if (stations.length % 2 === 0) { station.y = streetCenterY - streetBgHeight / 2 - 40; // above street } else { station.y = streetCenterY + streetBgHeight / 2 + 40; // below street } // Place at given x station.x = x; // Spawn travelers immediately if pickup station if (station.isPickup) { var numTravelers = 1 + Math.floor(Math.random() * 10); var travelerYOffset = station.y < streetCenterY ? -140 : 140; for (var i = 0; i < numTravelers; i++) { var traveler = new Traveler(); traveler.station = station; traveler.x = 0; traveler.y = travelerYOffset + (station.y < streetCenterY ? -i * 130 : i * 130); station.addChild(traveler); station.travelers.push(traveler); } } game.addChild(station); stations.push(station); } // (removed duplicate old station spawn code) // Move handler for dragging bus function handleMove(x, y, obj) { // Only drag if started on bus if (bus.dragging) { bus.y = y - bus.dragOffsetY; } } game.move = handleMove; // Down handler: start drag if on bus, or start holding for rightward movement var holdingRight = false; game.down = function (x, y, obj) { // Convert to bus local coordinates var local = bus.toLocal(game.toGlobal({ x: x, y: y })); // If within bus bounds, start drag if (local.x > -bus.width / 2 && local.x < bus.width / 2 && local.y > -bus.height && local.y < 0) { bus.dragging = true; bus.dragOffsetY = y - bus.y; } else { // Start holding for rightward movement holdingRight = true; } }; // Up handler: stop drag and stop holding rightward movement game.up = function (x, y, obj) { bus.dragging = false; holdingRight = false; }; // Main game update loop game.update = function () { // --- SHOP LOGIC --- // Show/hide shop panel if (shopBtnPressed) { shopPanelBg.visible = true; takeBtnBg.visible = false; dropBtnBg.visible = false; shopBtnBg.visible = false; shopBtnPressed = false; } // Shop close if (shopClosePressed) { shopPanelBg.visible = false; takeBtnBg.visible = true; dropBtnBg.visible = true; shopBtnBg.visible = true; shopClosePressed = false; } // Update shop upgrade button texts for (var i = 0; i < 3; i++) { var level = shopUpgradeLevels[i]; var cost = shopUpgradeCosts[i] + level * 20; var max = shopUpgradeMax[i]; var name = shopUpgradeNames[i]; var desc = shopUpgradeDesc[i]; // Update each text field shopUpgradeTxts[i].name.setText(name); shopUpgradeTxts[i].level.setText('(Lv.' + level + (level >= max ? ' MAX' : '') + ')'); shopUpgradeTxts[i].desc.setText(desc); shopUpgradeTxts[i].cost.setText('Cost: ' + (level >= max ? '-' : cost)); // Re-layout: update x positions in case text width changed shopUpgradeTxts[i].level.x = shopUpgradeTxts[i].name.x + shopUpgradeTxts[i].name.width + 32; shopUpgradeTxts[i].desc.x = shopUpgradeTxts[i].level.x + shopUpgradeTxts[i].level.width + 32; shopUpgradeTxts[i].cost.x = shopUpgradeTxts[i].desc.x + shopUpgradeTxts[i].desc.width + 32; shopUpgradeBtns[i].alpha = level < max ? 1 : 0.5; shopUpgradeBtns[i].interactive = level < max; } // Update shop bus capacity message if shop is open if (shopPanelBg.visible) { var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0; if (typeof maxCapacity === "undefined") maxCapacity = 10; shopBusCapacityText.setText(travelersOnBoardCount + "/" + maxCapacity); } // Handle shop upgrades for (var i = 0; i < 3; i++) { if (shopUpgradePressed[i]) { var level = shopUpgradeLevels[i]; var cost = shopUpgradeCosts[i] + level * 20; var max = shopUpgradeMax[i]; if (level < max && score >= cost) { score -= cost; scoreTxt.setText(score); shopUpgradeLevels[i]++; // Apply upgrade effect if (i === 0) { // Capacity maxCapacity += 2; } else if (i === 1) { // Speed scrollSpeed += 2; } else if (i === 2) { // Money if (typeof moneyPerTraveler === "undefined") moneyPerTraveler = 1; moneyPerTraveler += 1; } } shopUpgradePressed[i] = false; } } if (shopPanelBg.visible) { // Pause game logic when shop is open return; } // Move bus/world right if holding if (typeof holdingRight !== "undefined" && holdingRight) { var moveAmount = scrollSpeed; // Instead of moving the bus, move the world and keep bus centered scrollX += moveAmount; for (var i = 0; i < stations.length; i++) { stations[i].x -= moveAmount; } // Move and repeat street backgrounds for (var i = 0; i < streetBgs.length; i++) { streetBgs[i].x -= moveAmount; // If streetBg is fully off the left, move it to the right end if (streetBgs[i].x < -streetBgWidth / 2) { // Find the rightmost streetBg var maxX = streetBgs[0].x; for (var j = 1; j < streetBgs.length; j++) { if (streetBgs[j].x > maxX) maxX = streetBgs[j].x; } streetBgs[i].x = maxX + streetBgWidth; } } } // Always keep bus in the center of the screen horizontally bus.x = 2048 / 2; // Move all stations and their travelers (no auto scroll) for (var i = 0; i < stations.length; i++) { var station = stations[i]; // No station.x -= scrollSpeed; station.update(); for (var j = 0; j < station.travelers.length; j++) { station.travelers[j].update(); } } // Update bus bus.update(); // --- Meter Bar Update: Show distance to nearest upcoming station --- var nearestStation = null; var nearestDist = null; for (var i = 0; i < stations.length; i++) { var station = stations[i]; // Only consider stations ahead of the bus (to the right) var dx = station.x - bus.x; if (dx >= 0) { if (nearestStation === null || dx < nearestDist) { nearestStation = station; nearestDist = dx; } } } if (nearestStation) { var dist = Math.max(0, Math.floor(nearestDist)); var maxDist = 1200; // Max distance for full bar var barWidth = Math.max(0, Math.min(600, 600 * (1 - dist / maxDist))); meterBarFill.width = barWidth; meterBarText.setText(dist + "m"); } else { meterBarFill.width = 0; meterBarText.setText("0m"); } // Endless station spawning logic // Find the rightmost station's x var rightmostStationX = 0; for (var i = 0; i < stations.length; i++) { if (stations[i].x > rightmostStationX) rightmostStationX = stations[i].x; } // If the rightmost station is less than 2.5 screens ahead, spawn a new one if (rightmostStationX < scrollX + 2048 * 2.5) { // Alternate pickup/drop var isPickup = stations.length % 2 === 0; // Place new station at least minStationSpacing after the last one, with some randomization var spacing = minStationSpacing + Math.floor(Math.random() * (maxStationSpacing - minStationSpacing + 1)); var newX = rightmostStationX + spacing; spawnStation(newX, isPickup); } // --- Manual pickup and drop-off logic with Take Travelers button --- // --- Manual pickup and drop-off logic with Take Travelers button --- if (typeof bus.travelersOnBoard === "undefined") { bus.travelersOnBoard = []; bus.lastPickupStationIndex = -1; bus.lastDropStationIndex = -1; } // --- Enable/disable Take Travelers button based on action possibility --- var canTake = false; var canDrop = false; var dropStationIndex = -1; // Check if we can take travelers at a nearby station for (var i = 0; i < stations.length; i++) { var station = stations[i]; // Take: must be pickup station, has travelers, close, and not already picked up here if (station.isPickup && station.travelers.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastPickupStationIndex !== i) { canTake = true; } // Drop: must be drop station, bus has travelers, close, and not already dropped here if (!station.isPickup && bus.travelersOnBoard && bus.travelersOnBoard.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastDropStationIndex !== i) { canDrop = true; dropStationIndex = i; } } // --- Bus Capacity Bar Update --- if (typeof maxCapacity === "undefined") maxCapacity = 10; var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0; var capBarWidth = Math.max(0, Math.min(600, 600 * (travelersOnBoardCount / maxCapacity))); busCapacityBarFill.width = capBarWidth; // busCapacityBarText removed from main UI; only update shopBusCapacityText in shop panel // Visually enable/disable the take and drop buttons takeBtnBg.alpha = canTake ? 1 : 0.4; takeBtnBg.interactive = canTake; dropBtnBg.alpha = canDrop ? 1 : 0.4; dropBtnBg.interactive = canDrop; // --- Manual Pickup logic: only when button pressed --- if (typeof maxCapacity === "undefined") maxCapacity = 10; if (typeof moneyPerTraveler === "undefined") moneyPerTraveler = 1; if (takeBtnPressed) { for (var i = 0; i < stations.length; i++) { var station = stations[i]; // Only pick up if bus is close to pickup station, this is a new station, and this station has travelers if (station.isPickup && station.travelers.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastPickupStationIndex !== i) { // Pick up all waiting travelers at this station var waitingTravelers = []; for (var j = station.travelers.length - 1; j >= 0; j--) { var traveler = station.travelers[j]; if (traveler.waiting) { waitingTravelers.push(traveler); } } // Actually pick up the travelers, but only up to available capacity var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0; var availableCapacity = maxCapacity - travelersOnBoardCount; var numToPick = Math.min(availableCapacity, waitingTravelers.length); for (var w = 0; w < numToPick; w++) { var traveler = waitingTravelers[w]; traveler.waiting = false; // Animate traveler to bus, then destroy tween(traveler, { x: bus.x - station.x, y: bus.y - station.y - 100, alpha: 0 }, { duration: 400, easing: tween.easeIn, onFinish: function (trav) { return function () { trav.destroy(); }; }(traveler) }); // Add to bus's onboard list if (!bus.travelersOnBoard) bus.travelersOnBoard = []; bus.travelersOnBoard.push({ traveler: traveler, pickedUpAt: i }); // Remove from station station.removeTraveler(traveler); score += moneyPerTraveler; scoreTxt.setText(score); } // Mark this station as the last pickup bus.lastPickupStationIndex = i; break; // Only pick up at one station per press } } takeBtnPressed = false; // Reset button press } // --- Manual Drop-off logic: only when drop button pressed --- if (dropBtnPressed && canDrop && dropStationIndex !== -1) { var station = stations[dropStationIndex]; // Drop all travelers currently on the bus if (bus.travelersOnBoard && bus.travelersOnBoard.length > 0) { // Calculate base Y for stacking var baseY = 0; var stackDir = 1; // If station is above street, stack upwards; if below, stack downwards var streetCenterY = streetBgY; if (station.y < streetCenterY) { baseY = -140; stackDir = -1; } else { baseY = 140; stackDir = 1; } // Count how many travelers are already at this drop station (for stacking) var alreadyDropped = 0; for (var tt = 0; tt < station.travelers.length; tt++) { if (station.travelers[tt].dropped) alreadyDropped++; } for (var t = 0; t < bus.travelersOnBoard.length; t++) { var travelerObj = bus.travelersOnBoard[t]; var traveler = travelerObj.traveler; // Animate traveler to station, then keep at station (do NOT destroy) var newTraveler = new Traveler(); newTraveler.x = bus.x - station.x; newTraveler.y = bus.y - station.y - 100; newTraveler.alpha = 0; newTraveler.waiting = false; newTraveler.dropped = true; newTraveler.station = station; // Stack vertically at the station var stackIndex = alreadyDropped + t; newTraveler.x = 0; newTraveler.y = baseY + stackDir * stackIndex * 130; newTraveler.alpha = 0; station.addChild(newTraveler); station.travelers.push(newTraveler); tween(newTraveler, { x: 0, y: baseY + stackDir * stackIndex * 130, alpha: 1 }, { duration: 400, easing: tween.easeOut }); } // Clear bus bus.travelersOnBoard = []; // Mark this station as the last drop bus.lastDropStationIndex = dropStationIndex; } dropBtnPressed = false; // Reset button press } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bus (player) class
var Bus = Container.expand(function () {
var self = Container.call(this);
var busAsset = self.attachAsset('bus', {
anchorX: 0.5,
anchorY: 1
});
// For touch drag
self.dragging = false;
self.dragOffsetY = 0;
// Called every tick
self.update = function () {
// Clamp bus to road (vertical bounds)
if (self.y < 400) self.y = 400;
if (self.y > 2200) self.y = 2200;
};
// Touch down on bus
self.down = function (x, y, obj) {
self.dragging = true;
self.dragOffsetY = y - self.y;
};
// Touch up on bus
self.up = function (x, y, obj) {
self.dragging = false;
};
return self;
});
// Bus Station class
var BusStation = Container.expand(function () {
var self = Container.call(this);
// Use dropStation asset if isPickup is false, otherwise use station
var assetId = typeof self.isPickup !== "undefined" && self.isPickup === false ? 'dropStation' : 'station';
var stationAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 1
});
// List of travelers at this station
self.travelers = [];
// Travelers are now spawned in spawnStation, not here
// Remove traveler from this station
self.removeTraveler = function (traveler) {
for (var i = 0; i < self.travelers.length; i++) {
if (self.travelers[i] === traveler) {
self.travelers.splice(i, 1);
break;
}
}
};
// Called every tick
self.update = function () {
// No longer remove station when bus passes; stations persist
};
return self;
});
// Traveler class
var Traveler = Container.expand(function () {
var self = Container.call(this);
var travelerAsset = self.attachAsset('traveler', {
anchorX: 0.5,
anchorY: 1
});
// Reference to the station this traveler belongs to
self.station = null;
// Whether this traveler is still waiting at the station
self.waiting = true;
// Track if this traveler was dropped (for possible future logic)
self.dropped = false;
// Time (in ticks) until this traveler leaves
self.leaveTick = 0;
// Called every tick
self.update = function () {
// If not waiting, do nothing
if (!self.waiting) return;
// Travelers no longer leave by themselves
// Remove the leave-tick logic entirely
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// visually distinguish drop station (flipX as example)
var streetBgWidth = 900;
var streetBgHeight = 400;
var streetBgY = 1500;
var streetBgs = [];
for (var i = 0; i < 3; i++) {
var streetBg = LK.getAsset('streetBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + (i - 1) * streetBgWidth,
y: streetBgY
});
game.addChild(streetBg);
streetBgs.push(streetBg);
}
// Traveler
// Bus station
// Bus (player vehicle)
// Game world scroll variables
var scrollX = 0; // How far the world has scrolled right
var scrollSpeed = 10; // Pixels per tick
// Bus (player)
var bus = new Bus();
game.addChild(bus);
bus.x = 400;
bus.y = 1500;
// List of stations in the world
var stations = [];
// Spawn fewer stations, with much greater spacing, and ensure max 2 stations visible on screen
var lastStationX = 1200;
var NUM_STATIONS = 6; // fewer stations for less crowding
var minStationSpacing = 1200; // minimum distance between stations (at least 1 screen width)
var maxStationSpacing = 1600; // maximum distance between stations
var stationWidth = 400;
for (var i = 0; i < NUM_STATIONS; i++) {
var isPickup = i % 2 === 0;
var tryCount = 0;
var valid = false;
var tryX = 0;
while (!valid && tryCount < 100) {
var spacing = minStationSpacing + Math.floor(Math.random() * (maxStationSpacing - minStationSpacing + 1));
if (i === 0) {
tryX = 1200;
} else {
tryX = lastStationX + spacing;
}
// Check for overlap with all previous stations (ensure at least minStationSpacing between centers)
valid = true;
for (var j = 0; j < stations.length; j++) {
var prev = stations[j];
if (Math.abs(tryX - prev.x) < minStationSpacing) {
valid = false;
break;
}
}
tryCount++;
}
lastStationX = tryX;
spawnStation(lastStationX, isPickup);
}
// GUI: Score (number of travelers picked up)
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Meter Bar UI ---
var meterBarBg = LK.getAsset('streetBg', {
anchorX: 0,
anchorY: 0.5,
x: 200,
y: 120,
width: 600,
height: 40,
color: 0x222222
});
var meterBarFill = LK.getAsset('streetBg', {
anchorX: 0,
anchorY: 0.5,
x: 200,
y: 120,
width: 600,
height: 40,
color: 0x2d8cf0
});
meterBarFill.width = 0;
LK.gui.top.addChild(meterBarBg);
LK.gui.top.addChild(meterBarFill);
// Add a text label to the meter bar showing the remaining distance in meters
var meterBarText = new Text2('0m', {
size: 60,
fill: 0xffffff
});
meterBarText.anchor.set(0.5, 0.5);
meterBarText.x = 200 + 600 / 2;
meterBarText.y = 120;
LK.gui.top.addChild(meterBarText);
// --- Bus Capacity Bar UI ---
var busCapacityBarBg = LK.getAsset('streetBg', {
anchorX: 0,
anchorY: 0.5,
x: 200,
y: 200,
width: 600,
height: 32,
color: 0x444444
});
var busCapacityBarFill = LK.getAsset('streetBg', {
anchorX: 0,
anchorY: 0.5,
x: 200,
y: 200,
width: 600,
height: 32,
color: 0x83de44
});
busCapacityBarFill.width = 0;
LK.gui.top.addChild(busCapacityBarBg);
LK.gui.top.addChild(busCapacityBarFill);
// (busCapacityBarText definition moved to after shopPanelBg is defined)
// For dragging bus
var dragBus = false;
// --- Take Travelers Button ---
var takeBtnBg = LK.getAsset('takeBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 320,
y: 2732 - 200
});
var takeBtnTxt = new Text2('Take Travelers', {
size: 60,
fill: 0xffffff
});
takeBtnTxt.anchor.set(0.5, 0.5);
takeBtnBg.addChild(takeBtnTxt);
game.addChild(takeBtnBg);
// --- Drop Travelers Button ---
var dropBtnBg = LK.getAsset('takeBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 320,
y: 2732 - 200
});
var dropBtnTxt = new Text2('Drop Travelers', {
size: 60,
fill: 0xffffff
});
dropBtnTxt.anchor.set(0.5, 0.5);
dropBtnBg.addChild(dropBtnTxt);
game.addChild(dropBtnBg);
// --- Shop Button ---
var shopBtnBg = LK.getAsset('takeBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 320,
// Move to left side of the screen, away from top left 100x100 area
y: 2732 - 200
});
var shopBtnTxt = new Text2('Shop', {
size: 60,
fill: 0xffffff
});
shopBtnTxt.anchor.set(0.5, 0.5);
shopBtnBg.addChild(shopBtnTxt);
game.addChild(shopBtnBg);
// Shop UI elements (hidden by default)
var shopPanelBg = LK.getAsset('whitePanel', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
shopPanelBg.visible = false;
game.addChild(shopPanelBg);
// Add text to capacity bar (above the bus capacity bar, in the main UI)
// (Removed from main UI, now only in shop panel)
// Add a bus capacity message to the shop panel, clearly inside and visually separated
var shopBusCapacityText = new Text2('0/10', {
size: 60,
fill: 0x222222,
fontWeight: "bold"
});
shopBusCapacityText.anchor.set(0.5, 0);
// Place at the top center of the white panel, with margin from the top
shopBusCapacityText.x = 0;
// Move the bus capacity message higher (closer to the top edge of the white panel)
shopBusCapacityText.y = -340;
shopPanelBg.addChild(shopBusCapacityText);
// Shop title, below the capacity message, centered
var shopTitle = new Text2('Shop', {
size: 90,
fill: 0x222222
});
shopTitle.anchor.set(0.5, 0);
shopTitle.x = 0;
// Move the shop title higher as well, just below the bus capacity message
shopTitle.y = shopBusCapacityText.y + shopBusCapacityText.height + 8;
shopPanelBg.addChild(shopTitle);
// Shop upgrade buttons and texts
var shopUpgradeBtns = [];
var shopUpgradeTxts = [];
var shopUpgradeCosts = [30, 30, 30]; // initial costs
var shopUpgradeLevels = [0, 0, 0]; // [capacity, speed, money]
var shopUpgradeMax = [10, 10, 10];
var shopUpgradeNames = ['Capacity', 'Speed', 'Money'];
var shopUpgradeDesc = ['Increase bus capacity by 2', 'Increase speed by 2', 'Increase money per traveler by 1'];
for (var i = 0; i < 3; i++) {
// Create a container for each row
var row = new Container();
// Vertically space rows within the white panel, below the title, with even spacing
var rowHeight = 180;
// Move the upgrade rows higher as well
var panelContentTop = shopTitle.y + shopTitle.height + 16;
row.y = panelContentTop + i * rowHeight;
// Center row horizontally in the panel
row.x = 0;
// --- Lay out texts from left to right, all inside the white panel ---
// Name
var nameTxt = new Text2(shopUpgradeNames[i], {
size: 56,
fill: 0x222222
});
nameTxt.anchor.set(0, 0.5);
nameTxt.x = -900 / 2 + 40;
nameTxt.y = 0;
// Level
var levelTxt = new Text2('(Lv.0)', {
size: 56,
fill: 0x222222
});
levelTxt.anchor.set(0, 0.5);
levelTxt.x = nameTxt.x + nameTxt.width + 24;
levelTxt.y = 0;
// Desc
var descTxt = new Text2(shopUpgradeDesc[i], {
size: 44,
fill: 0x222222
});
descTxt.anchor.set(0, 0.5);
descTxt.x = levelTxt.x + levelTxt.width + 24;
descTxt.y = 0;
// Cost
var costTxt = new Text2('Cost: 30', {
size: 56,
fill: 0x222222
});
costTxt.anchor.set(0, 0.5);
costTxt.x = descTxt.x + descTxt.width + 24;
costTxt.y = 0;
// Upgrade button (right side, inside panel, with margin)
var btn = LK.getAsset('takeBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 900 / 2 - 120,
y: 0,
width: 180,
height: 70
});
btn.visible = true;
// Button label
var btnLabel = new Text2('Upgrade', {
size: 32,
fill: 0xffffff
});
btnLabel.anchor.set(0.5, 0.5);
btn.addChild(btnLabel);
// Add all texts and button to row
row.addChild(nameTxt);
row.addChild(levelTxt);
row.addChild(descTxt);
row.addChild(costTxt);
row.addChild(btn);
// Add row to shop panel
shopPanelBg.addChild(row);
// Track for logic
shopUpgradeBtns.push(btn);
// Store all text objects for update logic
shopUpgradeTxts.push({
name: nameTxt,
level: levelTxt,
desc: descTxt,
cost: costTxt
});
}
shopPanelBg.visible = false;
// Shop close button
var shopCloseBtn = LK.getAsset('takeBtnBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 900 / 2,
y: 820
});
var shopCloseTxt = new Text2('Close', {
size: 48,
fill: 0x222222
});
shopCloseTxt.anchor.set(0.5, 0.5);
shopCloseBtn.addChild(shopCloseTxt);
shopPanelBg.addChild(shopCloseBtn);
// Track if take or drop or shop button is pressed this frame
var takeBtnPressed = false;
var dropBtnPressed = false;
var shopBtnPressed = false;
var shopUpgradePressed = [false, false, false];
var shopClosePressed = false;
// Button press handlers
takeBtnBg.down = function (x, y, obj) {
if (takeBtnBg.interactive !== false && !shopPanelBg.visible) {
takeBtnPressed = true;
}
};
dropBtnBg.down = function (x, y, obj) {
if (dropBtnBg.interactive !== false && !shopPanelBg.visible) {
dropBtnPressed = true;
}
};
// Shop button handler
shopBtnBg.down = function (x, y, obj) {
if (!shopPanelBg.visible) {
shopBtnPressed = true;
}
};
// Shop upgrade button handlers
for (var i = 0; i < 3; i++) {
(function (idx) {
shopUpgradeBtns[idx].down = function (x, y, obj) {
if (shopPanelBg.visible) {
shopUpgradePressed[idx] = true;
}
};
})(i);
}
// Shop close button handler
shopCloseBtn.down = function (x, y, obj) {
if (shopPanelBg.visible) {
shopClosePressed = true;
}
};
// Generate a station at a given x, alternating pickup/drop and up/down
function spawnStation(x, isPickup) {
var station = new BusStation();
station.isPickup = !!isPickup;
// Re-attach correct asset if drop station (for existing BusStation instances)
if (!station.isPickup) {
if (station.children.length > 0) {
station.removeChild(station.children[0]);
}
station.attachAsset('dropStation', {
anchorX: 0.5,
anchorY: 1
});
}
// Alternate up/down for each station
var streetCenterY = streetBgY;
if (stations.length % 2 === 0) {
station.y = streetCenterY - streetBgHeight / 2 - 40; // above street
} else {
station.y = streetCenterY + streetBgHeight / 2 + 40; // below street
}
// Place at given x
station.x = x;
// Spawn travelers immediately if pickup station
if (station.isPickup) {
var numTravelers = 1 + Math.floor(Math.random() * 10);
var travelerYOffset = station.y < streetCenterY ? -140 : 140;
for (var i = 0; i < numTravelers; i++) {
var traveler = new Traveler();
traveler.station = station;
traveler.x = 0;
traveler.y = travelerYOffset + (station.y < streetCenterY ? -i * 130 : i * 130);
station.addChild(traveler);
station.travelers.push(traveler);
}
}
game.addChild(station);
stations.push(station);
}
// (removed duplicate old station spawn code)
// Move handler for dragging bus
function handleMove(x, y, obj) {
// Only drag if started on bus
if (bus.dragging) {
bus.y = y - bus.dragOffsetY;
}
}
game.move = handleMove;
// Down handler: start drag if on bus, or start holding for rightward movement
var holdingRight = false;
game.down = function (x, y, obj) {
// Convert to bus local coordinates
var local = bus.toLocal(game.toGlobal({
x: x,
y: y
}));
// If within bus bounds, start drag
if (local.x > -bus.width / 2 && local.x < bus.width / 2 && local.y > -bus.height && local.y < 0) {
bus.dragging = true;
bus.dragOffsetY = y - bus.y;
} else {
// Start holding for rightward movement
holdingRight = true;
}
};
// Up handler: stop drag and stop holding rightward movement
game.up = function (x, y, obj) {
bus.dragging = false;
holdingRight = false;
};
// Main game update loop
game.update = function () {
// --- SHOP LOGIC ---
// Show/hide shop panel
if (shopBtnPressed) {
shopPanelBg.visible = true;
takeBtnBg.visible = false;
dropBtnBg.visible = false;
shopBtnBg.visible = false;
shopBtnPressed = false;
}
// Shop close
if (shopClosePressed) {
shopPanelBg.visible = false;
takeBtnBg.visible = true;
dropBtnBg.visible = true;
shopBtnBg.visible = true;
shopClosePressed = false;
}
// Update shop upgrade button texts
for (var i = 0; i < 3; i++) {
var level = shopUpgradeLevels[i];
var cost = shopUpgradeCosts[i] + level * 20;
var max = shopUpgradeMax[i];
var name = shopUpgradeNames[i];
var desc = shopUpgradeDesc[i];
// Update each text field
shopUpgradeTxts[i].name.setText(name);
shopUpgradeTxts[i].level.setText('(Lv.' + level + (level >= max ? ' MAX' : '') + ')');
shopUpgradeTxts[i].desc.setText(desc);
shopUpgradeTxts[i].cost.setText('Cost: ' + (level >= max ? '-' : cost));
// Re-layout: update x positions in case text width changed
shopUpgradeTxts[i].level.x = shopUpgradeTxts[i].name.x + shopUpgradeTxts[i].name.width + 32;
shopUpgradeTxts[i].desc.x = shopUpgradeTxts[i].level.x + shopUpgradeTxts[i].level.width + 32;
shopUpgradeTxts[i].cost.x = shopUpgradeTxts[i].desc.x + shopUpgradeTxts[i].desc.width + 32;
shopUpgradeBtns[i].alpha = level < max ? 1 : 0.5;
shopUpgradeBtns[i].interactive = level < max;
}
// Update shop bus capacity message if shop is open
if (shopPanelBg.visible) {
var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0;
if (typeof maxCapacity === "undefined") maxCapacity = 10;
shopBusCapacityText.setText(travelersOnBoardCount + "/" + maxCapacity);
}
// Handle shop upgrades
for (var i = 0; i < 3; i++) {
if (shopUpgradePressed[i]) {
var level = shopUpgradeLevels[i];
var cost = shopUpgradeCosts[i] + level * 20;
var max = shopUpgradeMax[i];
if (level < max && score >= cost) {
score -= cost;
scoreTxt.setText(score);
shopUpgradeLevels[i]++;
// Apply upgrade effect
if (i === 0) {
// Capacity
maxCapacity += 2;
} else if (i === 1) {
// Speed
scrollSpeed += 2;
} else if (i === 2) {
// Money
if (typeof moneyPerTraveler === "undefined") moneyPerTraveler = 1;
moneyPerTraveler += 1;
}
}
shopUpgradePressed[i] = false;
}
}
if (shopPanelBg.visible) {
// Pause game logic when shop is open
return;
}
// Move bus/world right if holding
if (typeof holdingRight !== "undefined" && holdingRight) {
var moveAmount = scrollSpeed;
// Instead of moving the bus, move the world and keep bus centered
scrollX += moveAmount;
for (var i = 0; i < stations.length; i++) {
stations[i].x -= moveAmount;
}
// Move and repeat street backgrounds
for (var i = 0; i < streetBgs.length; i++) {
streetBgs[i].x -= moveAmount;
// If streetBg is fully off the left, move it to the right end
if (streetBgs[i].x < -streetBgWidth / 2) {
// Find the rightmost streetBg
var maxX = streetBgs[0].x;
for (var j = 1; j < streetBgs.length; j++) {
if (streetBgs[j].x > maxX) maxX = streetBgs[j].x;
}
streetBgs[i].x = maxX + streetBgWidth;
}
}
}
// Always keep bus in the center of the screen horizontally
bus.x = 2048 / 2;
// Move all stations and their travelers (no auto scroll)
for (var i = 0; i < stations.length; i++) {
var station = stations[i];
// No station.x -= scrollSpeed;
station.update();
for (var j = 0; j < station.travelers.length; j++) {
station.travelers[j].update();
}
}
// Update bus
bus.update();
// --- Meter Bar Update: Show distance to nearest upcoming station ---
var nearestStation = null;
var nearestDist = null;
for (var i = 0; i < stations.length; i++) {
var station = stations[i];
// Only consider stations ahead of the bus (to the right)
var dx = station.x - bus.x;
if (dx >= 0) {
if (nearestStation === null || dx < nearestDist) {
nearestStation = station;
nearestDist = dx;
}
}
}
if (nearestStation) {
var dist = Math.max(0, Math.floor(nearestDist));
var maxDist = 1200; // Max distance for full bar
var barWidth = Math.max(0, Math.min(600, 600 * (1 - dist / maxDist)));
meterBarFill.width = barWidth;
meterBarText.setText(dist + "m");
} else {
meterBarFill.width = 0;
meterBarText.setText("0m");
}
// Endless station spawning logic
// Find the rightmost station's x
var rightmostStationX = 0;
for (var i = 0; i < stations.length; i++) {
if (stations[i].x > rightmostStationX) rightmostStationX = stations[i].x;
}
// If the rightmost station is less than 2.5 screens ahead, spawn a new one
if (rightmostStationX < scrollX + 2048 * 2.5) {
// Alternate pickup/drop
var isPickup = stations.length % 2 === 0;
// Place new station at least minStationSpacing after the last one, with some randomization
var spacing = minStationSpacing + Math.floor(Math.random() * (maxStationSpacing - minStationSpacing + 1));
var newX = rightmostStationX + spacing;
spawnStation(newX, isPickup);
}
// --- Manual pickup and drop-off logic with Take Travelers button ---
// --- Manual pickup and drop-off logic with Take Travelers button ---
if (typeof bus.travelersOnBoard === "undefined") {
bus.travelersOnBoard = [];
bus.lastPickupStationIndex = -1;
bus.lastDropStationIndex = -1;
}
// --- Enable/disable Take Travelers button based on action possibility ---
var canTake = false;
var canDrop = false;
var dropStationIndex = -1;
// Check if we can take travelers at a nearby station
for (var i = 0; i < stations.length; i++) {
var station = stations[i];
// Take: must be pickup station, has travelers, close, and not already picked up here
if (station.isPickup && station.travelers.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastPickupStationIndex !== i) {
canTake = true;
}
// Drop: must be drop station, bus has travelers, close, and not already dropped here
if (!station.isPickup && bus.travelersOnBoard && bus.travelersOnBoard.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastDropStationIndex !== i) {
canDrop = true;
dropStationIndex = i;
}
}
// --- Bus Capacity Bar Update ---
if (typeof maxCapacity === "undefined") maxCapacity = 10;
var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0;
var capBarWidth = Math.max(0, Math.min(600, 600 * (travelersOnBoardCount / maxCapacity)));
busCapacityBarFill.width = capBarWidth;
// busCapacityBarText removed from main UI; only update shopBusCapacityText in shop panel
// Visually enable/disable the take and drop buttons
takeBtnBg.alpha = canTake ? 1 : 0.4;
takeBtnBg.interactive = canTake;
dropBtnBg.alpha = canDrop ? 1 : 0.4;
dropBtnBg.interactive = canDrop;
// --- Manual Pickup logic: only when button pressed ---
if (typeof maxCapacity === "undefined") maxCapacity = 10;
if (typeof moneyPerTraveler === "undefined") moneyPerTraveler = 1;
if (takeBtnPressed) {
for (var i = 0; i < stations.length; i++) {
var station = stations[i];
// Only pick up if bus is close to pickup station, this is a new station, and this station has travelers
if (station.isPickup && station.travelers.length > 0 && Math.abs(station.x - bus.x) < 180 && bus.lastPickupStationIndex !== i) {
// Pick up all waiting travelers at this station
var waitingTravelers = [];
for (var j = station.travelers.length - 1; j >= 0; j--) {
var traveler = station.travelers[j];
if (traveler.waiting) {
waitingTravelers.push(traveler);
}
}
// Actually pick up the travelers, but only up to available capacity
var travelersOnBoardCount = bus.travelersOnBoard ? bus.travelersOnBoard.length : 0;
var availableCapacity = maxCapacity - travelersOnBoardCount;
var numToPick = Math.min(availableCapacity, waitingTravelers.length);
for (var w = 0; w < numToPick; w++) {
var traveler = waitingTravelers[w];
traveler.waiting = false;
// Animate traveler to bus, then destroy
tween(traveler, {
x: bus.x - station.x,
y: bus.y - station.y - 100,
alpha: 0
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function (trav) {
return function () {
trav.destroy();
};
}(traveler)
});
// Add to bus's onboard list
if (!bus.travelersOnBoard) bus.travelersOnBoard = [];
bus.travelersOnBoard.push({
traveler: traveler,
pickedUpAt: i
});
// Remove from station
station.removeTraveler(traveler);
score += moneyPerTraveler;
scoreTxt.setText(score);
}
// Mark this station as the last pickup
bus.lastPickupStationIndex = i;
break; // Only pick up at one station per press
}
}
takeBtnPressed = false; // Reset button press
}
// --- Manual Drop-off logic: only when drop button pressed ---
if (dropBtnPressed && canDrop && dropStationIndex !== -1) {
var station = stations[dropStationIndex];
// Drop all travelers currently on the bus
if (bus.travelersOnBoard && bus.travelersOnBoard.length > 0) {
// Calculate base Y for stacking
var baseY = 0;
var stackDir = 1;
// If station is above street, stack upwards; if below, stack downwards
var streetCenterY = streetBgY;
if (station.y < streetCenterY) {
baseY = -140;
stackDir = -1;
} else {
baseY = 140;
stackDir = 1;
}
// Count how many travelers are already at this drop station (for stacking)
var alreadyDropped = 0;
for (var tt = 0; tt < station.travelers.length; tt++) {
if (station.travelers[tt].dropped) alreadyDropped++;
}
for (var t = 0; t < bus.travelersOnBoard.length; t++) {
var travelerObj = bus.travelersOnBoard[t];
var traveler = travelerObj.traveler;
// Animate traveler to station, then keep at station (do NOT destroy)
var newTraveler = new Traveler();
newTraveler.x = bus.x - station.x;
newTraveler.y = bus.y - station.y - 100;
newTraveler.alpha = 0;
newTraveler.waiting = false;
newTraveler.dropped = true;
newTraveler.station = station;
// Stack vertically at the station
var stackIndex = alreadyDropped + t;
newTraveler.x = 0;
newTraveler.y = baseY + stackDir * stackIndex * 130;
newTraveler.alpha = 0;
station.addChild(newTraveler);
station.travelers.push(newTraveler);
tween(newTraveler, {
x: 0,
y: baseY + stackDir * stackIndex * 130,
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
}
// Clear bus
bus.travelersOnBoard = [];
// Mark this station as the last drop
bus.lastDropStationIndex = dropStationIndex;
}
dropBtnPressed = false; // Reset button press
}
};