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
****/
// Create beautiful gradient background
// Beautiful gradient background layers
// Decorative elements
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 = 600000; // 10 minutes in milliseconds - doubled regeneration time
// 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 - significantly increased
var difficultyMultiplier = Math.floor((levelNum - 1) / 5) + 1;
var baseScore = 1500 + (levelNum - 1) * 200; // Increased from 1000 + 150
var baseMoves = Math.max(3, 18 - Math.floor(levelNum / 8)); // Reduced from 20 and faster decrease
// Obstacle scaling with caps to prevent impossibility
var stoneBlocks = Math.min(25, Math.floor(2 + levelNum * 0.5)); // Increased from 1 + 0.4
var lockedCandies = Math.min(20, Math.floor(levelNum * 0.4)); // Increased from 0.3
var honeyCandies = Math.min(15, Math.floor(levelNum * 0.3)); // Increased from 0.25
// Special milestone levels (every 50 levels) with increased difficulty
if (levelNum % 50 === 0) {
baseScore = Math.floor(baseScore * 1.8); // Increased from 1.5
baseMoves = Math.max(2, baseMoves - 3); // Reduced from 3 and increased penalty
stoneBlocks = Math.min(30, Math.floor(stoneBlocks * 1.4)); // Increased from 1.3
lockedCandies = Math.min(25, Math.floor(lockedCandies * 1.4)); // Increased from 1.3
honeyCandies = Math.min(20, Math.floor(honeyCandies * 1.4)); // Increased from 1.3
}
// Boss levels (every 100 levels) with maximum difficulty
if (levelNum % 100 === 0) {
baseScore = Math.floor(baseScore * 2.5); // Increased from 2
baseMoves = Math.max(2, baseMoves - 4); // Reduced from 3 and increased penalty
stoneBlocks = Math.min(35, Math.floor(stoneBlocks * 1.6)); // Increased from 1.5
lockedCandies = Math.min(30, Math.floor(lockedCandies * 1.6)); // Increased from 1.5
honeyCandies = Math.min(25, Math.floor(honeyCandies * 1.6)); // Increased from 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);
// Create dynamic gradient background with multiple layers
var gradientLayer1 = LK.getAsset('bg_gradient1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.9
});
var gradientLayer2 = LK.getAsset('bg_gradient2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.7
});
var gradientLayer3 = LK.getAsset('bg_pattern', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.4
});
menuContainer.addChild(gradientLayer1);
menuContainer.addChild(gradientLayer2);
menuContainer.addChild(gradientLayer3);
// Animate background layers with subtle movement
tween(gradientLayer2, {
x: 50,
y: 30
}, {
duration: 8000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(gradientLayer2, {
x: -30,
y: -20
}, {
duration: 8000,
easing: tween.easeInOut
});
}
});
tween(gradientLayer3, {
x: -40,
y: 25
}, {
duration: 10000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(gradientLayer3, {
x: 20,
y: -15
}, {
duration: 10000,
easing: tween.easeInOut
});
}
});
// Create modern card-based layout with rounded corners effect
var mainCard = LK.getAsset('menu_overlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0.95,
scaleY: 0.9,
alpha: 0.85
});
menuContainer.addChild(mainCard);
// Add animated border effect around main card
var borderEffect = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 15,
scaleY: 12,
alpha: 0.3
});
menuContainer.addChild(borderEffect);
// Animate border glow
tween(borderEffect, {
alpha: 0.6,
scaleX: 15.2,
scaleY: 12.2
}, {
duration: 3000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(borderEffect, {
alpha: 0.3,
scaleX: 15,
scaleY: 12
}, {
duration: 3000,
easing: tween.easeInOut
});
}
});
// Floating geometric shapes for modern look
for (var i = 0; i < 8; i++) {
var shape = LK.getAsset('grid_cell', {
anchorX: 0.5,
anchorY: 0.5,
x: 200 + Math.random() * 1648,
y: 200 + Math.random() * 2332,
scaleX: 0.3 + Math.random() * 0.4,
scaleY: 0.3 + Math.random() * 0.4,
rotation: Math.random() * Math.PI * 2
});
shape.alpha = 0.1 + Math.random() * 0.15;
menuContainer.addChild(shape);
// Slow rotating animation for geometric shapes
var rotationDuration = 15000 + Math.random() * 10000;
tween(shape, {
rotation: shape.rotation + Math.PI * 2,
x: shape.x + (Math.random() - 0.5) * 300,
y: shape.y + (Math.random() - 0.5) * 300
}, {
duration: rotationDuration,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(shape, {
rotation: shape.rotation + Math.PI * 2,
x: 200 + Math.random() * 1648,
y: 200 + Math.random() * 2332
}, {
duration: rotationDuration,
easing: tween.easeInOut
});
}
});
}
// Modern minimalist candy accents
for (var j = 0; j < 6; j++) {
var candyAccent = LK.getAsset('candy_' + CANDY_TYPES[j % CANDY_TYPES.length], {
anchorX: 0.5,
anchorY: 0.5,
x: 150 + j * 320,
y: 150 + j % 2 * 2400,
scaleX: 0.6,
scaleY: 0.6
});
candyAccent.alpha = 0.4;
candyAccent.rotation = j * Math.PI / 3;
menuContainer.addChild(candyAccent);
// Gentle floating animation for candy accents
tween(candyAccent, {
y: candyAccent.y + (Math.random() - 0.5) * 100,
rotation: candyAccent.rotation + Math.PI / 4
}, {
duration: 4000 + Math.random() * 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(candyAccent, {
y: candyAccent.y - (Math.random() - 0.5) * 100,
rotation: candyAccent.rotation + Math.PI / 4
}, {
duration: 4000 + Math.random() * 2000,
easing: tween.easeInOut
});
}
});
}
// Modern typography - Main title with shadow effect
var titleShadow = new Text2('SWEET MATCH', {
size: 160,
fill: 0x000000
});
titleShadow.anchor.set(0.5, 0.5);
titleShadow.x = 2048 / 2 + 8;
titleShadow.y = 450 + 8;
titleShadow.alpha = 0.3;
menuContainer.addChild(titleShadow);
var titleText = new Text2('SWEET MATCH', {
size: 160,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 450;
titleText.scaleX = 0;
titleText.scaleY = 0;
menuContainer.addChild(titleText);
// Modern subtitle
var subtitleText = new Text2('Premium Puzzle Experience', {
size: 55,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = 550;
subtitleText.alpha = 0;
menuContainer.addChild(subtitleText);
// Developer credit
var developerText = new Text2('By Luanity', {
size: 45,
fill: 0xFFD700
});
developerText.anchor.set(0.5, 0.5);
developerText.x = 2048 / 2;
developerText.y = 620;
developerText.alpha = 0;
menuContainer.addChild(developerText);
// Animate title with modern entrance
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeInOut
});
}
});
// Animate subtitle
tween(subtitleText, {
alpha: 0.8,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
delay: 600,
easing: tween.easeOut
});
// Animate developer credit
tween(developerText, {
alpha: 0.9,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
delay: 800,
easing: tween.easeOut
});
// Create modern button container with card design
var buttonCard = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1366,
scaleX: 2.5,
scaleY: 8,
alpha: 0.2
});
menuContainer.addChild(buttonCard);
// Main action button - redesigned
var playButtonBorder = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.6
});
var playButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.6
});
var playButtonGlow = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.35,
scaleY: 1.55
});
var playButtonContainer = new Container();
playButtonContainer.addChild(playButtonBorder);
playButtonContainer.addChild(playButton);
playButtonContainer.addChild(playButtonGlow);
playButtonContainer.x = 2048 / 2;
playButtonContainer.y = 850;
playButtonContainer.scaleX = 0;
playButtonContainer.scaleY = 0;
// Position button elements
playButtonBorder.y = 0;
playButton.y = -4;
playButtonGlow.y = -8;
playButtonGlow.alpha = 0.5;
var playText = new Text2('PLAY NOW', {
size: 75,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playButtonContainer.addChild(playText);
// Modern button entrance animation
tween(playButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 800,
delay: 1000,
easing: tween.easeOut
});
// Enhanced glow effect
tween(playButtonGlow, {
alpha: 0.8,
scaleX: 1.4,
scaleY: 1.6
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playButtonGlow, {
alpha: 0.5,
scaleX: 1.35,
scaleY: 1.55
}, {
duration: 2000,
easing: tween.easeInOut
});
}
});
// Modern press interaction
playButtonContainer.down = function (x, y, obj) {
tween(playButtonContainer, {
scaleX: 0.93,
scaleY: 0.93
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playButtonContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
startGame();
}
});
}
});
};
menuContainer.addChild(playButtonContainer);
// Level selection section with modern design
var levelSectionTitle = new Text2('LEVEL SELECT', {
size: 70,
fill: 0xFFDD44
});
levelSectionTitle.anchor.set(0.5, 0.5);
levelSectionTitle.x = 2048 / 2;
levelSectionTitle.y = 1100;
levelSectionTitle.alpha = 0;
menuContainer.addChild(levelSectionTitle);
tween(levelSectionTitle, {
alpha: 1,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
delay: 1200,
easing: tween.easeOut
});
// Create level grid with modern card-based design
var buttonsPerRow = 5;
var buttonSpacing = 140;
var startX = 2048 / 2 - (buttonsPerRow - 1) * buttonSpacing / 2;
var startY = 1250;
var maxVisibleLevels = 20; // Show 20 levels (4 rows)
var levelPage = Math.floor((currentLevel - 1) / maxVisibleLevels);
var startLevel = levelPage * maxVisibleLevels + 1;
var endLevel = Math.min(startLevel + maxVisibleLevels - 1, maxLevel);
// Page indicator with modern styling
if (maxLevel > maxVisibleLevels) {
var pageIndicator = new Text2('Page ' + (levelPage + 1) + ' of ' + Math.ceil(maxLevel / maxVisibleLevels), {
size: 45,
fill: 0xCCCCCC
});
pageIndicator.anchor.set(0.5, 0.5);
pageIndicator.x = 2048 / 2;
pageIndicator.y = startY - 60;
pageIndicator.alpha = 0;
menuContainer.addChild(pageIndicator);
tween(pageIndicator, {
alpha: 0.8
}, {
duration: 500,
delay: 1400,
easing: tween.easeOut
});
}
// Modern level buttons with card design
for (var i = startLevel; i <= endLevel; i++) {
var row = Math.floor((i - startLevel) / buttonsPerRow);
var col = (i - startLevel) % buttonsPerRow;
// Level card background
var levelCard = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.32,
scaleY: 0.45
});
var levelButton = LK.getAsset('menu_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.32,
scaleY: 0.45
});
var levelGlow = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.42
});
var levelButtonContainer = new Container();
levelButtonContainer.addChild(levelCard);
levelButtonContainer.addChild(levelButton);
levelButtonContainer.addChild(levelGlow);
levelButtonContainer.x = startX + col * buttonSpacing;
levelButtonContainer.y = startY + row * 120;
levelButtonContainer.scaleX = 0;
levelButtonContainer.scaleY = 0;
// Position elements
levelCard.y = 0;
levelButton.y = -2;
levelGlow.y = -4;
levelGlow.alpha = i === currentLevel ? 0.6 : 0.2;
// Level number with modern typography
var levelNumText = new Text2(i.toString(), {
size: 40,
fill: i === currentLevel ? 0xFFD700 : 0xFFFFFF
});
levelNumText.anchor.set(0.5, 0.5);
levelButtonContainer.addChild(levelNumText);
// Staggered entrance animation
var animDelay = 1400 + (i - startLevel) * 100;
tween(levelButtonContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 400,
delay: animDelay,
easing: tween.easeOut
});
// Current level highlighting
if (i === currentLevel) {
tween(levelGlow, {
alpha: 0.8,
scaleX: 0.32,
scaleY: 0.44
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(levelGlow, {
alpha: 0.6,
scaleX: 0.3,
scaleY: 0.42
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
}
// Modern interaction
levelButtonContainer.levelNum = i;
levelButtonContainer.down = function (x, y, obj) {
tween(this, {
scaleX: 0.88,
scaleY: 0.88
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function () {
tween(this, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function () {
currentLevel = this.levelNum;
startGame();
}.bind(this)
});
}.bind(this)
});
};
menuContainer.addChild(levelButtonContainer);
}
// Modern settings button at bottom
var settingsContainer = new Container();
var settingsCard = LK.getAsset('settings_button_border', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 1.1
});
var settingsButton = LK.getAsset('settings_button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 1.1
});
var settingsGlow = LK.getAsset('score_button_highlight', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.85,
scaleY: 1.05
});
settingsContainer.addChild(settingsCard);
settingsContainer.addChild(settingsButton);
settingsContainer.addChild(settingsGlow);
settingsContainer.x = 2048 / 2;
settingsContainer.y = 2200;
settingsContainer.scaleX = 0;
settingsContainer.scaleY = 0;
settingsCard.y = 0;
settingsButton.y = -3;
settingsGlow.y = -6;
settingsGlow.alpha = 0.3;
var settingsText = new Text2('SETTINGS', {
size: 48,
fill: 0xFFFFFF
});
settingsText.anchor.set(0.5, 0.5);
settingsContainer.addChild(settingsText);
// Animate settings button entrance
tween(settingsContainer, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 1
}, {
duration: 500,
delay: 2000,
easing: tween.easeOut
});
// Settings button interaction
settingsContainer.down = function (x, y, obj) {
tween(settingsContainer, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(settingsContainer, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
showSettings();
}
});
}
});
};
menuContainer.addChild(settingsContainer);
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);
}
// Show ad every 3 levels
if (currentLevel % 3 === 1 && currentLevel > 1) {
showLevelTransitionAd();
} else {
initializeLevel();
}
}
});
}
});
}
function showLevelTransitionAd() {
// Show interstitial ad between levels
ads.showInterstitial({
onAdClosed: function onAdClosed() {
// Continue to next level after ad is closed
initializeLevel();
},
onAdFailed: function onAdFailed() {
// If ad fails to load, continue anyway
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 - reduced scoring for increased difficulty
var baseScore = matches.length * 30; // Reduced from 50
var comboMultiplier = game.comboMultiplier || 1;
var bonusScore = Math.floor(baseScore * comboMultiplier * 0.8); // Apply 20% reduction
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
@@ -937,8 +937,18 @@
subtitleText.x = 2048 / 2;
subtitleText.y = 550;
subtitleText.alpha = 0;
menuContainer.addChild(subtitleText);
+ // Developer credit
+ var developerText = new Text2('By Luanity', {
+ size: 45,
+ fill: 0xFFD700
+ });
+ developerText.anchor.set(0.5, 0.5);
+ developerText.x = 2048 / 2;
+ developerText.y = 620;
+ developerText.alpha = 0;
+ menuContainer.addChild(developerText);
// Animate title with modern entrance
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1,
@@ -965,8 +975,18 @@
duration: 800,
delay: 600,
easing: tween.easeOut
});
+ // Animate developer credit
+ tween(developerText, {
+ alpha: 0.9,
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 600,
+ delay: 800,
+ easing: tween.easeOut
+ });
// Create modern button container with card design
var buttonCard = LK.getAsset('menu_button_border', {
anchorX: 0.5,
anchorY: 0.5,
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