/**** * Classes ****/ //var tween = LK.import("@upit/tween.v1"); // Civilian car class (obstacle) var Car = Container.expand(function () { var self = Container.call(this); self.speed = 8 + Math.random() * 6; self.direction = Math.random() < 0.5 ? 1 : -1; // 1: right, -1: left var carSprite = self.attachAsset('car', { anchorX: 0.5, anchorY: 0.5 }); // Update: move horizontally self.update = function () { self.x += self.speed * self.direction; }; return self; }); // Health pack class var HealthPack = Container.expand(function () { var self = Container.call(this); var healthSprite = self.attachAsset('health', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Loot class var Loot = Container.expand(function () { var self = Container.call(this); var lootSprite = self.attachAsset('loot', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); self.isInVehicle = false; self.health = 30; self.speed = 12; self.vehicleSpeed = 22; self.invincible = false; self.invincibleTimer = 0; // Attach player asset var playerSprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Attach vehicle asset (hidden by default) var vehicleSprite = self.attachAsset('stolenCar', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); // Switch to vehicle mode self.enterVehicle = function () { self.isInVehicle = true; playerSprite.alpha = 0; vehicleSprite.alpha = 1; }; // Exit vehicle mode self.exitVehicle = function () { self.isInVehicle = false; playerSprite.alpha = 1; vehicleSprite.alpha = 0; }; // Take damage (with invincibility frames) self.takeDamage = function () { if (self.invincible) { return; } self.health -= 1; self.invincible = true; self.invincibleTimer = 60; // 1 second at 60fps LK.effects.flashObject(self, 0xff0000, 400); }; // Heal self.heal = function () { if (!self.maxHealth) self.maxHealth = 30; if (self.health < self.maxHealth) { self.health += 1; } }; // Update (invincibility timer) self.update = function () { if (self.invincible) { self.invincibleTimer--; if (self.invincibleTimer <= 0) { self.invincible = false; } } }; return self; }); // Police car class var Police = Container.expand(function () { var self = Container.call(this); self.speed = 10 + Math.random() * 4; self.target = null; var policeSprite = self.attachAsset('police', { anchorX: 0.5, anchorY: 0.5 }); // Set target (player) self.setTarget = function (target) { self.target = target; }; // Update: chase player self.update = function () { if (!self.target) { return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xe0e0e0 }); /**** * Game Code ****/ // --- Global variables --- // City background (large, light gray) // Player (thief) - red ellipse // Police car - blue box // Civilian car - gray box // Loot - yellow ellipse // Health pack - green ellipse // Stolen vehicle (player) - orange box var player; var policeCars = []; var cars = []; var loots = []; var healthPacks = []; var score = 0; var heistObjective = 5; // Number of loot to collect per level var lootCollected = 0; var level = 1; var dragNode = null; var lastMoveX = 0, lastMoveY = 0; // --- Background --- var cityBg = LK.getAsset('cityBg', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(cityBg); // --- Score and Health UI --- var scoreTxt = new Text2('Score: 0 | HP: 30', { size: 90, fill: "#222" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var healthTxt = new Text2('♥♥♥', { size: 90, fill: 0xD83318 }); healthTxt.anchor.set(0.5, 0); LK.gui.top.addChild(healthTxt); healthTxt.y = 100; // --- Objective UI --- var objTxt = new Text2('Loot: 0/5', { size: 70, fill: "#444" }); objTxt.anchor.set(0.5, 0); LK.gui.top.addChild(objTxt); objTxt.y = 200; // --- Helper functions --- function updateScoreUI() { if (player) { scoreTxt.setText('Score: ' + score + ' | HP: ' + player.health); } else { scoreTxt.setText('Score: ' + score); } } function updateHealthUI() { var hearts = ''; var maxHearts = player.maxHealth ? player.maxHealth : 30; for (var i = 0; i < player.health && i < maxHearts; i++) { hearts += '♥'; } healthTxt.setText(hearts + ' (' + player.health + ')'); updateScoreUI(); } function updateObjectiveUI() { objTxt.setText('Loot: ' + lootCollected + '/' + heistObjective); } function spawnLoot() { var loot = new Loot(); // Place randomly, not too close to edges or top left loot.x = 200 + Math.random() * (2048 - 400); loot.y = 300 + Math.random() * (2732 - 600); loots.push(loot); game.addChild(loot); } function spawnHealthPack() { var hp = new HealthPack(); hp.x = 200 + Math.random() * (2048 - 400); hp.y = 300 + Math.random() * (2732 - 600); healthPacks.push(hp); game.addChild(hp); } function spawnPolice() { var police = new Police(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // Top police.x = 200 + Math.random() * (2048 - 400); police.y = 0; } else if (edge === 1) { // Bottom police.x = 200 + Math.random() * (2048 - 400); police.y = 2732; } else if (edge === 2) { // Left police.x = 0; police.y = 300 + Math.random() * (2732 - 600); } else { // Right police.x = 2048; police.y = 300 + Math.random() * (2732 - 600); } police.setTarget(player); policeCars.push(police); game.addChild(police); } function spawnCar() { var car = new Car(); // Randomly choose top or bottom lane var laneY = 500 + Math.floor(Math.random() * 8) * 250; car.y = laneY; if (car.direction === 1) { car.x = -100; } else { car.x = 2048 + 100; } cars.push(car); game.addChild(car); } function resetLevel() { // Remove all loot, police, cars, health packs for (var i = 0; i < loots.length; i++) { loots[i].destroy(); } for (var i = 0; i < policeCars.length; i++) { policeCars[i].destroy(); } for (var i = 0; i < cars.length; i++) { cars[i].destroy(); } for (var i = 0; i < healthPacks.length; i++) { healthPacks[i].destroy(); } loots = []; policeCars = []; cars = []; healthPacks = []; lootCollected = 0; heistObjective = 5 + (level - 1) * 2; updateObjectiveUI(); // Spawn loot for (var i = 0; i < heistObjective; i++) { spawnLoot(); } // Spawn police immediately at level start for (var i = 0; i < Math.min(2 + level, 6); i++) { spawnPolice(); } // Spawn cars for (var i = 0; i < 6 + level * 2; i++) { spawnCar(); } // Spawn health pack if (level > 1) { spawnHealthPack(); } // Reset player position and state player.x = 2048 / 2; player.y = 2732 - 300; player.exitVehicle(); // Increase max health by 1 for each completed level, up to a reasonable cap (e.g. 100) if (!player.maxHealth) { player.maxHealth = 30; } if (level > 1) { player.maxHealth += 1; if (player.maxHealth > 100) player.maxHealth = 100; } player.health = player.maxHealth; updateHealthUI(); } // --- Initialize player --- player = new Player(); player.x = 2048 / 2; player.y = 2732 - 300; game.addChild(player); // --- Start first level --- resetLevel(); updateScoreUI(); // --- Touch/drag controls --- function clamp(val, min, max) { if (val < min) { return min; } if (val > max) { return max; } return val; } function handleMove(x, y, obj) { if (!dragNode) { return; } // Clamp to game area, avoid top left 100x100 var px = clamp(x, 100 + 50, 2048 - 50); var py = clamp(y, 100 + 50, 2732 - 50); // Move player smoothly var speed = dragNode.isInVehicle ? dragNode.vehicleSpeed : dragNode.speed; var dx = px - dragNode.x; var dy = py - dragNode.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > speed) { dragNode.x += dx / dist * speed; dragNode.y += dy / dist * speed; } else { dragNode.x = px; dragNode.y = py; } lastMoveX = px; lastMoveY = py; } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if not in top left 100x100 if (x < 100 && y < 100) { return; } dragNode = player; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; // --- Main game update loop --- game.update = function () { // Update player (invincibility, etc) player.update(); // Update police for (var i = policeCars.length - 1; i >= 0; i--) { var p = policeCars[i]; p.update(); // Check collision with player if (p.intersects(player)) { if (!player.invincible) { player.takeDamage(); updateHealthUI(); if (player.health <= 0) { LK.effects.flashScreen(0x0000ff, 1000); LK.showGameOver(); return; } } } } // Update cars (obstacles) for (var i = cars.length - 1; i >= 0; i--) { var c = cars[i]; c.update(); // Remove if off screen if (c.direction === 1 && c.x > 2048 + 200 || c.direction === -1 && c.x < -200) { c.destroy(); cars.splice(i, 1); continue; } // Collision with player if (c.intersects(player)) { if (!player.isInVehicle && !player.invincible) { player.takeDamage(); updateHealthUI(); if (player.health <= 0) { LK.effects.flashScreen(0x0000ff, 1000); LK.showGameOver(); return; } } } // Steal vehicle: if player is not in vehicle and collides, enter vehicle if (!player.isInVehicle && c.intersects(player)) { player.enterVehicle(); // Remove the car c.destroy(); cars.splice(i, 1); continue; } } // Update loot for (var i = loots.length - 1; i >= 0; i--) { var l = loots[i]; if (l.intersects(player)) { score += 10; lootCollected += 1; updateScoreUI(); updateObjectiveUI(); l.destroy(); loots.splice(i, 1); // Win level if all loot collected if (lootCollected >= heistObjective) { level += 1; LK.effects.flashScreen(0x44de83, 800); LK.setTimeout(function () { resetLevel(); }, 900); return; } } } // Update health packs for (var i = healthPacks.length - 1; i >= 0; i--) { var hp = healthPacks[i]; if (hp.intersects(player)) { player.heal(); updateHealthUI(); hp.destroy(); healthPacks.splice(i, 1); } } // Player exits vehicle after a while (simulate "stolen car runs out of gas") if (player.isInVehicle) { if (!player.vehicleTimer) { player.vehicleTimer = 180; } // 3 seconds player.vehicleTimer--; if (player.vehicleTimer <= 0) { player.exitVehicle(); player.vehicleTimer = null; } } // Spawn new cars and police at intervals if (LK.ticks % (90 - Math.min(level * 5, 60)) === 0) { spawnCar(); } if (LK.ticks % (300 - Math.min(level * 10, 200)) === 0) { spawnPolice(); } // Occasionally spawn health pack if (LK.ticks % 900 === 0 && healthPacks.length < 1 && player.health < 3) { spawnHealthPack(); } };
/****
* Classes
****/
//var tween = LK.import("@upit/tween.v1");
// Civilian car class (obstacle)
var Car = Container.expand(function () {
var self = Container.call(this);
self.speed = 8 + Math.random() * 6;
self.direction = Math.random() < 0.5 ? 1 : -1; // 1: right, -1: left
var carSprite = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
// Update: move horizontally
self.update = function () {
self.x += self.speed * self.direction;
};
return self;
});
// Health pack class
var HealthPack = Container.expand(function () {
var self = Container.call(this);
var healthSprite = self.attachAsset('health', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Loot class
var Loot = Container.expand(function () {
var self = Container.call(this);
var lootSprite = self.attachAsset('loot', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
self.isInVehicle = false;
self.health = 30;
self.speed = 12;
self.vehicleSpeed = 22;
self.invincible = false;
self.invincibleTimer = 0;
// Attach player asset
var playerSprite = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach vehicle asset (hidden by default)
var vehicleSprite = self.attachAsset('stolenCar', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Switch to vehicle mode
self.enterVehicle = function () {
self.isInVehicle = true;
playerSprite.alpha = 0;
vehicleSprite.alpha = 1;
};
// Exit vehicle mode
self.exitVehicle = function () {
self.isInVehicle = false;
playerSprite.alpha = 1;
vehicleSprite.alpha = 0;
};
// Take damage (with invincibility frames)
self.takeDamage = function () {
if (self.invincible) {
return;
}
self.health -= 1;
self.invincible = true;
self.invincibleTimer = 60; // 1 second at 60fps
LK.effects.flashObject(self, 0xff0000, 400);
};
// Heal
self.heal = function () {
if (!self.maxHealth) self.maxHealth = 30;
if (self.health < self.maxHealth) {
self.health += 1;
}
};
// Update (invincibility timer)
self.update = function () {
if (self.invincible) {
self.invincibleTimer--;
if (self.invincibleTimer <= 0) {
self.invincible = false;
}
}
};
return self;
});
// Police car class
var Police = Container.expand(function () {
var self = Container.call(this);
self.speed = 10 + Math.random() * 4;
self.target = null;
var policeSprite = self.attachAsset('police', {
anchorX: 0.5,
anchorY: 0.5
});
// Set target (player)
self.setTarget = function (target) {
self.target = target;
};
// Update: chase player
self.update = function () {
if (!self.target) {
return;
}
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xe0e0e0
});
/****
* Game Code
****/
// --- Global variables ---
// City background (large, light gray)
// Player (thief) - red ellipse
// Police car - blue box
// Civilian car - gray box
// Loot - yellow ellipse
// Health pack - green ellipse
// Stolen vehicle (player) - orange box
var player;
var policeCars = [];
var cars = [];
var loots = [];
var healthPacks = [];
var score = 0;
var heistObjective = 5; // Number of loot to collect per level
var lootCollected = 0;
var level = 1;
var dragNode = null;
var lastMoveX = 0,
lastMoveY = 0;
// --- Background ---
var cityBg = LK.getAsset('cityBg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(cityBg);
// --- Score and Health UI ---
var scoreTxt = new Text2('Score: 0 | HP: 30', {
size: 90,
fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var healthTxt = new Text2('♥♥♥', {
size: 90,
fill: 0xD83318
});
healthTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(healthTxt);
healthTxt.y = 100;
// --- Objective UI ---
var objTxt = new Text2('Loot: 0/5', {
size: 70,
fill: "#444"
});
objTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(objTxt);
objTxt.y = 200;
// --- Helper functions ---
function updateScoreUI() {
if (player) {
scoreTxt.setText('Score: ' + score + ' | HP: ' + player.health);
} else {
scoreTxt.setText('Score: ' + score);
}
}
function updateHealthUI() {
var hearts = '';
var maxHearts = player.maxHealth ? player.maxHealth : 30;
for (var i = 0; i < player.health && i < maxHearts; i++) {
hearts += '♥';
}
healthTxt.setText(hearts + ' (' + player.health + ')');
updateScoreUI();
}
function updateObjectiveUI() {
objTxt.setText('Loot: ' + lootCollected + '/' + heistObjective);
}
function spawnLoot() {
var loot = new Loot();
// Place randomly, not too close to edges or top left
loot.x = 200 + Math.random() * (2048 - 400);
loot.y = 300 + Math.random() * (2732 - 600);
loots.push(loot);
game.addChild(loot);
}
function spawnHealthPack() {
var hp = new HealthPack();
hp.x = 200 + Math.random() * (2048 - 400);
hp.y = 300 + Math.random() * (2732 - 600);
healthPacks.push(hp);
game.addChild(hp);
}
function spawnPolice() {
var police = new Police();
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// Top
police.x = 200 + Math.random() * (2048 - 400);
police.y = 0;
} else if (edge === 1) {
// Bottom
police.x = 200 + Math.random() * (2048 - 400);
police.y = 2732;
} else if (edge === 2) {
// Left
police.x = 0;
police.y = 300 + Math.random() * (2732 - 600);
} else {
// Right
police.x = 2048;
police.y = 300 + Math.random() * (2732 - 600);
}
police.setTarget(player);
policeCars.push(police);
game.addChild(police);
}
function spawnCar() {
var car = new Car();
// Randomly choose top or bottom lane
var laneY = 500 + Math.floor(Math.random() * 8) * 250;
car.y = laneY;
if (car.direction === 1) {
car.x = -100;
} else {
car.x = 2048 + 100;
}
cars.push(car);
game.addChild(car);
}
function resetLevel() {
// Remove all loot, police, cars, health packs
for (var i = 0; i < loots.length; i++) {
loots[i].destroy();
}
for (var i = 0; i < policeCars.length; i++) {
policeCars[i].destroy();
}
for (var i = 0; i < cars.length; i++) {
cars[i].destroy();
}
for (var i = 0; i < healthPacks.length; i++) {
healthPacks[i].destroy();
}
loots = [];
policeCars = [];
cars = [];
healthPacks = [];
lootCollected = 0;
heistObjective = 5 + (level - 1) * 2;
updateObjectiveUI();
// Spawn loot
for (var i = 0; i < heistObjective; i++) {
spawnLoot();
}
// Spawn police immediately at level start
for (var i = 0; i < Math.min(2 + level, 6); i++) {
spawnPolice();
}
// Spawn cars
for (var i = 0; i < 6 + level * 2; i++) {
spawnCar();
}
// Spawn health pack
if (level > 1) {
spawnHealthPack();
}
// Reset player position and state
player.x = 2048 / 2;
player.y = 2732 - 300;
player.exitVehicle();
// Increase max health by 1 for each completed level, up to a reasonable cap (e.g. 100)
if (!player.maxHealth) {
player.maxHealth = 30;
}
if (level > 1) {
player.maxHealth += 1;
if (player.maxHealth > 100) player.maxHealth = 100;
}
player.health = player.maxHealth;
updateHealthUI();
}
// --- Initialize player ---
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 300;
game.addChild(player);
// --- Start first level ---
resetLevel();
updateScoreUI();
// --- Touch/drag controls ---
function clamp(val, min, max) {
if (val < min) {
return min;
}
if (val > max) {
return max;
}
return val;
}
function handleMove(x, y, obj) {
if (!dragNode) {
return;
}
// Clamp to game area, avoid top left 100x100
var px = clamp(x, 100 + 50, 2048 - 50);
var py = clamp(y, 100 + 50, 2732 - 50);
// Move player smoothly
var speed = dragNode.isInVehicle ? dragNode.vehicleSpeed : dragNode.speed;
var dx = px - dragNode.x;
var dy = py - dragNode.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > speed) {
dragNode.x += dx / dist * speed;
dragNode.y += dy / dist * speed;
} else {
dragNode.x = px;
dragNode.y = py;
}
lastMoveX = px;
lastMoveY = py;
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if not in top left 100x100
if (x < 100 && y < 100) {
return;
}
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Main game update loop ---
game.update = function () {
// Update player (invincibility, etc)
player.update();
// Update police
for (var i = policeCars.length - 1; i >= 0; i--) {
var p = policeCars[i];
p.update();
// Check collision with player
if (p.intersects(player)) {
if (!player.invincible) {
player.takeDamage();
updateHealthUI();
if (player.health <= 0) {
LK.effects.flashScreen(0x0000ff, 1000);
LK.showGameOver();
return;
}
}
}
}
// Update cars (obstacles)
for (var i = cars.length - 1; i >= 0; i--) {
var c = cars[i];
c.update();
// Remove if off screen
if (c.direction === 1 && c.x > 2048 + 200 || c.direction === -1 && c.x < -200) {
c.destroy();
cars.splice(i, 1);
continue;
}
// Collision with player
if (c.intersects(player)) {
if (!player.isInVehicle && !player.invincible) {
player.takeDamage();
updateHealthUI();
if (player.health <= 0) {
LK.effects.flashScreen(0x0000ff, 1000);
LK.showGameOver();
return;
}
}
}
// Steal vehicle: if player is not in vehicle and collides, enter vehicle
if (!player.isInVehicle && c.intersects(player)) {
player.enterVehicle();
// Remove the car
c.destroy();
cars.splice(i, 1);
continue;
}
}
// Update loot
for (var i = loots.length - 1; i >= 0; i--) {
var l = loots[i];
if (l.intersects(player)) {
score += 10;
lootCollected += 1;
updateScoreUI();
updateObjectiveUI();
l.destroy();
loots.splice(i, 1);
// Win level if all loot collected
if (lootCollected >= heistObjective) {
level += 1;
LK.effects.flashScreen(0x44de83, 800);
LK.setTimeout(function () {
resetLevel();
}, 900);
return;
}
}
}
// Update health packs
for (var i = healthPacks.length - 1; i >= 0; i--) {
var hp = healthPacks[i];
if (hp.intersects(player)) {
player.heal();
updateHealthUI();
hp.destroy();
healthPacks.splice(i, 1);
}
}
// Player exits vehicle after a while (simulate "stolen car runs out of gas")
if (player.isInVehicle) {
if (!player.vehicleTimer) {
player.vehicleTimer = 180;
} // 3 seconds
player.vehicleTimer--;
if (player.vehicleTimer <= 0) {
player.exitVehicle();
player.vehicleTimer = null;
}
}
// Spawn new cars and police at intervals
if (LK.ticks % (90 - Math.min(level * 5, 60)) === 0) {
spawnCar();
}
if (LK.ticks % (300 - Math.min(level * 10, 200)) === 0) {
spawnPolice();
}
// Occasionally spawn health pack
if (LK.ticks % 900 === 0 && healthPacks.length < 1 && player.health < 3) {
spawnHealthPack();
}
};