/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Brick class
var Brick = Container.expand(function () {
var self = Container.call(this);
var brickAsset = self.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.row = 0;
self.col = 0;
self.destroyBrick = function () {
if (self.isDestroyed) return;
self.isDestroyed = true;
// Add physics-like destruction: random velocity, rotation, gravity, fade out
// Give each brick a random velocity and rotation
var vx = (Math.random() - 0.5) * 32 + (self.x - 1024) / 64; // bias outward from center
var vy = -Math.random() * 24 - 12; // upward burst
var vr = (Math.random() - 0.5) * 0.2; // random spin
var gravity = 2.2 + Math.random() * 0.8;
var totalTime = 650 + Math.random() * 200;
var startX = self.x;
var startY = self.y;
var startR = self.rotation;
var endAlpha = 0;
var startAlpha = self.alpha;
var startScale = self.scaleX;
var endScale = 1.5 + Math.random() * 0.5;
var t0 = Date.now();
function animate() {
var t = Date.now() - t0;
var progress = Math.min(t / totalTime, 1);
// Physics: x, y, rotation, scale, alpha
self.x = startX + vx * t / 16;
self.y = startY + vy * t / 16 + 0.5 * gravity * Math.pow(t / 32, 2);
self.rotation = startR + vr * t / 16;
self.alpha = startAlpha * (1 - progress);
self.scaleX = self.scaleY = startScale + (endScale - startScale) * progress;
if (progress < 1) {
LK.setTimeout(animate, 16);
} else {
self.visible = false;
}
}
animate();
};
return self;
});
// Explosion effect class
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionAsset = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
scaleX: 0.2,
scaleY: 0.2
});
self.radius = 120; // pixels, effective blast radius
self.play = function (_onFinish) {
// Animate scale up and fade out
tween(explosionAsset, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
if (_onFinish) _onFinish();
}
});
};
return self;
});
// Person class
var Person = Container.expand(function () {
var self = Container.call(this);
var personAsset = self.attachAsset('person_sprite1', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.destroyPerson = function () {
if (self.isDestroyed) return;
self.isDestroyed = true;
// Physics-like destruction: random velocity, rotation, gravity, fade out (match Brick)
var vx = (Math.random() - 0.5) * 32 + (self.x - 1024) / 64;
var vy = -Math.random() * 24 - 12;
var vr = (Math.random() - 0.5) * 0.2;
var gravity = 2.2 + Math.random() * 0.8;
var totalTime = 650 + Math.random() * 200;
var startX = self.x;
var startY = self.y;
var startR = self.rotation;
var endAlpha = 0;
var startAlpha = self.alpha;
var startScale = self.scaleX;
var endScale = 1.5 + Math.random() * 0.5;
var t0 = Date.now();
function animate() {
var t = Date.now() - t0;
var progress = Math.min(t / totalTime, 1);
self.x = startX + vx * t / 16;
self.y = startY + vy * t / 16 + 0.5 * gravity * Math.pow(t / 32, 2);
self.rotation = startR + vr * t / 16;
self.alpha = startAlpha * (1 - progress);
self.scaleX = self.scaleY = startScale + (endScale - startScale) * progress;
if (progress < 1) {
LK.setTimeout(animate, 16);
} else {
self.visible = false;
}
}
animate();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// --- Add global counters and GUI bar for bricks broken and people accidentally killed ---
// Wall/grid settings
// Bricks: simple colored boxes
var bricksBroken = 0;
var peopleKilled = 0;
// GUI: Bricks Broken Bar
var bricksBarBg = LK.getAsset('brick', {
anchorX: 0,
anchorY: 0,
width: 420,
height: 60
});
bricksBarBg.alpha = 0.18;
var bricksBarFill = LK.getAsset('brick', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 44
});
bricksBarFill.y = 8;
bricksBarFill.x = 10;
bricksBarFill.tint = 0xffe066;
var bricksBarText = new Text2('Bricks Broken: 0', {
size: 38,
fill: 0xFFFBE0
});
bricksBarText.anchor.set(0, 0.5);
bricksBarText.x = 20;
bricksBarText.y = 30;
var bricksBarContainer = new Container();
bricksBarContainer.addChild(bricksBarBg);
bricksBarContainer.addChild(bricksBarFill);
bricksBarContainer.addChild(bricksBarText);
bricksBarContainer.x = 120;
bricksBarContainer.y = 24;
LK.gui.top.addChild(bricksBarContainer);
// GUI: People Accidentally Killed Bar
var peopleBarBg = LK.getAsset('person_sprite1', {
anchorX: 0,
anchorY: 0,
width: 420,
height: 60
});
peopleBarBg.alpha = 0.18;
var peopleBarFill = LK.getAsset('person_sprite1', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 44
});
peopleBarFill.y = 8;
peopleBarFill.x = 10;
peopleBarFill.tint = 0xff6666;
var peopleBarText = new Text2('People Killed: 0', {
size: 38,
fill: 0xFFFBE0
});
peopleBarText.anchor.set(0, 0.5);
peopleBarText.x = 20;
peopleBarText.y = 30;
var peopleBarContainer = new Container();
peopleBarContainer.addChild(peopleBarBg);
peopleBarContainer.addChild(peopleBarFill);
peopleBarContainer.addChild(peopleBarText);
// Place below bricks bar, with a little vertical gap
peopleBarContainer.x = 120;
peopleBarContainer.y = 24 + 70;
LK.gui.top.addChild(peopleBarContainer);
// Helper to update bars
function updateBars() {
// Bricks: fill width proportional to total bricks destroyed this round
var totalBricks = WALL_COLS * WALL_ROWS;
var bricksFrac = Math.min(bricksBroken / totalBricks, 1);
bricksBarFill.width = 400 * bricksFrac;
bricksBarText.setText('Bricks Broken: ' + bricksBroken);
// People: fill width proportional to people killed (max bar at 20 for fun)
var peopleFrac = Math.min(peopleKilled / 20, 1);
peopleBarFill.width = 400 * peopleFrac;
peopleBarText.setText('People Killed: ' + peopleKilled);
}
// --- Add random photo background using facekit plugin ---
var photoBackground = null;
// Use facekit.photos array (if available) to select a random photo for the background
if (facekit.photos && facekit.photos.length > 0) {
var randomIndex = Math.floor(Math.random() * facekit.photos.length);
var photoAsset = facekit.photos[randomIndex];
// Remove previous background if any
if (photoBackground && photoBackground.parent) {
photoBackground.parent.removeChild(photoBackground);
}
// Place photo as background, scaled to cover the game area
photoBackground = LK.getAsset(photoAsset.id, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
// Insert as the first child so it's behind everything
game.addChildAt(photoBackground, 0);
}
// Level settings
var LEVELS = [{
cols: 20,
rows: 20,
brickSize: 90,
gap: 6
},
// Level 1: fills most of the screen
{
cols: 22,
rows: 24,
brickSize: 80,
gap: 5
},
// Level 2: even more bricks, smaller
{
cols: 24,
rows: 28,
brickSize: 70,
gap: 4
} // Level 3: max fill
];
var currentLevel = 0;
// Wall/grid settings (will be set per level)
var BRICK_SIZE = LEVELS[0].brickSize;
var BRICK_GAP = LEVELS[0].gap;
var WALL_COLS = LEVELS[0].cols;
var WALL_ROWS = LEVELS[0].rows;
var wallOffsetX = Math.floor((2048 - (WALL_COLS * BRICK_SIZE + (WALL_COLS - 1) * BRICK_GAP)) / 2);
var wallOffsetY = Math.floor((2732 - (WALL_ROWS * BRICK_SIZE + (WALL_ROWS - 1) * BRICK_GAP)) / 2);
// Game state
var bricks = [];
var isAnimating = false;
// Build wall of bricks
function buildWall() {
// Update wall/grid settings for current level
BRICK_SIZE = LEVELS[currentLevel].brickSize;
BRICK_GAP = LEVELS[currentLevel].gap;
WALL_COLS = LEVELS[currentLevel].cols;
WALL_ROWS = LEVELS[currentLevel].rows;
wallOffsetX = Math.floor((2048 - (WALL_COLS * BRICK_SIZE + (WALL_COLS - 1) * BRICK_GAP)) / 2);
wallOffsetY = Math.floor((2732 - (WALL_ROWS * BRICK_SIZE + (WALL_ROWS - 1) * BRICK_GAP)) / 2);
bricks = [];
for (var row = 0; row < WALL_ROWS; row++) {
for (var col = 0; col < WALL_COLS; col++) {
var brick = new Brick();
brick.x = wallOffsetX + col * (BRICK_SIZE + BRICK_GAP) + BRICK_SIZE / 2;
brick.y = wallOffsetY + row * (BRICK_SIZE + BRICK_GAP) + BRICK_SIZE / 2;
brick.row = row;
brick.col = col;
// Reset transform and visibility for respawned bricks
brick.visible = true;
brick.alpha = 1;
brick.scaleX = brick.scaleY = 1;
brick.rotation = 0;
game.addChild(brick);
// 1 in 20 chance to spawn a person on this brick
if (Math.floor(Math.random() * 20) === 0) {
var person = new Person();
person.x = brick.x;
person.y = brick.y;
game.addChild(person);
brick.person = person;
} else {
brick.person = null;
}
if (!bricks[row]) bricks[row] = [];
bricks[row][col] = brick;
}
}
}
// Reset game state
function resetGame() {
buildWall();
bricksBroken = 0;
peopleKilled = 0;
updateBars();
isAnimating = false;
}
// Helper: get bricks within radius of (x, y)
function getBricksInRadius(x, y, radius) {
var hit = [];
for (var row = 0; row < WALL_ROWS; row++) {
for (var col = 0; col < WALL_COLS; col++) {
var brick = bricks[row][col];
if (brick && !brick.isDestroyed) {
var dx = brick.x - x;
var dy = brick.y - y;
if (dx * dx + dy * dy <= radius * radius) {
hit.push(brick);
}
}
}
}
return hit;
}
// Chain reaction: destroy bricks, trigger new explosions if enough bricks destroyed
function triggerExplosion(x, y, chainLevel) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
game.addChild(explosion);
explosion.play();
// Play explosion sound
LK.getSound('Explode').play();
// Play explosion sound
LK.getSound('Explode').play();
var affected = getBricksInRadius(x, y, explosion.radius);
var destroyed = [];
for (var i = 0; i < affected.length; i++) {
var brick = affected[i];
if (!brick.isDestroyed) {
brick.destroyBrick();
bricksBroken++;
updateBars();
destroyed.push(brick);
// If there is a person on this brick, explode them too
if (brick.person && !brick.person.isDestroyed) {
brick.person.destroyPerson();
peopleKilled++;
updateBars();
}
}
}
// Chain reaction: if 3+ bricks destroyed, trigger new explosions at their positions (but only up to 2 chains deep)
if (destroyed.length >= 3 && chainLevel < 2) {
// Delay next chain for effect
LK.setTimeout(function () {
for (var j = 0; j < destroyed.length; j++) {
var b = destroyed[j];
triggerExplosion(b.x, b.y, chainLevel + 1);
}
}, 180);
}
// No win/lose check, play infinitely
}
// Advance to next level (wraps around)
function nextLevel() {
// Remove all bricks from game
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col]) {
bricks[row][col].destroy();
}
}
}
currentLevel = (currentLevel + 1) % LEVELS.length;
resetGame();
}
// --- Drag-to-explode implementation ---
var dragActive = false;
var lastDragPoint = null;
var DRAG_EXPLODE_DIST = 80; // Minimum distance between explosions along drag
// Allow drag-to-explode at any time
game.down = function (x, y, obj) {
// Don't allow taps in top 100px (menu area)
if (y < 100) return;
// If tap is in bottom 150px, go to next level (leave 100px for bottom GUI)
if (y > 2732 - 150) {
nextLevel();
return;
}
dragActive = true;
lastDragPoint = {
x: x,
y: y
};
triggerExplosion(x, y, 0);
};
game.move = function (x, y, obj) {
if (!dragActive) return;
// Don't allow drag in top 100px (menu area)
if (y < 100) return;
// Only trigger new explosion if moved far enough from last explosion point
if (lastDragPoint) {
var dx = x - lastDragPoint.x;
var dy = y - lastDragPoint.y;
if (dx * dx + dy * dy >= DRAG_EXPLODE_DIST * DRAG_EXPLODE_DIST) {
lastDragPoint = {
x: x,
y: y
};
triggerExplosion(x, y, 0);
}
}
};
game.up = function (x, y, obj) {
dragActive = false;
lastDragPoint = null;
};
// Main update loop: respawn bricks if all are destroyed
game.update = function () {
// Check if all bricks are destroyed
var allDestroyed = true;
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col] && !bricks[row][col].isDestroyed) {
allDestroyed = false;
break;
}
}
if (!allDestroyed) break;
}
// If all destroyed and not animating, respawn wall
if (allDestroyed && !isAnimating) {
// Remove all old brick containers
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col]) {
bricks[row][col].destroy();
}
}
}
resetGame();
}
};
// Start game
resetGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Brick class
var Brick = Container.expand(function () {
var self = Container.call(this);
var brickAsset = self.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.row = 0;
self.col = 0;
self.destroyBrick = function () {
if (self.isDestroyed) return;
self.isDestroyed = true;
// Add physics-like destruction: random velocity, rotation, gravity, fade out
// Give each brick a random velocity and rotation
var vx = (Math.random() - 0.5) * 32 + (self.x - 1024) / 64; // bias outward from center
var vy = -Math.random() * 24 - 12; // upward burst
var vr = (Math.random() - 0.5) * 0.2; // random spin
var gravity = 2.2 + Math.random() * 0.8;
var totalTime = 650 + Math.random() * 200;
var startX = self.x;
var startY = self.y;
var startR = self.rotation;
var endAlpha = 0;
var startAlpha = self.alpha;
var startScale = self.scaleX;
var endScale = 1.5 + Math.random() * 0.5;
var t0 = Date.now();
function animate() {
var t = Date.now() - t0;
var progress = Math.min(t / totalTime, 1);
// Physics: x, y, rotation, scale, alpha
self.x = startX + vx * t / 16;
self.y = startY + vy * t / 16 + 0.5 * gravity * Math.pow(t / 32, 2);
self.rotation = startR + vr * t / 16;
self.alpha = startAlpha * (1 - progress);
self.scaleX = self.scaleY = startScale + (endScale - startScale) * progress;
if (progress < 1) {
LK.setTimeout(animate, 16);
} else {
self.visible = false;
}
}
animate();
};
return self;
});
// Explosion effect class
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionAsset = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7,
scaleX: 0.2,
scaleY: 0.2
});
self.radius = 120; // pixels, effective blast radius
self.play = function (_onFinish) {
// Animate scale up and fade out
tween(explosionAsset, {
scaleX: 1,
scaleY: 1,
alpha: 0
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
if (_onFinish) _onFinish();
}
});
};
return self;
});
// Person class
var Person = Container.expand(function () {
var self = Container.call(this);
var personAsset = self.attachAsset('person_sprite1', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDestroyed = false;
self.destroyPerson = function () {
if (self.isDestroyed) return;
self.isDestroyed = true;
// Physics-like destruction: random velocity, rotation, gravity, fade out (match Brick)
var vx = (Math.random() - 0.5) * 32 + (self.x - 1024) / 64;
var vy = -Math.random() * 24 - 12;
var vr = (Math.random() - 0.5) * 0.2;
var gravity = 2.2 + Math.random() * 0.8;
var totalTime = 650 + Math.random() * 200;
var startX = self.x;
var startY = self.y;
var startR = self.rotation;
var endAlpha = 0;
var startAlpha = self.alpha;
var startScale = self.scaleX;
var endScale = 1.5 + Math.random() * 0.5;
var t0 = Date.now();
function animate() {
var t = Date.now() - t0;
var progress = Math.min(t / totalTime, 1);
self.x = startX + vx * t / 16;
self.y = startY + vy * t / 16 + 0.5 * gravity * Math.pow(t / 32, 2);
self.rotation = startR + vr * t / 16;
self.alpha = startAlpha * (1 - progress);
self.scaleX = self.scaleY = startScale + (endScale - startScale) * progress;
if (progress < 1) {
LK.setTimeout(animate, 16);
} else {
self.visible = false;
}
}
animate();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// --- Add global counters and GUI bar for bricks broken and people accidentally killed ---
// Wall/grid settings
// Bricks: simple colored boxes
var bricksBroken = 0;
var peopleKilled = 0;
// GUI: Bricks Broken Bar
var bricksBarBg = LK.getAsset('brick', {
anchorX: 0,
anchorY: 0,
width: 420,
height: 60
});
bricksBarBg.alpha = 0.18;
var bricksBarFill = LK.getAsset('brick', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 44
});
bricksBarFill.y = 8;
bricksBarFill.x = 10;
bricksBarFill.tint = 0xffe066;
var bricksBarText = new Text2('Bricks Broken: 0', {
size: 38,
fill: 0xFFFBE0
});
bricksBarText.anchor.set(0, 0.5);
bricksBarText.x = 20;
bricksBarText.y = 30;
var bricksBarContainer = new Container();
bricksBarContainer.addChild(bricksBarBg);
bricksBarContainer.addChild(bricksBarFill);
bricksBarContainer.addChild(bricksBarText);
bricksBarContainer.x = 120;
bricksBarContainer.y = 24;
LK.gui.top.addChild(bricksBarContainer);
// GUI: People Accidentally Killed Bar
var peopleBarBg = LK.getAsset('person_sprite1', {
anchorX: 0,
anchorY: 0,
width: 420,
height: 60
});
peopleBarBg.alpha = 0.18;
var peopleBarFill = LK.getAsset('person_sprite1', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 44
});
peopleBarFill.y = 8;
peopleBarFill.x = 10;
peopleBarFill.tint = 0xff6666;
var peopleBarText = new Text2('People Killed: 0', {
size: 38,
fill: 0xFFFBE0
});
peopleBarText.anchor.set(0, 0.5);
peopleBarText.x = 20;
peopleBarText.y = 30;
var peopleBarContainer = new Container();
peopleBarContainer.addChild(peopleBarBg);
peopleBarContainer.addChild(peopleBarFill);
peopleBarContainer.addChild(peopleBarText);
// Place below bricks bar, with a little vertical gap
peopleBarContainer.x = 120;
peopleBarContainer.y = 24 + 70;
LK.gui.top.addChild(peopleBarContainer);
// Helper to update bars
function updateBars() {
// Bricks: fill width proportional to total bricks destroyed this round
var totalBricks = WALL_COLS * WALL_ROWS;
var bricksFrac = Math.min(bricksBroken / totalBricks, 1);
bricksBarFill.width = 400 * bricksFrac;
bricksBarText.setText('Bricks Broken: ' + bricksBroken);
// People: fill width proportional to people killed (max bar at 20 for fun)
var peopleFrac = Math.min(peopleKilled / 20, 1);
peopleBarFill.width = 400 * peopleFrac;
peopleBarText.setText('People Killed: ' + peopleKilled);
}
// --- Add random photo background using facekit plugin ---
var photoBackground = null;
// Use facekit.photos array (if available) to select a random photo for the background
if (facekit.photos && facekit.photos.length > 0) {
var randomIndex = Math.floor(Math.random() * facekit.photos.length);
var photoAsset = facekit.photos[randomIndex];
// Remove previous background if any
if (photoBackground && photoBackground.parent) {
photoBackground.parent.removeChild(photoBackground);
}
// Place photo as background, scaled to cover the game area
photoBackground = LK.getAsset(photoAsset.id, {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
// Insert as the first child so it's behind everything
game.addChildAt(photoBackground, 0);
}
// Level settings
var LEVELS = [{
cols: 20,
rows: 20,
brickSize: 90,
gap: 6
},
// Level 1: fills most of the screen
{
cols: 22,
rows: 24,
brickSize: 80,
gap: 5
},
// Level 2: even more bricks, smaller
{
cols: 24,
rows: 28,
brickSize: 70,
gap: 4
} // Level 3: max fill
];
var currentLevel = 0;
// Wall/grid settings (will be set per level)
var BRICK_SIZE = LEVELS[0].brickSize;
var BRICK_GAP = LEVELS[0].gap;
var WALL_COLS = LEVELS[0].cols;
var WALL_ROWS = LEVELS[0].rows;
var wallOffsetX = Math.floor((2048 - (WALL_COLS * BRICK_SIZE + (WALL_COLS - 1) * BRICK_GAP)) / 2);
var wallOffsetY = Math.floor((2732 - (WALL_ROWS * BRICK_SIZE + (WALL_ROWS - 1) * BRICK_GAP)) / 2);
// Game state
var bricks = [];
var isAnimating = false;
// Build wall of bricks
function buildWall() {
// Update wall/grid settings for current level
BRICK_SIZE = LEVELS[currentLevel].brickSize;
BRICK_GAP = LEVELS[currentLevel].gap;
WALL_COLS = LEVELS[currentLevel].cols;
WALL_ROWS = LEVELS[currentLevel].rows;
wallOffsetX = Math.floor((2048 - (WALL_COLS * BRICK_SIZE + (WALL_COLS - 1) * BRICK_GAP)) / 2);
wallOffsetY = Math.floor((2732 - (WALL_ROWS * BRICK_SIZE + (WALL_ROWS - 1) * BRICK_GAP)) / 2);
bricks = [];
for (var row = 0; row < WALL_ROWS; row++) {
for (var col = 0; col < WALL_COLS; col++) {
var brick = new Brick();
brick.x = wallOffsetX + col * (BRICK_SIZE + BRICK_GAP) + BRICK_SIZE / 2;
brick.y = wallOffsetY + row * (BRICK_SIZE + BRICK_GAP) + BRICK_SIZE / 2;
brick.row = row;
brick.col = col;
// Reset transform and visibility for respawned bricks
brick.visible = true;
brick.alpha = 1;
brick.scaleX = brick.scaleY = 1;
brick.rotation = 0;
game.addChild(brick);
// 1 in 20 chance to spawn a person on this brick
if (Math.floor(Math.random() * 20) === 0) {
var person = new Person();
person.x = brick.x;
person.y = brick.y;
game.addChild(person);
brick.person = person;
} else {
brick.person = null;
}
if (!bricks[row]) bricks[row] = [];
bricks[row][col] = brick;
}
}
}
// Reset game state
function resetGame() {
buildWall();
bricksBroken = 0;
peopleKilled = 0;
updateBars();
isAnimating = false;
}
// Helper: get bricks within radius of (x, y)
function getBricksInRadius(x, y, radius) {
var hit = [];
for (var row = 0; row < WALL_ROWS; row++) {
for (var col = 0; col < WALL_COLS; col++) {
var brick = bricks[row][col];
if (brick && !brick.isDestroyed) {
var dx = brick.x - x;
var dy = brick.y - y;
if (dx * dx + dy * dy <= radius * radius) {
hit.push(brick);
}
}
}
}
return hit;
}
// Chain reaction: destroy bricks, trigger new explosions if enough bricks destroyed
function triggerExplosion(x, y, chainLevel) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
game.addChild(explosion);
explosion.play();
// Play explosion sound
LK.getSound('Explode').play();
// Play explosion sound
LK.getSound('Explode').play();
var affected = getBricksInRadius(x, y, explosion.radius);
var destroyed = [];
for (var i = 0; i < affected.length; i++) {
var brick = affected[i];
if (!brick.isDestroyed) {
brick.destroyBrick();
bricksBroken++;
updateBars();
destroyed.push(brick);
// If there is a person on this brick, explode them too
if (brick.person && !brick.person.isDestroyed) {
brick.person.destroyPerson();
peopleKilled++;
updateBars();
}
}
}
// Chain reaction: if 3+ bricks destroyed, trigger new explosions at their positions (but only up to 2 chains deep)
if (destroyed.length >= 3 && chainLevel < 2) {
// Delay next chain for effect
LK.setTimeout(function () {
for (var j = 0; j < destroyed.length; j++) {
var b = destroyed[j];
triggerExplosion(b.x, b.y, chainLevel + 1);
}
}, 180);
}
// No win/lose check, play infinitely
}
// Advance to next level (wraps around)
function nextLevel() {
// Remove all bricks from game
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col]) {
bricks[row][col].destroy();
}
}
}
currentLevel = (currentLevel + 1) % LEVELS.length;
resetGame();
}
// --- Drag-to-explode implementation ---
var dragActive = false;
var lastDragPoint = null;
var DRAG_EXPLODE_DIST = 80; // Minimum distance between explosions along drag
// Allow drag-to-explode at any time
game.down = function (x, y, obj) {
// Don't allow taps in top 100px (menu area)
if (y < 100) return;
// If tap is in bottom 150px, go to next level (leave 100px for bottom GUI)
if (y > 2732 - 150) {
nextLevel();
return;
}
dragActive = true;
lastDragPoint = {
x: x,
y: y
};
triggerExplosion(x, y, 0);
};
game.move = function (x, y, obj) {
if (!dragActive) return;
// Don't allow drag in top 100px (menu area)
if (y < 100) return;
// Only trigger new explosion if moved far enough from last explosion point
if (lastDragPoint) {
var dx = x - lastDragPoint.x;
var dy = y - lastDragPoint.y;
if (dx * dx + dy * dy >= DRAG_EXPLODE_DIST * DRAG_EXPLODE_DIST) {
lastDragPoint = {
x: x,
y: y
};
triggerExplosion(x, y, 0);
}
}
};
game.up = function (x, y, obj) {
dragActive = false;
lastDragPoint = null;
};
// Main update loop: respawn bricks if all are destroyed
game.update = function () {
// Check if all bricks are destroyed
var allDestroyed = true;
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col] && !bricks[row][col].isDestroyed) {
allDestroyed = false;
break;
}
}
if (!allDestroyed) break;
}
// If all destroyed and not animating, respawn wall
if (allDestroyed && !isAnimating) {
// Remove all old brick containers
for (var row = 0; row < bricks.length; row++) {
for (var col = 0; bricks[row] && col < bricks[row].length; col++) {
if (bricks[row][col]) {
bricks[row][col].destroy();
}
}
}
resetGame();
}
};
// Start game
resetGame();