/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BlockManager = Container.expand(function () { var self = Container.call(this); var blockRows = []; var index = 0; for (var i = 0; i < ROW_COUNT; i++) { addRow({ x: game.width / 2, y: LAVA_LINE - i * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN), index: index++ }); } blockRows[0].blocks[Math.floor(ROW_SPAN / 2)].onLit(true); self.update = function () { if (blockRows[0].y > game.height) { popRow(); } }; function addRow(settings) { var prevRow = blockRows[blockRows.length - 1]; var newRow = self.addChild(new BlockRow(settings)); blockRows.push(newRow); if (prevRow) { newRow.setDown(prevRow); prevRow.setUp(newRow); } } function popRow() { blockRows.shift().callDestroy(); blockRows[0].blocks.forEach(function (block) { if (block) { block.downBlock = undefined; } }); addRow({ x: game.width / 2, y: blockRows[blockRows.length - 1].y - BLOCK_SIZE * BLOCK_SCALE - BLOCK_MARGIN, index: index++, disabled: true }); adjustRowSpeed(); } return self; }); var ConfigContainer = Container.expand(function (config) { var self = Container.call(this); config = config || {}; self.destroyed = false; self.tags = {}; self.x = config.x || 0; self.y = config.y || 0; self.rotation = config.rotation || 0; self.alpha = config.alpha !== undefined ? config.alpha : 1.0; if (config.scale !== undefined || config.scaleX !== undefined || config.scaleY !== undefined) { var scaleX = config.scaleX !== undefined ? config.scaleX : config.scale !== undefined ? config.scale : 1; var scaleY = config.scaleY !== undefined ? config.scaleY : config.scale !== undefined ? config.scale : 1; self.scale.set(scaleX, scaleY); } self.callDestroy = function () { if (!self.destroyed) { self.destroyed = true; self.onDestroy(); self.destroy(); } }; self.onDestroy = function () {}; return self; }); var PointText = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var text = self.addChild(new BorderedText('+1', { anchorX: 0.5, anchorY: 0.5, size: 100 })); tween(self, { y: self.y - 50 }, { duration: 2000 }); LK.setTimeout(function () { tween(self, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { self.callDestroy(); } }); }, 1000); return self; }); var Light = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var lightShape = self.addChild(new Glow({ y: -LIGHT_OFFSET, width: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10, height: BLOCK_SIZE - 2 * LIGHT_OFFSET - 10, anchorX: 0.5, anchorY: 1, layers: 5, rangeX: 20, rangeY: 10, tint: 0xFFFFFF, scaleX: 0, scaleY: 0, asset: 'shapeEllipse', solid: true })); tween(lightShape, { scaleX: 1, scaleY: 1 }, { duration: LIGHT_GROW_SPEED + Math.random() * LIGHT_GROW_VARIANCE, onFinish: function onFinish() { if (self.parent) { config.callback(); } } }); return self; }); var LavaSlice = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); self.attachAsset('lava' + config.index, { anchorX: 0.5, anchorY: 0, width: LAVA_SLICE_WIDTH, tint: 0xFFA500 }); self.attachAsset('shapeBox', { width: LAVA_SLICE_WIDTH, height: 10, anchorX: 0.5, anchorY: 0, tint: 0xFF4D00 }); self.addChild(new Glow({ anchorX: 0.5, anchorY: 0.75, height: 20, rangeY: 150, width: 3 * LAVA_SLICE_WIDTH, alpha: 0.35, tint: 0xFF4D00 })); self.update = function () { self.y = Math.sin(LK.ticks * LAVA_BOB_PERIOD + config.index * LAVA_BOB_OFFSET) * LAVA_BOB_HEIGHT; if (Math.random() < 0.0025) { self.parent.particleContainer.addChild(new LavaParticle({ x: self.x + Math.random() * LAVA_SLICE_WIDTH - LAVA_SLICE_WIDTH / 2, y: self.y, scale: 1 + Math.random() * 0.5 // Random scale between 1 and 1.5 })); } }; return self; }); var LavaParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); // Attach a glow asset with specified properties self.rotation = Math.random() * Math.PI; // Random rotation between 0 and pi self.attachAsset('shapeBox', { anchorX: 0.5, anchorY: 0.5, width: 20, height: 20, tint: 0xFF4D00, alpha: 0.5 }); // Attach a smaller shapeBox with black tint and 0.5 alpha self.attachAsset('shapeBox', { anchorX: 0.5, anchorY: 0.5, width: 10, height: 10, tint: 0x000000, alpha: 0.25 }); // Set initial random velocities increased by a factor of 10 self.vx = (1 - 2 * Math.random()) * 10; // Random x velocity between 10 and -10 self.vy = (1 - 0.5 * Math.random()) * -8; // Random y velocity between -8 and -4 // Update function to apply gravity and movement self.update = function () { self.vy += 0.1; // Gravity effect self.vx *= 0.975; self.x += self.vx; self.y += self.vy; // Destroy the particle if it goes below the game height if (self.y > LAVA_BOB_HEIGHT) { self.callDestroy(); } }; if (Math.random() < 0.25) { var bubbleSounds = ['bubble1', 'bubble2', 'bubble3', 'bubble4', 'bubble5']; var randomBubbleSound = bubbleSounds[Math.floor(Math.random() * bubbleSounds.length)]; LK.getSound(randomBubbleSound).play(); } return self; }); var Lava = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); self.particleContainer = self.addChild(new Container()); var position = Math.round((-0.5 - LAVA_SLICE_COUNT / 2) * LAVA_SLICE_WIDTH); for (var i = 1; i <= LAVA_SLICE_COUNT; i++) { var lavaSlice = self.addChild(new LavaSlice({ x: position += LAVA_SLICE_WIDTH, index: i })); } // Function to play the 'flow' sound at random intervals between 5s to 10s function playFlowSound() { LK.getSound('flow').play(); var nextInterval = 5000 + Math.random() * 5000; // Random interval between 5000ms (5s) and 10000ms (10s) LK.setTimeout(playFlowSound, nextInterval); } // Start playing the 'flow' sound immediately playFlowSound(); return self; }); var Glow = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var layers = Math.max(2, config.layers || 10); var layerAlpha = 1 / layers; var widthStep = (config.rangeX || 0) * layerAlpha; var heightStep = (config.rangeY || 0) * layerAlpha; for (var i = 0; i < layers; i++) { self.attachAsset(config.asset || 'shapeBox', { width: config.width + widthStep * i, height: config.height + heightStep * i, anchorX: config.anchorX, anchorY: config.anchorY, tint: config.tint, alpha: i === 0 && config.solid ? 1 : layerAlpha }); } return self; }); /** * var config = { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || 0, * anchorY : Number || 1, * size : Number || TEXT_DEFAULT_SIZE, * font : String || TEXT_DEFAULT_FONT, * fill : String || TEXT_DEFAULT_FILL, * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedText = ConfigContainer.expand(function (text, config) { var self = ConfigContainer.call(this, config); config = config || {}; var anchorX = config.anchorX !== undefined ? config.anchorX : 0; var anchorY = config.anchorY !== undefined ? config.anchorY : 1; var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE; var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT; var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL; var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER; var mainAsset; var textAssets = []; ; self.setText = setText; self.setFill = setFill; ; function setText(newText) { for (var i = 0; i < textAssets.length; i++) { textAssets[i].setText(newText); } } function setFill(newFill) { textFill = newFill; mainAsset.fill = newFill; } function buildTextAssets(newText) { for (var i = 0; i < TEXT_OFFSETS.length; i++) { var main = i === TEXT_OFFSETS.length - 1; var textAsset = textAssets[i]; if (textAsset) { textAsset.destroy(); } textAsset = self.addChild(new Text2(newText, { fill: main ? textFill : borderFill, font: font, size: size })); textAsset.anchor = { x: anchorX, y: anchorY }; // NOTE: Cannot be set in config textAsset.x = TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config textAsset.y = TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT; // NOTE: Cannot be set in config textAssets[i] = textAsset; } mainAsset = textAssets[TEXT_OFFSETS.length - 1]; } ; buildTextAssets(text); return self; }); /** * var config = { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || .5, * anchorY : Number || .5, * scale : Number || undefined, * scaleX : Number || scale, * scaleY : Number || scale, * width : Number || undefined, // Auto-calculated if left undefined and height is set * height : Number || undefined, // Auto-calculated if left undefined and width is set * tint : String || 0xFFFFFF, // Not tinted by default * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedSymbol = ConfigContainer.expand(function (symbol, config) { var self = ConfigContainer.call(this, config); config = config || {}; var width = config.width !== undefined ? config.width : undefined; var height = config.height !== undefined ? config.height : undefined; var scale = config.scale !== undefined ? config.scale : undefined; var scaleX = config.scaleX !== undefined ? config.scaleX : scale; var scaleY = config.scaleY !== undefined ? config.scaleX : scale; var anchorX = config.anchorX !== undefined ? config.anchorX : .5; var anchorY = config.anchorY !== undefined ? config.anchorY : .5; var symbolTint = config.tint !== undefined ? config.tint : 0xFFFFFF; var borderTint = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER; var mainSymbol; var symbolAssets = []; ; self.setSymbol = buildSymbolAssets; self.setTint = setTint; ; function setTint(newTint) { // NOTE: Tinting is currently broken (cannot use string) // mainSymbol.tint = newTint; // symbolConfig.tint = newTint; } function buildSymbolAssets(newSymbol) { for (var i = 0; i < TEXT_OFFSETS.length; i++) { var main = i === TEXT_OFFSETS.length - 1; var symbolAsset = symbolAssets[i]; if (symbolAsset) { symbolAsset.destroy(); } symbolAsset = self.attachAsset(newSymbol, { // tint: main ? symbolTint : borderTint, tint: main ? 0xFFFFFF : 0x000000, // NOTE: Tinting is currently broken (cannot use string) x: TEXT_OFFSETS[i][0] * TEXT_BORDER_WEIGHT, y: TEXT_OFFSETS[i][1] * TEXT_BORDER_WEIGHT, anchorX: anchorX, anchorY: anchorY }); if (width !== undefined && height === undefined) { height = symbolAsset.height * (width / symbolAsset.width); } else if (height !== undefined && width === undefined) { width = symbolAsset.width * (height / symbolAsset.height); } symbolAsset.width = width; symbolAsset.height = height; if (scaleX !== undefined && scaleY !== undefined) { symbolAsset.scale.set(scaleX, scaleY); } symbolAssets[i] = symbolAsset; } mainSymbol = symbolAssets[TEXT_OFFSETS.length - 1]; } ; buildSymbolAssets(symbol); return self; }); var Border = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var radius = 70; var totalHeight = 0; var borderAssets = ['border1', 'border2']; while (totalHeight < game.height) { var randomAsset = borderAssets[Math.floor(Math.random() * borderAssets.length)]; var borderSegment = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0, y: totalHeight }); totalHeight += borderSegment.height; } var borderGear = self.attachAsset('borderGear', { width: 2 * radius, height: 2 * radius, anchorX: 0.5, anchorY: 0.5, y: LIGHT_LEVEL, rotation: Math.random() * Math.PI * 2 // Initialize with random rotation }); var borderLevel = self.attachAsset('borderLevel', { anchorX: 0.15, anchorY: 0.85, y: LIGHT_LEVEL, rotation: Math.PI / 4 // 45 degree rotation }); self.update = function () { borderGear.rotation += rowSpeed / radius; }; return self; }); var BlockSparkParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var shapeBox = self.attachAsset('shapeBox', { width: 10, height: 10, anchorX: 0.5, anchorY: 0.5, rotation: Math.random() * Math.PI // Random rotation between 0 and pi }); // Set initial random direction and speed var angle = Math.random() * 2 * Math.PI; var offset = Math.random() * 50; // Random offset between 0 and 50 self.x += Math.cos(angle) * offset; self.y += Math.sin(angle) * offset; self.vx = Math.cos(angle) * 10; self.vy = Math.sin(angle) * 10; // Update function to move the particle self.update = function () { self.vy += 0.5; // Apply gravity effect self.x += self.vx; self.y += self.vy; }; // Tween to fade out the particle tween(self, { alpha: 0 }, { duration: 350, onFinish: function onFinish() { self.callDestroy(); } }); return self; }); var BlockRow = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var blockClasses = generateBlockClasses(config.index); self.index = config.index; self.disabled = !!config.disabled; self.blocks = []; for (var i = 0; i < ROW_SPAN; i++) { var blockClass = blockClasses[i]; self.blocks[i] = self.addChild(new blockClass({ x: (0.5 + i - ROW_SPAN / 2) * (BLOCK_SIZE * BLOCK_SCALE + BLOCK_MARGIN), scale: BLOCK_SCALE, disabled: self.disabled, index: i, row: self })); } for (var i = 0; i < ROW_SPAN; i++) { var block = self.blocks[i]; if (i > 0) { block.leftBlock = self.blocks[i - 1]; } if (i < ROW_SPAN - 1) { block.rightBlock = self.blocks[i + 1]; } } self.update = function () { self.y += rowSpeed; if (self.disabled && self.y > LIGHT_LEVEL - BLOCK_SIZE * BLOCK_SCALE / 2) { self.disabled = false; self.blocks.forEach(function (block) { block.disabled = false; }); self.blocks.forEach(function (block) { if (!block.isRotating) { block.onSettle(); } }); } }; self.setUp = function (upRow) { for (var i = 0; i < ROW_SPAN; i++) { var selfBlock = self.blocks[i]; var upBlock = upRow.blocks[i]; upBlock.downBlock = selfBlock; selfBlock.upBlock = upBlock; } }; self.setDown = function (downRow) { for (var i = 0; i < ROW_SPAN; i++) { var selfBlock = self.blocks[i]; var downBlock = downRow.blocks[i]; downBlock.upBlock = selfBlock; selfBlock.downBlock = downBlock; } }; self.onDestroy = function () { self.blocks.forEach(function (block) { block.callDestroy(); }); }; return self; }); var BlockLitParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var shapeBox = self.attachAsset('particleBlockLit', { scaleX: 1.0, scaleY: 1.0, anchorX: 0.5, anchorY: 0.5, alpha: 0.1 }); tween(shapeBox, { scaleX: 2.0, scaleY: 2.0, alpha: 0.0 }, { duration: 350, easing: tween.linear, onFinish: function onFinish() { self.callDestroy(); } }); return self; }); var BlockBreakParticle = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var blockAssets = ['blockX1', 'blockX2', 'blockX3', 'blockX4']; var randomAsset = blockAssets[Math.floor(Math.random() * blockAssets.length)]; var shapeBox = self.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, rotation: Math.random() * Math.PI * 2 }); // Set initial random direction and speed var angle = Math.random() * 2 * Math.PI; var offset = 50 + Math.random() * 50; // Random offset between 0 and 50 self.x += Math.cos(angle) * offset; self.y += Math.sin(angle) * offset; self.vx = Math.cos(angle) * 10; self.vy = Math.sin(angle) * 10; // Update function to move the particle self.update = function () { self.vy += 0.5; // Apply gravity effect self.x += self.vx; self.y += self.vy; }; // Tween to fade out the particle tween(self, { alpha: 0 }, { duration: 350, onFinish: function onFinish() { self.callDestroy(); } }); return self; }); var Block = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); self.isRotating = false; self.disabled = config.disabled; self.row = config.row; self.index = config.index; self.orientation = config.orientation !== undefined ? config.orientation : Math.floor(4 * Math.random()); self.toLight = false; self.upPath = false; self.rightPath = false; self.downPath = false; self.leftPath = false; self.upBlock; self.rightBlock; self.downBlock; self.leftBlock; self.attachAsset('shapeBox', { width: BLOCK_SIZE, height: BLOCK_SIZE, anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.lightContainer = lightManager.addChild(new ConfigContainer({ scale: BLOCK_SCALE })); self.blockContainer = self.addChild(new ConfigContainer({ rotation: self.orientation * Math.PI / 2 })); self.rotate = function () { if (self.lit) { self.showLock(); } else if (!self.isRotating) { self.toLight = false; self.isRotating = true; LK.getSound('rotate').play(); self.lightContainer.removeChildren(); tween(self.blockContainer, { rotation: self.blockContainer.rotation + Math.PI / 2 }, { duration: BLOCK_ROTATE_SPEED, onFinish: function onFinish() { if (!self.destroyed) { self.isRotating = false; self.orientation = (self.orientation + 1) % 4; self.onSettle(); } } }); } }; self.update = function () { if (self.parent && !self.destroyed) { self.y = columns[self.index].y; self.lightContainer.x = self.x + self.parent.x; self.lightContainer.y = self.y + self.parent.y; } if (self.toLight && self.row.y >= LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) { self.toLight = false; self.onLit(); } }; self.down = function () { self.rotate(); tween(self.scale, { x: 0.9 * BLOCK_SCALE, y: 0.9 * BLOCK_SCALE }, { duration: BLOCK_ROTATE_SPEED / 2, onFinish: function onFinish() { tween(self.scale, { x: BLOCK_SCALE, y: BLOCK_SCALE }, { duration: BLOCK_ROTATE_SPEED / 2 }); } }); }; self.onLit = function (pointless) { if (self.row.y < LIGHT_LEVEL + BLOCK_SCALE * BLOCK_HALFSIZE) { self.toLight = true; } else if (!self.lit && !self.destroyed && (self.upPath || self.downPath || self.leftPath || self.rightPath)) { self.lit = true; self.lightContainer.removeChildren(); self.lightContainer.attachAsset('shapeEllipse', { width: BLOCK_SIZE - 2 * LIGHT_OFFSET, height: BLOCK_SIZE - 2 * LIGHT_OFFSET, anchorX: 0.5, anchorY: 0.5 }); if (self.upPath && (!self.upBlock || !self.upBlock.lit || !self.upBlock.downPath)) { makeGlow(0, -BLOCK_SIZE / 2 - BLOCK_MARGIN / 4); } if (self.rightPath && (!self.rightBlock || !self.rightBlock.lit || !self.rightBlock.leftPath)) { makeGlow(BLOCK_SIZE / 2 + BLOCK_MARGIN / 4, 0); } if (self.downPath && (!self.downBlock || !self.downBlock.lit || !self.downBlock.upPath)) { makeGlow(0, BLOCK_SIZE / 2 + BLOCK_MARGIN / 4); } if (self.leftPath && (!self.leftBlock || !self.leftBlock.lit || !self.leftBlock.rightPath)) { makeGlow(-BLOCK_SIZE / 2 - BLOCK_MARGIN / 4, 0); } if (!pointless) { LK.setScore(LK.getScore() + 1); scoreText.setText(LK.getScore()); game.addChild(new BlockLitParticle({ // Create a BlockLitParticle x: self.x + self.parent.x, y: self.y + self.parent.y, scale: BLOCK_SCALE })); game.addChild(new PointText({ x: self.x + self.parent.x, y: self.y + self.parent.y })); } lightSources += 1; LK.getSound('light').play(); self.onSettle(); } }; self.onSettle = function () { self.updatePaths(); if (!self.disabled) { var litRotationFactor = self.lit ? 0 : 1; var litPositionFactor = self.lit ? 1 : -1; [{ direction: 'up', rotation: 0, y: 1 }, { direction: 'right', rotation: 0.5, x: -1 }, { direction: 'down', rotation: 1, y: -1 }, { direction: 'left', rotation: 1.5, x: 1 }].forEach(function (item) { if (self[item.direction + 'Path']) { var block = self[item.direction + 'Block']; if (block && !block.disabled && block.lit !== self.lit && block[COMPLIMENTS[item.direction] + 'Path']) { (self.lit ? block : self).lightContainer.addChild(new Light({ x: (item.x || 0) * litPositionFactor * BLOCK_HALFSIZE, y: (item.y || 0) * litPositionFactor * BLOCK_HALFSIZE, rotation: Math.PI * (item.rotation + litRotationFactor), callback: self.lit ? block.onLit : self.onLit })); } } }); } }; self.showLock = function () { // Check and destroy existing lockSymbol before creating a new one if (self.lockSymbol) { self.lockSymbol.destroy(); } var lockSymbol = self.addChild(LK.getAsset('iconLock', { anchorX: 0.5, anchorY: 0.5, scaleX: 1 / self.scale.x, scaleY: 1 / self.scale.y })); // Play error sound if not already playing if (!errorSoundPlaying) { errorSoundPlaying = true; LK.getSound('error').play(); LK.setTimeout(function () { errorSoundPlaying = false; }, 500); } self.lockSymbol = lockSymbol; // Set a timeout to fade out the lockSymbol after 500ms LK.setTimeout(function () { tween(lockSymbol, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { lockSymbol.destroy(); self.lockSymbol = null; } }); }, 500); }; self.updatePaths = function () {}; function makeGlow(x, y) { var glow = self.lightContainer.addChild(new Glow({ x: x, y: y, width: LIGHT_SPILL_SIZE, height: LIGHT_SPILL_SIZE, anchorX: 0.5, anchorY: 0.5, rangeX: 20, rangeY: 20, layers: 4, solid: true, tint: 0xFFFFFF, alpha: 0 })); tween(glow, { alpha: 1 }, { duration: 250 }); } self.onDestroy = function () { if (self.lit) { lightSources -= 1; if (lightSources === 0) { LK.getSound('gong').play(); // Play the gong sound var gameOverText = game.addChild(new BorderedText("- Your Light is Dead -", { size: 150, anchorX: 0.5, anchorY: 0.5, x: game.width / 2, y: game.height / 4 })); LK.stopMusic(); // Stop the background music when the game ends LK.setTimeout(function () { // Delay the game over widget by 1 second LK.showGameOver(); }, 1000); } } if (self.lightContainer) { self.lightContainer.destroy(); } }; return self; }); var BlockX = Block.expand(function (config) { var self = Block.call(this, config); var shiftY = 2; self.upPath = true; self.rightPath = true; self.downPath = true; self.leftPath = true; self.blockContainer.attachAsset('blockX1', { x: -BLOCK_HALFSIZE, y: -BLOCK_HALFSIZE + shiftY, anchorX: 0, anchorY: 0 }); self.blockContainer.attachAsset('blockX2', { x: BLOCK_HALFSIZE, y: -BLOCK_HALFSIZE + shiftY, anchorX: 1, anchorY: 0 }); self.blockContainer.attachAsset('blockX3', { x: -BLOCK_HALFSIZE, y: BLOCK_HALFSIZE + shiftY, anchorX: 0, anchorY: 1 }); self.blockContainer.attachAsset('blockX4', { x: BLOCK_HALFSIZE, y: BLOCK_HALFSIZE + shiftY, anchorX: 1, anchorY: 1 }); return self; }); var BlockT = Block.expand(function (config) { var self = Block.call(this, config); self.blockContainer.attachAsset('blockT1', { x: -BLOCK_HALFSIZE, y: -BLOCK_HALFSIZE, anchorX: 0, anchorY: 0 }); self.blockContainer.attachAsset('blockT2', { x: BLOCK_HALFSIZE, y: -BLOCK_HALFSIZE, anchorX: 1, anchorY: 0 }); self.blockContainer.attachAsset('blockT3', { y: BLOCK_HALFSIZE, anchorX: 0.5, anchorY: 1 }); self.updatePaths = function () { self.downPath = self.orientation !== 0; self.leftPath = self.orientation !== 1; self.upPath = self.orientation !== 2; self.rightPath = self.orientation !== 3; }; self.updatePaths(); return self; }); var BlockLine = Block.expand(function (config) { var self = Block.call(this, config); self.blockContainer.attachAsset('blockLine1', { x: -BLOCK_HALFSIZE, anchorX: 0, anchorY: 0.5, height: BLOCK_SIZE }); self.blockContainer.attachAsset('blockLine2', { x: BLOCK_HALFSIZE, anchorX: 1, anchorY: 0.5, height: BLOCK_SIZE }); self.updatePaths = function () { var vertical = !(self.orientation % 2); self.upPath = vertical; self.downPath = vertical; self.leftPath = !vertical; self.rightPath = !vertical; }; self.updatePaths(); return self; }); var BlockL = Block.expand(function (config) { var self = Block.call(this, config); self.blockContainer.attachAsset('blockL1', { anchorX: 0.5, anchorY: 0.5, height: BLOCK_SIZE }); self.blockContainer.attachAsset('blockL2', { x: -BLOCK_HALFSIZE, y: BLOCK_HALFSIZE, anchorX: 0, anchorY: 1 }); self.updatePaths = function () { self.leftPath = self.orientation === 0 || self.orientation === 1; self.upPath = self.orientation === 1 || self.orientation === 2; self.rightPath = self.orientation === 2 || self.orientation === 3; self.downPath = self.orientation === 3 || self.orientation === 0; }; self.updatePaths(); return self; }); var BlockBlank = Block.expand(function (config) { var self = Block.call(this, config); var crackAsset; var crackLevel = 0; var blockBlankAssets = ['blockBlank1', 'blockBlank2', 'blockBlank3']; var randomAsset = blockBlankAssets[Math.floor(Math.random() * blockBlankAssets.length)]; self.blockContainer.attachAsset(randomAsset, { anchorX: 0.5, anchorY: 0.5, width: BLOCK_SIZE, height: BLOCK_SIZE }); self.rotate = function (force) { if (force || crackLevel > 0) { if (++crackLevel <= 4) { if (crackAsset) { crackAsset.destroy(); } if (!force) { LK.getSound('crack').play(); } crackAsset = self.blockContainer.attachAsset('crack' + crackLevel, { anchorX: 0.5, anchorY: 0.5, rotation: crackLevel === 1 ? Math.random() * Math.PI * 2 : 0 // Random rotation if crackLevel is 1 }); // Create BlockSparkParticles if (self.parent) { for (var i = 0; i < 2 * crackLevel; i++) { game.addChild(new BlockSparkParticle({ x: self.x + self.parent.x, y: self.y + self.parent.y })); } } } else { LK.getSound('break').play(); var blockClass = randomizeBlockClass({ index: self.row.index, blanks: ROW_SPAN // Prevent spawning blocks }); var newBlock = self.parent.addChild(new blockClass({ x: self.x, y: self.y, scale: BLOCK_SCALE, index: self.index, row: self.row })); self.row.blocks[self.index] = newBlock; // Update block references if (self.upBlock) { self.upBlock.downBlock = newBlock; newBlock.upBlock = self.upBlock; } if (self.downBlock) { self.downBlock.upBlock = newBlock; newBlock.downBlock = self.downBlock; } if (self.leftBlock) { self.leftBlock.rightBlock = newBlock; newBlock.leftBlock = self.leftBlock; } if (self.rightBlock) { self.rightBlock.leftBlock = newBlock; newBlock.rightBlock = self.rightBlock; } if (!self.disabled) { newBlock.onSettle(); } // Create BlockBreakParticles for (var i = 0; i < 6; i++) { game.addChild(new BlockBreakParticle({ x: self.x + self.parent.x, y: self.y + self.parent.y })); } self.callDestroy(); } } else { self.showLock(); } }; if (Math.random() < BLOCK_CRACK_CHANCE) { self.rotate(true); } return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Math constants / pre-calculations var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, SymbolText ; // Text settings var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, SymbolText var TEXT_BORDER_WEIGHT = 5; // Required by: BorderedText, BorderedSymbol, SymbolText var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, SymbolText var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_FONT = 'Arial'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_SIZE = 50; // Required by: BorderedText, SymbolText ; // Other settings var LAVA_LINE = game.height - 200; var LAVA_SLICE_COUNT = 18; var LAVA_SLICE_WIDTH = 128; var LAVA_BOB_HEIGHT = 10; var LAVA_BOB_OFFSET = Math.PI / 5; var LAVA_BOB_PERIOD = Math.PI / 60; var BLOCK_SCALE = 2.5; var BLOCK_SIZE = 100; var BLOCK_MARGIN = 20; var BLOCK_HALFSIZE = BLOCK_SIZE * 0.5; var BLOCK_CRACK_CHANCE = 0.45; var BLOCK_ROTATE_SPEED = 100; var LIGHT_LEVEL = 800; var LIGHT_GROW_SPEED = 4500; var LIGHT_GROW_VARIANCE = 1000; var LIGHT_SPILL_SIZE = 35; var LIGHT_OFFSET = 5; var ROW_SPAN = 7; var ROW_COUNT = 11; var ROW_SPEED_BASE = 0.2; var ROW_SPEED_INCREASE = 0.04; var ROW_SPEED_INCREASE_MIN = 0.01; var ROW_SPEED_INCREASE_FACTOR = 0.9; var COL_SLIP_MIN = 10; var COL_SLIP_MAX = 30; var COL_SLIP_TIME = 750; var COL_TIMEOUT_MIN = 1000; var COL_TIMEOUT_MAX = 10000; var COL_RISE_FACTOR = 0.2; var COMPLIMENTS = { up: 'down', right: 'left', down: 'up', left: 'right' }; var lightSources = 0; var rowSpeed = ROW_SPEED_BASE; var rowSpeedIncrease = ROW_SPEED_INCREASE; var errorSoundPlaying = false; var columns = []; for (var i = 0; i < ROW_SPAN; i++) { columns.push({ y: 0, timer: false, index: i }); } // Play background music on repeat when the game starts LK.playMusic('background', { loop: true }); game.update = function () { for (var i = 1; i < columns.length - 1; i++) { var column = columns[i]; if (!column.timer) { if (column.y > 0) { column.y = Math.max(0, column.y - rowSpeed * COL_RISE_FACTOR); } else { startColumnTimer(i); } } } }; var scoreText = new BorderedText('0', { size: 100, anchorX: 0.5, anchorY: 0 }); LK.gui.top.addChild(scoreText); var rowSpeedText = LK.gui.topRight.addChild(new Text2((rowSpeed * 60).toFixed(1), { size: 50, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 5 })); rowSpeedText.anchor.set(1.0, -0.5); var speedIcon = LK.gui.topRight.addChild(LK.getAsset('iconGear', { anchorX: 0.5, anchorY: 0.5, x: rowSpeedText.x - rowSpeedText.width - 40, y: rowSpeedText.height })); var iconRotate = LK.gui.topRight.addChild(new BorderedSymbol('iconRotate', { anchorX: 0.2, anchorY: 1.0, x: speedIcon.x, y: speedIcon.y })); var lightManager = game.addChild(new Container()); game.addChild(new Glow({ width: game.width, height: LIGHT_LEVEL, rangeY: 20, layers: 5, solid: true })); var blockManager = game.addChild(new BlockManager()); var leftBorder = game.addChild(new Border({ x: 30 })); var rightBorder = game.addChild(new Border({ x: game.width - 30, scaleX: -1 })); var lava = game.addChild(new Lava({ x: game.width / 2, y: LAVA_LINE })); game.addChild(new Glow({ x: game.width / 2, width: game.width, height: 200, anchorX: 0.5, anchorY: 0, rangeY: 200, tint: 0x000000, alpha: 2.0 })); var iconLight = game.addChild(LK.getAsset('iconLight', { x: game.width / 2, y: 100, anchorX: 0.5, anchorY: 0.5, tint: 0xFF4D00 })); function shuffle(array) { var currentIndex = array.length; while (currentIndex != 0) { var randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; var ref = [array[randomIndex], array[currentIndex]]; array[currentIndex] = ref[0]; array[randomIndex] = ref[1]; } return array; } function generateBlockClasses(index) { var settings = { index: index, blanks: 0, xs: 0 }; switch (index) { case 0: return [BlockBlank, BlockBlank, BlockBlank, BlockX, BlockBlank, BlockBlank, BlockBlank]; case 1: settings.blanks = ROW_SPAN; settings.xs = 1; return [BlockBlank, BlockBlank, randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), BlockBlank, BlockBlank]; case 2: settings.blanks = ROW_SPAN; settings.xs = 1; return [BlockBlank, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockX, randomizeBlockClass(settings), randomizeBlockClass(settings), BlockBlank]; default: var blockClasses = []; for (var i = 0; i < ROW_SPAN; i++) { blockClasses[i] = randomizeBlockClass(settings); } return shuffle(blockClasses); } } function adjustRowSpeed() { rowSpeed += rowSpeedIncrease; rowSpeedText.setText((rowSpeed * 60).toFixed(1)); rowSpeedIncrease = Math.max(ROW_SPEED_INCREASE_MIN, rowSpeedIncrease * ROW_SPEED_INCREASE_FACTOR); } function startColumnTimer(index) { var column = columns[index]; column.timer = true; var timeoutDuration = COL_TIMEOUT_MIN + Math.random() * (COL_TIMEOUT_MAX - COL_TIMEOUT_MIN); LK.setTimeout(function () { var targetY = COL_SLIP_MIN + Math.random() * (COL_SLIP_MAX - COL_SLIP_MIN); tween(column, { y: targetY }, { duration: COL_SLIP_TIME, easing: tween.easeIn, // Apply ease in for the tween onFinish: function onFinish() { column.timer = false; // Reset the timer to false after tween completes } }); }, timeoutDuration); } function randomizeBlockClass(settings) { var classes = [{ blockClass: BlockBlank, chance: Math.max(0, 1.5 - 0.5 * (settings.blanks || 0)) }, { blockClass: BlockT, chance: 1 }, { blockClass: BlockX, chance: Math.max(0, 1 - 1 * (settings.xs || 0)) }, { blockClass: BlockLine, chance: 1 }, { blockClass: BlockL, chance: 1 }]; var totalChance = classes.reduce(function (sum, item) { return sum + item.chance; }, 0); var randomValue = Math.random() * totalChance; var accumulatedChance = 0; var blockClass = BlockBlank; for (var i = 0; i < classes.length; i++) { accumulatedChance += classes[i].chance; if (randomValue < accumulatedChance) { blockClass = classes[i].blockClass; break; } } switch (blockClass) { case BlockBlank: settings.blanks = (settings.blanks || 0) + 1; break; case BlockX: settings.xs = (settings.xs || 0) + 1; break; } return blockClass; }
===================================================================
--- original.js
+++ change.js
@@ -788,8 +788,9 @@
anchorY: 0.5,
x: game.width / 2,
y: game.height / 4
}));
+ LK.stopMusic(); // Stop the background music when the game ends
LK.setTimeout(function () {
// Delay the game over widget by 1 second
LK.showGameOver();
}, 1000);
@@ -1027,9 +1028,9 @@
var BLOCK_SCALE = 2.5;
var BLOCK_SIZE = 100;
var BLOCK_MARGIN = 20;
var BLOCK_HALFSIZE = BLOCK_SIZE * 0.5;
-var BLOCK_CRACK_CHANCE = 0.3;
+var BLOCK_CRACK_CHANCE = 0.45;
var BLOCK_ROTATE_SPEED = 100;
var LIGHT_LEVEL = 800;
var LIGHT_GROW_SPEED = 4500;
var LIGHT_GROW_VARIANCE = 1000;
@@ -1041,9 +1042,9 @@
var ROW_SPEED_INCREASE = 0.04;
var ROW_SPEED_INCREASE_MIN = 0.01;
var ROW_SPEED_INCREASE_FACTOR = 0.9;
var COL_SLIP_MIN = 10;
-var COL_SLIP_MAX = 50;
+var COL_SLIP_MAX = 30;
var COL_SLIP_TIME = 750;
var COL_TIMEOUT_MIN = 1000;
var COL_TIMEOUT_MAX = 10000;
var COL_RISE_FACTOR = 0.2;