/****
* 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();
}
};