/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Building = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var CashPickup = Container.expand(function () {
var self = Container.call(this);
var cashSprite = self.attachAsset('cash', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
cashSprite.rotation += 0.1;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var carSprite = self.attachAsset('player_car', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.friction = 0.95;
self.turnSpeed = 0.08;
self.health = 100;
self.maxHealth = 100;
self.update = function () {
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Keep player on screen with wrapping
if (self.x < -40) self.x = 2088;
if (self.x > 2088) self.x = -40;
if (self.y < -60) self.y = 2792;
if (self.y > 2792) self.y = -60;
};
self.steerTowards = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 20) {
var targetAngle = Math.atan2(dy, dx);
var currentAngle = Math.atan2(self.velocityY, self.velocityX);
// Smooth angle interpolation
var angleDiff = targetAngle - currentAngle;
if (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
if (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;
var steerAngle = currentAngle + angleDiff * self.turnSpeed;
// Apply acceleration in steering direction
self.velocityX += Math.cos(steerAngle) * self.acceleration;
self.velocityY += Math.sin(steerAngle) * self.acceleration;
// Limit speed
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > self.maxSpeed) {
self.velocityX = self.velocityX / speed * self.maxSpeed;
self.velocityY = self.velocityY / speed * self.maxSpeed;
}
// Update sprite rotation
carSprite.rotation = Math.atan2(self.velocityY, self.velocityX) + Math.PI / 2;
}
};
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
} else {
LK.effects.flashObject(self, 0xff0000, 500);
}
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var policeSprite = self.attachAsset('police_car', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.maxSpeed = 6;
self.acceleration = 0.25;
self.friction = 0.96;
self.turnSpeed = 0.06;
self.update = function () {
// Chase player
var dx = playerCar.x - self.x;
var dy = playerCar.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var targetAngle = Math.atan2(dy, dx);
// Apply acceleration towards player
self.velocityX += Math.cos(targetAngle) * self.acceleration;
self.velocityY += Math.sin(targetAngle) * self.acceleration;
// Limit speed
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > self.maxSpeed) {
self.velocityX = self.velocityX / speed * self.maxSpeed;
self.velocityY = self.velocityY / speed * self.maxSpeed;
}
// Update sprite rotation
policeSprite.rotation = Math.atan2(self.velocityY, self.velocityX) + Math.PI / 2;
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if too far off screen
if (self.x < -200 || self.x > 2248 || self.y < -200 || self.y > 2932) {
self.shouldRemove = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x27ae60
});
/****
* Game Code
****/
// Game variables
var playerCar;
var policeCars = [];
var buildings = [];
var cashPickups = [];
var wantedLevel = 1;
var lastPoliceSpawn = 0;
var lastCashSpawn = 0;
var targetX = 1024;
var targetY = 1366;
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var healthTxt = new Text2('Health: 100', {
size: 50,
fill: 0xFFFFFF
});
healthTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(healthTxt);
// Initialize player
playerCar = game.addChild(new PlayerCar());
playerCar.x = 1024;
playerCar.y = 1366;
// Generate city layout
function createBuildings() {
var buildingPositions = [{
x: 300,
y: 400
}, {
x: 600,
y: 300
}, {
x: 900,
y: 500
}, {
x: 1200,
y: 350
}, {
x: 1500,
y: 600
}, {
x: 1800,
y: 400
}, {
x: 400,
y: 800
}, {
x: 800,
y: 900
}, {
x: 1300,
y: 1000
}, {
x: 1600,
y: 850
}, {
x: 200,
y: 1200
}, {
x: 700,
y: 1300
}, {
x: 1100,
y: 1400
}, {
x: 1400,
y: 1200
}, {
x: 1700,
y: 1500
}, {
x: 300,
y: 1800
}, {
x: 800,
y: 1700
}, {
x: 1200,
y: 1900
}, {
x: 1500,
y: 1800
}, {
x: 500,
y: 2100
}, {
x: 1000,
y: 2200
}, {
x: 1400,
y: 2000
}, {
x: 1800,
y: 2100
}];
for (var i = 0; i < buildingPositions.length; i++) {
var building = game.addChild(new Building());
building.x = buildingPositions[i].x;
building.y = buildingPositions[i].y;
buildings.push(building);
}
}
function spawnCash() {
var cash = game.addChild(new CashPickup());
cash.x = Math.random() * 1848 + 100;
cash.y = Math.random() * 2532 + 100;
// Make sure cash doesn't spawn inside buildings
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 10) {
validPosition = true;
for (var i = 0; i < buildings.length; i++) {
if (cash.intersects(buildings[i])) {
cash.x = Math.random() * 1848 + 100;
cash.y = Math.random() * 2532 + 100;
validPosition = false;
break;
}
}
attempts++;
}
cashPickups.push(cash);
}
function spawnPolice() {
var police = game.addChild(new PoliceCar());
// Spawn police at screen edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
police.x = Math.random() * 2048;
police.y = -100;
break;
case 1:
// Right
police.x = 2148;
police.y = Math.random() * 2732;
break;
case 2:
// Bottom
police.x = Math.random() * 2048;
police.y = 2832;
break;
case 3:
// Left
police.x = -100;
police.y = Math.random() * 2732;
break;
}
policeCars.push(police);
}
// Initialize city
createBuildings();
// Spawn initial cash
for (var i = 0; i < 5; i++) {
spawnCash();
}
// Touch controls
game.down = function (x, y, obj) {
targetX = x;
targetY = y;
};
game.move = function (x, y, obj) {
targetX = x;
targetY = y;
};
// Main game loop
game.update = function () {
// Update wanted level over time
if (LK.ticks % 1800 == 0) {
// Every 30 seconds
wantedLevel = Math.min(wantedLevel + 1, 5);
}
// Steer player car
playerCar.steerTowards(targetX, targetY);
// Spawn police based on wanted level
var policeSpawnRate = Math.max(300 - wantedLevel * 50, 120);
if (LK.ticks - lastPoliceSpawn > policeSpawnRate && policeCars.length < wantedLevel * 2) {
spawnPolice();
lastPoliceSpawn = LK.ticks;
}
// Spawn cash periodically
if (LK.ticks - lastCashSpawn > 600 && cashPickups.length < 8) {
spawnCash();
lastCashSpawn = LK.ticks;
}
// Check collisions with buildings
for (var i = 0; i < buildings.length; i++) {
if (playerCar.intersects(buildings[i])) {
// Push player away from building
var dx = playerCar.x - buildings[i].x;
var dy = playerCar.y - buildings[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
playerCar.x = buildings[i].x + dx / distance * 130;
playerCar.y = buildings[i].y + dy / distance * 130;
}
// Reduce speed and take damage
playerCar.velocityX *= 0.3;
playerCar.velocityY *= 0.3;
playerCar.takeDamage(5);
LK.getSound('crash').play();
}
}
// Check collisions with cash
for (var i = cashPickups.length - 1; i >= 0; i--) {
var cash = cashPickups[i];
if (playerCar.intersects(cash)) {
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
cash.destroy();
cashPickups.splice(i, 1);
LK.getSound('collect_cash').play();
}
}
// Check collisions with police
for (var i = policeCars.length - 1; i >= 0; i--) {
var police = policeCars[i];
if (police.shouldRemove) {
police.destroy();
policeCars.splice(i, 1);
continue;
}
if (playerCar.intersects(police)) {
// Push cars apart
var dx = playerCar.x - police.x;
var dy = playerCar.y - police.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var pushForce = 5;
playerCar.velocityX += dx / distance * pushForce;
playerCar.velocityY += dy / distance * pushForce;
police.velocityX -= dx / distance * pushForce;
police.velocityY -= dy / distance * pushForce;
}
playerCar.takeDamage(10);
LK.getSound('crash').play();
}
}
// Update health display
healthTxt.setText('Health: ' + Math.ceil(playerCar.health));
// Add survival score
if (LK.ticks % 60 == 0) {
// Every second
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Building = Container.expand(function () {
var self = Container.call(this);
self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var CashPickup = Container.expand(function () {
var self = Container.call(this);
var cashSprite = self.attachAsset('cash', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
cashSprite.rotation += 0.1;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var carSprite = self.attachAsset('player_car', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.maxSpeed = 8;
self.acceleration = 0.3;
self.friction = 0.95;
self.turnSpeed = 0.08;
self.health = 100;
self.maxHealth = 100;
self.update = function () {
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Keep player on screen with wrapping
if (self.x < -40) self.x = 2088;
if (self.x > 2088) self.x = -40;
if (self.y < -60) self.y = 2792;
if (self.y > 2792) self.y = -60;
};
self.steerTowards = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 20) {
var targetAngle = Math.atan2(dy, dx);
var currentAngle = Math.atan2(self.velocityY, self.velocityX);
// Smooth angle interpolation
var angleDiff = targetAngle - currentAngle;
if (angleDiff > Math.PI) angleDiff -= 2 * Math.PI;
if (angleDiff < -Math.PI) angleDiff += 2 * Math.PI;
var steerAngle = currentAngle + angleDiff * self.turnSpeed;
// Apply acceleration in steering direction
self.velocityX += Math.cos(steerAngle) * self.acceleration;
self.velocityY += Math.sin(steerAngle) * self.acceleration;
// Limit speed
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > self.maxSpeed) {
self.velocityX = self.velocityX / speed * self.maxSpeed;
self.velocityY = self.velocityY / speed * self.maxSpeed;
}
// Update sprite rotation
carSprite.rotation = Math.atan2(self.velocityY, self.velocityX) + Math.PI / 2;
}
};
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
} else {
LK.effects.flashObject(self, 0xff0000, 500);
}
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var policeSprite = self.attachAsset('police_car', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.maxSpeed = 6;
self.acceleration = 0.25;
self.friction = 0.96;
self.turnSpeed = 0.06;
self.update = function () {
// Chase player
var dx = playerCar.x - self.x;
var dy = playerCar.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var targetAngle = Math.atan2(dy, dx);
// Apply acceleration towards player
self.velocityX += Math.cos(targetAngle) * self.acceleration;
self.velocityY += Math.sin(targetAngle) * self.acceleration;
// Limit speed
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > self.maxSpeed) {
self.velocityX = self.velocityX / speed * self.maxSpeed;
self.velocityY = self.velocityY / speed * self.maxSpeed;
}
// Update sprite rotation
policeSprite.rotation = Math.atan2(self.velocityY, self.velocityX) + Math.PI / 2;
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Remove if too far off screen
if (self.x < -200 || self.x > 2248 || self.y < -200 || self.y > 2932) {
self.shouldRemove = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x27ae60
});
/****
* Game Code
****/
// Game variables
var playerCar;
var policeCars = [];
var buildings = [];
var cashPickups = [];
var wantedLevel = 1;
var lastPoliceSpawn = 0;
var lastCashSpawn = 0;
var targetX = 1024;
var targetY = 1366;
// UI elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var healthTxt = new Text2('Health: 100', {
size: 50,
fill: 0xFFFFFF
});
healthTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(healthTxt);
// Initialize player
playerCar = game.addChild(new PlayerCar());
playerCar.x = 1024;
playerCar.y = 1366;
// Generate city layout
function createBuildings() {
var buildingPositions = [{
x: 300,
y: 400
}, {
x: 600,
y: 300
}, {
x: 900,
y: 500
}, {
x: 1200,
y: 350
}, {
x: 1500,
y: 600
}, {
x: 1800,
y: 400
}, {
x: 400,
y: 800
}, {
x: 800,
y: 900
}, {
x: 1300,
y: 1000
}, {
x: 1600,
y: 850
}, {
x: 200,
y: 1200
}, {
x: 700,
y: 1300
}, {
x: 1100,
y: 1400
}, {
x: 1400,
y: 1200
}, {
x: 1700,
y: 1500
}, {
x: 300,
y: 1800
}, {
x: 800,
y: 1700
}, {
x: 1200,
y: 1900
}, {
x: 1500,
y: 1800
}, {
x: 500,
y: 2100
}, {
x: 1000,
y: 2200
}, {
x: 1400,
y: 2000
}, {
x: 1800,
y: 2100
}];
for (var i = 0; i < buildingPositions.length; i++) {
var building = game.addChild(new Building());
building.x = buildingPositions[i].x;
building.y = buildingPositions[i].y;
buildings.push(building);
}
}
function spawnCash() {
var cash = game.addChild(new CashPickup());
cash.x = Math.random() * 1848 + 100;
cash.y = Math.random() * 2532 + 100;
// Make sure cash doesn't spawn inside buildings
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 10) {
validPosition = true;
for (var i = 0; i < buildings.length; i++) {
if (cash.intersects(buildings[i])) {
cash.x = Math.random() * 1848 + 100;
cash.y = Math.random() * 2532 + 100;
validPosition = false;
break;
}
}
attempts++;
}
cashPickups.push(cash);
}
function spawnPolice() {
var police = game.addChild(new PoliceCar());
// Spawn police at screen edges
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
police.x = Math.random() * 2048;
police.y = -100;
break;
case 1:
// Right
police.x = 2148;
police.y = Math.random() * 2732;
break;
case 2:
// Bottom
police.x = Math.random() * 2048;
police.y = 2832;
break;
case 3:
// Left
police.x = -100;
police.y = Math.random() * 2732;
break;
}
policeCars.push(police);
}
// Initialize city
createBuildings();
// Spawn initial cash
for (var i = 0; i < 5; i++) {
spawnCash();
}
// Touch controls
game.down = function (x, y, obj) {
targetX = x;
targetY = y;
};
game.move = function (x, y, obj) {
targetX = x;
targetY = y;
};
// Main game loop
game.update = function () {
// Update wanted level over time
if (LK.ticks % 1800 == 0) {
// Every 30 seconds
wantedLevel = Math.min(wantedLevel + 1, 5);
}
// Steer player car
playerCar.steerTowards(targetX, targetY);
// Spawn police based on wanted level
var policeSpawnRate = Math.max(300 - wantedLevel * 50, 120);
if (LK.ticks - lastPoliceSpawn > policeSpawnRate && policeCars.length < wantedLevel * 2) {
spawnPolice();
lastPoliceSpawn = LK.ticks;
}
// Spawn cash periodically
if (LK.ticks - lastCashSpawn > 600 && cashPickups.length < 8) {
spawnCash();
lastCashSpawn = LK.ticks;
}
// Check collisions with buildings
for (var i = 0; i < buildings.length; i++) {
if (playerCar.intersects(buildings[i])) {
// Push player away from building
var dx = playerCar.x - buildings[i].x;
var dy = playerCar.y - buildings[i].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
playerCar.x = buildings[i].x + dx / distance * 130;
playerCar.y = buildings[i].y + dy / distance * 130;
}
// Reduce speed and take damage
playerCar.velocityX *= 0.3;
playerCar.velocityY *= 0.3;
playerCar.takeDamage(5);
LK.getSound('crash').play();
}
}
// Check collisions with cash
for (var i = cashPickups.length - 1; i >= 0; i--) {
var cash = cashPickups[i];
if (playerCar.intersects(cash)) {
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
cash.destroy();
cashPickups.splice(i, 1);
LK.getSound('collect_cash').play();
}
}
// Check collisions with police
for (var i = policeCars.length - 1; i >= 0; i--) {
var police = policeCars[i];
if (police.shouldRemove) {
police.destroy();
policeCars.splice(i, 1);
continue;
}
if (playerCar.intersects(police)) {
// Push cars apart
var dx = playerCar.x - police.x;
var dy = playerCar.y - police.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var pushForce = 5;
playerCar.velocityX += dx / distance * pushForce;
playerCar.velocityY += dy / distance * pushForce;
police.velocityX -= dx / distance * pushForce;
police.velocityY -= dy / distance * pushForce;
}
playerCar.takeDamage(10);
LK.getSound('crash').play();
}
}
// Update health display
healthTxt.setText('Health: ' + Math.ceil(playerCar.health));
// Add survival score
if (LK.ticks % 60 == 0) {
// Every second
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
}
};