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