User prompt
hafif titreyerek ve bazen ani yön değiştirerek gezsinler. Gerçekçi olsun
User prompt
dört böcek de arka planda random gezsin
User prompt
şimdi arka plan için pasif 4 tane böcek tanımla. Örümcek, kırkayak, karafatma, hamamböceği. bunlar arada ekrana çıkıp random dolaşıp sonr kaybolacaklar yeniden. Dinamik arkaplan olacak
User prompt
Bomb'u kullandım ama 0 olmadı
User prompt
Freeze yazısını da beyaz yap. Ayrıca parantez içinde kalan hakların sayısı haklar kullandıkça azalsın ve sıfırlansın
User prompt
arka plan asseti ata
User prompt
bomb butonunun içine de Bomb(1) yaz. Freeze için de Freeze(3). kaç hak olduklarını öyle anlayalım
User prompt
harikA oldu. Şimdi swap butonunu hemen spin'in altına al
User prompt
Şimdi en alta bir swap tuşu koy. Swap jokeri 5 defa kullanılabilir. swap'e tıkladıktan sonra ilk tıklanılan kristal patlar ve yerine başka renkte random bir kristal gelir.
User prompt
allah aşkına önce tüm swap işlemlerini sil. tamamen swap'i sil
User prompt
swap'a tıklıyorum. sonra herhangi bir kristale tıklıyorum ama hiçbir şey olmuyor
User prompt
olmadı yine. Baştan incele ve düzelt. hata yapıyorsun bir yerde
User prompt
swap tuşunu aktif et artık ya. Yüz kere yazdım. Swap aktifken ilk tıkladığım kristal patlayacak ve yerine yeni bir kristal gelecek ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
swap tuşunu aktif ettiğimde tıkladığım kristal patlasın ve yerine random farklı renkte bir kristal gelsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Olmadı. Düzeltir misin? Yüz defa anlattım
User prompt
Niye düzeltmiyorsun swap tuşunu. Swap tuşu aktifken tıklanılan kristalin renginin random değişmesi lazım
User prompt
Seap tuşunu düzeltir misin? Değiştirmiyor kristalin rengini
User prompt
Swap tuşunun kristalin rengini animasyonla değiştirmesi lazım. Düzeltir misin lütfen. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Seap tuşuna bastıktan sonra tıkladığım kristalin random değişmesi lazım. Düzelt lütfen
User prompt
Swap tuşuna bastıktan sonra hangi kristale tıklarsam o an random başka renkte kristale dönüşsün. Seçimi çerçeve ile sabitle bir tur ki anlaşılsın swap kullanıldığı
User prompt
Swap tuşuna bastıktan sonra hangi kristale tıklarsam random o an değişsin
User prompt
Swap tuşuna bastıktan sonra tıkladığım kristal random başka renkte kristale dönüşsün
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'type')' in or related to this line: 'var currentType = crystal.type;' Line Number: 949
User prompt
Şimdi swap tuşu beş defa kullanılabilsin. Swape tıkladıktan sonra hangi kristale tıklarsam random değişsin. Eğer şartlar sağlanırsa patlasın
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Passive Bug class (background animation) var Bug = Container.expand(function () { var self = Container.call(this); // Pick a random bug type var bugTypes = [{ id: 'bocek_orumcek', name: 'örümcek' }, { id: 'bocek_kirkayak', name: 'kırkayak' }, { id: 'bocek_karafatma', name: 'karafatma' }, { id: 'bocek_hamamb', name: 'hamamböceği' }]; var bugType = bugTypes[Math.floor(Math.random() * bugTypes.length)]; self.bugType = bugType.name; // Attach bug asset self.asset = self.attachAsset(bugType.id, { anchorX: 0.5, anchorY: 0.5 }); // State self.active = false; self.targetX = 0; self.targetY = 0; self.speed = 2 + Math.random() * 2; // px per frame self.hideTimeout = null; self.showTimeout = null; // Helper: set random position (offscreen or edge) self.setRandomStart = function () { // Appear from a random edge var edge = Math.floor(Math.random() * 4); // 0: left, 1: right, 2: top, 3: bottom var margin = 100; if (edge === 0) { // left self.x = -margin; self.y = margin + Math.random() * (2732 - 2 * margin); } else if (edge === 1) { // right self.x = 2048 + margin; self.y = margin + Math.random() * (2732 - 2 * margin); } else if (edge === 2) { // top self.x = margin + Math.random() * (2048 - 2 * margin); self.y = -margin; } else { // bottom self.x = margin + Math.random() * (2048 - 2 * margin); self.y = 2732 + margin; } }; // Helper: set random target inside screen self.setRandomTarget = function () { var margin = 200; self.targetX = margin + Math.random() * (2048 - 2 * margin); self.targetY = margin + Math.random() * (2732 - 2 * margin); }; // Show bug: appear and start moving self.showBug = function () { self.setRandomStart(); self.setRandomTarget(); self.visible = true; self.active = true; self.alpha = 0.7 + Math.random() * 0.3; self.scaleX = self.scaleY = 0.7 + Math.random() * 0.5; // Set random speed self.speed = 2 + Math.random() * 2; // Set random zIndex so bugs can overlap self.zIndex = 0; // Set random rotation self.rotation = Math.random() * Math.PI * 2; // Set how long bug will stay visible var minShow = 2000, maxShow = 5000; if (self.hideTimeout) LK.clearTimeout(self.hideTimeout); self.hideTimeout = LK.setTimeout(function () { self.hideBug(); }, minShow + Math.random() * (maxShow - minShow)); }; // Hide bug: disappear and schedule next appearance self.hideBug = function () { self.visible = false; self.active = false; // Schedule next appearance var minDelay = 1500, maxDelay = 4000; if (self.showTimeout) LK.clearTimeout(self.showTimeout); self.showTimeout = LK.setTimeout(function () { self.showBug(); }, minDelay + Math.random() * (maxDelay - minDelay)); }; // Per-frame update self.update = function () { if (!self.active) return; // --- Jitter: bugs shake a little as they move --- // Add a small random offset to position for jitter var jitterAmount = 2 + Math.random() * 2; var jitterAngle = Math.random() * Math.PI * 2; var jitterX = Math.cos(jitterAngle) * jitterAmount; var jitterY = Math.sin(jitterAngle) * jitterAmount; // --- Sudden direction change: sometimes pick a new target suddenly --- if (typeof self._framesToNextTurn === "undefined") { self._framesToNextTurn = 30 + Math.floor(Math.random() * 60); } self._framesToNextTurn--; if (self._framesToNextTurn <= 0) { // 40% chance to pick a new random target (simulate sudden turn) if (Math.random() < 0.4) { self.setRandomTarget(); // Also randomize speed and rotation for realism self.speed = 2 + Math.random() * 2; self.rotation = Math.random() * Math.PI * 2; } self._framesToNextTurn = 30 + Math.floor(Math.random() * 60); } // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < self.speed) { // Arrived at target, pick a new target self.setRandomTarget(); } else { // Move with a little jitter self.x += dx / dist * self.speed + jitterX; self.y += dy / dist * self.speed + jitterY; // Optionally, face the direction of movement self.rotation = Math.atan2(dy, dx) + (Math.random() - 0.5) * 0.2; } }; // Start hidden, then schedule first appearance self.visible = false; self.active = false; self.setRandomStart(); self.setRandomTarget(); // Schedule first appearance self.showTimeout = LK.setTimeout(function () { self.showBug(); }, 1000 + Math.random() * 2000); return self; }); // Crystal class var Crystal = Container.expand(function () { var self = Container.call(this); // type: 'blue', 'yellow', 'red', 'purple', 'white', 'joker' self.type = 'blue'; self.row = 0; self.col = 0; self.popping = false; // Attach correct asset function setAsset() { if (self.asset) self.removeChild(self.asset); var assetId = 'crystal_' + self.type; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); } self.setType = function (type) { self.type = type; setAsset(); }; // Animate pop self.pop = function (_onFinish) { if (self.popping) return; self.popping = true; tween(self, { scaleX: 1.4, scaleY: 1.4, alpha: 0 }, { duration: 350, easing: tween.easeOut, onFinish: function onFinish() { if (_onFinish) _onFinish(); } }); LK.getSound('crystal_pop').play(); }; // Reset visual state self.resetVisual = function () { self.scaleX = 1; self.scaleY = 1; self.alpha = 1; self.popping = false; // Remove freeze frame if present if (self.freezeFrame) { self.removeChild(self.freezeFrame); self.freezeFrame = null; } }; // Add or remove freeze frame self.setFreezeFrame = function (show) { if (show) { if (!self.freezeFrame) { // Create a square frame using a box shape, slightly larger than the crystal var frame = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); frame.width = self.asset.width * 1.18; frame.height = self.asset.height * 1.18; frame.alpha = 0.7; frame.tint = 0x00e6b8; frame.zIndex = -1; self.addChildAt(frame, 0); self.freezeFrame = frame; } if (self.freezeFrame) self.freezeFrame.visible = true; } else { if (self.freezeFrame) { self.removeChild(self.freezeFrame); self.freezeFrame = null; } } }; setAsset(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c2c }); /**** * Game Code ****/ // Böcek görselleri (örümcek, kırkayak, karafatma, hamamböceği) // Add background image behind all elements var backgroundImage = LK.getAsset('background_main', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); game.addChildAt(backgroundImage, 0); // Always at the back // --- Passive Bugs (background animation) --- var bugs = []; // Ensure each bug type is present and moving var bugTypeIds = ['bocek_orumcek', 'bocek_kirkayak', 'bocek_karafatma', 'bocek_hamamb']; for (var i = 0; i < bugTypeIds.length; i++) { var bug = new Bug(); // Force the bug to use a specific type for each instance var bugTypes = [{ id: 'bocek_orumcek', name: 'örümcek' }, { id: 'bocek_kirkayak', name: 'kırkayak' }, { id: 'bocek_karafatma', name: 'karafatma' }, { id: 'bocek_hamamb', name: 'hamamböceği' }]; // Set bug type and asset bug.bugType = bugTypes[i].name; if (bug.asset) bug.removeChild(bug.asset); bug.asset = bug.attachAsset(bugTypeIds[i], { anchorX: 0.5, anchorY: 0.5 }); // Place bugs behind all game elements but above background game.addChildAt(bug, 1); bugs.push(bug); } // --- Game Constants --- // Crystal shapes (box for simplicity, different colors for each type) // Sound effects (placeholders, actual sound assets will be loaded by LK) var BOARD_COLS = 4; var BOARD_ROWS = 6; var CRYSTAL_SIZE = 300; // px var CRYSTAL_SPACING = 24; // px var BOARD_WIDTH = BOARD_COLS * CRYSTAL_SIZE + (BOARD_COLS - 1) * CRYSTAL_SPACING; var BOARD_HEIGHT = BOARD_ROWS * CRYSTAL_SIZE + (BOARD_ROWS - 1) * CRYSTAL_SPACING; var BOARD_X = (2048 - BOARD_WIDTH) / 2; var BOARD_Y = (2732 - BOARD_HEIGHT) / 2 - 180; // move board up to make space for spin button var CRYSTAL_TYPES = ['blue', 'yellow', 'red', 'purple', 'white', 'joker']; var CRYSTAL_COLORS = { blue: 0x3a8ee6, yellow: 0xf7e14a, red: 0xe64a3a, purple: 0xb44ae6, white: 0xffffff, joker: 0x00e6b8 }; // Score values per crystal type var CRYSTAL_SCORES = { blue: 10, yellow: 12, red: 14, purple: 16, white: 18, joker: 25 }; // --- Game State --- var board = []; // 2D array [row][col] of Crystal or null var poppingCrystals = []; // Crystals currently popping var isCascading = false; var scoreTxt; var cascadeTimeout = null; // --- Level and Joker Probability State --- var level = 1; var jokerProbability = 0.10; // Start at 10% // --- UI: Score --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Board Initialization --- function createEmptyBoard() { board = []; for (var row = 0; row < BOARD_ROWS; row++) { var rowArr = []; for (var col = 0; col < BOARD_COLS; col++) { rowArr.push(null); } board.push(rowArr); } } function randomCrystalType() { // Use current jokerProbability (decreases as level increases) var r = Math.random(); if (r < jokerProbability) return 'joker'; var idx = Math.floor(Math.random() * 5); return CRYSTAL_TYPES[idx]; } function spawnCrystal(row, col, type) { var crystal = new Crystal(); crystal.setType(type); crystal.row = row; crystal.col = col; // Position var x = BOARD_X + col * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; var y = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; crystal.x = x; crystal.y = y; crystal.resetVisual(); game.addChild(crystal); // Make crystal fixed: prevent any movement or change // If this crystal is frozen, make sure it cannot be replaced or destroyed if (crystal.frozen) { crystal.interactive = false; crystal.buttonMode = false; crystal.down = function () {}; crystal.pop = function () {}; crystal.setType = function (type) {}; crystal.resetVisual = function () {}; crystal.setFreezeFrame = function () {}; } return crystal; } function fillBoardRandom() { for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; } } refreshCrystalInteractivity(); } // --- Board Utility --- function getNeighbors(row, col) { // 4-directional neighbors var n = []; if (row > 0) n.push([row - 1, col]); if (row < BOARD_ROWS - 1) n.push([row + 1, col]); if (col > 0) n.push([row, col - 1]); if (col < BOARD_COLS - 1) n.push([row, col + 1]); return n; } // --- Find Groups for Popping --- function findPopGroups() { // Returns: [{type, crystals: [Crystal, ...], jokerCount: n}] var groups = []; // Count all crystals by type (excluding jokers) var typeCounts = {}; var typeCrystals = {}; var jokerCrystals = []; for (var i = 0; i < CRYSTAL_TYPES.length; i++) { var t = CRYSTAL_TYPES[i]; if (t !== 'joker') { typeCounts[t] = 0; typeCrystals[t] = []; } } for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { var crystal = board[row][col]; if (!crystal) continue; if (crystal.type === 'joker') { // Frozen jokers can pop if they are part of a valid pop group, so always count them jokerCrystals.push(crystal); } else { // Frozen crystals can pop if they are part of a valid pop group, so always count them typeCounts[crystal.type]++; typeCrystals[crystal.type].push(crystal); } } } // For each color, see if color+joker >= 10, if so, pop all of that color and enough jokers for (var t in typeCounts) { var total = typeCounts[t] + jokerCrystals.length; if (total >= 10) { // Add all of this color var groupCrystals = []; for (var i = 0; i < typeCrystals[t].length; i++) { groupCrystals.push(typeCrystals[t][i]); } // Add jokers for (var j = 0; j < jokerCrystals.length; j++) { groupCrystals.push(jokerCrystals[j]); } groups.push({ type: t, crystals: groupCrystals, jokerCount: jokerCrystals.length }); } } return groups; } // --- Pop Groups --- function popGroups(groups, onFinish) { if (groups.length === 0) { if (onFinish) onFinish(); return; } isCascading = true; poppingCrystals = []; var popped = {}; // --- Combo Multiplier Logic --- if (typeof comboMultiplier === "undefined") { comboMultiplier = 1; } if (typeof lastCascadeMoveId === "undefined") { lastCascadeMoveId = 0; } if (typeof currentCascadeMoveId === "undefined") { currentCascadeMoveId = 0; } // If this is a new cascade move, reset comboMultiplier if (typeof cascadeMoveActive === "undefined" || !cascadeMoveActive) { comboMultiplier = 1; currentCascadeMoveId = Date.now(); lastCascadeMoveId = currentCascadeMoveId; cascadeMoveActive = true; } else { // If still in the same move, increment comboMultiplier if (currentCascadeMoveId === lastCascadeMoveId) { comboMultiplier++; } else { comboMultiplier = 1; currentCascadeMoveId = Date.now(); lastCascadeMoveId = currentCascadeMoveId; } } // Mark all crystals to pop (avoid double pop) for (var g = 0; g < groups.length; g++) { var group = groups[g]; for (var i = 0; i < group.crystals.length; i++) { var c = group.crystals[i]; var key = c.row + ',' + c.col; if (!popped[key]) { popped[key] = true; poppingCrystals.push(c); } } } // Animate pop with 2s shake before popping var popCount = poppingCrystals.length; var finished = 0; for (var i = 0; i < poppingCrystals.length; i++) { var c = poppingCrystals[i]; (function (crystal) { // Save original position var origX = crystal.x; var origY = crystal.y; var shakeDuration = 2000; var shakeInterval = 30; var elapsed = 0; var shakeTimer = null; function startShake() { shakeTimer = LK.setInterval(function () { // Random shake offset, smaller amplitude for subtle effect var dx = (Math.random() - 0.5) * 24; var dy = (Math.random() - 0.5) * 24; crystal.x = origX + dx; crystal.y = origY + dy; elapsed += shakeInterval; if (elapsed >= shakeDuration) { // End shake, restore position LK.clearInterval(shakeTimer); crystal.x = origX; crystal.y = origY; // Now pop crystal.pop(function () { finished++; if (finished === popCount) { // Remove from board for (var j = 0; j < poppingCrystals.length; j++) { var pc = poppingCrystals[j]; if (board[pc.row][pc.col] === pc) { board[pc.row][pc.col] = null; pc.destroy(); } } poppingCrystals = []; if (onFinish) onFinish(); } }); } }, shakeInterval); } startShake(); })(c); } // Score with combo multiplier for (var g = 0; g < groups.length; g++) { var group = groups[g]; var baseScore = 0; for (var i = 0; i < group.crystals.length; i++) { var c = group.crystals[i]; var t = c.type === 'joker' ? group.type : c.type; baseScore += CRYSTAL_SCORES[t]; } LK.setScore(LK.getScore() + baseScore * comboMultiplier); } scoreTxt.setText(LK.getScore()); LK.getSound('cascade').play(); LK.effects.flashObject(scoreTxt, 0xffff00, 400); // --- Level Up Logic --- var newLevel = Math.floor(LK.getScore() / 1000) + 1; if (newLevel > level) { level = newLevel; // Decrease jokerProbability by 1% per level up, but not below 1% jokerProbability = Math.max(0.01, 0.10 - (level - 1) * 0.01); // Optional: flash score text or give feedback for level up LK.effects.flashObject(scoreTxt, 0x00ff00, 600); } } // --- Cascade: Drop Crystals Down and Fill --- function cascadeBoard(onFinish) { // For each column, drop crystals down to fill empty spaces var changed = false; for (var col = 0; col < BOARD_COLS; col++) { var emptyRows = []; for (var row = BOARD_ROWS - 1; row >= 0; row--) { if (!board[row][col]) { emptyRows.push(row); } else if (emptyRows.length > 0) { // Move crystal down var targetRow = emptyRows.shift(); var crystal = board[row][col]; board[targetRow][col] = crystal; board[row][col] = null; crystal.row = targetRow; crystal.col = col; // Animate drop var newY = BOARD_Y + targetRow * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(crystal, { y: newY }, { duration: 220, easing: tween.cubicOut }); emptyRows.push(row); changed = true; } } } // Fill empty spaces at the top for (var col = 0; col < BOARD_COLS; col++) { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row][col]) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Drop from above var startY = BOARD_Y - CRYSTAL_SIZE; crystal.y = startY; var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(crystal, { y: targetY }, { duration: 220, easing: tween.cubicOut }); changed = true; } } } // Wait for animation, then call onFinish LK.setTimeout(function () { refreshCrystalInteractivity(); if (onFinish) onFinish(); }, 250); } // --- Main Game Loop: Cascade, Pop, Repeat --- function startCascadeLoop() { if (cascadeTimeout) { LK.clearTimeout(cascadeTimeout); cascadeTimeout = null; } var groups = findPopGroups(); if (groups.length === 0) { isCascading = false; return; } popGroups(groups, function () { cascadeBoard(function () { // Chain reaction! cascadeTimeout = LK.setTimeout(function () { startCascadeLoop(); }, 120); }); }); } // --- Start New Game --- function startGame() { LK.setScore(2000); scoreTxt.setText('2000'); // Reset combo multiplier state for new game comboMultiplier = 1; cascadeMoveActive = false; // Reset bomb usage for new game bombUsed = false; // Reset swap usage for new game swapUsedCount = 0; if (swapBtnText) swapBtnText.setText('Swap (' + (swapMaxCount - swapUsedCount) + ')'); if (swapBtnBg) swapBtnBg.alpha = 1; if (swapBtnContainer) { swapBtnContainer.interactive = true; swapBtnContainer.buttonMode = true; } // Reset freeze usage for new game freezeUsedCount = 0; freezeBtnText.setText('Freeze (' + (freezeMaxCount - freezeUsedCount) + ')'); freezeBtnBg.alpha = 1; freezeBtnContainer.interactive = true; freezeBtnContainer.buttonMode = true; // Reset level and jokerProbability level = 1; jokerProbability = 0.10; // Remove all crystals for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { if (board[row] && board[row][col]) { board[row][col].frozen = false; board[row][col].alpha = 1; // Remove freeze frame if present if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } board[row][col].destroy(); } } } createEmptyBoard(); fillBoardRandom(); refreshCrystalInteractivity(); LK.setTimeout(function () { startCascadeLoop(); }, 400); } // --- Karıştır Button --- var shuffleBtn = new Text2('Karıştır', { size: 110, fill: 0x00E6B8, font: "Arial Black" }); shuffleBtn.anchor.set(0.5, 1); shuffleBtn.x = LK.gui.width / 2; shuffleBtn.y = LK.gui.height - 60 - 140; // Move up to make space for spin button shuffleBtn.interactive = true; shuffleBtn.buttonMode = true; LK.gui.bottom.addChild(shuffleBtn); function reshuffleBoardWithFall() { if (isCascading) return; // Reset combo multiplier state for new move comboMultiplier = 1; cascadeMoveActive = false; // Remove all crystals for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { if (board[row][col]) { // Only destroy if not a frozen crystal if (!board[row][col].frozen) { board[row][col].frozen = false; board[row][col].alpha = 1; // Remove freeze frame if present if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } board[row][col].destroy(); board[row][col] = null; } } } } // Do not recreate the board, just refill non-frozen spots // Fill board with new crystals, but spawn them above and animate falling for (var row = 0; row < BOARD_ROWS; row++) { for (var col = 0; col < BOARD_COLS; col++) { // Eğer kristal donmuş ve justFrozen ise, bu turda silme, sadece işaretle (removeNextTurn) if (board[row][col] && board[row][col].frozen && board[row][col].justFrozen) { // Bir tur bekle, bu turda sadece işaretle board[row][col].justFrozen = false; board[row][col].removeNextTurn = true; if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } tween(board[row][col], { alpha: 1 }, { duration: 300, easing: tween.easeOut }); } // Eğer kristal donmuş ve removeNextTurn işaretli ise, bu turda sil else if (board[row][col] && board[row][col].frozen && board[row][col].removeNextTurn) { board[row][col].frozen = false; board[row][col].removeNextTurn = false; if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } // Kristali sil board[row][col].destroy(); board[row][col] = null; } // Eğer kristal donmuş ve justFrozen değilse, donmayı kaldır (yani ikinci turda donma kalksın) else if (board[row][col] && board[row][col].frozen && !board[row][col].justFrozen) { board[row][col].frozen = false; if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(false); } tween(board[row][col], { alpha: 1 }, { duration: 300, easing: tween.easeOut }); } // If the cell is empty, fill with a new crystal if (!board[row][col]) { var type = randomCrystalType(); var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Start above the board var targetY = crystal.y; crystal.y = BOARD_Y - CRYSTAL_SIZE * 2; tween(crystal, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); } else if (board[row][col].frozen) { // Animate frozen crystal to its own position for effect var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(board[row][col], { y: targetY }, { duration: 3000, easing: tween.cubicOut }); // Ensure freeze frame is visible if (typeof board[row][col].setFreezeFrame === "function") { board[row][col].setFreezeFrame(true); } board[row][col].alpha = 0.5; } else if (!(board[row][col].type === "joker" && board[row][col].frozen)) { // For all non-frozen crystals (including non-jokers and non-frozen jokers), replace with a new random crystal var prev = board[row][col]; // If this is a frozen joker, skip replacing it if (prev.type === "joker" && prev.frozen) { // Animate frozen joker to its own position for effect var targetY = BOARD_Y + row * (CRYSTAL_SIZE + CRYSTAL_SPACING) + CRYSTAL_SIZE / 2; tween(prev, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); // Ensure freeze frame is visible if (typeof prev.setFreezeFrame === "function") { prev.setFreezeFrame(true); } prev.alpha = 0.5; continue; } var type = randomCrystalType(); // Remove old crystal prev.destroy(); // Spawn new crystal var crystal = spawnCrystal(row, col, type); board[row][col] = crystal; // Start above the board var targetY = crystal.y; crystal.y = BOARD_Y - CRYSTAL_SIZE * 2; tween(crystal, { y: targetY }, { duration: 3000, easing: tween.cubicOut }); } } } refreshCrystalInteractivity(); LK.setTimeout(function () { startCascadeLoop(); }, 3100); } // Button event shuffleBtn.down = function (x, y, obj) { reshuffleBoardWithFall(); }; // --- Spin Button (visible, below crystals) --- var spinBtnContainer = new Container(); var spinBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); spinBtnContainer.addChild(spinBtnBg); var spinBtnText = new Text2('Spin', { size: 90, fill: 0xffffff, font: "Arial Black" }); spinBtnText.anchor.set(0.5, 0.5); spinBtnText.x = 0; spinBtnText.y = 0; spinBtnContainer.addChild(spinBtnText); // Position: just below the board, centered horizontally spinBtnContainer.x = 2048 / 2; spinBtnContainer.y = BOARD_Y + BOARD_HEIGHT + 100 + spinBtnBg.height / 2; // Make interactive spinBtnContainer.interactive = true; spinBtnContainer.buttonMode = true; spinBtnContainer.down = function (x, y, obj) { if (isCascading) return; var currentCoins = LK.getScore(); if (currentCoins < 100) { // Not enough coins, flash red for feedback LK.effects.flashObject(spinBtnBg, 0xff0000, 300); return; } // Reset combo multiplier state for new move comboMultiplier = 1; cascadeMoveActive = false; LK.setScore(currentCoins - 100); scoreTxt.setText(LK.getScore()); reshuffleBoardWithFall(); // Optional: flash the button for feedback LK.effects.flashObject(spinBtnBg, 0xffffff, 200); }; // Add to game scene (not GUI, so it stays relative to board) game.addChild(spinBtnContainer); // --- Special Power Buttons --- // State for power selection var powerMode = null; // "bomb", "freeze", "swap" or null // --- Swap Button State --- var swapBtnContainer; var swapBtnBg; var swapBtnText; var swapUsedCount = 0; var swapMaxCount = 5; // Helper to clear power mode UI state function clearPowerMode() { powerMode = null; swapFirstCrystal = null; bombBtnBg.alpha = 1; freezeBtnBg.alpha = 1; if (swapBtnBg) swapBtnBg.alpha = 1; } // --- Bomb Button --- var bombBtnContainer = new Container(); var bombBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); bombBtnBg.tint = 0xff4444; bombBtnContainer.addChild(bombBtnBg); var bombBtnText = new Text2('Bomb (1)', { size: 70, fill: 0xffffff, font: "Arial Black" }); bombBtnText.anchor.set(0.5, 0.5); bombBtnText.x = 0; bombBtnText.y = 0; bombBtnContainer.addChild(bombBtnText); bombBtnContainer.x = spinBtnContainer.x - 500; bombBtnContainer.y = spinBtnContainer.y; bombBtnContainer.interactive = true; bombBtnContainer.buttonMode = true; bombBtnContainer.down = function () { clearPowerMode(); powerMode = "bomb"; bombBtnBg.alpha = 0.7; }; // --- Freeze Button --- var freezeBtnContainer = new Container(); var freezeBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); freezeBtnBg.tint = 0x44ffd0; freezeBtnContainer.addChild(freezeBtnBg); var freezeBtnText = new Text2('Freeze (' + (freezeMaxCount - freezeUsedCount) + ')', { size: 70, fill: 0xffffff, font: "Arial Black" }); freezeBtnText.anchor.set(0.5, 0.5); freezeBtnText.x = 0; freezeBtnText.y = 0; freezeBtnContainer.addChild(freezeBtnText); freezeBtnContainer.x = spinBtnContainer.x + 500; freezeBtnContainer.y = spinBtnContainer.y; freezeBtnContainer.interactive = true; freezeBtnContainer.buttonMode = true; // Track freeze usage if (typeof freezeUsedCount === "undefined") { var freezeUsedCount = 0; } var freezeMaxCount = 3; freezeBtnContainer.down = function () { clearPowerMode(); if (freezeUsedCount >= freezeMaxCount) { // Visually disable freeze button if limit reached freezeBtnBg.alpha = 0.3; freezeBtnContainer.interactive = false; freezeBtnContainer.buttonMode = false; return; } powerMode = "freeze"; freezeBtnBg.alpha = 0.7; }; // Add to game game.addChild(bombBtnContainer); game.addChild(freezeBtnContainer); // --- Swap Button --- swapBtnContainer = new Container(); swapBtnBg = LK.getAsset('spin_btn_shape', { anchorX: 0.5, anchorY: 0.5 }); swapBtnBg.tint = 0x4488ff; swapBtnContainer.addChild(swapBtnBg); swapBtnText = new Text2('Swap (' + (swapMaxCount - swapUsedCount) + ')', { size: 70, fill: 0xffffff, font: "Arial Black" }); swapBtnText.anchor.set(0.5, 0.5); swapBtnText.x = 0; swapBtnText.y = 0; swapBtnContainer.addChild(swapBtnText); // Position: just below the spin button, centered horizontally swapBtnContainer.x = spinBtnContainer.x; swapBtnContainer.y = spinBtnContainer.y + spinBtnBg.height + 40; swapBtnContainer.interactive = true; swapBtnContainer.buttonMode = true; swapBtnContainer.down = function () { clearPowerMode(); if (swapUsedCount >= swapMaxCount) { swapBtnBg.alpha = 0.3; swapBtnContainer.interactive = false; swapBtnContainer.buttonMode = false; return; } powerMode = "swap"; swapBtnBg.alpha = 0.7; }; // Add to game game.addChild(swapBtnContainer); // --- Power Button Crystal Selection Logic --- // Track bomb usage if (typeof bombUsed === "undefined") { var bombUsed = false; } // Helper to re-apply crystal interactivity for powers function applyPowerCrystalInteractivity() { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row]) continue; for (var col = 0; col < BOARD_COLS; col++) { (function (r, c) { if (!board[r]) return; var crystal = board[r][c]; if (!crystal) return; crystal.interactive = true; crystal.buttonMode = true; crystal.down = function () { if (isCascading) return; // Bomb: destroy selected and neighbors, only if not used yet if (powerMode === "bomb" && !bombUsed) { var finishBombPop = function finishBombPop() { clearPowerMode(); LK.setTimeout(function () { startCascadeLoop(); }, 400); }; bombUsed = true; bombBtnText.setText('Bomb (0)'); var targets = [[r, c]]; var neighbors = getNeighbors(r, c); for (var i = 0; i < neighbors.length; i++) { var nr = neighbors[i][0], nc = neighbors[i][1]; if (board[nr][nc]) targets.push([nr, nc]); } var poppedCount = 0; var toPop = []; for (var i = 0; i < targets.length; i++) { var tr = targets[i][0], tc = targets[i][1]; if (board[tr][tc]) { toPop.push([tr, tc]); } } if (toPop.length === 0) { finishBombPop(); return; } var finished = 0; for (var i = 0; i < toPop.length; i++) { var tr = toPop[i][0], tc = toPop[i][1]; if (board[tr][tc]) { board[tr][tc].pop(function () { finished++; if (finished === toPop.length) { // Remove all popped for (var j = 0; j < toPop.length; j++) { var rr = toPop[j][0], cc = toPop[j][1]; if (board[rr][cc]) { board[rr][cc].destroy(); board[rr][cc] = null; } } // After bomb pop, trigger cascadeBoard to fill empty spaces cascadeBoard(function () { finishBombPop(); }); } }); } } // Visually disable bomb button bombBtnBg.alpha = 0.3; bombBtnContainer.interactive = false; bombBtnContainer.buttonMode = false; return; } // Freeze: after clicking Freeze, the clicked crystal stays fixed in place and is not replaced on spin/reshuffle else if (powerMode === "freeze") { var crystal = board[r][c]; if (crystal && !crystal.frozen && freezeUsedCount < freezeMaxCount) { crystal.frozen = true; crystal.justFrozen = true; // Sadece bir tur için işaretle // Visually indicate frozen state tween(crystal, { alpha: 0.5 }, { duration: 300, easing: tween.easeOut }); // Show freeze frame if (typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(true); } freezeUsedCount++; freezeBtnText.setText('Freeze (' + (freezeMaxCount - freezeUsedCount) + ')'); // If reached max, disable freeze button if (freezeUsedCount >= freezeMaxCount) { freezeBtnBg.alpha = 0.3; freezeBtnContainer.interactive = false; freezeBtnContainer.buttonMode = false; } // Always clear selection and power mode after one freeze clearPowerMode(); } } // --- Swap Power Logic --- else if (powerMode === "swap") { var crystal = board[r][c]; if (crystal && !crystal.frozen && swapUsedCount < swapMaxCount) { // Only allow swap on non-frozen crystals var oldType = crystal.type; // Pick a new type different from current var possibleTypes = []; for (var i = 0; i < CRYSTAL_TYPES.length; i++) { var t = CRYSTAL_TYPES[i]; if (t !== oldType) possibleTypes.push(t); } var newType = possibleTypes[Math.floor(Math.random() * possibleTypes.length)]; // Animate pop, then replace crystal.pop(function () { // Remove old crystal from board and scene if (board[r][c] === crystal) { crystal.destroy(); // Spawn new crystal of newType at same position var newCrystal = spawnCrystal(r, c, newType); board[r][c] = newCrystal; newCrystal.x = crystal.x; newCrystal.y = crystal.y; newCrystal.resetVisual(); // Re-apply interactivity refreshCrystalInteractivity(); } }); swapUsedCount++; swapBtnText.setText('Swap (' + (swapMaxCount - swapUsedCount) + ')'); // If reached max, disable swap button if (swapUsedCount >= swapMaxCount) { swapBtnBg.alpha = 0.3; swapBtnContainer.interactive = false; swapBtnContainer.buttonMode = false; } // Always clear selection and power mode after one swap clearPowerMode(); } } }; })(row, col); } } } // Call this after board is filled or refreshed applyPowerCrystalInteractivity(); // --- Patch: When filling board, re-apply crystal interactivity for powers --- function refreshCrystalInteractivity() { for (var row = 0; row < BOARD_ROWS; row++) { if (!board[row]) continue; for (var col = 0; col < BOARD_COLS; col++) { var crystal = board[row][col]; if (!crystal) continue; crystal.interactive = true; crystal.buttonMode = true; crystal.down = function () {}; // Restore freeze frame if frozen if (crystal.type === "joker" && crystal.frozen && typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(true); crystal.alpha = 0.5; } else if (typeof crystal.setFreezeFrame === "function") { crystal.setFreezeFrame(false); crystal.alpha = 1; } } } // Re-apply power crystal interactivity applyPowerCrystalInteractivity(); } // --- Touch to Spin/Reshuffle (tap anywhere else, fallback for desktop) --- // Removed global tap-to-reshuffle so only Spin button restarts the game // --- Game Over/Win (not used, slot is endless) --- // --- Game Update (not needed, all logic is event/cascade driven) --- game.update = function () { // Update bugs (background animation) for (var i = 0; i < bugs.length; i++) { if (bugs[i] && typeof bugs[i].update === "function") { bugs[i].update(); } } }; // --- Start the game --- startGame(); ;
===================================================================
--- original.js
+++ change.js
@@ -102,18 +102,42 @@
};
// Per-frame update
self.update = function () {
if (!self.active) return;
+ // --- Jitter: bugs shake a little as they move ---
+ // Add a small random offset to position for jitter
+ var jitterAmount = 2 + Math.random() * 2;
+ var jitterAngle = Math.random() * Math.PI * 2;
+ var jitterX = Math.cos(jitterAngle) * jitterAmount;
+ var jitterY = Math.sin(jitterAngle) * jitterAmount;
+ // --- Sudden direction change: sometimes pick a new target suddenly ---
+ if (typeof self._framesToNextTurn === "undefined") {
+ self._framesToNextTurn = 30 + Math.floor(Math.random() * 60);
+ }
+ self._framesToNextTurn--;
+ if (self._framesToNextTurn <= 0) {
+ // 40% chance to pick a new random target (simulate sudden turn)
+ if (Math.random() < 0.4) {
+ self.setRandomTarget();
+ // Also randomize speed and rotation for realism
+ self.speed = 2 + Math.random() * 2;
+ self.rotation = Math.random() * Math.PI * 2;
+ }
+ self._framesToNextTurn = 30 + Math.floor(Math.random() * 60);
+ }
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < self.speed) {
// Arrived at target, pick a new target
self.setRandomTarget();
} else {
- self.x += dx / dist * self.speed;
- self.y += dy / dist * self.speed;
+ // Move with a little jitter
+ self.x += dx / dist * self.speed + jitterX;
+ self.y += dy / dist * self.speed + jitterY;
+ // Optionally, face the direction of movement
+ self.rotation = Math.atan2(dy, dx) + (Math.random() - 0.5) * 0.2;
}
};
// Start hidden, then schedule first appearance
self.visible = false;