/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.deceleration = 0.15;
self.turnSpeed = 0.08;
self.health = 100;
self.isDrifting = false;
self.update = function () {
// Apply deceleration when not accelerating
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
}
// Move car forward based on current rotation and speed
var radians = self.rotation;
self.x += Math.sin(radians) * self.speed;
self.y -= Math.cos(radians) * self.speed;
// Keep car within bounds
if (self.x < 30) self.x = 30;
if (self.x > 2018) self.x = 2018;
if (self.y < 60) self.y = 60;
if (self.y > 2672) self.y = 2672;
};
self.accelerate = function () {
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
}
};
self.turnLeft = function () {
if (self.speed > 1) {
self.rotation -= self.turnSpeed;
}
};
self.turnRight = function () {
if (self.speed > 1) {
self.rotation += self.turnSpeed;
}
};
self.crash = function () {
self.health -= 20;
self.speed *= 0.3;
LK.getSound('crash').play();
LK.effects.flashObject(self, 0xff0000, 500);
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var Checkpoint = Container.expand(function () {
var self = Container.call(this);
var checkpointGraphics = self.attachAsset('checkpoint', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
if (!self.collected) {
self.rotation += 0.05;
}
};
return self;
});
var GrassTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('grass', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var OilSpill = Container.expand(function () {
var self = Container.call(this);
var oilGraphics = self.attachAsset('oil', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var RoadTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var TrafficCar = Container.expand(function () {
var self = Container.call(this);
var trafficGraphics = self.attachAsset('traffic', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 3;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
self.x += Math.sin(self.direction) * self.speed;
self.y -= Math.cos(self.direction) * self.speed;
// Wrap around screen
if (self.x < -50) self.x = 2098;
if (self.x > 2098) self.x = -50;
if (self.y < -50) self.y = 2782;
if (self.y > 2782) self.y = -50;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2ecc71
});
/****
* Game Code
****/
// Game variables
var car = null;
var roadTiles = [];
var obstacles = [];
var checkpoints = [];
var trafficCars = [];
var oilSpills = [];
var checkpointsCollected = 0;
var totalCheckpoints = 5;
var gameTime = 0;
var raceStarted = false;
var currentLevel = storage.currentLevel || 1;
// UI Elements
var scoreTxt = new Text2('Checkpoints: 0/5', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var healthTxt = new Text2('Health: 100', {
size: 50,
fill: 0xFF0000
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 150;
healthTxt.y = 20;
LK.gui.topLeft.addChild(healthTxt);
var timeTxt = new Text2('Time: 0', {
size: 50,
fill: 0xFFFFFF
});
timeTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(timeTxt);
// Create road layout
function createRoadLayout() {
// Create a simple road pattern
for (var i = 0; i < 12; i++) {
for (var j = 0; j < 16; j++) {
var tile = null;
// Create roads in specific pattern
if (i >= 2 && i <= 9 && j >= 2 && j <= 13 || i >= 4 && i <= 7 && (j === 0 || j === 1 || j === 14 || j === 15)) {
tile = new RoadTile();
} else {
tile = new GrassTile();
}
tile.x = i * 170 + 85;
tile.y = j * 170 + 85;
game.addChild(tile);
roadTiles.push(tile);
}
}
}
// Create obstacles
function createObstacles() {
for (var i = 0; i < 8; i++) {
var obstacle = new Obstacle();
obstacle.x = 200 + Math.random() * 1600;
obstacle.y = 200 + Math.random() * 2200;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
// Create checkpoints
function createCheckpoints() {
var checkpointPositions = [{
x: 500,
y: 500
}, {
x: 1200,
y: 800
}, {
x: 800,
y: 1400
}, {
x: 1500,
y: 1800
}, {
x: 600,
y: 2200
}];
for (var i = 0; i < checkpointPositions.length; i++) {
var checkpoint = new Checkpoint();
checkpoint.x = checkpointPositions[i].x;
checkpoint.y = checkpointPositions[i].y;
checkpoints.push(checkpoint);
game.addChild(checkpoint);
}
totalCheckpoints = checkpoints.length;
}
// Create traffic
function createTraffic() {
for (var i = 0; i < 6; i++) {
var trafficCar = new TrafficCar();
trafficCar.x = Math.random() * 2048;
trafficCar.y = Math.random() * 2732;
trafficCars.push(trafficCar);
game.addChild(trafficCar);
}
}
// Create oil spills
function createOilSpills() {
for (var i = 0; i < 4; i++) {
var oil = new OilSpill();
oil.x = 300 + Math.random() * 1400;
oil.y = 300 + Math.random() * 2100;
oilSpills.push(oil);
game.addChild(oil);
}
}
// Initialize game elements
createRoadLayout();
createObstacles();
createCheckpoints();
createTraffic();
createOilSpills();
// Create player car
car = new Car();
car.x = 400;
car.y = 400;
game.addChild(car);
// Touch controls
var touchActive = false;
var lastTouchX = 0;
var lastTouchY = 0;
game.down = function (x, y, obj) {
touchActive = true;
lastTouchX = x;
lastTouchY = y;
raceStarted = true;
};
game.move = function (x, y, obj) {
if (touchActive) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
// Calculate desired angle based on touch movement
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
var targetAngle = Math.atan2(deltaX, -deltaY);
car.rotation = targetAngle;
car.accelerate();
}
lastTouchX = x;
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
touchActive = false;
};
// Main game update loop
game.update = function () {
if (!raceStarted) return;
gameTime++;
// Update time display
var seconds = Math.floor(gameTime / 60);
timeTxt.setText('Time: ' + seconds);
// Update health display
healthTxt.setText('Health: ' + Math.max(0, car.health));
// Check checkpoint collection
for (var i = checkpoints.length - 1; i >= 0; i--) {
var checkpoint = checkpoints[i];
if (!checkpoint.collected && car.intersects(checkpoint)) {
checkpoint.collected = true;
checkpointsCollected++;
LK.getSound('checkpoint').play();
LK.effects.flashObject(checkpoint, 0x00ff00, 300);
scoreTxt.setText('Checkpoints: ' + checkpointsCollected + '/' + totalCheckpoints);
// Check win condition
if (checkpointsCollected >= totalCheckpoints) {
storage.currentLevel = currentLevel + 1;
LK.setScore(1000 - Math.floor(gameTime / 6)); // Score based on time
LK.showYouWin();
}
checkpoint.destroy();
checkpoints.splice(i, 1);
}
}
// Check collisions with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (car.intersects(obstacle)) {
car.crash();
}
}
// Check collisions with traffic
for (var i = 0; i < trafficCars.length; i++) {
var trafficCar = trafficCars[i];
if (car.intersects(trafficCar)) {
car.crash();
}
}
// Check oil spill effects
for (var i = 0; i < oilSpills.length; i++) {
var oil = oilSpills[i];
if (car.intersects(oil)) {
car.isDrifting = true;
car.turnSpeed = 0.15; // Increased turning for drift effect
tween(car, {
turnSpeed: 0.08
}, {
duration: 2000
});
}
}
// Camera follow car (simple centering)
if (car.x > 1024 && car.x < roadTiles.length / 16 * 170 - 1024) {
game.x = 1024 - car.x;
}
if (car.y > 1366 && car.y < roadTiles.length / 12 * 170 - 1366) {
game.y = 1366 - car.y;
}
// Play engine sound occasionally
if (car.speed > 3 && LK.ticks % 60 === 0) {
LK.getSound('engine').play();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.deceleration = 0.15;
self.turnSpeed = 0.08;
self.health = 100;
self.isDrifting = false;
self.update = function () {
// Apply deceleration when not accelerating
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
}
// Move car forward based on current rotation and speed
var radians = self.rotation;
self.x += Math.sin(radians) * self.speed;
self.y -= Math.cos(radians) * self.speed;
// Keep car within bounds
if (self.x < 30) self.x = 30;
if (self.x > 2018) self.x = 2018;
if (self.y < 60) self.y = 60;
if (self.y > 2672) self.y = 2672;
};
self.accelerate = function () {
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
}
};
self.turnLeft = function () {
if (self.speed > 1) {
self.rotation -= self.turnSpeed;
}
};
self.turnRight = function () {
if (self.speed > 1) {
self.rotation += self.turnSpeed;
}
};
self.crash = function () {
self.health -= 20;
self.speed *= 0.3;
LK.getSound('crash').play();
LK.effects.flashObject(self, 0xff0000, 500);
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var Checkpoint = Container.expand(function () {
var self = Container.call(this);
var checkpointGraphics = self.attachAsset('checkpoint', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
if (!self.collected) {
self.rotation += 0.05;
}
};
return self;
});
var GrassTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('grass', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var OilSpill = Container.expand(function () {
var self = Container.call(this);
var oilGraphics = self.attachAsset('oil', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var RoadTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var TrafficCar = Container.expand(function () {
var self = Container.call(this);
var trafficGraphics = self.attachAsset('traffic', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 3;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
self.x += Math.sin(self.direction) * self.speed;
self.y -= Math.cos(self.direction) * self.speed;
// Wrap around screen
if (self.x < -50) self.x = 2098;
if (self.x > 2098) self.x = -50;
if (self.y < -50) self.y = 2782;
if (self.y > 2782) self.y = -50;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2ecc71
});
/****
* Game Code
****/
// Game variables
var car = null;
var roadTiles = [];
var obstacles = [];
var checkpoints = [];
var trafficCars = [];
var oilSpills = [];
var checkpointsCollected = 0;
var totalCheckpoints = 5;
var gameTime = 0;
var raceStarted = false;
var currentLevel = storage.currentLevel || 1;
// UI Elements
var scoreTxt = new Text2('Checkpoints: 0/5', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var healthTxt = new Text2('Health: 100', {
size: 50,
fill: 0xFF0000
});
healthTxt.anchor.set(0, 0);
healthTxt.x = 150;
healthTxt.y = 20;
LK.gui.topLeft.addChild(healthTxt);
var timeTxt = new Text2('Time: 0', {
size: 50,
fill: 0xFFFFFF
});
timeTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(timeTxt);
// Create road layout
function createRoadLayout() {
// Create a simple road pattern
for (var i = 0; i < 12; i++) {
for (var j = 0; j < 16; j++) {
var tile = null;
// Create roads in specific pattern
if (i >= 2 && i <= 9 && j >= 2 && j <= 13 || i >= 4 && i <= 7 && (j === 0 || j === 1 || j === 14 || j === 15)) {
tile = new RoadTile();
} else {
tile = new GrassTile();
}
tile.x = i * 170 + 85;
tile.y = j * 170 + 85;
game.addChild(tile);
roadTiles.push(tile);
}
}
}
// Create obstacles
function createObstacles() {
for (var i = 0; i < 8; i++) {
var obstacle = new Obstacle();
obstacle.x = 200 + Math.random() * 1600;
obstacle.y = 200 + Math.random() * 2200;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
// Create checkpoints
function createCheckpoints() {
var checkpointPositions = [{
x: 500,
y: 500
}, {
x: 1200,
y: 800
}, {
x: 800,
y: 1400
}, {
x: 1500,
y: 1800
}, {
x: 600,
y: 2200
}];
for (var i = 0; i < checkpointPositions.length; i++) {
var checkpoint = new Checkpoint();
checkpoint.x = checkpointPositions[i].x;
checkpoint.y = checkpointPositions[i].y;
checkpoints.push(checkpoint);
game.addChild(checkpoint);
}
totalCheckpoints = checkpoints.length;
}
// Create traffic
function createTraffic() {
for (var i = 0; i < 6; i++) {
var trafficCar = new TrafficCar();
trafficCar.x = Math.random() * 2048;
trafficCar.y = Math.random() * 2732;
trafficCars.push(trafficCar);
game.addChild(trafficCar);
}
}
// Create oil spills
function createOilSpills() {
for (var i = 0; i < 4; i++) {
var oil = new OilSpill();
oil.x = 300 + Math.random() * 1400;
oil.y = 300 + Math.random() * 2100;
oilSpills.push(oil);
game.addChild(oil);
}
}
// Initialize game elements
createRoadLayout();
createObstacles();
createCheckpoints();
createTraffic();
createOilSpills();
// Create player car
car = new Car();
car.x = 400;
car.y = 400;
game.addChild(car);
// Touch controls
var touchActive = false;
var lastTouchX = 0;
var lastTouchY = 0;
game.down = function (x, y, obj) {
touchActive = true;
lastTouchX = x;
lastTouchY = y;
raceStarted = true;
};
game.move = function (x, y, obj) {
if (touchActive) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
// Calculate desired angle based on touch movement
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
var targetAngle = Math.atan2(deltaX, -deltaY);
car.rotation = targetAngle;
car.accelerate();
}
lastTouchX = x;
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
touchActive = false;
};
// Main game update loop
game.update = function () {
if (!raceStarted) return;
gameTime++;
// Update time display
var seconds = Math.floor(gameTime / 60);
timeTxt.setText('Time: ' + seconds);
// Update health display
healthTxt.setText('Health: ' + Math.max(0, car.health));
// Check checkpoint collection
for (var i = checkpoints.length - 1; i >= 0; i--) {
var checkpoint = checkpoints[i];
if (!checkpoint.collected && car.intersects(checkpoint)) {
checkpoint.collected = true;
checkpointsCollected++;
LK.getSound('checkpoint').play();
LK.effects.flashObject(checkpoint, 0x00ff00, 300);
scoreTxt.setText('Checkpoints: ' + checkpointsCollected + '/' + totalCheckpoints);
// Check win condition
if (checkpointsCollected >= totalCheckpoints) {
storage.currentLevel = currentLevel + 1;
LK.setScore(1000 - Math.floor(gameTime / 6)); // Score based on time
LK.showYouWin();
}
checkpoint.destroy();
checkpoints.splice(i, 1);
}
}
// Check collisions with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (car.intersects(obstacle)) {
car.crash();
}
}
// Check collisions with traffic
for (var i = 0; i < trafficCars.length; i++) {
var trafficCar = trafficCars[i];
if (car.intersects(trafficCar)) {
car.crash();
}
}
// Check oil spill effects
for (var i = 0; i < oilSpills.length; i++) {
var oil = oilSpills[i];
if (car.intersects(oil)) {
car.isDrifting = true;
car.turnSpeed = 0.15; // Increased turning for drift effect
tween(car, {
turnSpeed: 0.08
}, {
duration: 2000
});
}
}
// Camera follow car (simple centering)
if (car.x > 1024 && car.x < roadTiles.length / 16 * 170 - 1024) {
game.x = 1024 - car.x;
}
if (car.y > 1366 && car.y < roadTiles.length / 12 * 170 - 1366) {
game.y = 1366 - car.y;
}
// Play engine sound occasionally
if (car.speed > 3 && LK.ticks % 60 === 0) {
LK.getSound('engine').play();
}
};
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "Open Road Rally" and with the description "Top-down car racing game with multiple challenging road maps and open world exploration featuring various terrains and obstacles.". No text on banner!
a grassy field with road trees and vehicles. In-Game asset. No shadows
a rad danger no entry sing board. In-Game asset. 2d. High contrast. No shadows
a gaint devil open its mouth looks horror. In-Game asset. 2d. High contrast. No shadows