/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bus = Container.expand(function () {
var self = Container.call(this);
var busGraphics = self.attachAsset('bus', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.maxSpeed = 5;
self.acceleration = 0.1;
self.deceleration = 0.2;
self.moving = false;
self.movingForward = true;
self.passengers = 0;
self.maxPassengers = 20;
self.destinationScore = 0;
self.heroScore = 0;
self.efficiencyScore = 0;
self.riskScore = 0;
self.startMoving = function () {
self.moving = true;
};
self.stopMoving = function () {
self.moving = false;
};
self.accelerate = function () {
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
}
if (self.speed > self.maxSpeed) {
self.speed = self.maxSpeed;
}
};
self.decelerate = function () {
if (self.speed > 0) {
self.speed -= self.deceleration;
}
if (self.speed < 0) {
self.speed = 0;
}
};
self.addPassenger = function () {
if (self.passengers < self.maxPassengers) {
self.passengers++;
return true;
}
return false;
};
self.honkHorn = function () {
LK.getSound('busHorn').play();
};
self.update = function () {
if (self.moving) {
self.accelerate();
} else {
self.decelerate();
}
self.y += self.speed * (self.movingForward ? -1 : 1);
};
return self;
});
var ChoiceButton = Container.expand(function () {
var self = Container.call(this);
self.background = self.attachAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 120,
color: 0x3498db
});
self.label = new Text2("", {
size: 50,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.choiceData = null;
self.setChoice = function (text, data) {
self.label.setText(text);
self.choiceData = data;
};
self.down = function () {
tween(self.background, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
self.up = function () {
tween(self.background, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
if (self.choiceData && typeof self.choiceData.action === 'function') {
self.choiceData.action();
}
}
});
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.disable = function () {
self.active = false;
tween(obstacleGraphics, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
var Passenger = Container.expand(function () {
var self = Container.call(this);
var passengerGraphics = self.attachAsset('passenger', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = "standard"; // standard, elderly, emergency, etc.
self.pointValue = 1;
self.destinationStopId = "";
self.highlight = function () {
tween(passengerGraphics, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeInOut
});
};
self.unhighlight = function () {
tween(passengerGraphics, {
alpha: 1
}, {
duration: 300,
easing: tween.easeInOut
});
};
return self;
});
var PassengerStop = Container.expand(function () {
var self = Container.call(this);
var stopGraphics = self.attachAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5
});
self.id = "";
self.choices = [];
self.passengersWaiting = 0;
self.visited = false;
self.active = false;
self.activate = function () {
self.active = true;
tween(stopGraphics, {
alpha: 0.5
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.deactivate = function () {
self.active = false;
tween(stopGraphics, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.reset = function () {
self.visited = false;
self.active = false;
stopGraphics.alpha = 1;
};
self.down = function (x, y, obj) {
if (self.active && !self.visited) {
showChoices(self);
}
};
return self;
});
var Police = Container.expand(function () {
var self = Container.call(this);
var policeGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
if (bus.moving) {
// Police follows the bus vertically
if (self.y < bus.y) {
self.y += self.speed;
} else {
self.y -= self.speed;
}
// Police follows the bus horizontally
if (self.x < bus.x) {
self.x += self.speed;
} else if (self.x > bus.x) {
self.x -= self.speed;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue
});
/****
* Game Code
****/
function showPoliceEnding() {
gameState = "ending";
// Stop music
LK.stopMusic();
// Clear game
clearGame();
// Create ending screen elements
var titleText = new Text2("Caught by the Police!", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 700;
game.addChild(titleText);
var descText = new Text2("The police caught up with your bus.\nYour journey ends here.", {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 900;
game.addChild(descText);
// Create restart button
var restartButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1500,
color: 0x27ae60
}));
var restartText = new Text2("Try Again", {
size: 60,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 1024;
restartText.y = 1500;
game.addChild(restartText);
// Restart button interaction
restartButton.interactive = true;
restartButton.down = function () {
tween(restartButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
restartButton.up = function () {
tween(restartButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
showTitleScreen();
}
});
};
}
// Game globals
var bus;
var police;
var currentStop = 0;
var stops = [];
var passengers = [];
var obstacles = [];
var choiceButtons = [];
var choicePanel;
var gameStarted = false;
var roadSegments = [];
var roadY = 0;
var scoreText;
var passengerCountText;
var destinationText;
var gameState = "title"; // title, playing, ending
// Game routes and choices data
var routes = [{
id: "downtown",
name: "Downtown Route",
stops: [{
id: "central_station",
name: "Central Station",
x: 1024,
y: 500,
//{2Z} // Move the sixth stop closer
// Move the first stop further down
choices: [{
text: "Pick up business commuters (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "financial_district"
}, {
text: "Take shortcut through alley (Risk +1)",
effect: {
risk: 1
},
nextStop: "market_street"
}]
}, {
id: "financial_district",
name: "Financial District",
x: 700,
y: -500,
// Move the final stop closer
//{28} // Move the second stop further down
choices: [{
text: "Continue on schedule (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "city_hall"
}, {
text: "Help lost tourist (Hero +1)",
effect: {
hero: 1
},
nextStop: "city_hall"
}]
}, {
id: "market_street",
name: "Market Street",
x: 1350,
y: 2000,
//{2m} // Move the third stop closer
//{2m} // Move the third stop further down
choices: [{
text: "Take main road (Destination +1)",
effect: {
destination: 1
},
nextStop: "city_hall"
}, {
text: "Speed through yellow lights (Risk +1)",
effect: {
risk: 1
},
nextStop: "city_park"
}]
}, {
id: "city_hall",
name: "City Hall",
x: 1024,
y: 1500,
//{2z} // Move the fourth stop closer
//{2z} // Move the fourth stop further down
choices: [{
text: "Follow standard route (Destination +1)",
effect: {
destination: 1
},
nextStop: "hospital"
}, {
text: "Wait for elderly passenger (Hero +1)",
effect: {
hero: 1
},
nextStop: "hospital"
}]
}, {
id: "city_park",
name: "City Park",
x: 1500,
y: 1000,
//{2M} // Move the fifth stop closer
//{2M} // Move the fifth stop further down
choices: [{
text: "Return to main route (Destination +1)",
effect: {
destination: 1
},
nextStop: "hospital"
}, {
text: "Drive through park scenery (Risk +1)",
effect: {
risk: 1
},
nextStop: "university"
}]
}, {
id: "hospital",
name: "Hospital",
x: 1024,
y: 0,
//{3c} // Move the seventh stop closer
//{2Z} // Move the sixth stop further down
choices: [{
text: "Complete route on time (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "final_downtown"
}, {
text: "Help medical emergency (Hero +2)",
effect: {
hero: 2
},
nextStop: "final_downtown"
}]
}, {
id: "university",
name: "University",
x: 1350,
y: 3000,
//{3c} // Move the seventh stop further down
choices: [{
text: "Drive carefully with students (Destination +1)",
effect: {
destination: 1
},
nextStop: "final_downtown"
}, {
text: "Race the campus loop (Risk +2)",
effect: {
risk: 2
},
nextStop: "final_downtown"
}]
}, {
id: "final_downtown",
name: "Downtown Terminal",
x: 1024,
y: 2500,
// Move the final stop further down
choices: [{
text: "Complete Journey",
effect: {},
nextStop: "end"
}]
}]
}];
// Road generation
function createRoad() {
for (var i = 0; i < 25; i++) {
// Increase the number of road segments to match the longer distance
var roadSegment = game.addChild(LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: roadY
}));
roadSegments.push(roadSegment);
roadY -= 400;
}
}
// Initialize game elements
function initGame() {
// Clear any existing elements
clearGame();
// Set game state
gameState = "playing";
// Create road
roadY = 5000; // Increase the initial roadY to extend the distance between stops
createRoad();
// Create bus
bus = game.addChild(new Bus());
bus.x = 1024;
bus.y = 2500;
// Create police
police = game.addChild(new Police());
police.x = 1024;
police.y = 2700;
// Initialize stops based on the downtown route
var routeData = routes[0]; // Use downtown route
for (var i = 0; i < routeData.stops.length; i++) {
var stopData = routeData.stops[i];
var stop = game.addChild(new PassengerStop());
stop.id = stopData.id;
stop.name = stopData.name;
stop.x = stopData.x;
stop.y = stopData.y;
stop.choices = stopData.choices;
stop.passengersWaiting = Math.floor(Math.random() * 5) + 1;
stops.push(stop);
}
// Create choice panel (initially hidden)
choicePanel = game.addChild(new Container());
choicePanel.visible = false;
// Create choice buttons
for (var i = 0; i < 2; i++) {
var button = choicePanel.addChild(new ChoiceButton());
button.x = 1024;
button.y = 1366 + i * 150;
choiceButtons.push(button);
}
// Create UI text elements
scoreText = new Text2("Score: 0", {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
passengerCountText = new Text2("Passengers: 0/" + bus.maxPassengers, {
size: 50,
fill: 0xFFFFFF
});
passengerCountText.anchor.set(1, 0);
passengerCountText.x = -50; // Offset from right edge
LK.gui.topRight.addChild(passengerCountText);
destinationText = new Text2("", {
size: 50,
fill: 0xFFFFFF
});
destinationText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(destinationText);
// Start game
gameStarted = true;
currentStop = 0;
// Play background music
LK.playMusic('busMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
});
// Activate first stop
if (stops.length > 0) {
stops[0].activate();
updateDestinationText(stops[0].name);
}
// Start the bus moving immediately
bus.startMoving();
}
// Clean up all game elements
function clearGame() {
// Clear arrays
stops = [];
passengers = [];
obstacles = [];
roadSegments = [];
choiceButtons = [];
// Remove all children from game
while (game.children.length > 0) {
game.removeChild(game.children[0]);
}
// Reset states
gameStarted = false;
currentStop = 0;
}
// Show title screen
function showTitleScreen() {
gameState = "title";
// Clear game
clearGame();
// Create title
var titleText = new Text2("Bus Route Destiny", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 900;
game.addChild(titleText);
// Create start button
var startButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1300,
color: 0x27ae60
}));
var startText = new Text2("Start Driving", {
size: 60,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 1024;
startText.y = 1300;
game.addChild(startText);
// Create description
var descText = new Text2("Drive the city bus, make choices at each stop,\nand discover your ultimate destination.", {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1100;
game.addChild(descText);
// Start button interaction
startButton.interactive = true;
startButton.down = function () {
tween(startButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
startButton.up = function () {
tween(startButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
initGame();
}
});
};
}
// Show choices at a stop
function showChoices(stop) {
// Stop the bus
bus.stopMoving();
// Make choice panel visible
choicePanel.visible = true;
// Setup choice buttons
for (var i = 0; i < stop.choices.length && i < choiceButtons.length; i++) {
var choice = stop.choices[i];
choiceButtons[i].visible = true;
choiceButtons[i].setChoice(choice.text, {
action: function (choiceIndex) {
return function () {
// Apply choice effects
var effect = stop.choices[choiceIndex].effect;
if (effect.efficiency) {
bus.efficiencyScore += effect.efficiency;
}
if (effect.hero) {
bus.heroScore += effect.hero;
}
if (effect.risk) {
bus.riskScore += effect.risk;
}
if (effect.destination) {
bus.destinationScore += effect.destination;
}
// Add passengers
for (var j = 0; j < stop.passengersWaiting; j++) {
if (bus.addPassenger()) {
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 1);
updateScoreText();
}
}
// Mark stop as visited
stop.visited = true;
stop.deactivate();
// Hide choice panel
choicePanel.visible = false;
// Find next stop
var nextStopId = stop.choices[choiceIndex].nextStop;
if (nextStopId === "end") {
// End the game and show the ending
LK.setTimeout(function () {
showEnding();
}, 1000);
} else {
// Find the next stop in the array
for (var j = 0; j < stops.length; j++) {
if (stops[j].id === nextStopId) {
currentStop = j;
stops[j].activate();
updateDestinationText(stops[j].name);
break;
}
}
// Resume driving
bus.startMoving();
}
};
}(i)
});
}
// Hide any unused buttons
for (var i = stop.choices.length; i < choiceButtons.length; i++) {
choiceButtons[i].visible = false;
}
}
// Show game ending based on scores
function showEnding() {
gameState = "ending";
// Stop music
LK.stopMusic();
// Determine ending type based on highest score
var endingType = "standard";
var highestScore = Math.max(bus.destinationScore, bus.heroScore, bus.efficiencyScore, bus.riskScore);
if (highestScore === bus.destinationScore) {
endingType = "destination";
} else if (highestScore === bus.heroScore) {
endingType = "hero";
} else if (highestScore === bus.efficiencyScore) {
endingType = "efficiency";
} else if (highestScore === bus.riskScore) {
endingType = "risk";
}
// Clear game
clearGame();
// Create ending screen elements
var titleText = new Text2("Your Journey Ends", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 700;
game.addChild(titleText);
var endingText = "";
switch (endingType) {
case "destination":
endingText = "You followed the standard route flawlessly.\nYou've earned the respect of the transit authority for your reliability.";
break;
case "hero":
endingText = "You went above and beyond to help passengers in need.\nYour compassion has made you a local hero in the community.";
break;
case "efficiency":
endingText = "You prioritized efficiency and schedule adherence.\nYou've been promoted to lead driver for your professionalism.";
break;
case "risk":
endingText = "Your adventurous driving style made for an exciting journey.\nPassengers remember your route as the most thrilling in town!";
break;
default:
endingText = "You completed your bus route.\nThank you for your service to the city.";
}
var descText = new Text2(endingText, {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 900;
game.addChild(descText);
// Show scores
var scoresText = new Text2("Passengers: " + bus.passengers + "\n" + "Reliability Score: " + bus.destinationScore + "\n" + "Heroism Score: " + bus.heroScore + "\n" + "Efficiency Score: " + bus.efficiencyScore + "\n" + "Adventure Score: " + bus.riskScore, {
size: 40,
fill: 0xFFFFFF
});
scoresText.anchor.set(0.5, 0.5);
scoresText.x = 1024;
scoresText.y = 1200;
game.addChild(scoresText);
// Create restart button
var restartButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1500,
color: 0x27ae60
}));
var restartText = new Text2("Drive Again", {
size: 60,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 1024;
restartText.y = 1500;
game.addChild(restartText);
// Restart button interaction
restartButton.interactive = true;
restartButton.down = function () {
tween(restartButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
restartButton.up = function () {
tween(restartButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
showTitleScreen();
}
});
};
}
// Update UI functions
function updateScoreText() {
scoreText.setText("Score: " + LK.getScore());
passengerCountText.setText("Passengers: " + bus.passengers + "/" + bus.maxPassengers);
}
function updateDestinationText(stopName) {
destinationText.setText("Next Stop: " + stopName);
}
// Game down event handler
game.down = function (x, y, obj) {
if (gameState === "title") {
// Title screen interaction handled by button
} else if (gameState === "playing") {
// Check if bus horn area is pressed
if (bus && !choicePanel.visible && x > bus.x - 150 && x < bus.x + 150 && y > bus.y - 75 && y < bus.y + 75) {
bus.honkHorn();
}
// Move bus left or right based on touch position
if (x < 1024) {
bus.x -= 50; // Move left
} else {
bus.x += 50; // Move right
bus.movingForward = !bus.movingForward; // Toggle direction
}
}
};
// Main game update
game.update = function () {
if (!gameStarted) {
// Show title screen if game hasn't started yet
if (gameState !== "title" && gameState !== "ending") {
showTitleScreen();
}
return;
}
// Update road
for (var i = 0; i < roadSegments.length; i++) {
if (bus.moving) {
roadSegments[i].y += bus.speed;
// If road segment is off screen, move it to the top
if (roadSegments[i].y > 2732 + 200) {
roadSegments[i].y = roadY;
roadY -= 400;
}
}
}
// Update stops
for (var i = 0; i < stops.length; i++) {
if (bus.moving) {
stops[i].y += bus.speed;
}
// Check if bus is at a stop
if (!stops[i].visited && stops[i].active && Math.abs(bus.y - stops[i].y) < 50) {
bus.stopMoving();
showChoices(stops[i]);
}
}
// Update police
police.update();
// Check for collision between police and bus
if (!police.lastWasIntersecting && police.intersects(bus)) {
// Collision just started
LK.setTimeout(function () {
showPoliceEnding();
}, 1000);
}
police.lastWasIntersecting = police.intersects(bus);
// Update UI
updateScoreText();
};
// Initialize by showing title screen
showTitleScreen(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bus = Container.expand(function () {
var self = Container.call(this);
var busGraphics = self.attachAsset('bus', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.maxSpeed = 5;
self.acceleration = 0.1;
self.deceleration = 0.2;
self.moving = false;
self.movingForward = true;
self.passengers = 0;
self.maxPassengers = 20;
self.destinationScore = 0;
self.heroScore = 0;
self.efficiencyScore = 0;
self.riskScore = 0;
self.startMoving = function () {
self.moving = true;
};
self.stopMoving = function () {
self.moving = false;
};
self.accelerate = function () {
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
}
if (self.speed > self.maxSpeed) {
self.speed = self.maxSpeed;
}
};
self.decelerate = function () {
if (self.speed > 0) {
self.speed -= self.deceleration;
}
if (self.speed < 0) {
self.speed = 0;
}
};
self.addPassenger = function () {
if (self.passengers < self.maxPassengers) {
self.passengers++;
return true;
}
return false;
};
self.honkHorn = function () {
LK.getSound('busHorn').play();
};
self.update = function () {
if (self.moving) {
self.accelerate();
} else {
self.decelerate();
}
self.y += self.speed * (self.movingForward ? -1 : 1);
};
return self;
});
var ChoiceButton = Container.expand(function () {
var self = Container.call(this);
self.background = self.attachAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 120,
color: 0x3498db
});
self.label = new Text2("", {
size: 50,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.choiceData = null;
self.setChoice = function (text, data) {
self.label.setText(text);
self.choiceData = data;
};
self.down = function () {
tween(self.background, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
self.up = function () {
tween(self.background, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
if (self.choiceData && typeof self.choiceData.action === 'function') {
self.choiceData.action();
}
}
});
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
self.disable = function () {
self.active = false;
tween(obstacleGraphics, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
};
return self;
});
var Passenger = Container.expand(function () {
var self = Container.call(this);
var passengerGraphics = self.attachAsset('passenger', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = "standard"; // standard, elderly, emergency, etc.
self.pointValue = 1;
self.destinationStopId = "";
self.highlight = function () {
tween(passengerGraphics, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeInOut
});
};
self.unhighlight = function () {
tween(passengerGraphics, {
alpha: 1
}, {
duration: 300,
easing: tween.easeInOut
});
};
return self;
});
var PassengerStop = Container.expand(function () {
var self = Container.call(this);
var stopGraphics = self.attachAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5
});
self.id = "";
self.choices = [];
self.passengersWaiting = 0;
self.visited = false;
self.active = false;
self.activate = function () {
self.active = true;
tween(stopGraphics, {
alpha: 0.5
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.deactivate = function () {
self.active = false;
tween(stopGraphics, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.reset = function () {
self.visited = false;
self.active = false;
stopGraphics.alpha = 1;
};
self.down = function (x, y, obj) {
if (self.active && !self.visited) {
showChoices(self);
}
};
return self;
});
var Police = Container.expand(function () {
var self = Container.call(this);
var policeGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
if (bus.moving) {
// Police follows the bus vertically
if (self.y < bus.y) {
self.y += self.speed;
} else {
self.y -= self.speed;
}
// Police follows the bus horizontally
if (self.x < bus.x) {
self.x += self.speed;
} else if (self.x > bus.x) {
self.x -= self.speed;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB // Sky blue
});
/****
* Game Code
****/
function showPoliceEnding() {
gameState = "ending";
// Stop music
LK.stopMusic();
// Clear game
clearGame();
// Create ending screen elements
var titleText = new Text2("Caught by the Police!", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 700;
game.addChild(titleText);
var descText = new Text2("The police caught up with your bus.\nYour journey ends here.", {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 900;
game.addChild(descText);
// Create restart button
var restartButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1500,
color: 0x27ae60
}));
var restartText = new Text2("Try Again", {
size: 60,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 1024;
restartText.y = 1500;
game.addChild(restartText);
// Restart button interaction
restartButton.interactive = true;
restartButton.down = function () {
tween(restartButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
restartButton.up = function () {
tween(restartButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
showTitleScreen();
}
});
};
}
// Game globals
var bus;
var police;
var currentStop = 0;
var stops = [];
var passengers = [];
var obstacles = [];
var choiceButtons = [];
var choicePanel;
var gameStarted = false;
var roadSegments = [];
var roadY = 0;
var scoreText;
var passengerCountText;
var destinationText;
var gameState = "title"; // title, playing, ending
// Game routes and choices data
var routes = [{
id: "downtown",
name: "Downtown Route",
stops: [{
id: "central_station",
name: "Central Station",
x: 1024,
y: 500,
//{2Z} // Move the sixth stop closer
// Move the first stop further down
choices: [{
text: "Pick up business commuters (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "financial_district"
}, {
text: "Take shortcut through alley (Risk +1)",
effect: {
risk: 1
},
nextStop: "market_street"
}]
}, {
id: "financial_district",
name: "Financial District",
x: 700,
y: -500,
// Move the final stop closer
//{28} // Move the second stop further down
choices: [{
text: "Continue on schedule (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "city_hall"
}, {
text: "Help lost tourist (Hero +1)",
effect: {
hero: 1
},
nextStop: "city_hall"
}]
}, {
id: "market_street",
name: "Market Street",
x: 1350,
y: 2000,
//{2m} // Move the third stop closer
//{2m} // Move the third stop further down
choices: [{
text: "Take main road (Destination +1)",
effect: {
destination: 1
},
nextStop: "city_hall"
}, {
text: "Speed through yellow lights (Risk +1)",
effect: {
risk: 1
},
nextStop: "city_park"
}]
}, {
id: "city_hall",
name: "City Hall",
x: 1024,
y: 1500,
//{2z} // Move the fourth stop closer
//{2z} // Move the fourth stop further down
choices: [{
text: "Follow standard route (Destination +1)",
effect: {
destination: 1
},
nextStop: "hospital"
}, {
text: "Wait for elderly passenger (Hero +1)",
effect: {
hero: 1
},
nextStop: "hospital"
}]
}, {
id: "city_park",
name: "City Park",
x: 1500,
y: 1000,
//{2M} // Move the fifth stop closer
//{2M} // Move the fifth stop further down
choices: [{
text: "Return to main route (Destination +1)",
effect: {
destination: 1
},
nextStop: "hospital"
}, {
text: "Drive through park scenery (Risk +1)",
effect: {
risk: 1
},
nextStop: "university"
}]
}, {
id: "hospital",
name: "Hospital",
x: 1024,
y: 0,
//{3c} // Move the seventh stop closer
//{2Z} // Move the sixth stop further down
choices: [{
text: "Complete route on time (Efficiency +1)",
effect: {
efficiency: 1
},
nextStop: "final_downtown"
}, {
text: "Help medical emergency (Hero +2)",
effect: {
hero: 2
},
nextStop: "final_downtown"
}]
}, {
id: "university",
name: "University",
x: 1350,
y: 3000,
//{3c} // Move the seventh stop further down
choices: [{
text: "Drive carefully with students (Destination +1)",
effect: {
destination: 1
},
nextStop: "final_downtown"
}, {
text: "Race the campus loop (Risk +2)",
effect: {
risk: 2
},
nextStop: "final_downtown"
}]
}, {
id: "final_downtown",
name: "Downtown Terminal",
x: 1024,
y: 2500,
// Move the final stop further down
choices: [{
text: "Complete Journey",
effect: {},
nextStop: "end"
}]
}]
}];
// Road generation
function createRoad() {
for (var i = 0; i < 25; i++) {
// Increase the number of road segments to match the longer distance
var roadSegment = game.addChild(LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: roadY
}));
roadSegments.push(roadSegment);
roadY -= 400;
}
}
// Initialize game elements
function initGame() {
// Clear any existing elements
clearGame();
// Set game state
gameState = "playing";
// Create road
roadY = 5000; // Increase the initial roadY to extend the distance between stops
createRoad();
// Create bus
bus = game.addChild(new Bus());
bus.x = 1024;
bus.y = 2500;
// Create police
police = game.addChild(new Police());
police.x = 1024;
police.y = 2700;
// Initialize stops based on the downtown route
var routeData = routes[0]; // Use downtown route
for (var i = 0; i < routeData.stops.length; i++) {
var stopData = routeData.stops[i];
var stop = game.addChild(new PassengerStop());
stop.id = stopData.id;
stop.name = stopData.name;
stop.x = stopData.x;
stop.y = stopData.y;
stop.choices = stopData.choices;
stop.passengersWaiting = Math.floor(Math.random() * 5) + 1;
stops.push(stop);
}
// Create choice panel (initially hidden)
choicePanel = game.addChild(new Container());
choicePanel.visible = false;
// Create choice buttons
for (var i = 0; i < 2; i++) {
var button = choicePanel.addChild(new ChoiceButton());
button.x = 1024;
button.y = 1366 + i * 150;
choiceButtons.push(button);
}
// Create UI text elements
scoreText = new Text2("Score: 0", {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
passengerCountText = new Text2("Passengers: 0/" + bus.maxPassengers, {
size: 50,
fill: 0xFFFFFF
});
passengerCountText.anchor.set(1, 0);
passengerCountText.x = -50; // Offset from right edge
LK.gui.topRight.addChild(passengerCountText);
destinationText = new Text2("", {
size: 50,
fill: 0xFFFFFF
});
destinationText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(destinationText);
// Start game
gameStarted = true;
currentStop = 0;
// Play background music
LK.playMusic('busMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
});
// Activate first stop
if (stops.length > 0) {
stops[0].activate();
updateDestinationText(stops[0].name);
}
// Start the bus moving immediately
bus.startMoving();
}
// Clean up all game elements
function clearGame() {
// Clear arrays
stops = [];
passengers = [];
obstacles = [];
roadSegments = [];
choiceButtons = [];
// Remove all children from game
while (game.children.length > 0) {
game.removeChild(game.children[0]);
}
// Reset states
gameStarted = false;
currentStop = 0;
}
// Show title screen
function showTitleScreen() {
gameState = "title";
// Clear game
clearGame();
// Create title
var titleText = new Text2("Bus Route Destiny", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 900;
game.addChild(titleText);
// Create start button
var startButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1300,
color: 0x27ae60
}));
var startText = new Text2("Start Driving", {
size: 60,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startText.x = 1024;
startText.y = 1300;
game.addChild(startText);
// Create description
var descText = new Text2("Drive the city bus, make choices at each stop,\nand discover your ultimate destination.", {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 1100;
game.addChild(descText);
// Start button interaction
startButton.interactive = true;
startButton.down = function () {
tween(startButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
startButton.up = function () {
tween(startButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
initGame();
}
});
};
}
// Show choices at a stop
function showChoices(stop) {
// Stop the bus
bus.stopMoving();
// Make choice panel visible
choicePanel.visible = true;
// Setup choice buttons
for (var i = 0; i < stop.choices.length && i < choiceButtons.length; i++) {
var choice = stop.choices[i];
choiceButtons[i].visible = true;
choiceButtons[i].setChoice(choice.text, {
action: function (choiceIndex) {
return function () {
// Apply choice effects
var effect = stop.choices[choiceIndex].effect;
if (effect.efficiency) {
bus.efficiencyScore += effect.efficiency;
}
if (effect.hero) {
bus.heroScore += effect.hero;
}
if (effect.risk) {
bus.riskScore += effect.risk;
}
if (effect.destination) {
bus.destinationScore += effect.destination;
}
// Add passengers
for (var j = 0; j < stop.passengersWaiting; j++) {
if (bus.addPassenger()) {
LK.getSound('pickup').play();
LK.setScore(LK.getScore() + 1);
updateScoreText();
}
}
// Mark stop as visited
stop.visited = true;
stop.deactivate();
// Hide choice panel
choicePanel.visible = false;
// Find next stop
var nextStopId = stop.choices[choiceIndex].nextStop;
if (nextStopId === "end") {
// End the game and show the ending
LK.setTimeout(function () {
showEnding();
}, 1000);
} else {
// Find the next stop in the array
for (var j = 0; j < stops.length; j++) {
if (stops[j].id === nextStopId) {
currentStop = j;
stops[j].activate();
updateDestinationText(stops[j].name);
break;
}
}
// Resume driving
bus.startMoving();
}
};
}(i)
});
}
// Hide any unused buttons
for (var i = stop.choices.length; i < choiceButtons.length; i++) {
choiceButtons[i].visible = false;
}
}
// Show game ending based on scores
function showEnding() {
gameState = "ending";
// Stop music
LK.stopMusic();
// Determine ending type based on highest score
var endingType = "standard";
var highestScore = Math.max(bus.destinationScore, bus.heroScore, bus.efficiencyScore, bus.riskScore);
if (highestScore === bus.destinationScore) {
endingType = "destination";
} else if (highestScore === bus.heroScore) {
endingType = "hero";
} else if (highestScore === bus.efficiencyScore) {
endingType = "efficiency";
} else if (highestScore === bus.riskScore) {
endingType = "risk";
}
// Clear game
clearGame();
// Create ending screen elements
var titleText = new Text2("Your Journey Ends", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 700;
game.addChild(titleText);
var endingText = "";
switch (endingType) {
case "destination":
endingText = "You followed the standard route flawlessly.\nYou've earned the respect of the transit authority for your reliability.";
break;
case "hero":
endingText = "You went above and beyond to help passengers in need.\nYour compassion has made you a local hero in the community.";
break;
case "efficiency":
endingText = "You prioritized efficiency and schedule adherence.\nYou've been promoted to lead driver for your professionalism.";
break;
case "risk":
endingText = "Your adventurous driving style made for an exciting journey.\nPassengers remember your route as the most thrilling in town!";
break;
default:
endingText = "You completed your bus route.\nThank you for your service to the city.";
}
var descText = new Text2(endingText, {
size: 50,
fill: 0xFFFFFF
});
descText.anchor.set(0.5, 0.5);
descText.x = 1024;
descText.y = 900;
game.addChild(descText);
// Show scores
var scoresText = new Text2("Passengers: " + bus.passengers + "\n" + "Reliability Score: " + bus.destinationScore + "\n" + "Heroism Score: " + bus.heroScore + "\n" + "Efficiency Score: " + bus.efficiencyScore + "\n" + "Adventure Score: " + bus.riskScore, {
size: 40,
fill: 0xFFFFFF
});
scoresText.anchor.set(0.5, 0.5);
scoresText.x = 1024;
scoresText.y = 1200;
game.addChild(scoresText);
// Create restart button
var restartButton = game.addChild(LK.getAsset('passengerStop', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 100,
x: 1024,
y: 1500,
color: 0x27ae60
}));
var restartText = new Text2("Drive Again", {
size: 60,
fill: 0xFFFFFF
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 1024;
restartText.y = 1500;
game.addChild(restartText);
// Restart button interaction
restartButton.interactive = true;
restartButton.down = function () {
tween(restartButton, {
alpha: 0.7
}, {
duration: 100,
easing: tween.linear
});
};
restartButton.up = function () {
tween(restartButton, {
alpha: 1
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
showTitleScreen();
}
});
};
}
// Update UI functions
function updateScoreText() {
scoreText.setText("Score: " + LK.getScore());
passengerCountText.setText("Passengers: " + bus.passengers + "/" + bus.maxPassengers);
}
function updateDestinationText(stopName) {
destinationText.setText("Next Stop: " + stopName);
}
// Game down event handler
game.down = function (x, y, obj) {
if (gameState === "title") {
// Title screen interaction handled by button
} else if (gameState === "playing") {
// Check if bus horn area is pressed
if (bus && !choicePanel.visible && x > bus.x - 150 && x < bus.x + 150 && y > bus.y - 75 && y < bus.y + 75) {
bus.honkHorn();
}
// Move bus left or right based on touch position
if (x < 1024) {
bus.x -= 50; // Move left
} else {
bus.x += 50; // Move right
bus.movingForward = !bus.movingForward; // Toggle direction
}
}
};
// Main game update
game.update = function () {
if (!gameStarted) {
// Show title screen if game hasn't started yet
if (gameState !== "title" && gameState !== "ending") {
showTitleScreen();
}
return;
}
// Update road
for (var i = 0; i < roadSegments.length; i++) {
if (bus.moving) {
roadSegments[i].y += bus.speed;
// If road segment is off screen, move it to the top
if (roadSegments[i].y > 2732 + 200) {
roadSegments[i].y = roadY;
roadY -= 400;
}
}
}
// Update stops
for (var i = 0; i < stops.length; i++) {
if (bus.moving) {
stops[i].y += bus.speed;
}
// Check if bus is at a stop
if (!stops[i].visited && stops[i].active && Math.abs(bus.y - stops[i].y) < 50) {
bus.stopMoving();
showChoices(stops[i]);
}
}
// Update police
police.update();
// Check for collision between police and bus
if (!police.lastWasIntersecting && police.intersects(bus)) {
// Collision just started
LK.setTimeout(function () {
showPoliceEnding();
}, 1000);
}
police.lastWasIntersecting = police.intersects(bus);
// Update UI
updateScoreText();
};
// Initialize by showing title screen
showTitleScreen();