/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('roadLane', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphics.scaleX = 0.2;
bulletGraphics.scaleY = 0.3;
bulletGraphics.tint = 0xffff00;
self.speed = 15;
self.update = function () {
self.y -= self.speed;
};
return self;
});
var EnemyVehicle = Container.expand(function (vehicleType) {
var self = Container.call(this);
var assetId = vehicleType || 'enemyCar';
var vehicleGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.vehicleType = vehicleType;
self.speed = 8 + Math.random() * 4; // Random speed between 8-12
self.hasTriggeredNearMiss = false;
// Set health based on vehicle type
if (vehicleType === 'motorcycle') {
self.health = 1;
} else if (vehicleType === 'truck') {
self.health = 5;
} else {
self.health = 2; // enemyCar default
}
self.maxHealth = self.health;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = self.x;
self.laneWidth = 340;
self.lanes = [-510, -170, 170, 510]; // 4 lanes positioned across screen - same as enemy vehicles
self.update = function () {
// Smooth movement towards target position
var diff = self.targetX - self.x;
self.x += diff * 0.3; // Increased responsiveness
};
self.moveTo = function (targetX) {
// Find closest lane (adjusted for screen center offset like enemy vehicles)
var closestLane = 1024 + self.lanes[0];
var minDistance = Math.abs(targetX - closestLane);
for (var i = 1; i < self.lanes.length; i++) {
var adjustedLane = 1024 + self.lanes[i];
var distance = Math.abs(targetX - adjustedLane);
if (distance < minDistance) {
minDistance = distance;
closestLane = adjustedLane;
}
}
self.targetX = closestLane;
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var policeGraphics = self.attachAsset('policeCar', {
anchorX: 0.5,
anchorY: 0.5
});
policeGraphics.tint = 0x0066ff; // Blue tint for police car
self.speed = 6;
self.hasPlayedSiren = false;
self.update = function () {
self.y += self.speed;
// Play siren sound once when police car appears
if (!self.hasPlayedSiren && self.y > -100) {
LK.getSound('siren').play();
self.hasPlayedSiren = true;
}
// Clear enemy vehicles in front of police car
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy = enemyVehicles[i];
var horizontalDistance = Math.abs(enemy.x - self.x);
var verticalDistance = enemy.y - self.y;
// If enemy is in front of police car and in same lane
if (horizontalDistance < 100 && verticalDistance > -200 && verticalDistance < 400) {
// Create explosion effect for cleared enemy
tween(enemy, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x0066ff,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Remove enemy immediately
enemy.destroy();
enemyVehicles.splice(i, 1);
}
}
};
return self;
});
var RoadLane = Container.expand(function () {
var self = Container.call(this);
var laneGraphics = self.attachAsset('roadLane', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.update = function () {
self.y += self.speed;
// Reset position when off screen
if (self.y > 2732 + 100) {
self.y = -100;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var playerCar;
var enemyVehicles = [];
var roadLanes = [];
var bullets = [];
var gameSpeed = 1;
var distanceScore = 0;
var nearMissBonus = 0;
var spawnTimer = 0;
var speedIncreaseTimer = 0;
var dragStartX = 0;
var isDragging = false;
var playerHealth = 5;
var shootTimer = 0;
var leftButtonCooldown = false;
var rightButtonCooldown = false;
var leftButtonPressCount = 0;
var rightButtonPressCount = 0;
var policeCars = [];
var policeSpawnTimer = 0;
var policeSpawnCooldown = 0;
function spawnPoliceCar() {
// Only spawn if no police cars are currently active and cooldown is over
if (policeCars.length === 0 && policeSpawnCooldown <= 0) {
var lanes = [-510, -170, 170, 510];
var selectedLane = lanes[Math.floor(Math.random() * lanes.length)];
var policeCar = new PoliceCar();
policeCar.x = 1024 + selectedLane;
policeCar.y = -200;
policeCar.speed = (6 + Math.random() * 2) * gameSpeed;
policeCars.push(policeCar);
game.addChild(policeCar);
// Set cooldown before next police car can spawn (30-60 seconds)
policeSpawnCooldown = 1800 + Math.random() * 1800;
}
}
// Create road lanes
for (var i = 0; i < 3; i++) {
var lane1 = new RoadLane();
lane1.x = -85;
lane1.y = i * 300 - 200;
roadLanes.push(lane1);
game.addChild(lane1);
var lane2 = new RoadLane();
lane2.x = 85;
lane2.y = i * 300 - 200;
roadLanes.push(lane2);
game.addChild(lane2);
var lane3 = new RoadLane();
lane3.x = 255;
lane3.y = i * 300 - 200;
roadLanes.push(lane3);
game.addChild(lane3);
}
// Create player car
playerCar = new PlayerCar();
playerCar.x = 1024 + 170; // Start in third lane (same lane system as enemies)
playerCar.y = 2200; // Near bottom of screen
playerCar.targetX = playerCar.x;
game.addChild(playerCar);
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create speed display
var speedTxt = new Text2('Speed: 1x', {
size: 60,
fill: 0xFFFFFF
});
speedTxt.anchor.set(1, 0);
speedTxt.y = 100;
LK.gui.topRight.addChild(speedTxt);
// Create health display
var healthTxt = new Text2('Health: ❤❤❤❤❤', {
size: 60,
fill: 0xff0000
});
healthTxt.anchor.set(0, 0);
healthTxt.y = 100;
LK.gui.topLeft.addChild(healthTxt);
// Create left shoot button
var leftShootButton = new Text2('🔫', {
size: 130,
fill: 0xffff00
});
leftShootButton.anchor.set(0, 1);
leftShootButton.x = 50;
leftShootButton.y = -50;
LK.gui.bottomLeft.addChild(leftShootButton);
// Create right shoot button
var rightShootButton = new Text2('🔫', {
size: 130,
fill: 0xffff00
});
rightShootButton.anchor.set(1, 1);
rightShootButton.x = -50;
rightShootButton.y = -50;
LK.gui.bottomRight.addChild(rightShootButton);
function spawnEnemyVehicle() {
var vehicleTypes = ['enemyCar', 'truck', 'motorcycle'];
var lanes = [-510, -170, 170, 510];
// Spawn 1-3 vehicles at once with higher probability of multiple spawns
var numVehicles = Math.random() < 0.7 ? Math.random() < 0.4 ? 3 : 2 : 1;
var usedLanes = [];
for (var v = 0; v < numVehicles; v++) {
var randomType = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var enemy = new EnemyVehicle(randomType);
// Select random lane that hasn't been used
var availableLanes = lanes.filter(function (lane) {
return usedLanes.indexOf(lane) === -1;
});
if (availableLanes.length > 0) {
var selectedLane = availableLanes[Math.floor(Math.random() * availableLanes.length)];
usedLanes.push(selectedLane);
enemy.x = 1024 + selectedLane;
enemy.y = -200 - v * 150; // Stagger spawn positions slightly
// Adjust speed based on game speed with more variation
enemy.speed = (8 + Math.random() * 6) * gameSpeed;
enemyVehicles.push(enemy);
game.addChild(enemy);
}
}
}
function checkCollisions() {
// Check enemy-to-enemy collisions first
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy1 = enemyVehicles[i];
for (var j = i - 1; j >= 0; j--) {
var enemy2 = enemyVehicles[j];
if (enemy1.intersects(enemy2)) {
// Create explosion effect
tween(enemy1, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(enemy2, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Damage nearby vehicles
for (var k = enemyVehicles.length - 1; k >= 0; k--) {
var nearbyEnemy = enemyVehicles[k];
if (nearbyEnemy !== enemy1 && nearbyEnemy !== enemy2) {
var distance1 = Math.sqrt(Math.pow(nearbyEnemy.x - enemy1.x, 2) + Math.pow(nearbyEnemy.y - enemy1.y, 2));
var distance2 = Math.sqrt(Math.pow(nearbyEnemy.x - enemy2.x, 2) + Math.pow(nearbyEnemy.y - enemy2.y, 2));
if (distance1 < 200 || distance2 < 200) {
tween(nearbyEnemy, {
tint: 0xff8888
}, {
duration: 200,
onFinish: function onFinish() {
tween(nearbyEnemy, {
tint: 0xffffff
}, {
duration: 200
});
}
});
nearbyEnemy.speed *= 0.7; // Slow down damaged vehicle
}
}
}
LK.getSound('crash').play();
LK.effects.flashObject(enemy1, 0xff0000, 300);
LK.effects.flashObject(enemy2, 0xff0000, 300);
// Remove collided vehicles after animation
LK.setTimeout(function () {
enemy1.destroy();
enemy2.destroy();
var index1 = enemyVehicles.indexOf(enemy1);
var index2 = enemyVehicles.indexOf(enemy2);
if (index1 !== -1) {
enemyVehicles.splice(index1, 1);
}
if (index2 !== -1) {
var newIndex2 = enemyVehicles.indexOf(enemy2);
if (newIndex2 !== -1) {
enemyVehicles.splice(newIndex2, 1);
}
}
}, 300);
return;
}
}
}
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy = enemyVehicles[i];
// Check collision with player
if (playerCar.intersects(enemy)) {
playerHealth--;
updateHealthDisplay();
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 500);
// Remove enemy that hit player
enemy.destroy();
enemyVehicles.splice(i, 1);
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
// Check for near miss bonus
var distance = Math.abs(enemy.x - playerCar.x);
var verticalDistance = Math.abs(enemy.y - playerCar.y);
if (!enemy.hasTriggeredNearMiss && distance < 150 && verticalDistance < 200 && enemy.y > playerCar.y - 100) {
enemy.hasTriggeredNearMiss = true;
nearMissBonus += 10;
LK.getSound('nearMiss').play();
// Flash effect for near miss
tween(enemy, {
tint: 0xffff00
}, {
duration: 200,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xffffff
}, {
duration: 200
});
}
});
}
// Remove off-screen enemies
if (enemy.y > 2732 + 200) {
enemy.destroy();
enemyVehicles.splice(i, 1);
}
}
}
function updateScore() {
distanceScore += 1;
var totalScore = distanceScore + nearMissBonus;
LK.setScore(totalScore);
scoreTxt.setText('Score: ' + totalScore);
}
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < playerHealth; i++) {
hearts += '❤';
}
for (var i = playerHealth; i < 5; i++) {
hearts += '🤍';
}
healthTxt.setText('Health: ' + hearts);
}
function increaseGameSpeed() {
gameSpeed += 0.002;
if (gameSpeed > 3) {
gameSpeed = 3;
}
speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x');
// Update road lane speeds
for (var i = 0; i < roadLanes.length; i++) {
roadLanes[i].speed = 12 * gameSpeed;
}
}
function fireWeapon(buttonSide) {
// Check if the specific button is on cooldown (only applies after 10 presses)
if (buttonSide === 'left' && leftButtonPressCount >= 10 && leftButtonCooldown || buttonSide === 'right' && rightButtonPressCount >= 10 && rightButtonCooldown) {
return; // Don't fire if on cooldown
}
// Increment press counter
if (buttonSide === 'left') {
leftButtonPressCount++;
} else if (buttonSide === 'right') {
rightButtonPressCount++;
}
// Fire left bullet
var bulletLeft = new Bullet();
bulletLeft.x = playerCar.x - 30; // Offset to the left
bulletLeft.y = playerCar.y - 100;
bullets.push(bulletLeft);
game.addChild(bulletLeft);
// Fire right bullet
var bulletRight = new Bullet();
bulletRight.x = playerCar.x + 30; // Offset to the right
bulletRight.y = playerCar.y - 100;
bullets.push(bulletRight);
game.addChild(bulletRight);
// Set cooldown for the pressed button (only after 10 presses)
if (buttonSide === 'left' && leftButtonPressCount >= 10) {
leftButtonCooldown = true;
// Reset cooldown after 1 second and restart the cycle
LK.setTimeout(function () {
leftButtonCooldown = false;
leftButtonPressCount = 0; // Reset counter to restart the cycle
}, 1000);
} else if (buttonSide === 'right' && rightButtonPressCount >= 10) {
rightButtonCooldown = true;
// Reset cooldown after 1 second and restart the cycle
LK.setTimeout(function () {
rightButtonCooldown = false;
rightButtonPressCount = 0; // Reset counter to restart the cycle
}, 1000);
}
}
// Add left shoot button event handler
leftShootButton.down = function (x, y, obj) {
fireWeapon('left');
// Visual feedback for button press
tween(leftShootButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
tween(leftShootButton, {
scaleX: 1,
scaleY: 1,
tint: leftButtonPressCount >= 10 && leftButtonCooldown ? 0x888888 : 0xffff00
}, {
duration: 100
});
}
});
};
// Add right shoot button event handler
rightShootButton.down = function (x, y, obj) {
fireWeapon('right');
// Visual feedback for button press
tween(rightShootButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
tween(rightShootButton, {
scaleX: 1,
scaleY: 1,
tint: rightButtonPressCount >= 10 && rightButtonCooldown ? 0x888888 : 0xffff00
}, {
duration: 100
});
}
});
};
// Touch controls
game.down = function (x, y, obj) {
isDragging = true;
dragStartX = x;
// Remove automatic weapon firing from general touch
// Fixed distance movement per tap
var moveDistance = 340; // Distance to move per tap (one lane width)
var currentX = playerCar.x;
var newTargetX;
// Determine direction based on touch position relative to car
if (x < currentX) {
// Tap on left side - move left
newTargetX = currentX - moveDistance;
} else {
// Tap on right side - move right
newTargetX = currentX + moveDistance;
}
// Clamp to lane boundaries (same as enemy vehicles)
if (newTargetX < 1024 + -510) {
newTargetX = 1024 + -510;
} // Left boundary for leftmost lane
if (newTargetX > 1024 + 510) {
newTargetX = 1024 + 510;
} // Right boundary for rightmost lane
playerCar.moveTo(newTargetX);
// Force immediate movement
playerCar.targetX = newTargetX;
};
game.move = function (x, y, obj) {
// Remove continuous movement - car should only move once per touch
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Spawn enemy vehicles
spawnTimer++;
var spawnRate = Math.max(30 - gameSpeed * 3, 20);
if (spawnTimer >= spawnRate) {
spawnEnemyVehicle();
spawnTimer = 0;
}
// Increase game speed over time
speedIncreaseTimer++;
if (speedIncreaseTimer >= 60) {
// Every second
increaseGameSpeed();
speedIncreaseTimer = 0;
}
// Bullet shooting is now manual - controlled by touch/tap
// Update bullets and check bullet collisions
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
// Remove off-screen bullets - increased range
if (bullet.y < -500) {
bullet.destroy();
bullets.splice(b, 1);
continue;
}
// Check bullet collision with enemies
for (var e = enemyVehicles.length - 1; e >= 0; e--) {
var enemy = enemyVehicles[e];
if (bullet.intersects(enemy)) {
// Damage enemy
enemy.health--;
// Visual damage feedback
tween(enemy, {
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
if (enemy.health > 0) {
tween(enemy, {
tint: 0xffffff
}, {
duration: 100
});
}
}
});
// Remove bullet
bullet.destroy();
bullets.splice(b, 1);
// Check if enemy is destroyed
if (enemy.health <= 0) {
// Create explosion with area damage
tween(enemy, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
// Area damage to nearby vehicles
for (var k = enemyVehicles.length - 1; k >= 0; k--) {
var nearbyEnemy = enemyVehicles[k];
if (nearbyEnemy !== enemy) {
var distance = Math.sqrt(Math.pow(nearbyEnemy.x - enemy.x, 2) + Math.pow(nearbyEnemy.y - enemy.y, 2));
if (distance < 250) {
nearbyEnemy.health--;
tween(nearbyEnemy, {
tint: 0xff6666
}, {
duration: 150,
onFinish: function onFinish() {
if (nearbyEnemy.health > 0) {
tween(nearbyEnemy, {
tint: 0xffffff
}, {
duration: 150
});
}
}
});
nearbyEnemy.speed *= 0.8;
}
}
}
// Player takes damage if too close
var playerDistance = Math.sqrt(Math.pow(playerCar.x - enemy.x, 2) + Math.pow(playerCar.y - enemy.y, 2));
if (playerDistance < 300) {
playerHealth--;
updateHealthDisplay();
LK.effects.flashScreen(0xff0000, 200);
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
LK.getSound('crash').play();
// Remove destroyed enemy after animation
LK.setTimeout(function () {
enemy.destroy();
var index = enemyVehicles.indexOf(enemy);
if (index !== -1) {
enemyVehicles.splice(index, 1);
}
}, 400);
}
break;
}
}
}
// Police car spawning logic
policeSpawnTimer++;
if (policeSpawnCooldown > 0) {
policeSpawnCooldown--;
}
// Random chance to spawn police car (every 5-10 seconds when available)
if (policeSpawnTimer >= 300 + Math.random() * 300) {
if (Math.random() < 0.3) {
// 30% chance when timer is ready
spawnPoliceCar();
}
policeSpawnTimer = 0;
}
// Update and manage police cars
for (var p = policeCars.length - 1; p >= 0; p--) {
var policeCar = policeCars[p];
// Remove off-screen police cars
if (policeCar.y > 2732 + 200) {
policeCar.destroy();
policeCars.splice(p, 1);
}
}
// Update score
updateScore();
// Check collisions
checkCollisions();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('roadLane', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphics.scaleX = 0.2;
bulletGraphics.scaleY = 0.3;
bulletGraphics.tint = 0xffff00;
self.speed = 15;
self.update = function () {
self.y -= self.speed;
};
return self;
});
var EnemyVehicle = Container.expand(function (vehicleType) {
var self = Container.call(this);
var assetId = vehicleType || 'enemyCar';
var vehicleGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.vehicleType = vehicleType;
self.speed = 8 + Math.random() * 4; // Random speed between 8-12
self.hasTriggeredNearMiss = false;
// Set health based on vehicle type
if (vehicleType === 'motorcycle') {
self.health = 1;
} else if (vehicleType === 'truck') {
self.health = 5;
} else {
self.health = 2; // enemyCar default
}
self.maxHealth = self.health;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetX = self.x;
self.laneWidth = 340;
self.lanes = [-510, -170, 170, 510]; // 4 lanes positioned across screen - same as enemy vehicles
self.update = function () {
// Smooth movement towards target position
var diff = self.targetX - self.x;
self.x += diff * 0.3; // Increased responsiveness
};
self.moveTo = function (targetX) {
// Find closest lane (adjusted for screen center offset like enemy vehicles)
var closestLane = 1024 + self.lanes[0];
var minDistance = Math.abs(targetX - closestLane);
for (var i = 1; i < self.lanes.length; i++) {
var adjustedLane = 1024 + self.lanes[i];
var distance = Math.abs(targetX - adjustedLane);
if (distance < minDistance) {
minDistance = distance;
closestLane = adjustedLane;
}
}
self.targetX = closestLane;
};
return self;
});
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
var policeGraphics = self.attachAsset('policeCar', {
anchorX: 0.5,
anchorY: 0.5
});
policeGraphics.tint = 0x0066ff; // Blue tint for police car
self.speed = 6;
self.hasPlayedSiren = false;
self.update = function () {
self.y += self.speed;
// Play siren sound once when police car appears
if (!self.hasPlayedSiren && self.y > -100) {
LK.getSound('siren').play();
self.hasPlayedSiren = true;
}
// Clear enemy vehicles in front of police car
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy = enemyVehicles[i];
var horizontalDistance = Math.abs(enemy.x - self.x);
var verticalDistance = enemy.y - self.y;
// If enemy is in front of police car and in same lane
if (horizontalDistance < 100 && verticalDistance > -200 && verticalDistance < 400) {
// Create explosion effect for cleared enemy
tween(enemy, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0x0066ff,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Remove enemy immediately
enemy.destroy();
enemyVehicles.splice(i, 1);
}
}
};
return self;
});
var RoadLane = Container.expand(function () {
var self = Container.call(this);
var laneGraphics = self.attachAsset('roadLane', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.update = function () {
self.y += self.speed;
// Reset position when off screen
if (self.y > 2732 + 100) {
self.y = -100;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var playerCar;
var enemyVehicles = [];
var roadLanes = [];
var bullets = [];
var gameSpeed = 1;
var distanceScore = 0;
var nearMissBonus = 0;
var spawnTimer = 0;
var speedIncreaseTimer = 0;
var dragStartX = 0;
var isDragging = false;
var playerHealth = 5;
var shootTimer = 0;
var leftButtonCooldown = false;
var rightButtonCooldown = false;
var leftButtonPressCount = 0;
var rightButtonPressCount = 0;
var policeCars = [];
var policeSpawnTimer = 0;
var policeSpawnCooldown = 0;
function spawnPoliceCar() {
// Only spawn if no police cars are currently active and cooldown is over
if (policeCars.length === 0 && policeSpawnCooldown <= 0) {
var lanes = [-510, -170, 170, 510];
var selectedLane = lanes[Math.floor(Math.random() * lanes.length)];
var policeCar = new PoliceCar();
policeCar.x = 1024 + selectedLane;
policeCar.y = -200;
policeCar.speed = (6 + Math.random() * 2) * gameSpeed;
policeCars.push(policeCar);
game.addChild(policeCar);
// Set cooldown before next police car can spawn (30-60 seconds)
policeSpawnCooldown = 1800 + Math.random() * 1800;
}
}
// Create road lanes
for (var i = 0; i < 3; i++) {
var lane1 = new RoadLane();
lane1.x = -85;
lane1.y = i * 300 - 200;
roadLanes.push(lane1);
game.addChild(lane1);
var lane2 = new RoadLane();
lane2.x = 85;
lane2.y = i * 300 - 200;
roadLanes.push(lane2);
game.addChild(lane2);
var lane3 = new RoadLane();
lane3.x = 255;
lane3.y = i * 300 - 200;
roadLanes.push(lane3);
game.addChild(lane3);
}
// Create player car
playerCar = new PlayerCar();
playerCar.x = 1024 + 170; // Start in third lane (same lane system as enemies)
playerCar.y = 2200; // Near bottom of screen
playerCar.targetX = playerCar.x;
game.addChild(playerCar);
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create speed display
var speedTxt = new Text2('Speed: 1x', {
size: 60,
fill: 0xFFFFFF
});
speedTxt.anchor.set(1, 0);
speedTxt.y = 100;
LK.gui.topRight.addChild(speedTxt);
// Create health display
var healthTxt = new Text2('Health: ❤❤❤❤❤', {
size: 60,
fill: 0xff0000
});
healthTxt.anchor.set(0, 0);
healthTxt.y = 100;
LK.gui.topLeft.addChild(healthTxt);
// Create left shoot button
var leftShootButton = new Text2('🔫', {
size: 130,
fill: 0xffff00
});
leftShootButton.anchor.set(0, 1);
leftShootButton.x = 50;
leftShootButton.y = -50;
LK.gui.bottomLeft.addChild(leftShootButton);
// Create right shoot button
var rightShootButton = new Text2('🔫', {
size: 130,
fill: 0xffff00
});
rightShootButton.anchor.set(1, 1);
rightShootButton.x = -50;
rightShootButton.y = -50;
LK.gui.bottomRight.addChild(rightShootButton);
function spawnEnemyVehicle() {
var vehicleTypes = ['enemyCar', 'truck', 'motorcycle'];
var lanes = [-510, -170, 170, 510];
// Spawn 1-3 vehicles at once with higher probability of multiple spawns
var numVehicles = Math.random() < 0.7 ? Math.random() < 0.4 ? 3 : 2 : 1;
var usedLanes = [];
for (var v = 0; v < numVehicles; v++) {
var randomType = vehicleTypes[Math.floor(Math.random() * vehicleTypes.length)];
var enemy = new EnemyVehicle(randomType);
// Select random lane that hasn't been used
var availableLanes = lanes.filter(function (lane) {
return usedLanes.indexOf(lane) === -1;
});
if (availableLanes.length > 0) {
var selectedLane = availableLanes[Math.floor(Math.random() * availableLanes.length)];
usedLanes.push(selectedLane);
enemy.x = 1024 + selectedLane;
enemy.y = -200 - v * 150; // Stagger spawn positions slightly
// Adjust speed based on game speed with more variation
enemy.speed = (8 + Math.random() * 6) * gameSpeed;
enemyVehicles.push(enemy);
game.addChild(enemy);
}
}
}
function checkCollisions() {
// Check enemy-to-enemy collisions first
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy1 = enemyVehicles[i];
for (var j = i - 1; j >= 0; j--) {
var enemy2 = enemyVehicles[j];
if (enemy1.intersects(enemy2)) {
// Create explosion effect
tween(enemy1, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
tween(enemy2, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Damage nearby vehicles
for (var k = enemyVehicles.length - 1; k >= 0; k--) {
var nearbyEnemy = enemyVehicles[k];
if (nearbyEnemy !== enemy1 && nearbyEnemy !== enemy2) {
var distance1 = Math.sqrt(Math.pow(nearbyEnemy.x - enemy1.x, 2) + Math.pow(nearbyEnemy.y - enemy1.y, 2));
var distance2 = Math.sqrt(Math.pow(nearbyEnemy.x - enemy2.x, 2) + Math.pow(nearbyEnemy.y - enemy2.y, 2));
if (distance1 < 200 || distance2 < 200) {
tween(nearbyEnemy, {
tint: 0xff8888
}, {
duration: 200,
onFinish: function onFinish() {
tween(nearbyEnemy, {
tint: 0xffffff
}, {
duration: 200
});
}
});
nearbyEnemy.speed *= 0.7; // Slow down damaged vehicle
}
}
}
LK.getSound('crash').play();
LK.effects.flashObject(enemy1, 0xff0000, 300);
LK.effects.flashObject(enemy2, 0xff0000, 300);
// Remove collided vehicles after animation
LK.setTimeout(function () {
enemy1.destroy();
enemy2.destroy();
var index1 = enemyVehicles.indexOf(enemy1);
var index2 = enemyVehicles.indexOf(enemy2);
if (index1 !== -1) {
enemyVehicles.splice(index1, 1);
}
if (index2 !== -1) {
var newIndex2 = enemyVehicles.indexOf(enemy2);
if (newIndex2 !== -1) {
enemyVehicles.splice(newIndex2, 1);
}
}
}, 300);
return;
}
}
}
for (var i = enemyVehicles.length - 1; i >= 0; i--) {
var enemy = enemyVehicles[i];
// Check collision with player
if (playerCar.intersects(enemy)) {
playerHealth--;
updateHealthDisplay();
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 500);
// Remove enemy that hit player
enemy.destroy();
enemyVehicles.splice(i, 1);
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
// Check for near miss bonus
var distance = Math.abs(enemy.x - playerCar.x);
var verticalDistance = Math.abs(enemy.y - playerCar.y);
if (!enemy.hasTriggeredNearMiss && distance < 150 && verticalDistance < 200 && enemy.y > playerCar.y - 100) {
enemy.hasTriggeredNearMiss = true;
nearMissBonus += 10;
LK.getSound('nearMiss').play();
// Flash effect for near miss
tween(enemy, {
tint: 0xffff00
}, {
duration: 200,
onFinish: function onFinish() {
tween(enemy, {
tint: 0xffffff
}, {
duration: 200
});
}
});
}
// Remove off-screen enemies
if (enemy.y > 2732 + 200) {
enemy.destroy();
enemyVehicles.splice(i, 1);
}
}
}
function updateScore() {
distanceScore += 1;
var totalScore = distanceScore + nearMissBonus;
LK.setScore(totalScore);
scoreTxt.setText('Score: ' + totalScore);
}
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < playerHealth; i++) {
hearts += '❤';
}
for (var i = playerHealth; i < 5; i++) {
hearts += '🤍';
}
healthTxt.setText('Health: ' + hearts);
}
function increaseGameSpeed() {
gameSpeed += 0.002;
if (gameSpeed > 3) {
gameSpeed = 3;
}
speedTxt.setText('Speed: ' + gameSpeed.toFixed(1) + 'x');
// Update road lane speeds
for (var i = 0; i < roadLanes.length; i++) {
roadLanes[i].speed = 12 * gameSpeed;
}
}
function fireWeapon(buttonSide) {
// Check if the specific button is on cooldown (only applies after 10 presses)
if (buttonSide === 'left' && leftButtonPressCount >= 10 && leftButtonCooldown || buttonSide === 'right' && rightButtonPressCount >= 10 && rightButtonCooldown) {
return; // Don't fire if on cooldown
}
// Increment press counter
if (buttonSide === 'left') {
leftButtonPressCount++;
} else if (buttonSide === 'right') {
rightButtonPressCount++;
}
// Fire left bullet
var bulletLeft = new Bullet();
bulletLeft.x = playerCar.x - 30; // Offset to the left
bulletLeft.y = playerCar.y - 100;
bullets.push(bulletLeft);
game.addChild(bulletLeft);
// Fire right bullet
var bulletRight = new Bullet();
bulletRight.x = playerCar.x + 30; // Offset to the right
bulletRight.y = playerCar.y - 100;
bullets.push(bulletRight);
game.addChild(bulletRight);
// Set cooldown for the pressed button (only after 10 presses)
if (buttonSide === 'left' && leftButtonPressCount >= 10) {
leftButtonCooldown = true;
// Reset cooldown after 1 second and restart the cycle
LK.setTimeout(function () {
leftButtonCooldown = false;
leftButtonPressCount = 0; // Reset counter to restart the cycle
}, 1000);
} else if (buttonSide === 'right' && rightButtonPressCount >= 10) {
rightButtonCooldown = true;
// Reset cooldown after 1 second and restart the cycle
LK.setTimeout(function () {
rightButtonCooldown = false;
rightButtonPressCount = 0; // Reset counter to restart the cycle
}, 1000);
}
}
// Add left shoot button event handler
leftShootButton.down = function (x, y, obj) {
fireWeapon('left');
// Visual feedback for button press
tween(leftShootButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
tween(leftShootButton, {
scaleX: 1,
scaleY: 1,
tint: leftButtonPressCount >= 10 && leftButtonCooldown ? 0x888888 : 0xffff00
}, {
duration: 100
});
}
});
};
// Add right shoot button event handler
rightShootButton.down = function (x, y, obj) {
fireWeapon('right');
// Visual feedback for button press
tween(rightShootButton, {
scaleX: 1.2,
scaleY: 1.2,
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
tween(rightShootButton, {
scaleX: 1,
scaleY: 1,
tint: rightButtonPressCount >= 10 && rightButtonCooldown ? 0x888888 : 0xffff00
}, {
duration: 100
});
}
});
};
// Touch controls
game.down = function (x, y, obj) {
isDragging = true;
dragStartX = x;
// Remove automatic weapon firing from general touch
// Fixed distance movement per tap
var moveDistance = 340; // Distance to move per tap (one lane width)
var currentX = playerCar.x;
var newTargetX;
// Determine direction based on touch position relative to car
if (x < currentX) {
// Tap on left side - move left
newTargetX = currentX - moveDistance;
} else {
// Tap on right side - move right
newTargetX = currentX + moveDistance;
}
// Clamp to lane boundaries (same as enemy vehicles)
if (newTargetX < 1024 + -510) {
newTargetX = 1024 + -510;
} // Left boundary for leftmost lane
if (newTargetX > 1024 + 510) {
newTargetX = 1024 + 510;
} // Right boundary for rightmost lane
playerCar.moveTo(newTargetX);
// Force immediate movement
playerCar.targetX = newTargetX;
};
game.move = function (x, y, obj) {
// Remove continuous movement - car should only move once per touch
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game loop
game.update = function () {
// Spawn enemy vehicles
spawnTimer++;
var spawnRate = Math.max(30 - gameSpeed * 3, 20);
if (spawnTimer >= spawnRate) {
spawnEnemyVehicle();
spawnTimer = 0;
}
// Increase game speed over time
speedIncreaseTimer++;
if (speedIncreaseTimer >= 60) {
// Every second
increaseGameSpeed();
speedIncreaseTimer = 0;
}
// Bullet shooting is now manual - controlled by touch/tap
// Update bullets and check bullet collisions
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
// Remove off-screen bullets - increased range
if (bullet.y < -500) {
bullet.destroy();
bullets.splice(b, 1);
continue;
}
// Check bullet collision with enemies
for (var e = enemyVehicles.length - 1; e >= 0; e--) {
var enemy = enemyVehicles[e];
if (bullet.intersects(enemy)) {
// Damage enemy
enemy.health--;
// Visual damage feedback
tween(enemy, {
tint: 0xff8888
}, {
duration: 100,
onFinish: function onFinish() {
if (enemy.health > 0) {
tween(enemy, {
tint: 0xffffff
}, {
duration: 100
});
}
}
});
// Remove bullet
bullet.destroy();
bullets.splice(b, 1);
// Check if enemy is destroyed
if (enemy.health <= 0) {
// Create explosion with area damage
tween(enemy, {
scaleX: 2,
scaleY: 2,
tint: 0xff4444,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
// Area damage to nearby vehicles
for (var k = enemyVehicles.length - 1; k >= 0; k--) {
var nearbyEnemy = enemyVehicles[k];
if (nearbyEnemy !== enemy) {
var distance = Math.sqrt(Math.pow(nearbyEnemy.x - enemy.x, 2) + Math.pow(nearbyEnemy.y - enemy.y, 2));
if (distance < 250) {
nearbyEnemy.health--;
tween(nearbyEnemy, {
tint: 0xff6666
}, {
duration: 150,
onFinish: function onFinish() {
if (nearbyEnemy.health > 0) {
tween(nearbyEnemy, {
tint: 0xffffff
}, {
duration: 150
});
}
}
});
nearbyEnemy.speed *= 0.8;
}
}
}
// Player takes damage if too close
var playerDistance = Math.sqrt(Math.pow(playerCar.x - enemy.x, 2) + Math.pow(playerCar.y - enemy.y, 2));
if (playerDistance < 300) {
playerHealth--;
updateHealthDisplay();
LK.effects.flashScreen(0xff0000, 200);
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
LK.getSound('crash').play();
// Remove destroyed enemy after animation
LK.setTimeout(function () {
enemy.destroy();
var index = enemyVehicles.indexOf(enemy);
if (index !== -1) {
enemyVehicles.splice(index, 1);
}
}, 400);
}
break;
}
}
}
// Police car spawning logic
policeSpawnTimer++;
if (policeSpawnCooldown > 0) {
policeSpawnCooldown--;
}
// Random chance to spawn police car (every 5-10 seconds when available)
if (policeSpawnTimer >= 300 + Math.random() * 300) {
if (Math.random() < 0.3) {
// 30% chance when timer is ready
spawnPoliceCar();
}
policeSpawnTimer = 0;
}
// Update and manage police cars
for (var p = policeCars.length - 1; p >= 0; p--) {
var policeCar = policeCars[p];
// Remove off-screen police cars
if (policeCar.y > 2732 + 200) {
policeCar.destroy();
policeCars.splice(p, 1);
}
}
// Update score
updateScore();
// Check collisions
checkCollisions();
};
Arkası dönük Ferrari. In-Game asset. 2d. High contrast. No shadows
Arkası dönük tır kamyon. In-Game asset. 2d. High contrast. No shadows
Arkası dönük motosiklet. In-Game asset. 2d. High contrast. No shadows
Arkası dönük lamborghini. In-Game asset. 2d. High contrast. No shadows
Arkası dönük polis arabası olan Ferrari. In-Game asset. 2d. High contrast. No shadows