User prompt
speed increase 2 times,
User prompt
decrease diamonds
User prompt
make player move with a 360 degree console button make cars moving in all directions like real cars
User prompt
show player's car in different colour decrease number of diamonds make a continuous background with like a city map
User prompt
put chasing car in the middle, and make the map is moving with pace (increases after each crash with a 1 percent) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Police Chase Escape
Initial prompt
police runner, 2D, top-down, controlling car, escaping from police cars, there are exceptional gold diamonds etc., police and background changes smoothly after milestones, aim is to crush police cars with each other (like police pursuit game) while not crushing with them
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CityBackground = Container.expand(function () {
var self = Container.call(this);
var backgroundElements = [];
self.tileHeight = 400;
self.tilesPerRow = 10;
self.rows = 10;
// Helper function to create building complex
function createBuildingComplex(col, row, topY) {
var complex = new Container();
var buildingTypes = ['building', 'tallBuilding', 'skyscraper', 'apartment', 'office'];
var buildingType = buildingTypes[Math.floor(Math.random() * buildingTypes.length)];
var building = LK.getAsset(buildingType, {
anchorX: 0,
anchorY: 0
});
building.width = 150 + Math.random() * 50;
building.height = 200 + Math.random() * 200;
building.alpha = 0.8;
complex.addChild(building);
// Add windows effect with alpha variations
building.alpha = 0.7 + Math.random() * 0.3;
// Add sidewalk
var sidewalk = LK.getAsset('sidewalk', {
anchorX: 0,
anchorY: 0
});
sidewalk.width = 200;
sidewalk.height = 30;
sidewalk.y = building.height - 30;
complex.addChild(sidewalk);
// Randomly add street elements
if (Math.random() < 0.3) {
var streetLight = LK.getAsset('streetLight', {
anchorX: 0,
anchorY: 0
});
streetLight.x = 20 + Math.random() * 160;
streetLight.y = building.height - 80;
complex.addChild(streetLight);
}
if (Math.random() < 0.2) {
var tree = LK.getAsset('tree', {
anchorX: 0,
anchorY: 0
});
tree.x = 30 + Math.random() * 140;
tree.y = building.height - 60;
complex.addChild(tree);
}
if (Math.random() < 0.15) {
var mailbox = LK.getAsset('mailbox', {
anchorX: 0,
anchorY: 0
});
mailbox.x = 40 + Math.random() * 120;
mailbox.y = building.height - 30;
complex.addChild(mailbox);
}
complex.x = col * 200;
complex.y = topY;
return complex;
}
// Helper function to create road with details
function createRoadSection(col, row, topY) {
var roadSection = new Container();
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0
});
road.width = 200;
road.height = 100;
roadSection.addChild(road);
// Add lane markings
for (var i = 0; i < 3; i++) {
var laneLine = LK.getAsset('laneLine', {
anchorX: 0,
anchorY: 0
});
laneLine.width = 200;
laneLine.height = 3;
laneLine.y = 25 + i * 25;
laneLine.alpha = 0.8;
roadSection.addChild(laneLine);
}
// Randomly add crosswalk
if (Math.random() < 0.2) {
var crosswalk = LK.getAsset('crosswalk', {
anchorX: 0,
anchorY: 0
});
crosswalk.width = 200;
crosswalk.height = 15;
crosswalk.y = 85;
crosswalk.alpha = 0.9;
roadSection.addChild(crosswalk);
}
// Randomly add parked vehicles
if (Math.random() < 0.3) {
var vehicleTypes = ['parkedCar', 'taxi'];
var vehicleType = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var vehicle = LK.getAsset(vehicleType, {
anchorX: 0,
anchorY: 0
});
vehicle.width = 60;
vehicle.height = 100;
vehicle.x = 10 + Math.random() * 130;
vehicle.y = 0;
vehicle.alpha = 0.8;
roadSection.addChild(vehicle);
}
// Randomly add bus
if (Math.random() < 0.1) {
var bus = LK.getAsset('bus', {
anchorX: 0,
anchorY: 0
});
bus.width = 90;
bus.height = 200;
bus.x = 55;
bus.y = -50;
bus.alpha = 0.8;
roadSection.addChild(bus);
}
roadSection.x = col * 200;
roadSection.y = topY;
return roadSection;
}
// Create initial background tiles
for (var row = 0; row < self.rows; row++) {
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var topY = (row - 2) * self.tileHeight;
if (elementType < 3) {
// Road with details (30% chance)
element = createRoadSection(col, row, topY);
} else if (elementType < 8) {
// Building complex (50% chance)
element = createBuildingComplex(col, row, topY);
} else {
// City block (20% chance)
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = topY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
self.update = function () {
// Move background based on player movement to keep player centered
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Find the bounds of current background elements
var minY = Infinity;
var maxY = -Infinity;
var minX = Infinity;
var maxX = -Infinity;
for (var i = 0; i < backgroundElements.length; i++) {
var element = backgroundElements[i];
minY = Math.min(minY, element.y);
maxY = Math.max(maxY, element.y);
minX = Math.min(minX, element.x);
maxX = Math.max(maxX, element.x);
}
// Add new tiles in all directions as needed for endless scrolling
// Add rows above if needed
if (minY > -self.y - 800) {
var newTopY = minY - self.tileHeight;
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
if (elementType < 3) {
element = createRoadSection(col, 0, newTopY);
} else if (elementType < 8) {
element = createBuildingComplex(col, 0, newTopY);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = newTopY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
// Add rows below if needed
if (maxY < -self.y + 3500) {
var newBottomY = maxY + self.tileHeight;
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
if (elementType < 3) {
element = createRoadSection(col, 0, newBottomY);
} else if (elementType < 8) {
element = createBuildingComplex(col, 0, newBottomY);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = newBottomY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
// Add columns left if needed
if (minX > -self.x - 400) {
var newLeftX = minX - 200;
for (var row = 0; row < Math.ceil((maxY - minY) / self.tileHeight) + 2; row++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var yPos = minY + row * self.tileHeight;
if (elementType < 3) {
element = createRoadSection(0, 0, yPos);
} else if (elementType < 8) {
element = createBuildingComplex(0, 0, yPos);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.y = yPos;
element.alpha = 0.7;
}
element.x = newLeftX;
self.addChild(element);
backgroundElements.push(element);
}
}
// Add columns right if needed
if (maxX < -self.x + 2400) {
var newRightX = maxX + 200;
for (var row = 0; row < Math.ceil((maxY - minY) / self.tileHeight) + 2; row++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var yPos = minY + row * self.tileHeight;
if (elementType < 3) {
element = createRoadSection(0, 0, yPos);
} else if (elementType < 8) {
element = createBuildingComplex(0, 0, yPos);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.y = yPos;
element.alpha = 0.7;
}
element.x = newRightX;
self.addChild(element);
backgroundElements.push(element);
}
}
// Remove elements that are too far away for memory management
for (var i = backgroundElements.length - 1; i >= 0; i--) {
var element = backgroundElements[i];
var distanceFromPlayer = Math.sqrt(Math.pow(element.x + self.x, 2) + Math.pow(element.y + self.y, 2));
if (distanceFromPlayer > 4000) {
element.destroy();
backgroundElements.splice(i, 1);
}
}
};
return self;
});
var Diamond = Container.expand(function () {
var self = Container.call(this);
var diamondGraphics = self.attachAsset('diamond', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.05;
self.update = function () {
diamondGraphics.rotation += self.rotationSpeed;
// Move diamonds based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Diamonds stay static in world - no movement with map
// Remove diamonds that go off screen (player moved away)
if (self.y > 2732 + 100 || self.y < -100 || self.x > 2048 + 100 || self.x < -100) {
self.destroy();
}
};
return self;
});
var DragEffect = Container.expand(function () {
var self = Container.call(this);
self.effectGraphics = self.attachAsset('getawayCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.effectGraphics.alpha = 0.3;
self.effectGraphics.tint = 0x00ffff;
self.effectGraphics.scaleX = 0.6;
self.effectGraphics.scaleY = 0.6;
self.lifetime = 20;
self.age = 0;
self.initialAlpha = 0.5;
self.update = function () {
self.age++;
var fadeRatio = 1 - self.age / self.lifetime;
self.effectGraphics.alpha = self.initialAlpha * fadeRatio;
self.effectGraphics.scaleX = 0.6 * fadeRatio;
self.effectGraphics.scaleY = 0.6 * fadeRatio;
// Move with world
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 30;
self.age = 0;
self.update = function () {
self.age++;
explosionGraphics.alpha = 1 - self.age / self.lifetime;
explosionGraphics.scaleX = 1 + self.age / self.lifetime;
explosionGraphics.scaleY = 1 + self.age / self.lifetime;
// Move explosions based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Explosions stay static in world - no movement with map
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var GetawayCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('getawayCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 36; // Increased base speed by 3x
self.maxSpeed = 72; // Increased max speed by 3x to be faster than police
self.velocityX = 0;
self.velocityY = 0;
self.acceleration = 2.4; // Increased acceleration by 3x
self.friction = 0.85;
// Drag effect properties
self.dragTrail = [];
self.maxTrailLength = 8;
self.trailFadeSpeed = 0.8;
self.update = function () {
var inputX = 0;
var inputY = 0;
var hasInput = false;
// Apply active button input if available (mobile)
if (activeButton && activeButton.isActive) {
inputX = activeButton.currentX;
inputY = activeButton.currentY;
hasInput = true;
}
// Keyboard input removed - not supported in LK engine
// Apply input to velocity
if (hasInput) {
self.velocityX += inputX * self.acceleration;
self.velocityY += inputY * self.acceleration;
// Rotate car to face movement direction
if (inputX !== 0 || inputY !== 0) {
var angle = Math.atan2(inputY, inputX);
carGraphics.rotation = angle + Math.PI / 2;
}
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Limit velocity
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 drag trail effect
if (speed > 1) {
// Add current position to trail
self.dragTrail.unshift({
x: self.x,
y: self.y,
alpha: 1.0,
scale: 1.0
});
// Limit trail length
if (self.dragTrail.length > self.maxTrailLength) {
self.dragTrail.pop();
}
}
// Update trail particles
for (var i = 0; i < self.dragTrail.length; i++) {
var trail = self.dragTrail[i];
trail.alpha *= self.trailFadeSpeed;
trail.scale *= 0.95;
if (trail.alpha < 0.1) {
self.dragTrail.splice(i, 1);
i--;
}
}
// Keep player car centered - move world instead of car
self.x = 1024; // Always center horizontally
self.y = 1366; // Always center vertically
// Store velocity for world movement
self.worldVelocityX = self.velocityX;
self.worldVelocityY = self.velocityY;
};
return self;
});
var JoystickControl = Container.expand(function () {
var self = Container.call(this);
var joystickBase = self.attachAsset('joystickBase', {
anchorX: 0.5,
anchorY: 0.5
});
var joystickKnob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5
});
joystickBase.alpha = 1.0;
joystickKnob.alpha = 1.0;
joystickBase.tint = 0x7f8c8d; // Light gray for better visibility
joystickKnob.tint = 0xffffff; // White knob for contrast
self.isActive = false;
self.currentX = 0;
self.currentY = 0;
self.maxDistance = 100;
self.down = function (x, y, obj) {
self.isActive = true;
self.updateKnob(x, y);
};
self.move = function (x, y, obj) {
if (self.isActive) {
self.updateKnob(x, y);
}
};
self.up = function (x, y, obj) {
self.isActive = false;
joystickKnob.x = 0;
joystickKnob.y = 0;
self.currentX = 0;
self.currentY = 0;
};
self.updateKnob = function (x, y) {
var deltaX = x;
var deltaY = y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > self.maxDistance) {
deltaX = deltaX / distance * self.maxDistance;
deltaY = deltaY / distance * self.maxDistance;
}
joystickKnob.x = deltaX;
joystickKnob.y = deltaY;
self.currentX = deltaX / self.maxDistance;
self.currentY = deltaY / self.maxDistance;
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('policeCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 24; // Base speed slower than player (3x increase)
self.speed = self.baseSpeed;
self.targetCar = null;
self.lastCollisionCheck = false;
self.velocityX = 0;
self.velocityY = 0;
self.acceleration = 0.6; // Increased acceleration by 3x
self.friction = 0.95;
// Drag effect properties
self.dragTrail = [];
self.maxTrailLength = 6;
self.trailFadeSpeed = 0.75;
self.update = function () {
if (self.targetCar) {
var deltaX = self.targetCar.x - self.x;
var deltaY = self.targetCar.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 5) {
// Apply acceleration towards target
self.velocityX += deltaX / distance * self.acceleration;
self.velocityY += deltaY / distance * self.acceleration;
// Rotate car to face movement direction
var angle = Math.atan2(deltaY, deltaX);
carGraphics.rotation = angle + Math.PI / 2;
}
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Apply difficulty scaling to speed
var difficultyMultiplier = 1 + milestone * 0.3 + diamondsCollected * 0.02 + policeKills * 0.05;
var currentSpeed = self.baseSpeed * difficultyMultiplier;
// Ensure police are always slower than player max speed (3x increase)
if (currentSpeed > 60) currentSpeed = 60;
// Limit velocity
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > currentSpeed) {
self.velocityX = self.velocityX / speed * currentSpeed;
self.velocityY = self.velocityY / speed * currentSpeed;
}
// Move police car
self.x += self.velocityX;
self.y += self.velocityY;
// Update drag trail effect
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > 0.5) {
// Add current position to trail before world movement
self.dragTrail.unshift({
x: self.x,
y: self.y,
alpha: 0.8,
scale: 0.8
});
// Limit trail length
if (self.dragTrail.length > self.maxTrailLength) {
self.dragTrail.pop();
}
}
// Update trail particles
for (var i = 0; i < self.dragTrail.length; i++) {
var trail = self.dragTrail[i];
trail.alpha *= self.trailFadeSpeed;
trail.scale *= 0.92;
if (trail.alpha < 0.05) {
self.dragTrail.splice(i, 1);
i--;
}
}
// Move police cars based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
// Also move trail positions to keep them consistent with world movement
for (var i = 0; i < self.dragTrail.length; i++) {
self.dragTrail[i].x -= player.worldVelocityX;
self.dragTrail[i].y -= player.worldVelocityY;
}
}
// Police cars stay in world - no map movement
// Remove police cars that go off screen
if (self.y > 2732 + 100 || self.y < -100 || self.x > 2048 + 100 || self.x < -100) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var player;
var policeCars = [];
var diamonds = [];
var explosions = [];
var gameSpeed = 1;
var milestone = 0;
var diamondsCollected = 0;
var policeKills = 0;
var mapSpeed = 36; // Increased by 3x
var mapOffsetY = 0;
var baseMapSpeed = 36; // Increased by 3x
// Background colors for different milestones
var backgroundColors = [0x2c3e50, 0x34495e, 0x1abc9c, 0x16a085, 0x27ae60, 0x2980b9];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var diamondsTxt = new Text2('Diamonds: 0', {
size: 50,
fill: 0xF1C40F
});
diamondsTxt.anchor.set(0.5, 0);
diamondsTxt.x = 0;
diamondsTxt.y = 80;
LK.gui.top.addChild(diamondsTxt);
var killsTxt = new Text2('Police Crashes: 0', {
size: 50,
fill: 0xE74C3C
});
killsTxt.anchor.set(0.5, 0);
killsTxt.x = 0;
killsTxt.y = 140;
LK.gui.top.addChild(killsTxt);
// Initialize city background
var cityBackground = game.addChild(new CityBackground());
// Initialize joystick control
var joystick = new JoystickControl();
// Create right action button
var rightButton = new JoystickControl();
rightButton.x = 0;
rightButton.y = 0;
// Scale up the button for better visibility
rightButton.scaleX = 1.5;
rightButton.scaleY = 1.5;
LK.gui.center.addChild(rightButton);
rightButton.x = 300; // Move more left from center
rightButton.y = 400; // Move down from center
// Only show right button
rightButton.visible = true;
var activeButton = rightButton;
// Initialize player
player = game.addChild(new GetawayCar());
player.x = 1024; // Center horizontally
player.y = 1366; // Center vertically
// Spawn initial police cars
function spawnPoliceCar() {
var police = new PoliceCar();
// Spawn from screen edges
var edge = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left
var margin = 50;
switch (edge) {
case 0:
// Top edge
police.x = Math.random() * 2048;
police.y = -margin;
break;
case 1:
// Right edge
police.x = 2048 + margin;
police.y = Math.random() * 2732;
break;
case 2:
// Bottom edge
police.x = Math.random() * 2048;
police.y = 2732 + margin;
break;
case 3:
// Left edge
police.x = -margin;
police.y = Math.random() * 2732;
break;
}
police.targetCar = player;
police.baseSpeed = 24; // Set base speed (3x increase)
police.speed = police.baseSpeed;
policeCars.push(police);
game.addChild(police);
}
// Spawn initial diamonds
function spawnDiamond() {
var diamond = new Diamond();
// Spawn diamonds around the current play area
diamond.x = player.x - 500 + Math.random() * 1000;
diamond.y = player.y - 500 + Math.random() * 1000;
// Keep diamonds within reasonable bounds
if (diamond.x < 50) diamond.x = 50;
if (diamond.x > 1998) diamond.x = 1998;
if (diamond.y < 50) diamond.y = 50;
if (diamond.y > 2682) diamond.y = 2682;
diamonds.push(diamond);
game.addChild(diamond);
}
// Initialize game objects
for (var i = 0; i < 3; i++) {
spawnPoliceCar();
}
for (var i = 0; i < 1; i++) {
spawnDiamond();
}
// Joystick controls are now handled by the JoystickControl class
// Desktop keyboard controls (removed - not supported in LK engine)
var keys = {};
// Touch and mouse controls for action buttons
game.down = function (x, y, obj) {
// Check if touch is in right button area
if (rightButton.visible) {
// Touch in right button area
var buttonPos = LK.gui.center.toLocal({
x: x,
y: y
});
buttonPos.x -= 300; // Adjust for right button offset
buttonPos.y -= 400; // Adjust for right button Y offset
var distance = Math.sqrt(buttonPos.x * buttonPos.x + buttonPos.y * buttonPos.y);
if (distance <= rightButton.maxDistance * 1.5) {
activeButton = rightButton;
rightButton.down(buttonPos.x, buttonPos.y, obj);
}
}
};
game.move = function (x, y, obj) {
if (activeButton && activeButton.isActive) {
if (activeButton === rightButton) {
var buttonPos = LK.gui.center.toLocal({
x: x,
y: y
});
buttonPos.x -= 300; // Adjust for right button offset
buttonPos.y -= 400; // Adjust for right button Y offset
rightButton.move(buttonPos.x, buttonPos.y, obj);
}
}
};
game.up = function (x, y, obj) {
if (activeButton && activeButton.isActive) {
activeButton.up(x, y, obj);
}
};
// Update score display
function updateScore() {
var totalScore = diamondsCollected * 100 + policeKills * 500;
LK.setScore(totalScore);
scoreTxt.setText('Score: ' + totalScore);
diamondsTxt.setText('Diamonds: ' + diamondsCollected);
killsTxt.setText('Police Crashes: ' + policeKills);
}
// Check milestone progression
function checkMilestone() {
var newMilestone = Math.floor(LK.getScore() / 1000);
if (newMilestone > milestone) {
milestone = newMilestone;
// Change background color
if (milestone < backgroundColors.length) {
tween(game, {
backgroundColor: backgroundColors[milestone]
}, {
duration: 2000
});
}
// Spawn additional police car
spawnPoliceCar();
}
}
// Create explosion effect
function createExplosion(x, y) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
explosions.push(explosion);
game.addChild(explosion);
// Make explosion more dramatic with tween animations
// Scale explosion from small to large
tween(explosion, {
scaleX: 3,
scaleY: 3
}, {
duration: 300,
easing: tween.easeOut
});
// Fade out with pulsing effect
tween(explosion, {
alpha: 0
}, {
duration: 600,
easing: tween.easeInOut
});
// Add rotation for more dynamic effect
tween(explosion, {
rotation: Math.PI * 2
}, {
duration: 400,
easing: tween.linear
});
// Add color tint animation to explosion for more visual impact
tween(explosion, {
tint: 0xff4500
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(explosion, {
tint: 0xffffff
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
// Main game loop
game.update = function () {
// Render drag effects for player car
if (player && player.dragTrail) {
for (var i = 0; i < player.dragTrail.length; i++) {
var trail = player.dragTrail[i];
if (trail.alpha > 0.1) {
var dragEffect = new DragEffect();
dragEffect.x = trail.x;
dragEffect.y = trail.y;
dragEffect.effectGraphics.alpha = trail.alpha * 0.4;
dragEffect.effectGraphics.scaleX = trail.scale * 0.7;
dragEffect.effectGraphics.scaleY = trail.scale * 0.7;
dragEffect.effectGraphics.tint = 0x6f869c;
dragEffect.lifetime = 15;
game.addChild(dragEffect);
}
}
}
// Render drag effects for police cars
for (var p = 0; p < policeCars.length; p++) {
var policeCar = policeCars[p];
if (policeCar.dragTrail) {
for (var i = 0; i < policeCar.dragTrail.length; i++) {
var trail = policeCar.dragTrail[i];
if (trail.alpha > 0.05) {
var dragEffect = new DragEffect();
dragEffect.x = trail.x;
dragEffect.y = trail.y;
dragEffect.effectGraphics.alpha = trail.alpha * 0.3;
dragEffect.effectGraphics.scaleX = trail.scale * 0.6;
dragEffect.effectGraphics.scaleY = trail.scale * 0.6;
dragEffect.effectGraphics.tint = 0x8e44ad;
dragEffect.lifetime = 12;
game.addChild(dragEffect);
}
}
}
}
// Check diamond collection
for (var i = diamonds.length - 1; i >= 0; i--) {
var diamond = diamonds[i];
if (!diamond.collected && player.intersects(diamond)) {
diamond.collected = true;
diamondsCollected++;
LK.getSound('collectDiamond').play();
diamond.destroy();
diamonds.splice(i, 1);
// Spawn new diamond
spawnDiamond();
}
}
// Check police car collisions with player
for (var i = 0; i < policeCars.length; i++) {
var police = policeCars[i];
if (player.intersects(police)) {
LK.getSound('gameOver').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Check police car collisions with each other
for (var i = policeCars.length - 1; i >= 0; i--) {
var police1 = policeCars[i];
var collided = false;
for (var j = i + 1; j < policeCars.length; j++) {
var police2 = policeCars[j];
if (police1.intersects(police2)) {
// Create explosion
var explosionX = (police1.x + police2.x) / 2;
var explosionY = (police1.y + police2.y) / 2;
createExplosion(explosionX, explosionY);
policeKills++;
LK.getSound('policeExplode').play();
// Increase map speed by 1%
mapSpeed = mapSpeed * 1.01;
// Remove both police cars
police1.destroy();
police2.destroy();
policeCars.splice(j, 1);
policeCars.splice(i, 1);
collided = true;
break;
}
}
if (collided) break;
}
// Clean up police cars that went off screen
for (var i = policeCars.length - 1; i >= 0; i--) {
var police = policeCars[i];
if (police.y > 2732 + 100) {
police.destroy();
policeCars.splice(i, 1);
}
}
// Clean up diamonds that went off screen
for (var i = diamonds.length - 1; i >= 0; i--) {
var diamond = diamonds[i];
if (diamond.y > 2732 + 100) {
diamond.destroy();
diamonds.splice(i, 1);
// Spawn new diamond
spawnDiamond();
}
}
// Clean up explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
if (explosion.age >= explosion.lifetime) {
explosions.splice(i, 1);
}
}
// Spawn new police cars periodically - increased frequency
if (LK.ticks % (120 - milestone * 15) === 0) {
spawnPoliceCar();
}
// Spawn new diamonds periodically
if (LK.ticks % 500 === 0) {
spawnDiamond();
}
// Map speed logic removed - car moves instead of map
// Update score and check milestones
updateScore();
checkMilestone();
// Win condition
if (LK.getScore() >= 10000) {
LK.showYouWin();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CityBackground = Container.expand(function () {
var self = Container.call(this);
var backgroundElements = [];
self.tileHeight = 400;
self.tilesPerRow = 10;
self.rows = 10;
// Helper function to create building complex
function createBuildingComplex(col, row, topY) {
var complex = new Container();
var buildingTypes = ['building', 'tallBuilding', 'skyscraper', 'apartment', 'office'];
var buildingType = buildingTypes[Math.floor(Math.random() * buildingTypes.length)];
var building = LK.getAsset(buildingType, {
anchorX: 0,
anchorY: 0
});
building.width = 150 + Math.random() * 50;
building.height = 200 + Math.random() * 200;
building.alpha = 0.8;
complex.addChild(building);
// Add windows effect with alpha variations
building.alpha = 0.7 + Math.random() * 0.3;
// Add sidewalk
var sidewalk = LK.getAsset('sidewalk', {
anchorX: 0,
anchorY: 0
});
sidewalk.width = 200;
sidewalk.height = 30;
sidewalk.y = building.height - 30;
complex.addChild(sidewalk);
// Randomly add street elements
if (Math.random() < 0.3) {
var streetLight = LK.getAsset('streetLight', {
anchorX: 0,
anchorY: 0
});
streetLight.x = 20 + Math.random() * 160;
streetLight.y = building.height - 80;
complex.addChild(streetLight);
}
if (Math.random() < 0.2) {
var tree = LK.getAsset('tree', {
anchorX: 0,
anchorY: 0
});
tree.x = 30 + Math.random() * 140;
tree.y = building.height - 60;
complex.addChild(tree);
}
if (Math.random() < 0.15) {
var mailbox = LK.getAsset('mailbox', {
anchorX: 0,
anchorY: 0
});
mailbox.x = 40 + Math.random() * 120;
mailbox.y = building.height - 30;
complex.addChild(mailbox);
}
complex.x = col * 200;
complex.y = topY;
return complex;
}
// Helper function to create road with details
function createRoadSection(col, row, topY) {
var roadSection = new Container();
var road = LK.getAsset('road', {
anchorX: 0,
anchorY: 0
});
road.width = 200;
road.height = 100;
roadSection.addChild(road);
// Add lane markings
for (var i = 0; i < 3; i++) {
var laneLine = LK.getAsset('laneLine', {
anchorX: 0,
anchorY: 0
});
laneLine.width = 200;
laneLine.height = 3;
laneLine.y = 25 + i * 25;
laneLine.alpha = 0.8;
roadSection.addChild(laneLine);
}
// Randomly add crosswalk
if (Math.random() < 0.2) {
var crosswalk = LK.getAsset('crosswalk', {
anchorX: 0,
anchorY: 0
});
crosswalk.width = 200;
crosswalk.height = 15;
crosswalk.y = 85;
crosswalk.alpha = 0.9;
roadSection.addChild(crosswalk);
}
// Randomly add parked vehicles
if (Math.random() < 0.3) {
var vehicleTypes = ['parkedCar', 'taxi'];
var vehicleType = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var vehicle = LK.getAsset(vehicleType, {
anchorX: 0,
anchorY: 0
});
vehicle.width = 60;
vehicle.height = 100;
vehicle.x = 10 + Math.random() * 130;
vehicle.y = 0;
vehicle.alpha = 0.8;
roadSection.addChild(vehicle);
}
// Randomly add bus
if (Math.random() < 0.1) {
var bus = LK.getAsset('bus', {
anchorX: 0,
anchorY: 0
});
bus.width = 90;
bus.height = 200;
bus.x = 55;
bus.y = -50;
bus.alpha = 0.8;
roadSection.addChild(bus);
}
roadSection.x = col * 200;
roadSection.y = topY;
return roadSection;
}
// Create initial background tiles
for (var row = 0; row < self.rows; row++) {
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var topY = (row - 2) * self.tileHeight;
if (elementType < 3) {
// Road with details (30% chance)
element = createRoadSection(col, row, topY);
} else if (elementType < 8) {
// Building complex (50% chance)
element = createBuildingComplex(col, row, topY);
} else {
// City block (20% chance)
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = topY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
self.update = function () {
// Move background based on player movement to keep player centered
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Find the bounds of current background elements
var minY = Infinity;
var maxY = -Infinity;
var minX = Infinity;
var maxX = -Infinity;
for (var i = 0; i < backgroundElements.length; i++) {
var element = backgroundElements[i];
minY = Math.min(minY, element.y);
maxY = Math.max(maxY, element.y);
minX = Math.min(minX, element.x);
maxX = Math.max(maxX, element.x);
}
// Add new tiles in all directions as needed for endless scrolling
// Add rows above if needed
if (minY > -self.y - 800) {
var newTopY = minY - self.tileHeight;
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
if (elementType < 3) {
element = createRoadSection(col, 0, newTopY);
} else if (elementType < 8) {
element = createBuildingComplex(col, 0, newTopY);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = newTopY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
// Add rows below if needed
if (maxY < -self.y + 3500) {
var newBottomY = maxY + self.tileHeight;
for (var col = 0; col < self.tilesPerRow; col++) {
var element;
var elementType = Math.floor(Math.random() * 10);
if (elementType < 3) {
element = createRoadSection(col, 0, newBottomY);
} else if (elementType < 8) {
element = createBuildingComplex(col, 0, newBottomY);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.x = col * 200;
element.y = newBottomY;
element.alpha = 0.7;
}
self.addChild(element);
backgroundElements.push(element);
}
}
// Add columns left if needed
if (minX > -self.x - 400) {
var newLeftX = minX - 200;
for (var row = 0; row < Math.ceil((maxY - minY) / self.tileHeight) + 2; row++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var yPos = minY + row * self.tileHeight;
if (elementType < 3) {
element = createRoadSection(0, 0, yPos);
} else if (elementType < 8) {
element = createBuildingComplex(0, 0, yPos);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.y = yPos;
element.alpha = 0.7;
}
element.x = newLeftX;
self.addChild(element);
backgroundElements.push(element);
}
}
// Add columns right if needed
if (maxX < -self.x + 2400) {
var newRightX = maxX + 200;
for (var row = 0; row < Math.ceil((maxY - minY) / self.tileHeight) + 2; row++) {
var element;
var elementType = Math.floor(Math.random() * 10);
var yPos = minY + row * self.tileHeight;
if (elementType < 3) {
element = createRoadSection(0, 0, yPos);
} else if (elementType < 8) {
element = createBuildingComplex(0, 0, yPos);
} else {
element = LK.getAsset('cityBlock', {
anchorX: 0,
anchorY: 0
});
element.width = 200;
element.height = 200;
element.y = yPos;
element.alpha = 0.7;
}
element.x = newRightX;
self.addChild(element);
backgroundElements.push(element);
}
}
// Remove elements that are too far away for memory management
for (var i = backgroundElements.length - 1; i >= 0; i--) {
var element = backgroundElements[i];
var distanceFromPlayer = Math.sqrt(Math.pow(element.x + self.x, 2) + Math.pow(element.y + self.y, 2));
if (distanceFromPlayer > 4000) {
element.destroy();
backgroundElements.splice(i, 1);
}
}
};
return self;
});
var Diamond = Container.expand(function () {
var self = Container.call(this);
var diamondGraphics = self.attachAsset('diamond', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.05;
self.update = function () {
diamondGraphics.rotation += self.rotationSpeed;
// Move diamonds based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Diamonds stay static in world - no movement with map
// Remove diamonds that go off screen (player moved away)
if (self.y > 2732 + 100 || self.y < -100 || self.x > 2048 + 100 || self.x < -100) {
self.destroy();
}
};
return self;
});
var DragEffect = Container.expand(function () {
var self = Container.call(this);
self.effectGraphics = self.attachAsset('getawayCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.effectGraphics.alpha = 0.3;
self.effectGraphics.tint = 0x00ffff;
self.effectGraphics.scaleX = 0.6;
self.effectGraphics.scaleY = 0.6;
self.lifetime = 20;
self.age = 0;
self.initialAlpha = 0.5;
self.update = function () {
self.age++;
var fadeRatio = 1 - self.age / self.lifetime;
self.effectGraphics.alpha = self.initialAlpha * fadeRatio;
self.effectGraphics.scaleX = 0.6 * fadeRatio;
self.effectGraphics.scaleY = 0.6 * fadeRatio;
// Move with world
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphics = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 30;
self.age = 0;
self.update = function () {
self.age++;
explosionGraphics.alpha = 1 - self.age / self.lifetime;
explosionGraphics.scaleX = 1 + self.age / self.lifetime;
explosionGraphics.scaleY = 1 + self.age / self.lifetime;
// Move explosions based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
}
// Explosions stay static in world - no movement with map
if (self.age >= self.lifetime) {
self.destroy();
}
};
return self;
});
var GetawayCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('getawayCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 36; // Increased base speed by 3x
self.maxSpeed = 72; // Increased max speed by 3x to be faster than police
self.velocityX = 0;
self.velocityY = 0;
self.acceleration = 2.4; // Increased acceleration by 3x
self.friction = 0.85;
// Drag effect properties
self.dragTrail = [];
self.maxTrailLength = 8;
self.trailFadeSpeed = 0.8;
self.update = function () {
var inputX = 0;
var inputY = 0;
var hasInput = false;
// Apply active button input if available (mobile)
if (activeButton && activeButton.isActive) {
inputX = activeButton.currentX;
inputY = activeButton.currentY;
hasInput = true;
}
// Keyboard input removed - not supported in LK engine
// Apply input to velocity
if (hasInput) {
self.velocityX += inputX * self.acceleration;
self.velocityY += inputY * self.acceleration;
// Rotate car to face movement direction
if (inputX !== 0 || inputY !== 0) {
var angle = Math.atan2(inputY, inputX);
carGraphics.rotation = angle + Math.PI / 2;
}
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Limit velocity
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 drag trail effect
if (speed > 1) {
// Add current position to trail
self.dragTrail.unshift({
x: self.x,
y: self.y,
alpha: 1.0,
scale: 1.0
});
// Limit trail length
if (self.dragTrail.length > self.maxTrailLength) {
self.dragTrail.pop();
}
}
// Update trail particles
for (var i = 0; i < self.dragTrail.length; i++) {
var trail = self.dragTrail[i];
trail.alpha *= self.trailFadeSpeed;
trail.scale *= 0.95;
if (trail.alpha < 0.1) {
self.dragTrail.splice(i, 1);
i--;
}
}
// Keep player car centered - move world instead of car
self.x = 1024; // Always center horizontally
self.y = 1366; // Always center vertically
// Store velocity for world movement
self.worldVelocityX = self.velocityX;
self.worldVelocityY = self.velocityY;
};
return self;
});
var JoystickControl = Container.expand(function () {
var self = Container.call(this);
var joystickBase = self.attachAsset('joystickBase', {
anchorX: 0.5,
anchorY: 0.5
});
var joystickKnob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5
});
joystickBase.alpha = 1.0;
joystickKnob.alpha = 1.0;
joystickBase.tint = 0x7f8c8d; // Light gray for better visibility
joystickKnob.tint = 0xffffff; // White knob for contrast
self.isActive = false;
self.currentX = 0;
self.currentY = 0;
self.maxDistance = 100;
self.down = function (x, y, obj) {
self.isActive = true;
self.updateKnob(x, y);
};
self.move = function (x, y, obj) {
if (self.isActive) {
self.updateKnob(x, y);
}
};
self.up = function (x, y, obj) {
self.isActive = false;
joystickKnob.x = 0;
joystickKnob.y = 0;
self.currentX = 0;
self.currentY = 0;
};
self.updateKnob = function (x, y) {
var deltaX = x;
var deltaY = y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > self.maxDistance) {
deltaX = deltaX / distance * self.maxDistance;
deltaY = deltaY / distance * self.maxDistance;
}
joystickKnob.x = deltaX;
joystickKnob.y = deltaY;
self.currentX = deltaX / self.maxDistance;
self.currentY = deltaY / self.maxDistance;
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('policeCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 24; // Base speed slower than player (3x increase)
self.speed = self.baseSpeed;
self.targetCar = null;
self.lastCollisionCheck = false;
self.velocityX = 0;
self.velocityY = 0;
self.acceleration = 0.6; // Increased acceleration by 3x
self.friction = 0.95;
// Drag effect properties
self.dragTrail = [];
self.maxTrailLength = 6;
self.trailFadeSpeed = 0.75;
self.update = function () {
if (self.targetCar) {
var deltaX = self.targetCar.x - self.x;
var deltaY = self.targetCar.y - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 5) {
// Apply acceleration towards target
self.velocityX += deltaX / distance * self.acceleration;
self.velocityY += deltaY / distance * self.acceleration;
// Rotate car to face movement direction
var angle = Math.atan2(deltaY, deltaX);
carGraphics.rotation = angle + Math.PI / 2;
}
}
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Apply difficulty scaling to speed
var difficultyMultiplier = 1 + milestone * 0.3 + diamondsCollected * 0.02 + policeKills * 0.05;
var currentSpeed = self.baseSpeed * difficultyMultiplier;
// Ensure police are always slower than player max speed (3x increase)
if (currentSpeed > 60) currentSpeed = 60;
// Limit velocity
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > currentSpeed) {
self.velocityX = self.velocityX / speed * currentSpeed;
self.velocityY = self.velocityY / speed * currentSpeed;
}
// Move police car
self.x += self.velocityX;
self.y += self.velocityY;
// Update drag trail effect
var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
if (speed > 0.5) {
// Add current position to trail before world movement
self.dragTrail.unshift({
x: self.x,
y: self.y,
alpha: 0.8,
scale: 0.8
});
// Limit trail length
if (self.dragTrail.length > self.maxTrailLength) {
self.dragTrail.pop();
}
}
// Update trail particles
for (var i = 0; i < self.dragTrail.length; i++) {
var trail = self.dragTrail[i];
trail.alpha *= self.trailFadeSpeed;
trail.scale *= 0.92;
if (trail.alpha < 0.05) {
self.dragTrail.splice(i, 1);
i--;
}
}
// Move police cars based on player movement to keep world consistent
if (player && player.worldVelocityX !== undefined) {
self.x -= player.worldVelocityX;
self.y -= player.worldVelocityY;
// Also move trail positions to keep them consistent with world movement
for (var i = 0; i < self.dragTrail.length; i++) {
self.dragTrail[i].x -= player.worldVelocityX;
self.dragTrail[i].y -= player.worldVelocityY;
}
}
// Police cars stay in world - no map movement
// Remove police cars that go off screen
if (self.y > 2732 + 100 || self.y < -100 || self.x > 2048 + 100 || self.x < -100) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var player;
var policeCars = [];
var diamonds = [];
var explosions = [];
var gameSpeed = 1;
var milestone = 0;
var diamondsCollected = 0;
var policeKills = 0;
var mapSpeed = 36; // Increased by 3x
var mapOffsetY = 0;
var baseMapSpeed = 36; // Increased by 3x
// Background colors for different milestones
var backgroundColors = [0x2c3e50, 0x34495e, 0x1abc9c, 0x16a085, 0x27ae60, 0x2980b9];
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var diamondsTxt = new Text2('Diamonds: 0', {
size: 50,
fill: 0xF1C40F
});
diamondsTxt.anchor.set(0.5, 0);
diamondsTxt.x = 0;
diamondsTxt.y = 80;
LK.gui.top.addChild(diamondsTxt);
var killsTxt = new Text2('Police Crashes: 0', {
size: 50,
fill: 0xE74C3C
});
killsTxt.anchor.set(0.5, 0);
killsTxt.x = 0;
killsTxt.y = 140;
LK.gui.top.addChild(killsTxt);
// Initialize city background
var cityBackground = game.addChild(new CityBackground());
// Initialize joystick control
var joystick = new JoystickControl();
// Create right action button
var rightButton = new JoystickControl();
rightButton.x = 0;
rightButton.y = 0;
// Scale up the button for better visibility
rightButton.scaleX = 1.5;
rightButton.scaleY = 1.5;
LK.gui.center.addChild(rightButton);
rightButton.x = 300; // Move more left from center
rightButton.y = 400; // Move down from center
// Only show right button
rightButton.visible = true;
var activeButton = rightButton;
// Initialize player
player = game.addChild(new GetawayCar());
player.x = 1024; // Center horizontally
player.y = 1366; // Center vertically
// Spawn initial police cars
function spawnPoliceCar() {
var police = new PoliceCar();
// Spawn from screen edges
var edge = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left
var margin = 50;
switch (edge) {
case 0:
// Top edge
police.x = Math.random() * 2048;
police.y = -margin;
break;
case 1:
// Right edge
police.x = 2048 + margin;
police.y = Math.random() * 2732;
break;
case 2:
// Bottom edge
police.x = Math.random() * 2048;
police.y = 2732 + margin;
break;
case 3:
// Left edge
police.x = -margin;
police.y = Math.random() * 2732;
break;
}
police.targetCar = player;
police.baseSpeed = 24; // Set base speed (3x increase)
police.speed = police.baseSpeed;
policeCars.push(police);
game.addChild(police);
}
// Spawn initial diamonds
function spawnDiamond() {
var diamond = new Diamond();
// Spawn diamonds around the current play area
diamond.x = player.x - 500 + Math.random() * 1000;
diamond.y = player.y - 500 + Math.random() * 1000;
// Keep diamonds within reasonable bounds
if (diamond.x < 50) diamond.x = 50;
if (diamond.x > 1998) diamond.x = 1998;
if (diamond.y < 50) diamond.y = 50;
if (diamond.y > 2682) diamond.y = 2682;
diamonds.push(diamond);
game.addChild(diamond);
}
// Initialize game objects
for (var i = 0; i < 3; i++) {
spawnPoliceCar();
}
for (var i = 0; i < 1; i++) {
spawnDiamond();
}
// Joystick controls are now handled by the JoystickControl class
// Desktop keyboard controls (removed - not supported in LK engine)
var keys = {};
// Touch and mouse controls for action buttons
game.down = function (x, y, obj) {
// Check if touch is in right button area
if (rightButton.visible) {
// Touch in right button area
var buttonPos = LK.gui.center.toLocal({
x: x,
y: y
});
buttonPos.x -= 300; // Adjust for right button offset
buttonPos.y -= 400; // Adjust for right button Y offset
var distance = Math.sqrt(buttonPos.x * buttonPos.x + buttonPos.y * buttonPos.y);
if (distance <= rightButton.maxDistance * 1.5) {
activeButton = rightButton;
rightButton.down(buttonPos.x, buttonPos.y, obj);
}
}
};
game.move = function (x, y, obj) {
if (activeButton && activeButton.isActive) {
if (activeButton === rightButton) {
var buttonPos = LK.gui.center.toLocal({
x: x,
y: y
});
buttonPos.x -= 300; // Adjust for right button offset
buttonPos.y -= 400; // Adjust for right button Y offset
rightButton.move(buttonPos.x, buttonPos.y, obj);
}
}
};
game.up = function (x, y, obj) {
if (activeButton && activeButton.isActive) {
activeButton.up(x, y, obj);
}
};
// Update score display
function updateScore() {
var totalScore = diamondsCollected * 100 + policeKills * 500;
LK.setScore(totalScore);
scoreTxt.setText('Score: ' + totalScore);
diamondsTxt.setText('Diamonds: ' + diamondsCollected);
killsTxt.setText('Police Crashes: ' + policeKills);
}
// Check milestone progression
function checkMilestone() {
var newMilestone = Math.floor(LK.getScore() / 1000);
if (newMilestone > milestone) {
milestone = newMilestone;
// Change background color
if (milestone < backgroundColors.length) {
tween(game, {
backgroundColor: backgroundColors[milestone]
}, {
duration: 2000
});
}
// Spawn additional police car
spawnPoliceCar();
}
}
// Create explosion effect
function createExplosion(x, y) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
explosions.push(explosion);
game.addChild(explosion);
// Make explosion more dramatic with tween animations
// Scale explosion from small to large
tween(explosion, {
scaleX: 3,
scaleY: 3
}, {
duration: 300,
easing: tween.easeOut
});
// Fade out with pulsing effect
tween(explosion, {
alpha: 0
}, {
duration: 600,
easing: tween.easeInOut
});
// Add rotation for more dynamic effect
tween(explosion, {
rotation: Math.PI * 2
}, {
duration: 400,
easing: tween.linear
});
// Add color tint animation to explosion for more visual impact
tween(explosion, {
tint: 0xff4500
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(explosion, {
tint: 0xffffff
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
// Main game loop
game.update = function () {
// Render drag effects for player car
if (player && player.dragTrail) {
for (var i = 0; i < player.dragTrail.length; i++) {
var trail = player.dragTrail[i];
if (trail.alpha > 0.1) {
var dragEffect = new DragEffect();
dragEffect.x = trail.x;
dragEffect.y = trail.y;
dragEffect.effectGraphics.alpha = trail.alpha * 0.4;
dragEffect.effectGraphics.scaleX = trail.scale * 0.7;
dragEffect.effectGraphics.scaleY = trail.scale * 0.7;
dragEffect.effectGraphics.tint = 0x6f869c;
dragEffect.lifetime = 15;
game.addChild(dragEffect);
}
}
}
// Render drag effects for police cars
for (var p = 0; p < policeCars.length; p++) {
var policeCar = policeCars[p];
if (policeCar.dragTrail) {
for (var i = 0; i < policeCar.dragTrail.length; i++) {
var trail = policeCar.dragTrail[i];
if (trail.alpha > 0.05) {
var dragEffect = new DragEffect();
dragEffect.x = trail.x;
dragEffect.y = trail.y;
dragEffect.effectGraphics.alpha = trail.alpha * 0.3;
dragEffect.effectGraphics.scaleX = trail.scale * 0.6;
dragEffect.effectGraphics.scaleY = trail.scale * 0.6;
dragEffect.effectGraphics.tint = 0x8e44ad;
dragEffect.lifetime = 12;
game.addChild(dragEffect);
}
}
}
}
// Check diamond collection
for (var i = diamonds.length - 1; i >= 0; i--) {
var diamond = diamonds[i];
if (!diamond.collected && player.intersects(diamond)) {
diamond.collected = true;
diamondsCollected++;
LK.getSound('collectDiamond').play();
diamond.destroy();
diamonds.splice(i, 1);
// Spawn new diamond
spawnDiamond();
}
}
// Check police car collisions with player
for (var i = 0; i < policeCars.length; i++) {
var police = policeCars[i];
if (player.intersects(police)) {
LK.getSound('gameOver').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Check police car collisions with each other
for (var i = policeCars.length - 1; i >= 0; i--) {
var police1 = policeCars[i];
var collided = false;
for (var j = i + 1; j < policeCars.length; j++) {
var police2 = policeCars[j];
if (police1.intersects(police2)) {
// Create explosion
var explosionX = (police1.x + police2.x) / 2;
var explosionY = (police1.y + police2.y) / 2;
createExplosion(explosionX, explosionY);
policeKills++;
LK.getSound('policeExplode').play();
// Increase map speed by 1%
mapSpeed = mapSpeed * 1.01;
// Remove both police cars
police1.destroy();
police2.destroy();
policeCars.splice(j, 1);
policeCars.splice(i, 1);
collided = true;
break;
}
}
if (collided) break;
}
// Clean up police cars that went off screen
for (var i = policeCars.length - 1; i >= 0; i--) {
var police = policeCars[i];
if (police.y > 2732 + 100) {
police.destroy();
policeCars.splice(i, 1);
}
}
// Clean up diamonds that went off screen
for (var i = diamonds.length - 1; i >= 0; i--) {
var diamond = diamonds[i];
if (diamond.y > 2732 + 100) {
diamond.destroy();
diamonds.splice(i, 1);
// Spawn new diamond
spawnDiamond();
}
}
// Clean up explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
if (explosion.age >= explosion.lifetime) {
explosions.splice(i, 1);
}
}
// Spawn new police cars periodically - increased frequency
if (LK.ticks % (120 - milestone * 15) === 0) {
spawnPoliceCar();
}
// Spawn new diamonds periodically
if (LK.ticks % 500 === 0) {
spawnDiamond();
}
// Map speed logic removed - car moves instead of map
// Update score and check milestones
updateScore();
checkMilestone();
// Win condition
if (LK.getScore() >= 10000) {
LK.showYouWin();
}
};