User prompt
Yapımcı ismini yazalım Luanity
User prompt
Menu tasarımını değiştir
User prompt
Bölüm geçişlerine reklam ekleyelim
User prompt
Zorluk artsın
User prompt
Özel gücü kaldır
User prompt
Oyuna özel bi güç ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Can't find variable: ü' in or related to this line: 'ü;' Line Number: 1007
Code edit (1 edits merged)
Please save this source code
User prompt
Select level değiştir
User prompt
Canlar bittiğinde süreli bi şekilde yenilensin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Seviyeleri 500 kadar çıkart
User prompt
Menuyu biraz daha aşşa indir
User prompt
Oyun ilk açıldığındada skor felan gözükmesin
User prompt
Menudeyken skor felan gözükmesin
User prompt
Oyunu biraz aşşa indir
User prompt
Oyunda can olsun 5 can olsun
User prompt
Oyundayken menuye girince arka plandan oyun kalksın
User prompt
Oyunda iken menu girince oyundan çıkış yapsın
User prompt
Şeker patlayınca patlama sesi çıksın
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Candy = Container.expand(function (type, gridX, gridY) {
var self = Container.call(this);
self.candyType = type;
self.gridX = gridX;
self.gridY = gridY;
self.isMoving = false;
self.isMarkedForDestroy = false;
var candyGraphics = self.attachAsset('candy_' + type, {
anchorX: 0.5,
anchorY: 0.5
});
self.moveTo = function (newGridX, newGridY, duration) {
self.gridX = newGridX;
self.gridY = newGridY;
self.isMoving = true;
var targetX = GRID_START_X + newGridX * CELL_SIZE + CELL_SIZE / 2;
var targetY = GRID_START_Y + newGridY * CELL_SIZE + CELL_SIZE / 2;
// Add slight anticipation before movement for falling candies
var isVerticalMove = Math.abs(self.y - targetY) > Math.abs(self.x - targetX);
if (isVerticalMove && targetY > self.y) {
// Falling motion - use bounce easing
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Add subtle landing effect
tween(self, {
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isMoving = false;
}
});
}
});
}
});
} else {
// Horizontal movement or upward movement
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isMoving = false;
}
});
}
};
self.destroy = function () {
self.isMarkedForDestroy = true;
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var GridCell = Container.expand(function (gridX, gridY) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
var cellGraphics = self.attachAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5
});
cellGraphics.alpha = 0.3;
return self;
});
var HoneyCandy = Container.expand(function (type, gridX, gridY) {
var self = Container.call(this);
self.candyType = type;
self.gridX = gridX;
self.gridY = gridY;
self.isMoving = false;
self.isMarkedForDestroy = false;
self.isSticky = true;
self.movesSlowly = true;
var candyGraphics = self.attachAsset('candy_' + type, {
anchorX: 0.5,
anchorY: 0.5
});
var honeyOverlay = self.attachAsset('honey_overlay', {
anchorX: 0.5,
anchorY: 0.5
});
honeyOverlay.alpha = 0.4;
self.moveTo = function (newGridX, newGridY, duration) {
self.gridX = newGridX;
self.gridY = newGridY;
self.isMoving = true;
var targetX = GRID_START_X + newGridX * CELL_SIZE + CELL_SIZE / 2;
var targetY = GRID_START_Y + newGridY * CELL_SIZE + CELL_SIZE / 2;
// Honey moves slower
var slowDuration = (duration || 300) * 1.5;
tween(self, {
x: targetX,
y: targetY
}, {
duration: slowDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isMoving = false;
}
});
};
self.destroy = function () {
self.isMarkedForDestroy = true;
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var LockedCandy = Container.expand(function (type, gridX, gridY, lockLevel) {
var self = Container.call(this);
self.candyType = type;
self.gridX = gridX;
self.gridY = gridY;
self.isMoving = false;
self.isMarkedForDestroy = false;
self.isLocked = true;
self.lockLevel = lockLevel || 1; // How many matches needed to unlock
var candyGraphics = self.attachAsset('candy_' + type, {
anchorX: 0.5,
anchorY: 0.5
});
var lockOverlay = self.attachAsset('locked_candy', {
anchorX: 0.5,
anchorY: 0.5
});
lockOverlay.alpha = 0.7;
self.unlock = function () {
self.lockLevel--;
if (self.lockLevel <= 0) {
self.isLocked = false;
tween(lockOverlay, {
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
};
self.destroy = function () {
self.isMarkedForDestroy = true;
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var StoneBlock = Container.expand(function (gridX, gridY, durability) {
var self = Container.call(this);
self.gridX = gridX;
self.gridY = gridY;
self.isMoving = false;
self.isMarkedForDestroy = false;
self.isObstacle = true;
self.durability = durability || 2;
var stoneGraphics = self.attachAsset('stone_block', {
anchorX: 0.5,
anchorY: 0.5
});
self.hit = function () {
self.durability--;
// Visual feedback for hit
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
if (self.durability <= 0) {
self.destroy();
}
};
self.destroy = function () {
self.isMarkedForDestroy = true;
createExplosionEffect(self.x, self.y);
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2a1810
});
/****
* Game Code
****/
// Decorative elements
// Beautiful gradient background layers
// Create beautiful gradient background
var backgroundContainer = new Container();
game.addChild(backgroundContainer);
// Create multiple layers for depth
var bgLayer1 = LK.getAsset('bg_gradient1', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
var bgLayer2 = LK.getAsset('bg_gradient2', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
var bgLayer3 = LK.getAsset('bg_pattern', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
backgroundContainer.addChild(bgLayer1);
backgroundContainer.addChild(bgLayer2);
backgroundContainer.addChild(bgLayer3);
// Set transparency for layering effect
bgLayer2.alpha = 0.7;
bgLayer3.alpha = 0.3;
var GRID_WIDTH = 10;
var GRID_HEIGHT = 10;
var CELL_SIZE = 150;
var GRID_START_X = (2048 - GRID_WIDTH * CELL_SIZE) / 2;
var GRID_START_Y = 750;
var CANDY_TYPES = ['green', 'blue', 'orange', 'yellow', 'red'];
var grid = [];
var candies = [];
var selectedCandy = null;
var draggedCandy = null;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var movesLeft = 20;
var currentScore = 0;
var targetScore = 1000;
var isProcessing = false;
var currentLevel = 1;
var maxLevel = 1;
var gameState = 'menu'; // 'menu', 'playing', 'settings'
var menuContainer = null;
var settingsContainer = null;
var soundEnabled = true;
var musicEnabled = true;
var masterVolume = 1.0;
var playerLives = 5;
var maxLives = 5;
var livesRegenerationTimer = null;
var lastLifeLostTime = null;
var livesRegenerationInterval = 300000; // 5 minutes in milliseconds
// Level configurations with challenging obstacles and requirements - Extended to 500 levels
var levelConfigs = [];
// Generate 500 levels with progressive difficulty
for (var levelNum = 1; levelNum <= 500; levelNum++) {
// Base difficulty scaling
var difficultyMultiplier = Math.floor((levelNum - 1) / 10) + 1;
var baseScore = 1000 + (levelNum - 1) * 150;
var baseMoves = Math.max(5, 20 - Math.floor(levelNum / 15));
// Obstacle scaling with caps to prevent impossibility
var stoneBlocks = Math.min(20, Math.floor(1 + levelNum * 0.4));
var lockedCandies = Math.min(15, Math.floor(levelNum * 0.3));
var honeyCandies = Math.min(12, Math.floor(levelNum * 0.25));
// Special milestone levels (every 50 levels) with increased difficulty
if (levelNum % 50 === 0) {
baseScore = Math.floor(baseScore * 1.5);
baseMoves = Math.max(3, baseMoves - 2);
stoneBlocks = Math.min(25, Math.floor(stoneBlocks * 1.3));
lockedCandies = Math.min(20, Math.floor(lockedCandies * 1.3));
honeyCandies = Math.min(15, Math.floor(honeyCandies * 1.3));
}
// Boss levels (every 100 levels) with maximum difficulty
if (levelNum % 100 === 0) {
baseScore = Math.floor(baseScore * 2);
baseMoves = Math.max(3, baseMoves - 3);
stoneBlocks = Math.min(30, Math.floor(stoneBlocks * 1.5));
lockedCandies = Math.min(25, Math.floor(lockedCandies * 1.5));
honeyCandies = Math.min(18, Math.floor(honeyCandies * 1.5));
}
levelConfigs.push({
level: levelNum,
targetScore: baseScore,
moves: baseMoves,
gridSize: 10,
obstacles: {
stoneBlocks: stoneBlocks,
lockedCandies: lockedCandies,
honeyCandies: honeyCandies
}
});
}
// Initialize grid cells
for (var y = 0; y < GRID_HEIGHT; y++) {
grid[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
var cell = new GridCell(x, y);
cell.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
cell.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
game.addChild(cell);
grid[y][x] = null;
}
}
// UI Elements - Score with button background
var scoreButtonBorder = LK.getAsset('score_button_border', {
anchorX: 0.5,
anchorY: 0.5
});
var scoreButtonBg = LK.getAsset('score_button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
var scoreButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5
});
// Create score button container
var scoreButtonContainer = new Container();
scoreButtonContainer.addChild(scoreButtonBorder);
scoreButtonContainer.addChild(scoreButtonBg);
scoreButtonContainer.addChild(scoreButtonHighlight);
// Position button elements
scoreButtonBorder.y = 0;
scoreButtonBg.y = -2;
scoreButtonHighlight.y = -5;
scoreButtonHighlight.alpha = 0.6;
// Add gradient effect with tween
tween(scoreButtonHighlight, {
alpha: 0.3
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(scoreButtonHighlight, {
alpha: 0.6
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0.5);
scoreButtonContainer.addChild(scoreText);
LK.gui.top.addChild(scoreButtonContainer);
scoreButtonContainer.y = 90;
scoreButtonContainer.visible = false; // Initially hidden when game opens in menu
// UI Elements - Moves with button background
var movesButtonBorder = LK.getAsset('score_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var movesButtonBg = LK.getAsset('score_button_bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var movesButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Create moves button container
var movesButtonContainer = new Container();
movesButtonContainer.addChild(movesButtonBorder);
movesButtonContainer.addChild(movesButtonBg);
movesButtonContainer.addChild(movesButtonHighlight);
// Position button elements
movesButtonBorder.y = 0;
movesButtonBg.y = -2;
movesButtonHighlight.y = -5;
movesButtonHighlight.alpha = 0.6;
// Add gradient effect with tween
tween(movesButtonHighlight, {
alpha: 0.3
}, {
duration: 2200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(movesButtonHighlight, {
alpha: 0.6
}, {
duration: 2200,
easing: tween.easeInOut
});
}
});
var movesText = new Text2('Moves: ' + movesLeft, {
size: 50,
fill: 0xFFFFFF
});
movesText.anchor.set(0.5, 0.5);
movesButtonContainer.addChild(movesText);
LK.gui.top.addChild(movesButtonContainer);
movesButtonContainer.y = 180;
movesButtonContainer.visible = false; // Initially hidden when game opens in menu
// UI Elements - Target with button background
var targetButtonBorder = LK.getAsset('score_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
var targetButtonBg = LK.getAsset('score_button_bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
var targetButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
// Create target button container
var targetButtonContainer = new Container();
targetButtonContainer.addChild(targetButtonBorder);
targetButtonContainer.addChild(targetButtonBg);
targetButtonContainer.addChild(targetButtonHighlight);
// Position button elements
targetButtonBorder.y = 0;
targetButtonBg.y = -2;
targetButtonHighlight.y = -5;
targetButtonHighlight.alpha = 0.6;
// Add gradient effect with tween
tween(targetButtonHighlight, {
alpha: 0.3
}, {
duration: 2400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(targetButtonHighlight, {
alpha: 0.6
}, {
duration: 2400,
easing: tween.easeInOut
});
}
});
var targetText = new Text2('Target: ' + targetScore, {
size: 40,
fill: 0xFFDD44
});
targetText.anchor.set(0.5, 0.5);
targetButtonContainer.addChild(targetText);
LK.gui.top.addChild(targetButtonContainer);
targetButtonContainer.y = 260;
targetButtonContainer.visible = false; // Initially hidden when game opens in menu
// UI Elements - Level with button background
var levelButtonBorder = LK.getAsset('score_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
var levelButtonBg = LK.getAsset('score_button_bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
var levelButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
// Create level button container
var levelButtonContainer = new Container();
levelButtonContainer.addChild(levelButtonBorder);
levelButtonContainer.addChild(levelButtonBg);
levelButtonContainer.addChild(levelButtonHighlight);
// Position button elements
levelButtonBorder.y = 0;
levelButtonBg.y = -2;
levelButtonHighlight.y = -5;
levelButtonHighlight.alpha = 0.6;
// Add gradient effect with tween
tween(levelButtonHighlight, {
alpha: 0.3
}, {
duration: 2600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(levelButtonHighlight, {
alpha: 0.6
}, {
duration: 2600,
easing: tween.easeInOut
});
}
});
var levelText = new Text2('Level: ' + currentLevel, {
size: 50,
fill: 0x00FF00
});
levelText.anchor.set(0.5, 0.5);
levelButtonContainer.addChild(levelText);
LK.gui.top.addChild(levelButtonContainer);
levelButtonContainer.y = 330;
levelButtonContainer.visible = false; // Initially hidden when game opens in menu
// Menu button
// UI Elements - Lives with button background
var livesButtonBorder = LK.getAsset('score_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
var livesButtonBg = LK.getAsset('score_button_bg', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
var livesButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
// Create lives button container
var livesButtonContainer = new Container();
livesButtonContainer.addChild(livesButtonBorder);
livesButtonContainer.addChild(livesButtonBg);
livesButtonContainer.addChild(livesButtonHighlight);
// Position button elements
livesButtonBorder.y = 0;
livesButtonBg.y = -2;
livesButtonHighlight.y = -5;
livesButtonHighlight.alpha = 0.6;
// Add gradient effect with tween
tween(livesButtonHighlight, {
alpha: 0.3
}, {
duration: 2800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(livesButtonHighlight, {
alpha: 0.6
}, {
duration: 2800,
easing: tween.easeInOut
});
}
});
var livesText = new Text2('Lives: ' + playerLives, {
size: 50,
fill: 0xFF4444
});
livesText.anchor.set(0.5, 0.5);
livesButtonContainer.addChild(livesText);
LK.gui.top.addChild(livesButtonContainer);
livesButtonContainer.y = 400;
livesButtonContainer.visible = false; // Initially hidden when game opens in menu
var menuButtonBorder = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
var menuButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.4
});
var menuButtonContainer = new Container();
menuButtonContainer.addChild(menuButtonBorder);
menuButtonContainer.addChild(menuButton);
var menuButtonText = new Text2('MENU', {
size: 40,
fill: 0xFFFFFF
});
menuButtonText.anchor.set(0.5, 0.5);
menuButtonContainer.addChild(menuButtonText);
menuButtonContainer.down = function (x, y, obj) {
if (gameState === 'playing') {
// Exit game and return to menu
gameState = 'menu';
// Reset game event handlers
game.move = null;
game.up = null;
// Show menu
showMenu();
} else {
showMenu();
}
};
LK.gui.top.addChild(menuButtonContainer);
menuButtonContainer.y = 470;
menuButtonContainer.visible = false; // Initially hidden when game opens in menu
function getRandomCandyType() {
return CANDY_TYPES[Math.floor(Math.random() * CANDY_TYPES.length)];
}
function loadProgress() {
var savedLevel = storage.currentLevel;
var savedMaxLevel = storage.maxLevel;
if (savedLevel) {
currentLevel = parseInt(savedLevel);
}
if (savedMaxLevel) {
maxLevel = parseInt(savedMaxLevel);
}
// Load settings
var savedSoundEnabled = storage.soundEnabled;
var savedMusicEnabled = storage.musicEnabled;
var savedMasterVolume = storage.masterVolume;
if (savedSoundEnabled !== undefined) {
soundEnabled = savedSoundEnabled === 'true';
}
if (savedMusicEnabled !== undefined) {
musicEnabled = savedMusicEnabled === 'true';
}
if (savedMasterVolume !== undefined) {
masterVolume = parseFloat(savedMasterVolume);
}
// Load lives
var savedLives = storage.playerLives;
if (savedLives !== undefined) {
playerLives = parseInt(savedLives);
}
}
function saveProgress() {
storage.currentLevel = currentLevel.toString();
storage.maxLevel = maxLevel.toString();
storage.playerLives = playerLives.toString();
}
function getCurrentLevelConfig() {
if (currentLevel <= levelConfigs.length) {
return levelConfigs[currentLevel - 1];
}
// Fallback for any level beyond 500 (shouldn't happen, but safety measure)
var obstacleCount = Math.min(30, currentLevel);
return {
level: currentLevel,
targetScore: 1000 + (currentLevel - 1) * 200,
moves: Math.max(3, 20 - Math.floor(currentLevel / 10)),
gridSize: 10,
obstacles: {
stoneBlocks: Math.min(30, obstacleCount),
lockedCandies: Math.min(25, Math.floor(obstacleCount * 0.8)),
honeyCandies: Math.min(18, Math.floor(obstacleCount * 0.6))
}
};
}
function createMenu() {
if (menuContainer) {
game.removeChild(menuContainer);
}
menuContainer = new Container();
game.addChild(menuContainer);
// Menu overlay background with gradient effect
var menuOverlay = LK.getAsset('menu_overlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.8
});
menuContainer.addChild(menuOverlay);
// Add floating animated background candies
for (var i = 0; i < 12; i++) {
var floatingCandy = LK.getAsset('candy_' + CANDY_TYPES[i % CANDY_TYPES.length], {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
scaleX: 0.4 + Math.random() * 0.3,
scaleY: 0.4 + Math.random() * 0.3,
rotation: Math.random() * Math.PI * 2
});
floatingCandy.alpha = 0.15 + Math.random() * 0.2;
menuContainer.addChild(floatingCandy);
// Animate floating motion
var animDuration = 4000 + Math.random() * 3000;
var targetX = Math.random() * 2048;
var targetY = Math.random() * 2732;
tween(floatingCandy, {
x: targetX,
y: targetY,
rotation: floatingCandy.rotation + Math.PI * 2
}, {
duration: animDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Continue animation loop
var newTargetX = Math.random() * 2048;
var newTargetY = Math.random() * 2732;
tween(floatingCandy, {
x: newTargetX,
y: newTargetY,
rotation: floatingCandy.rotation + Math.PI * 2
}, {
duration: animDuration,
easing: tween.easeInOut
});
}
});
}
// Add animated sparkles
for (var j = 0; j < 20; j++) {
var sparkle = LK.getAsset('sparkle', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.2 + Math.random() * 0.3
});
sparkle.alpha = 0.3 + Math.random() * 0.4;
menuContainer.addChild(sparkle);
// Twinkling animation
var twinkleDuration = 1500 + Math.random() * 2000;
tween(sparkle, {
alpha: 0.1,
scaleX: sparkle.scaleX * 0.3,
scaleY: sparkle.scaleY * 0.3
}, {
duration: twinkleDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sparkle, {
alpha: 0.3 + Math.random() * 0.4,
scaleX: 0.2 + Math.random() * 0.3,
scaleY: 0.2 + Math.random() * 0.3
}, {
duration: twinkleDuration,
easing: tween.easeInOut
});
}
});
}
// Game title with enhanced styling
var titleText = new Text2('CANDY CRUSH', {
size: 140,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 500;
titleText.scaleX = 0;
titleText.scaleY = 0;
menuContainer.addChild(titleText);
// Animate title entrance
tween(titleText, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
// Add pulsing glow effect
tween(titleText, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Start game button with enhanced styling
var startButtonBorder = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var startButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
var startButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.15,
scaleY: 1.15
});
var startButtonContainer = new Container();
startButtonContainer.addChild(startButtonBorder);
startButtonContainer.addChild(startButton);
startButtonContainer.addChild(startButtonHighlight);
startButtonContainer.x = 2048 / 2;
startButtonContainer.y = 900;
startButtonContainer.scaleX = 0;
startButtonContainer.scaleY = 0;
// Position button elements
startButtonBorder.y = 0;
startButton.y = -3;
startButtonHighlight.y = -6;
startButtonHighlight.alpha = 0.4;
var startText = new Text2('START GAME', {
size: 70,
fill: 0xFFFFFF
});
startText.anchor.set(0.5, 0.5);
startButtonContainer.addChild(startText);
// Animate button entrance
tween(startButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 600,
delay: 400,
easing: tween.easeOut
});
// Add pulsing highlight effect
tween(startButtonHighlight, {
alpha: 0.7
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButtonHighlight, {
alpha: 0.4
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
// Start button interaction with press animation
startButtonContainer.down = function (x, y, obj) {
tween(startButtonContainer, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(startButtonContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
startGame();
}
});
}
});
};
menuContainer.addChild(startButtonContainer);
// Level selection with enhanced styling
var levelSelectText = new Text2('SELECT LEVEL', {
size: 90,
fill: 0xFFDD44
});
levelSelectText.anchor.set(0.5, 0.5);
levelSelectText.x = 2048 / 2;
levelSelectText.y = 1100;
levelSelectText.scaleX = 0;
levelSelectText.scaleY = 0;
menuContainer.addChild(levelSelectText);
// Animate level select text
tween(levelSelectText, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 500,
delay: 800,
easing: tween.easeOut
});
// Add subtle glow animation
tween(levelSelectText, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 2500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(levelSelectText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 2500,
easing: tween.easeInOut
});
}
});
// Create level buttons with enhanced styling (show up to maxLevel, with pagination)
var buttonsPerRow = 5;
var buttonSize = 120;
var buttonSpacing = 150;
var startX = 2048 / 2 - (buttonsPerRow - 1) * buttonSpacing / 2;
var startY = 1300;
var maxVisibleLevels = 25; // Show 25 levels at a time (5 rows)
var levelPage = Math.floor((currentLevel - 1) / maxVisibleLevels);
var startLevel = levelPage * maxVisibleLevels + 1;
var endLevel = Math.min(startLevel + maxVisibleLevels - 1, maxLevel);
// Add navigation text if there are more levels
if (maxLevel > maxVisibleLevels) {
var pageText = new Text2('Levels ' + startLevel + '-' + endLevel + ' (Page ' + (levelPage + 1) + '/' + Math.ceil(maxLevel / maxVisibleLevels) + ')', {
size: 50,
fill: 0xFFDD44
});
pageText.anchor.set(0.5, 0.5);
pageText.x = 2048 / 2;
pageText.y = startY - 80;
menuContainer.addChild(pageText);
}
for (var i = startLevel; i <= endLevel; i++) {
var relativeIndex = i - startLevel;
var row = Math.floor((i - 1) / buttonsPerRow);
var col = (i - 1) % buttonsPerRow;
var levelButtonBorder = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.35,
scaleY: 0.35
});
var levelButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.35,
scaleY: 0.35
});
var levelButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.33,
scaleY: 0.33
});
var levelButtonContainer = new Container();
levelButtonContainer.addChild(levelButtonBorder);
levelButtonContainer.addChild(levelButton);
levelButtonContainer.addChild(levelButtonHighlight);
levelButtonContainer.x = startX + col * buttonSpacing;
levelButtonContainer.y = startY + row * 100;
levelButtonContainer.scaleX = 0;
levelButtonContainer.scaleY = 0;
// Position button elements
levelButtonBorder.y = 0;
levelButton.y = -2;
levelButtonHighlight.y = -4;
levelButtonHighlight.alpha = 0.3;
var levelNumText = new Text2(i.toString(), {
size: 45,
fill: i === currentLevel ? 0xFFDD44 : 0xFFFFFF
});
levelNumText.anchor.set(0.5, 0.5);
levelButtonContainer.addChild(levelNumText);
// Animate button entrance with stagger
var animDelay = 1000 + (i - 1) * 80;
tween(levelButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 300,
delay: animDelay,
easing: tween.easeOut
});
// Add gentle hover glow for current level
if (i === currentLevel) {
tween(levelButtonHighlight, {
alpha: 0.6
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(levelButtonHighlight, {
alpha: 0.3
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
// Store level number for button click
levelButtonContainer.levelNum = i;
levelButtonContainer.down = function (x, y, obj) {
// Add press animation
tween(this, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function () {
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function () {
currentLevel = this.levelNum;
startGame();
}.bind(this)
});
}.bind(this)
});
};
menuContainer.addChild(levelButtonContainer);
}
// Settings button with enhanced styling
var settingsButtonBorder = LK.getAsset('settings_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
var settingsButton = LK.getAsset('settings_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
var settingsButtonHighlight = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.95,
scaleY: 0.95
});
var settingsButtonContainer = new Container();
settingsButtonContainer.addChild(settingsButtonBorder);
settingsButtonContainer.addChild(settingsButton);
settingsButtonContainer.addChild(settingsButtonHighlight);
settingsButtonContainer.x = 2048 / 2;
settingsButtonContainer.y = 2100;
settingsButtonContainer.scaleX = 0;
settingsButtonContainer.scaleY = 0;
// Position button elements
settingsButtonBorder.y = 0;
settingsButton.y = -3;
settingsButtonHighlight.y = -6;
settingsButtonHighlight.alpha = 0.3;
var settingsText = new Text2('SETTINGS', {
size: 50,
fill: 0xFFFFFF
});
settingsText.anchor.set(0.5, 0.5);
settingsButtonContainer.addChild(settingsText);
// Animate button entrance
tween(settingsButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 400,
delay: 1400,
easing: tween.easeOut
});
// Add gentle glow animation
tween(settingsButtonHighlight, {
alpha: 0.6
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(settingsButtonHighlight, {
alpha: 0.3
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Settings button interaction
settingsButtonContainer.down = function (x, y, obj) {
tween(settingsButtonContainer, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(settingsButtonContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
showSettings();
}
});
}
});
};
menuContainer.addChild(settingsButtonContainer);
gameState = 'menu';
}
function startGame() {
if (menuContainer) {
game.removeChild(menuContainer);
menuContainer = null;
}
if (settingsContainer) {
game.removeChild(settingsContainer);
settingsContainer = null;
}
gameState = 'playing';
// Show UI elements when playing
scoreButtonContainer.visible = true;
movesButtonContainer.visible = true;
targetButtonContainer.visible = true;
levelButtonContainer.visible = true;
livesButtonContainer.visible = true;
menuButtonContainer.visible = true;
// Reset any custom event handlers from settings
game.move = null;
game.up = null;
initializeLevel();
// Start lives regeneration if we have lost lives
if (playerLives < maxLives) {
startLivesRegeneration();
}
}
function showMenu() {
gameState = 'menu';
// Reset game event handlers when returning to menu
game.move = null;
game.up = null;
// Hide UI elements when in menu
scoreButtonContainer.visible = false;
movesButtonContainer.visible = false;
targetButtonContainer.visible = false;
levelButtonContainer.visible = false;
livesButtonContainer.visible = false;
menuButtonContainer.visible = false;
// Remove settings container if it exists
if (settingsContainer) {
game.removeChild(settingsContainer);
settingsContainer = null;
}
// Clear all game elements when returning to menu from playing state
for (var i = candies.length - 1; i >= 0; i--) {
var candy = candies[i];
if (candy.parent) {
candy.parent.removeChild(candy);
}
}
candies = [];
// Reset grid
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
grid[y][x] = null;
}
}
// Stop lives regeneration when in menu
stopLivesRegeneration();
createMenu();
}
function showSettings() {
gameState = 'settings';
// Hide UI elements when in settings
scoreButtonContainer.visible = false;
movesButtonContainer.visible = false;
targetButtonContainer.visible = false;
levelButtonContainer.visible = false;
livesButtonContainer.visible = false;
menuButtonContainer.visible = false;
// Stop lives regeneration when in settings
stopLivesRegeneration();
createSettingsMenu();
}
function createSettingsMenu() {
if (settingsContainer) {
game.removeChild(settingsContainer);
}
settingsContainer = new Container();
game.addChild(settingsContainer);
// Settings overlay background
var settingsOverlay = LK.getAsset('menu_overlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
settingsContainer.addChild(settingsOverlay);
// Settings title
var settingsTitle = new Text2('SETTINGS', {
size: 120,
fill: 0xFFD700
});
settingsTitle.anchor.set(0.5, 0.5);
settingsTitle.x = 2048 / 2;
settingsTitle.y = 400;
settingsTitle.scaleX = 0;
settingsTitle.scaleY = 0;
settingsContainer.addChild(settingsTitle);
// Animate title entrance
tween(settingsTitle, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
var yPosition = 700;
var spacing = 150;
// Sound toggle
createToggleOption('SOUND EFFECTS', soundEnabled, yPosition, function (enabled) {
soundEnabled = enabled;
storage.soundEnabled = enabled.toString();
});
yPosition += spacing;
// Music toggle
createToggleOption('MUSIC', musicEnabled, yPosition, function (enabled) {
musicEnabled = enabled;
storage.musicEnabled = enabled.toString();
});
yPosition += spacing;
// Master volume slider
createVolumeSlider('MASTER VOLUME', masterVolume, yPosition, function (volume) {
masterVolume = volume;
storage.masterVolume = volume.toString();
});
yPosition += spacing + 100;
// Back button
var backButtonBorder = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var backButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var backButtonContainer = new Container();
backButtonContainer.addChild(backButtonBorder);
backButtonContainer.addChild(backButton);
backButtonContainer.x = 2048 / 2;
backButtonContainer.y = yPosition;
backButtonContainer.scaleX = 0;
backButtonContainer.scaleY = 0;
var backText = new Text2('BACK', {
size: 60,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButtonContainer.addChild(backText);
// Animate back button
tween(backButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 400,
delay: 800,
easing: tween.easeOut
});
backButtonContainer.down = function (x, y, obj) {
tween(backButtonContainer, {
scaleX: 0.75,
scaleY: 0.75
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(backButtonContainer, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
showMenu();
}
});
}
});
};
settingsContainer.addChild(backButtonContainer);
function createToggleOption(label, currentValue, yPos, callback) {
// Label text
var labelText = new Text2(label, {
size: 60,
fill: 0xFFFFFF
});
labelText.anchor.set(0, 0.5);
labelText.x = 400;
labelText.y = yPos;
labelText.alpha = 0;
settingsContainer.addChild(labelText);
// Toggle button
var toggleBorder = LK.getAsset('settings_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.6
});
var toggleButton = LK.getAsset(currentValue ? 'toggle_button_on' : 'toggle_button_off', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.6
});
var toggleContainer = new Container();
toggleContainer.addChild(toggleBorder);
toggleContainer.addChild(toggleButton);
toggleContainer.x = 1500;
toggleContainer.y = yPos;
toggleContainer.alpha = 0;
var toggleText = new Text2(currentValue ? 'ON' : 'OFF', {
size: 40,
fill: 0xFFFFFF
});
toggleText.anchor.set(0.5, 0.5);
toggleContainer.addChild(toggleText);
// Animate entrance
tween(labelText, {
alpha: 1
}, {
duration: 400,
delay: 400,
easing: tween.easeOut
});
tween(toggleContainer, {
alpha: 1
}, {
duration: 400,
delay: 500,
easing: tween.easeOut
});
toggleContainer.down = function (x, y, obj) {
var newValue = !currentValue;
currentValue = newValue;
// Update visual
toggleContainer.removeChild(toggleButton);
toggleButton = LK.getAsset(newValue ? 'toggle_button_on' : 'toggle_button_off', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 0.6
});
toggleContainer.addChild(toggleButton);
toggleText.setText(newValue ? 'ON' : 'OFF');
// Animate press
tween(toggleContainer, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(toggleContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
callback(newValue);
};
settingsContainer.addChild(toggleContainer);
}
function createVolumeSlider(label, currentValue, yPos, callback) {
// Label text
var labelText = new Text2(label, {
size: 60,
fill: 0xFFFFFF
});
labelText.anchor.set(0, 0.5);
labelText.x = 400;
labelText.y = yPos;
labelText.alpha = 0;
settingsContainer.addChild(labelText);
// Slider track
var sliderTrack = LK.getAsset('slider_track', {
anchorX: 0.5,
anchorY: 0.5
});
sliderTrack.x = 1400;
sliderTrack.y = yPos;
sliderTrack.alpha = 0;
settingsContainer.addChild(sliderTrack);
// Slider handle
var sliderHandle = LK.getAsset('slider_handle', {
anchorX: 0.5,
anchorY: 0.5
});
sliderHandle.x = 1400 - 100 + 200 * currentValue;
sliderHandle.y = yPos;
sliderHandle.alpha = 0;
settingsContainer.addChild(sliderHandle);
// Volume percentage text
var volumeText = new Text2(Math.round(currentValue * 100) + '%', {
size: 45,
fill: 0xFFDD44
});
volumeText.anchor.set(0.5, 0.5);
volumeText.x = 1600;
volumeText.y = yPos;
volumeText.alpha = 0;
settingsContainer.addChild(volumeText);
// Animate entrance
tween(labelText, {
alpha: 1
}, {
duration: 400,
delay: 400,
easing: tween.easeOut
});
tween(sliderTrack, {
alpha: 1
}, {
duration: 400,
delay: 500,
easing: tween.easeOut
});
tween(sliderHandle, {
alpha: 1
}, {
duration: 400,
delay: 600,
easing: tween.easeOut
});
tween(volumeText, {
alpha: 1
}, {
duration: 400,
delay: 700,
easing: tween.easeOut
});
var isDraggingSlider = false;
sliderHandle.down = function (x, y, obj) {
isDraggingSlider = true;
tween(sliderHandle, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut
});
};
game.move = function (x, y, obj) {
if (isDraggingSlider) {
var sliderX = Math.max(1300, Math.min(1500, x));
sliderHandle.x = sliderX;
var newValue = (sliderX - 1300) / 200;
volumeText.setText(Math.round(newValue * 100) + '%');
callback(newValue);
}
};
game.up = function (x, y, obj) {
if (isDraggingSlider) {
isDraggingSlider = false;
tween(sliderHandle, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
};
}
}
function startLivesRegeneration() {
// Only start regeneration if we have lost lives and timer isn't already running
if (playerLives < maxLives && !livesRegenerationTimer) {
livesRegenerationTimer = LK.setInterval(function () {
if (playerLives < maxLives) {
playerLives++;
livesText.setText('Lives: ' + playerLives);
saveProgress();
// Show life regenerated notification
var lifeRegenText = new Text2('Life Restored! ' + playerLives + '/' + maxLives, {
size: 60,
fill: 0x00FF00
});
lifeRegenText.anchor.set(0.5, 0.5);
lifeRegenText.x = 2048 / 2;
lifeRegenText.y = 2732 / 2 - 150;
lifeRegenText.alpha = 0;
game.addChild(lifeRegenText);
// Animate notification
tween(lifeRegenText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(lifeRegenText, {
alpha: 0,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
delay: 1200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (lifeRegenText.parent) {
lifeRegenText.parent.removeChild(lifeRegenText);
}
}
});
}
});
// Stop regeneration when max lives reached
if (playerLives >= maxLives) {
LK.clearInterval(livesRegenerationTimer);
livesRegenerationTimer = null;
}
} else {
// Stop timer if lives are full
LK.clearInterval(livesRegenerationTimer);
livesRegenerationTimer = null;
}
}, livesRegenerationInterval);
}
}
function stopLivesRegeneration() {
if (livesRegenerationTimer) {
LK.clearInterval(livesRegenerationTimer);
livesRegenerationTimer = null;
}
}
function initializeLevel() {
var config = getCurrentLevelConfig();
targetScore = config.targetScore;
movesLeft = config.moves;
currentScore = 0;
// Update UI
levelText.setText('Level: ' + currentLevel);
scoreText.setText('Score: 0');
movesText.setText('Moves: ' + movesLeft);
targetText.setText('Target: ' + targetScore);
livesText.setText('Lives: ' + playerLives);
// Clear existing candies
for (var i = candies.length - 1; i >= 0; i--) {
var candy = candies[i];
if (candy.parent) {
candy.parent.removeChild(candy);
}
}
candies = [];
// Reset grid
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
grid[y][x] = null;
}
}
// Initialize new grid
initializeGrid();
// Set up game event handlers for playing state
setupGameHandlers();
}
function completeLevel() {
if (currentLevel >= maxLevel) {
maxLevel = currentLevel + 1;
}
currentLevel++;
saveProgress();
// Show level complete message briefly before starting next level
var levelCompleteText = new Text2('Level Complete!', {
size: 80,
fill: 0x00FF00
});
levelCompleteText.anchor.set(0.5, 0.5);
levelCompleteText.x = 2048 / 2;
levelCompleteText.y = 2732 / 2;
game.addChild(levelCompleteText);
// Animate text
levelCompleteText.scaleX = 0;
levelCompleteText.scaleY = 0;
tween(levelCompleteText, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelCompleteText, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 500,
delay: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (levelCompleteText.parent) {
levelCompleteText.parent.removeChild(levelCompleteText);
}
initializeLevel();
}
});
}
});
}
function createCandy(x, y, type) {
type = type || getRandomCandyType();
var candy = new Candy(type, x, y);
candy.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
candy.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
game.addChild(candy);
candies.push(candy);
grid[y][x] = candy;
return candy;
}
function placeObstacles(config) {
if (!config.obstacles) {
return;
}
var obstacles = config.obstacles;
var placedPositions = [];
var totalObstacles = obstacles.stoneBlocks + obstacles.lockedCandies + obstacles.honeyCandies;
// Place stone blocks first (highest priority)
for (var i = 0; i < obstacles.stoneBlocks; i++) {
var placed = false;
var attempts = 0;
while (!placed && attempts < 50) {
var x = Math.floor(Math.random() * GRID_WIDTH);
var y = Math.floor(Math.random() * GRID_HEIGHT);
var posKey = x + ',' + y;
// Avoid corners and center, prefer edges and strategic positions
if (!placedPositions[posKey] && grid[y][x] && !(x < 2 && y < 2) && !(x > GRID_WIDTH - 3 && y < 2) && !(x < 2 && y > GRID_HEIGHT - 3) && !(x > GRID_WIDTH - 3 && y > GRID_HEIGHT - 3)) {
// Remove existing candy
var existingCandy = grid[y][x];
if (existingCandy && existingCandy.parent) {
existingCandy.parent.removeChild(existingCandy);
var candyIndex = candies.indexOf(existingCandy);
if (candyIndex > -1) {
candies.splice(candyIndex, 1);
}
}
// Create stone block
var stone = new StoneBlock(x, y, 1 + Math.floor(currentLevel / 3));
stone.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
stone.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
game.addChild(stone);
grid[y][x] = stone;
placedPositions[posKey] = true;
placed = true;
}
attempts++;
}
}
// Place locked candies
for (var j = 0; j < obstacles.lockedCandies; j++) {
var placed = false;
var attempts = 0;
while (!placed && attempts < 50) {
var x = Math.floor(Math.random() * GRID_WIDTH);
var y = Math.floor(Math.random() * GRID_HEIGHT);
var posKey = x + ',' + y;
if (!placedPositions[posKey] && grid[y][x] && !grid[y][x].isObstacle) {
// Convert existing candy to locked candy
var existingCandy = grid[y][x];
var type = existingCandy.candyType;
if (existingCandy.parent) {
existingCandy.parent.removeChild(existingCandy);
var candyIndex = candies.indexOf(existingCandy);
if (candyIndex > -1) {
candies.splice(candyIndex, 1);
}
}
var lockedCandy = new LockedCandy(type, x, y, 1 + Math.floor(currentLevel / 4));
lockedCandy.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
lockedCandy.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
game.addChild(lockedCandy);
candies.push(lockedCandy);
grid[y][x] = lockedCandy;
placedPositions[posKey] = true;
placed = true;
}
attempts++;
}
}
// Place honey candies
for (var k = 0; k < obstacles.honeyCandies; k++) {
var placed = false;
var attempts = 0;
while (!placed && attempts < 50) {
var x = Math.floor(Math.random() * GRID_WIDTH);
var y = Math.floor(Math.random() * GRID_HEIGHT);
var posKey = x + ',' + y;
if (!placedPositions[posKey] && grid[y][x] && !grid[y][x].isObstacle && !grid[y][x].isLocked) {
// Convert existing candy to honey candy
var existingCandy = grid[y][x];
var type = existingCandy.candyType;
if (existingCandy.parent) {
existingCandy.parent.removeChild(existingCandy);
var candyIndex = candies.indexOf(existingCandy);
if (candyIndex > -1) {
candies.splice(candyIndex, 1);
}
}
var honeyCandy = new HoneyCandy(type, x, y);
honeyCandy.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
honeyCandy.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
game.addChild(honeyCandy);
candies.push(honeyCandy);
grid[y][x] = honeyCandy;
placedPositions[posKey] = true;
placed = true;
}
attempts++;
}
}
}
function getLevelSpecificCandyType(x, y, level) {
// Define specific patterns for each level
switch (level) {
case 1:
// Level 1: More green and blue candies in corners
if (x < 3 && y < 3 || x > 6 && y > 6) {
return Math.random() < 0.6 ? Math.random() < 0.5 ? 'green' : 'blue' : getRandomCandyType();
}
break;
case 2:
// Level 2: Checkerboard pattern influence with green and yellow
if ((x + y) % 2 === 0) {
return Math.random() < 0.5 ? Math.random() < 0.5 ? 'green' : 'yellow' : getRandomCandyType();
}
break;
case 3:
// Level 3: Center focus with purple and orange
var centerDistance = Math.abs(x - 4.5) + Math.abs(y - 4.5);
if (centerDistance < 4) {
return Math.random() < 0.7 ? Math.random() < 0.5 ? 'purple' : 'orange' : getRandomCandyType();
}
break;
case 4:
// Level 4: Diagonal pattern with orange, green, and red
if (Math.abs(x - y) < 2 || Math.abs(x + y - 9) < 2) {
var candyChoice = Math.random();
if (candyChoice < 0.33) {
return 'orange';
} else if (candyChoice < 0.66) {
return 'green';
} else if (candyChoice < 0.8) {
return 'red';
} else {
return getRandomCandyType();
}
}
break;
case 5:
// Level 5: Border emphasis with blue and yellow
if (x < 2 || x > 7 || y < 2 || y > 7) {
return Math.random() < 0.7 ? Math.random() < 0.5 ? 'blue' : 'yellow' : getRandomCandyType();
}
break;
case 6:
// Level 6: Cross pattern with blue, orange, and red
if (x === 4 || x === 5 || y === 4 || y === 5) {
var candyChoice = Math.random();
if (candyChoice < 0.33) {
return 'blue';
} else if (candyChoice < 0.66) {
return 'orange';
} else if (candyChoice < 0.8) {
return 'red';
} else {
return getRandomCandyType();
}
}
break;
case 7:
// Level 7: Ring pattern with orange and green
var ringDistance = Math.max(Math.abs(x - 4.5), Math.abs(y - 4.5));
if (ringDistance > 2 && ringDistance < 5) {
return Math.random() < 0.6 ? Math.random() < 0.5 ? 'orange' : 'green' : getRandomCandyType();
}
break;
case 8:
// Level 8: Spiral influence with blue and yellow
var spiralValue = (x * 3 + y * 2) % 7;
if (spiralValue < 3) {
return Math.random() < 0.7 ? Math.random() < 0.5 ? 'blue' : 'yellow' : getRandomCandyType();
}
break;
case 9:
// Level 9: Scattered clusters with yellow, green, and red
if (x % 3 === 0 && y % 3 === 0 || x % 3 === 2 && y % 3 === 2) {
var candyChoice = Math.random();
if (candyChoice < 0.33) {
return 'yellow';
} else if (candyChoice < 0.66) {
return 'green';
} else if (candyChoice < 0.8) {
return 'red';
} else {
return getRandomCandyType();
}
}
break;
case 10:
// Level 10: Complex pattern with all colors but emphasis on green and orange
if ((x + y) % 4 < 2) {
return Math.random() < 0.5 ? Math.random() < 0.5 ? 'green' : 'orange' : getRandomCandyType();
}
break;
default:
// For levels beyond 10, create dynamic patterns based on level number
var patternType = level % 5;
switch (patternType) {
case 0:
// Diagonal emphasis
if (Math.abs(x - y) < 3) {
return Math.random() < 0.6 ? CANDY_TYPES[level % CANDY_TYPES.length] : getRandomCandyType();
}
break;
case 1:
// Corner concentration
if (x < 3 && y < 3 || x > 6 && y > 6 || x < 3 && y > 6 || x > 6 && y < 3) {
return Math.random() < 0.7 ? CANDY_TYPES[(level + 1) % CANDY_TYPES.length] : getRandomCandyType();
}
break;
case 2:
// Center ring
var centerDist = Math.max(Math.abs(x - 4.5), Math.abs(y - 4.5));
if (centerDist > 1 && centerDist < 4) {
return Math.random() < 0.6 ? CANDY_TYPES[(level + 2) % CANDY_TYPES.length] : getRandomCandyType();
}
break;
case 3:
// Checkerboard influence
if ((x + y + level) % 3 === 0) {
return Math.random() < 0.7 ? CANDY_TYPES[(level + 3) % CANDY_TYPES.length] : getRandomCandyType();
}
break;
case 4:
// Random clusters
if ((x * y + level) % 11 < 4) {
return Math.random() < 0.6 ? CANDY_TYPES[(level + 4) % CANDY_TYPES.length] : getRandomCandyType();
}
break;
}
break;
}
return getRandomCandyType();
}
function initializeGrid() {
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH; x++) {
var type;
var attempts = 0;
do {
// Use level-specific candy type generation
type = getLevelSpecificCandyType(x, y, currentLevel);
attempts++;
if (attempts > 10) {
// Fallback to completely random if level pattern is too restrictive
type = getRandomCandyType();
break;
}
} while (wouldCreateMatch(x, y, type));
createCandy(x, y, type);
}
}
// Place obstacles after initial candy generation
var config = getCurrentLevelConfig();
placeObstacles(config);
}
function wouldCreateMatch(x, y, type) {
var horizontalCount = 1;
var verticalCount = 1;
// Check horizontal
var i = x - 1;
while (i >= 0 && grid[y][i] && grid[y][i].candyType === type) {
horizontalCount++;
i--;
}
i = x + 1;
while (i < GRID_WIDTH && grid[y][i] && grid[y][i].candyType === type) {
horizontalCount++;
i++;
}
// Check vertical
i = y - 1;
while (i >= 0 && grid[i][x] && grid[i][x].candyType === type) {
verticalCount++;
i--;
}
i = y + 1;
while (i < GRID_HEIGHT && grid[i][x] && grid[i][x].candyType === type) {
verticalCount++;
i++;
}
return horizontalCount >= 3 || verticalCount >= 3;
}
function findMatches() {
var matches = [];
var processed = [];
for (var y = 0; y < GRID_HEIGHT; y++) {
processed[y] = [];
for (var x = 0; x < GRID_WIDTH; x++) {
processed[y][x] = false;
}
}
// Find horizontal matches
for (var y = 0; y < GRID_HEIGHT; y++) {
for (var x = 0; x < GRID_WIDTH - 2; x++) {
if (!grid[y][x] || processed[y][x]) {
continue;
}
var type = grid[y][x].candyType;
var matchLength = 1;
var startX = x;
while (x + matchLength < GRID_WIDTH && grid[y][x + matchLength] && grid[y][x + matchLength].candyType === type) {
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
if (!processed[y][startX + i]) {
matches.push(grid[y][startX + i]);
processed[y][startX + i] = true;
}
}
}
}
}
// Find vertical matches
for (var x = 0; x < GRID_WIDTH; x++) {
for (var y = 0; y < GRID_HEIGHT - 2; y++) {
if (!grid[y][x] || processed[y][x]) {
continue;
}
var type = grid[y][x].candyType;
var matchLength = 1;
var startY = y;
while (y + matchLength < GRID_HEIGHT && grid[y + matchLength][x] && grid[y + matchLength][x].candyType === type) {
matchLength++;
}
if (matchLength >= 3) {
for (var i = 0; i < matchLength; i++) {
if (!processed[startY + i][x]) {
matches.push(grid[startY + i][x]);
processed[startY + i][x] = true;
}
}
}
}
}
return matches;
}
function createExplosionEffect(x, y) {
// Create multiple particles for explosion effect
var particleCount = 8 + Math.floor(Math.random() * 4);
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('explosion_particle', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 0.8 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.4
});
game.addChild(particle);
// Random direction and distance
var angle = Math.PI * 2 * i / particleCount + (Math.random() - 0.5) * 0.5;
var distance = 60 + Math.random() * 40;
var targetX = x + Math.cos(angle) * distance;
var targetY = y + Math.sin(angle) * distance;
// Animate particle explosion
tween(particle, {
x: targetX,
y: targetY,
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 400 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle.parent) {
particle.parent.removeChild(particle);
}
}
});
}
// Create star particles for extra sparkle
var starCount = 4 + Math.floor(Math.random() * 3);
for (var j = 0; j < starCount; j++) {
var star = LK.getAsset('explosion_star', {
anchorX: 0.5,
anchorY: 0.5,
x: x + (Math.random() - 0.5) * 40,
y: y + (Math.random() - 0.5) * 40,
rotation: Math.random() * Math.PI * 2
});
game.addChild(star);
// Animate star particles
tween(star, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0,
rotation: star.rotation + Math.PI * 2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
if (star.parent) {
star.parent.removeChild(star);
}
}
});
}
}
function createEnhancedExplosionEffect(x, y) {
// Create larger, more intense explosion for special matches
var particleCount = 15 + Math.floor(Math.random() * 8);
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('explosion_particle', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
scaleX: 1.2 + Math.random() * 0.8,
scaleY: 1.2 + Math.random() * 0.8
});
game.addChild(particle);
// Random direction and larger distance
var angle = Math.PI * 2 * i / particleCount + (Math.random() - 0.5) * 0.7;
var distance = 80 + Math.random() * 60;
var targetX = x + Math.cos(angle) * distance;
var targetY = y + Math.sin(angle) * distance;
// Animate particle explosion with more dramatic effect
tween(particle, {
x: targetX,
y: targetY,
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 600 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (particle.parent) {
particle.parent.removeChild(particle);
}
}
});
}
// Create more star particles
var starCount = 8 + Math.floor(Math.random() * 6);
for (var j = 0; j < starCount; j++) {
var star = LK.getAsset('explosion_star', {
anchorX: 0.5,
anchorY: 0.5,
x: x + (Math.random() - 0.5) * 80,
y: y + (Math.random() - 0.5) * 80,
rotation: Math.random() * Math.PI * 2,
scaleX: 1.5,
scaleY: 1.5
});
game.addChild(star);
// Animate star particles with more dramatic effect
tween(star, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0,
rotation: star.rotation + Math.PI * 4
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (star.parent) {
star.parent.removeChild(star);
}
}
});
}
}
function showScorePopup(score, isSpecial) {
var scorePopup = new Text2('+' + score, {
size: isSpecial ? 100 : 70,
fill: isSpecial ? 0xFFD700 : 0x00FF00
});
scorePopup.anchor.set(0.5, 0.5);
scorePopup.x = 2048 / 2 + (Math.random() - 0.5) * 200;
scorePopup.y = 2732 / 2 + (Math.random() - 0.5) * 200;
scorePopup.scaleX = 0;
scorePopup.scaleY = 0;
game.addChild(scorePopup);
// Animate score popup
tween(scorePopup, {
scaleX: 1.2,
scaleY: 1.2,
y: scorePopup.y - 100,
alpha: 1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scorePopup, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 300,
delay: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (scorePopup.parent) {
scorePopup.parent.removeChild(scorePopup);
}
}
});
}
});
}
function clearMatches(matches) {
if (matches.length === 0) {
return;
}
// Play explosion sound when candies are cleared
if (soundEnabled) {
var explosionSound = LK.getSound('explosion');
if (explosionSound) {
explosionSound.play();
}
}
if (soundEnabled) {
var matchSound = LK.getSound('match');
if (matchSound) {
matchSound.play();
}
}
// Handle matches with combo multiplier
var baseScore = matches.length * 50;
var comboMultiplier = game.comboMultiplier || 1;
var bonusScore = baseScore * comboMultiplier;
currentScore += bonusScore;
scoreText.setText('Score: ' + currentScore);
// Show score popup for significant matches
if (matches.length >= 4 || comboMultiplier > 1) {
showScorePopup(bonusScore, matches.length >= 4);
}
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
// Handle locked candies - unlock instead of destroying
if (candy.isLocked) {
candy.unlock();
if (candy.lockLevel > 0) {
continue; // Don't destroy if still locked
}
}
// Create enhanced explosion effect for larger matches
if (matches.length >= 4) {
createEnhancedExplosionEffect(candy.x, candy.y);
} else {
createExplosionEffect(candy.x, candy.y);
}
// Check adjacent cells for obstacles to damage
var adjacentPositions = [{
x: candy.gridX - 1,
y: candy.gridY
}, {
x: candy.gridX + 1,
y: candy.gridY
}, {
x: candy.gridX,
y: candy.gridY - 1
}, {
x: candy.gridX,
y: candy.gridY + 1
}];
for (var j = 0; j < adjacentPositions.length; j++) {
var pos = adjacentPositions[j];
if (pos.x >= 0 && pos.x < GRID_WIDTH && pos.y >= 0 && pos.y < GRID_HEIGHT) {
var adjacentCell = grid[pos.y][pos.x];
if (adjacentCell && adjacentCell.isObstacle && adjacentCell.hit) {
adjacentCell.hit();
if (adjacentCell.isMarkedForDestroy) {
grid[pos.y][pos.x] = null;
}
}
}
}
grid[candy.gridY][candy.gridX] = null;
candy.destroy();
// Remove from candies array
var index = candies.indexOf(candy);
if (index > -1) {
candies.splice(index, 1);
}
}
}
function applyGravity() {
var moved = false;
var animationsToWait = [];
for (var x = 0; x < GRID_WIDTH; x++) {
var writeY = GRID_HEIGHT - 1;
for (var y = GRID_HEIGHT - 1; y >= 0; y--) {
if (grid[y][x] && !grid[y][x].isMarkedForDestroy) {
if (y !== writeY) {
grid[writeY][x] = grid[y][x];
grid[y][x] = null;
var fallDistance = writeY - y;
var animDuration = 150 + fallDistance * 50; // Longer fall = longer animation
if (grid[writeY][x] && grid[writeY][x].moveTo) {
grid[writeY][x].moveTo(x, writeY, animDuration);
}
moved = true;
}
writeY--;
}
}
// Fill empty spaces at top with staggered animation
for (var emptyY = writeY; emptyY >= 0; emptyY--) {
var newCandy = createCandy(x, emptyY, getRandomCandyType());
var dropDistance = writeY - emptyY + 1;
newCandy.y = GRID_START_Y - dropDistance * CELL_SIZE + CELL_SIZE / 2;
var dropAnimDuration = 200 + dropDistance * 60;
newCandy.moveTo(x, emptyY, dropAnimDuration);
// Add bounce effect for new candies
tween(newCandy, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: dropAnimDuration / 2,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(newCandy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: dropAnimDuration / 2,
easing: tween.easeIn
});
}
});
moved = true;
}
}
return moved;
}
function areAdjacent(candy1, candy2) {
// Check if candies are valid before checking adjacency
if (!candy1 || !candy2 || candy1.isMarkedForDestroy || candy2.isMarkedForDestroy) {
return false;
}
var dx = Math.abs(candy1.gridX - candy2.gridX);
var dy = Math.abs(candy1.gridY - candy2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapCandies(candy1, candy2) {
// Check if candies are valid before swapping
if (!candy1 || !candy2 || candy1.isMarkedForDestroy || candy2.isMarkedForDestroy) {
return false;
}
// Temporarily swap in grid to test for matches
var tempGridX1 = candy1.gridX;
var tempGridY1 = candy1.gridY;
var tempGridX2 = candy2.gridX;
var tempGridY2 = candy2.gridY;
// Update grid positions temporarily
grid[candy1.gridY][candy1.gridX] = candy2;
grid[candy2.gridY][candy2.gridX] = candy1;
candy1.gridX = tempGridX2;
candy1.gridY = tempGridY2;
candy2.gridX = tempGridX1;
candy2.gridY = tempGridY1;
// Check if this swap creates matches
var matches = findMatches();
var willCreateMatches = matches.length > 0;
// If no matches will be created, revert the temporary swap
if (!willCreateMatches) {
grid[tempGridY1][tempGridX1] = candy1;
grid[tempGridY2][tempGridX2] = candy2;
candy1.gridX = tempGridX1;
candy1.gridY = tempGridY1;
candy2.gridX = tempGridX2;
candy2.gridY = tempGridY2;
return false;
}
// If matches will be created, perform the actual visual swap for both candies
candy1.moveTo(tempGridX2, tempGridY2, 200);
candy2.moveTo(tempGridX1, tempGridY1, 200);
return true;
}
function processMatches() {
if (isProcessing) {
return;
}
isProcessing = true;
// Track combo multiplier
if (!game.comboMultiplier) {
game.comboMultiplier = 1;
}
if (!game.comboCount) {
game.comboCount = 0;
}
LK.setTimeout(function () {
var matches = findMatches();
if (matches.length > 0) {
// Increase combo count for cascading matches
game.comboCount++;
if (game.comboCount > 1) {
game.comboMultiplier = Math.min(game.comboCount, 5); // Max 5x multiplier
// Show combo text
showComboText(game.comboMultiplier);
}
clearMatches(matches);
LK.setTimeout(function () {
if (applyGravity()) {
LK.setTimeout(function () {
isProcessing = false;
processMatches(); // Check for cascading matches
}, 500); // Slightly longer delay for better visual flow
} else {
isProcessing = false;
// Reset combo after no more matches
game.comboMultiplier = 1;
game.comboCount = 0;
checkGameState();
}
}, 350); // Longer delay between match clearing and gravity
} else {
isProcessing = false;
// Reset combo when no matches found
game.comboMultiplier = 1;
game.comboCount = 0;
checkGameState();
}
}, 200); // Faster initial processing
}
function showComboText(multiplier) {
var comboText = new Text2('COMBO x' + multiplier + '!', {
size: 80,
fill: 0xFFD700
});
comboText.anchor.set(0.5, 0.5);
comboText.x = 2048 / 2;
comboText.y = 2732 / 2 - 200;
comboText.scaleX = 0;
comboText.scaleY = 0;
game.addChild(comboText);
// Animate combo text
tween(comboText, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboText, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 400,
delay: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (comboText.parent) {
comboText.parent.removeChild(comboText);
}
}
});
}
});
}
function checkGameState() {
if (currentScore >= targetScore) {
completeLevel();
return;
}
if (movesLeft <= 0) {
// Decrease lives instead of immediate game over
playerLives--;
livesText.setText('Lives: ' + playerLives);
lastLifeLostTime = Date.now();
saveProgress();
// Start lives regeneration timer when lives are lost
startLivesRegeneration();
if (playerLives <= 0) {
// Game over when no lives left
LK.setTimeout(function () {
// Reset lives to max when game over
playerLives = maxLives;
saveProgress();
showMenu();
}, 2000);
LK.showGameOver();
} else {
// Show lives lost message and restart level
var livesLostText = new Text2('Life Lost! ' + playerLives + ' Lives Remaining', {
size: 70,
fill: 0xFF4444
});
livesLostText.anchor.set(0.5, 0.5);
livesLostText.x = 2048 / 2;
livesLostText.y = 2732 / 2;
game.addChild(livesLostText);
// Animate text
livesLostText.scaleX = 0;
livesLostText.scaleY = 0;
tween(livesLostText, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(livesLostText, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 500,
delay: 1500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (livesLostText.parent) {
livesLostText.parent.removeChild(livesLostText);
}
initializeLevel(); // Restart the same level
}
});
}
});
}
return;
}
}
function setupGameHandlers() {
// Set up the main game event handlers
game.down = function (x, y, obj) {
if (isProcessing) {
return;
}
var gridX = Math.floor((x - GRID_START_X) / CELL_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (gridX < 0 || gridX >= GRID_WIDTH || gridY < 0 || gridY >= GRID_HEIGHT) {
selectedCandy = null;
return;
}
var clickedCandy = grid[gridY][gridX];
if (!clickedCandy || clickedCandy.isMoving || clickedCandy.isMarkedForDestroy) {
selectedCandy = null;
return;
}
// Start drag functionality
draggedCandy = clickedCandy;
isDragging = false;
dragStartX = x;
dragStartY = y;
if (selectedCandy === null) {
selectedCandy = clickedCandy;
selectedCandy.scaleX = 1.1;
selectedCandy.scaleY = 1.1;
} else if (selectedCandy === clickedCandy) {
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
selectedCandy = null;
} else if (areAdjacent(selectedCandy, clickedCandy)) {
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
// Try swap - only proceed if it will create matches
var swapSuccessful = swapCandies(selectedCandy, clickedCandy);
if (swapSuccessful) {
if (soundEnabled) {
LK.getSound('swap').play();
}
LK.setTimeout(function () {
movesLeft--;
movesText.setText('Moves: ' + movesLeft);
processMatches();
selectedCandy = null;
}, 250);
} else {
// No swap occurred because no matches would be created
selectedCandy = null;
}
} else {
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
selectedCandy = clickedCandy;
selectedCandy.scaleX = 1.1;
selectedCandy.scaleY = 1.1;
}
};
game.move = function (x, y, obj) {
if (!draggedCandy || isProcessing) {
return;
}
var dragDistance = Math.sqrt((x - dragStartX) * (x - dragStartX) + (y - dragStartY) * (y - dragStartY));
if (dragDistance > 30 && !isDragging) {
isDragging = true;
// Scale up dragged candy for visual feedback
tween(draggedCandy, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut
});
}
if (isDragging) {
// Move candy with finger/mouse
draggedCandy.x = GRID_START_X + draggedCandy.gridX * CELL_SIZE + CELL_SIZE / 2 + (x - dragStartX);
draggedCandy.y = GRID_START_Y + draggedCandy.gridY * CELL_SIZE + CELL_SIZE / 2 + (y - dragStartY);
}
};
game.up = function (x, y, obj) {
if (!draggedCandy) {
return;
}
if (isDragging) {
// Reset candy visual state
tween(draggedCandy, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
// Determine target grid position based on drag direction
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var targetGridX = draggedCandy.gridX;
var targetGridY = draggedCandy.gridY;
// Check drag direction and distance
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal drag
if (Math.abs(deltaX) > 50) {
if (deltaX > 0 && draggedCandy.gridX < GRID_WIDTH - 1) {
targetGridX = draggedCandy.gridX + 1;
} else if (deltaX < 0 && draggedCandy.gridX > 0) {
targetGridX = draggedCandy.gridX - 1;
}
}
} else {
// Vertical drag
if (Math.abs(deltaY) > 50) {
if (deltaY > 0 && draggedCandy.gridY < GRID_HEIGHT - 1) {
targetGridY = draggedCandy.gridY + 1;
} else if (deltaY < 0 && draggedCandy.gridY > 0) {
targetGridY = draggedCandy.gridY - 1;
}
}
}
// Reset candy position
draggedCandy.x = GRID_START_X + draggedCandy.gridX * CELL_SIZE + CELL_SIZE / 2;
draggedCandy.y = GRID_START_Y + draggedCandy.gridY * CELL_SIZE + CELL_SIZE / 2;
// Perform swap if valid target
if ((targetGridX !== draggedCandy.gridX || targetGridY !== draggedCandy.gridY) && targetGridX >= 0 && targetGridX < GRID_WIDTH && targetGridY >= 0 && targetGridY < GRID_HEIGHT) {
var targetCandy = grid[targetGridY][targetGridX];
if (targetCandy && !targetCandy.isMoving) {
// Clear any previous selection
if (selectedCandy) {
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
}
// Perform swap - only if it will create matches
var swapSuccessful = swapCandies(draggedCandy, targetCandy);
if (swapSuccessful) {
if (soundEnabled) {
LK.getSound('swap').play();
}
LK.setTimeout(function () {
movesLeft--;
movesText.setText('Moves: ' + movesLeft);
processMatches();
}, 250);
}
}
}
}
// Reset drag state
draggedCandy = null;
isDragging = false;
selectedCandy = null;
};
}
// Add decorative candy elements floating in background
var decorations = [];
for (var i = 0; i < 8; i++) {
var decoration = LK.getAsset('candy_decoration', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
scaleX: 0.5 + Math.random() * 0.5,
scaleY: 0.5 + Math.random() * 0.5
});
decoration.alpha = 0.2 + Math.random() * 0.3;
game.addChild(decoration);
decorations.push(decoration);
// Animate floating motion
var animDuration = 3000 + Math.random() * 2000;
var targetY = decoration.y + (Math.random() - 0.5) * 400;
tween(decoration, {
y: targetY,
rotation: Math.random() * Math.PI * 2
}, {
duration: animDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart animation
var newTargetY = decoration.y + (Math.random() - 0.5) * 400;
tween(decoration, {
y: newTargetY,
rotation: decoration.rotation + Math.PI * 2
}, {
duration: animDuration,
easing: tween.easeInOut
});
}
});
}
// Add sparkle effects
var sparkles = [];
for (var j = 0; j < 15; j++) {
var sparkle = LK.getAsset('sparkle', {
anchorX: 0.5,
anchorY: 0.5,
x: Math.random() * 2048,
y: Math.random() * 2732,
scaleX: 0.3 + Math.random() * 0.4,
scaleY: 0.3 + Math.random() * 0.4
});
sparkle.alpha = 0.4 + Math.random() * 0.6;
game.addChild(sparkle);
sparkles.push(sparkle);
// Twinkling animation
var twinkleDuration = 1000 + Math.random() * 1500;
tween(sparkle, {
alpha: 0.1,
scaleX: sparkle.scaleX * 0.5,
scaleY: sparkle.scaleY * 0.5
}, {
duration: twinkleDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sparkle, {
alpha: 0.4 + Math.random() * 0.6,
scaleX: 0.3 + Math.random() * 0.4,
scaleY: 0.3 + Math.random() * 0.4
}, {
duration: twinkleDuration,
easing: tween.easeInOut
});
}
});
}
// Initialize the game
loadProgress();
createMenu(); ===================================================================
--- original.js
+++ change.js
@@ -964,9 +964,8 @@
});
levelSelectText.anchor.set(0.5, 0.5);
levelSelectText.x = 2048 / 2;
levelSelectText.y = 1100;
- ü;
levelSelectText.scaleX = 0;
levelSelectText.scaleY = 0;
menuContainer.addChild(levelSelectText);
// Animate level select text
Modern App Store icon, high definition, square with rounded corners, for a game titled "Candy Match Saga" and with the description "A match-3 puzzle game where players swap candies to create matching lines, clear objectives, and progress through challenging levels.". No text on icon!
Mavi şeker resmi. In-Game asset. 2d. High contrast. No shadows
Sarı şeker. In-Game asset. 2d. High contrast. No shadows
Kırmızı şeker. In-Game asset. 2d. High contrast. No shadows
Yeşil şeker. In-Game asset. 2d. High contrast. No shadows
Turuncu şeker. In-Game asset. 2d. High contrast. No shadows