User prompt
Add time left
User prompt
Çalışmadı
User prompt
Gözükmüyor kodu kontrol et
User prompt
Hala gözükmüyor farklı renk yap
User prompt
Time left timer gözükmüyor
User prompt
Time left ekle
User prompt
Oyuna 3 dakika zaman ver eğer kazanilmazsa yenilgi sayilsin bir tane geri sayaç ekle sayfanın altına
User prompt
Timer left remove
User prompt
Sorunu düzelt
User prompt
Timer lefttext changed color white
User prompt
Time left animasyon kaldir
User prompt
Time left gözükmüyor çok siyah
User prompt
Time left textini kırmızı renk yap
User prompt
Arka plan siyah olduğu için timer gözükmüyor kırmızı renk yap
User prompt
Bir tane örnek ekle oyuna beğenmezsen değiştiririz
User prompt
I think it would be better if we added a single timer.
User prompt
Bu süslemeyi kaldır sade siyah olsun
User prompt
Saydamlığı kaldır
User prompt
Çıkan sayının üstünü şu anda kartta pembe rengi ile kapat
User prompt
Arka olan rengi dark yap
User prompt
Add
User prompt
Fix all
User prompt
Temayı değiştir
User prompt
Remove Pink color
User prompt
Komple temayı uzay yap
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // AI Robot: Animated character that dances in place (no left/right movement) var AIRobot = Container.expand(function () { var self = Container.call(this); // Attach a robot body (use aiIndicator image as the robot's head/body) var robotBody = self.attachAsset('aiIndicator', { anchorX: 0.5, anchorY: 0.5 }); // Add two "eyes" using small ellipses var leftEye = self.attachAsset('freeSpace', { width: 24, height: 24, color: 0xffffff, anchorX: 0.5, anchorY: 0.5 }); var rightEye = self.attachAsset('freeSpace', { width: 24, height: 24, color: 0xffffff, anchorX: 0.5, anchorY: 0.5 }); leftEye.x = -36; leftEye.y = -20; rightEye.x = 36; rightEye.y = -20; // Animation state self.danceTick = 0; // Initial position self.x = 2048 * 3 / 4; self.y = 2732 - 180; // Update method for in-place dance animation self.update = function () { // Dance in place: gentle rotation and scale pulse self.danceTick++; // Rotate gently back and forth self.rotation = Math.sin(self.danceTick / 30) * 0.18; // Scale up and down for a "bounce" effect var scalePulse = 1 + Math.sin(self.danceTick / 18) * 0.07; self.scale.x = scalePulse; self.scale.y = 1 - Math.sin(self.danceTick / 18) * 0.04; // Eyes: blink or wiggle in place var eyeWiggle = Math.sin(self.danceTick / 10) * 2; leftEye.x = -36 + eyeWiggle; rightEye.x = 36 - eyeWiggle; }; return self; }); // BingoCell: Represents a single cell on the bingo card var BingoCell = Container.expand(function () { var self = Container.call(this); // Properties self.number = 0; self.marked = false; // --- Space theme: cosmic background, blue/purple glow, and star/planet decor --- var cellBg = self.attachAsset('Background', { width: cellSize, height: cellSize, color: 0x0a0e1a, // Deep cosmic blue-black anchorX: 0.5, anchorY: 0.5 }); cellBg.radius = cellSize * 0.22; // Simulate rounded corners (if supported by engine) // Add a subtle blue/purple border for cosmic effect var border = self.attachAsset('Background', { width: cellSize * 0.98, height: cellSize * 0.98, color: 0x2d1b4d, // Deep purple/blue anchorX: 0.5, anchorY: 0.5 }); border.radius = cellSize * 0.19; border.alpha = 0.7; // --- Subtle star and planet pattern: add 2-3 faint stars and 1 planet randomly in the cell --- self.stars = []; for (var i = 0; i < 3; i++) { // Use white and yellow for stars var starColor = i % 2 === 0 ? 0xffffff : 0xf7d794; var star = self.attachAsset(i % 2 === 0 ? 'starWhite' : 'starYellow', { width: cellSize * (0.10 + Math.random() * 0.08), height: cellSize * (0.10 + Math.random() * 0.08), color: starColor, anchorX: 0.5, anchorY: 0.5 }); star.alpha = 0.10 + Math.random() * 0.08; // Place stars at random positions, but not center var angle = Math.random() * Math.PI * 2; var dist = cellSize * (0.23 + Math.random() * 0.18); star.x = Math.cos(angle) * dist; star.y = Math.sin(angle) * dist; self.stars.push(star); } // Add a random planet for extra space flavor var planetTypes = ['planetBlue', 'planetPurple', 'planetRed']; var planetType = planetTypes[Math.floor(Math.random() * planetTypes.length)]; var planet = self.attachAsset(planetType, { width: cellSize * 0.22, height: cellSize * 0.22, anchorX: 0.5, anchorY: 0.5 }); planet.alpha = 0.13 + Math.random() * 0.07; planet.x = (Math.random() - 0.5) * cellSize * 0.5; planet.y = (Math.random() - 0.5) * cellSize * 0.5; self.stars.push(planet); // Number text var numberText = new Text2('', { size: Math.floor(cellSize * 0.45), fill: 0x3a6cf6 // Neon blue for space theme }); numberText.anchor.set(0.5, 0.5); self.addChild(numberText); // --- Mark overlay: cosmic blue/purple ellipse, hidden by default --- var markOverlay = self.attachAsset('winHighlight', { width: cellSize * 0.82, height: cellSize * 0.82, anchorX: 0.5, anchorY: 0.5 }); markOverlay.alpha = 0; markOverlay.color = 0x3a6cf6; // Neon blue for space theme self.markOverlay = markOverlay; // --- Glow effect: subtle blue/purple glow when marked --- var glow = self.attachAsset('freeSpace', { width: cellSize * 1.18, height: cellSize * 1.18, color: 0x82589f, // Purple glow anchorX: 0.5, anchorY: 0.5 }); glow.alpha = 0; self.glow = glow; // Set number and update text self.setNumber = function (num) { self.number = num; numberText.setText(num > 0 ? num : ''); }; // Mark/unmark cell self.setMarked = function (val) { self.marked = val; if (val) { // Animate mark overlay in tween(markOverlay, { alpha: 0.92 }, { duration: 200, easing: tween.easeOut }); // Animate glow in tween(glow, { alpha: 0.22 }, { duration: 200, easing: tween.easeOut }); numberText.setText(self.number); numberText.setStyle({ fill: 0x000000 // Black for contrast on blue mark }); } else { // Animate mark overlay out tween(markOverlay, { alpha: 0 }, { duration: 200, easing: tween.easeOut }); // Animate glow out tween(glow, { alpha: 0 }, { duration: 200, easing: tween.easeOut }); numberText.setStyle({ fill: 0x3a6cf6 // Neon blue for space theme }); } }; // Touch event self.down = function (x, y, obj) { // Play click sound on any cell tap LK.getSound('Click').play(); if (self.marked) return; if (game.state !== 'playing') return; var p = self.playerIndex !== undefined ? self.playerIndex : 0; if (self.number === game.currentNumber && p === currentPlayer) { self.setMarked(true); // Flash with yellow and pulse LK.effects.flashObject(self, 0xfff200, 200); tween(self.scale, { x: 1.13, y: 1.13 }, { duration: 120, yoyo: true, repeat: 1, easing: tween.easeOut }); // Streak logic if (typeof streak !== "undefined") { streak[p]++; if (streak[p] > 1) { timeLeft[p] += 1000; } } game.checkWin(); } else { if (typeof streak !== "undefined") { streak[p] = 0; } LK.effects.flashObject(self, 0x8b0000, 200); } }; // Example: Trigger action when cell crosses X = 1000 from left to right if (self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) { // Place your action here, e.g. console.log("Cell crossed X=1000!"); } // Always update lastX at the end self.lastX = self.x; // Example: Trigger action when cell crosses Y = 800 from above to below if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800) { // Place your action here, e.g. console.log("Cell crossed Y=800!"); } // Always update lastY at the end self.lastY = self.y; // Example: Trigger action when cell crosses X=1000 and Y=800 at the same frame if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800 && self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) { // Place your action here, e.g. console.log("Cell arrived at (1000,800)!"); } // Always update lastX and lastY at the end self.lastX = self.x; self.lastY = self.y; return self; }); // CalledNumberBall: Shows a called number as a round ball var CalledNumberBall = Container.expand(function () { var self = Container.call(this); // Ball background var ball = self.attachAsset('bingoBall', { anchorX: 0.5, anchorY: 0.5 }); // Number text var numberText = new Text2('', { size: 60, fill: 0x000000 }); numberText.anchor.set(0.5, 0.5); numberText.x = 0; numberText.y = 0; self.addChild(numberText); self.setNumber = function (num) { numberText.setText(num); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0e1a // Deep cosmic blue }); /**** * Game Code ****/ // --- Added ses41 to ses75 sound assets (IDs to be filled by asset loader) --- // Save the current game state (called numbers, card numbers, marked cells, time left, streaks) // --- Kaydet (Save) Functionality --- // --- Functions --- // --- Hint Power-Up Button --- // Bingo game shapes // New shapes for improved UI // Images // New image assets for polish (IDs are placeholders, replace with real IDs if available) // Sounds // Neon blue planet // Deep space blue // Cyan for hover // Dark blue for pressed // Space black // Galaxy border // Neon green // Star yellow // Light blue // Space shadow // Neon cyan // Neon green // Space black // Space shadow // Neon green // Deep blue // Star yellow // Star yellow // Space/Galaxy themed assets for richer visuals // Space/galaxy decorative shapes // Space/galaxy themed overlays for cards // Space/galaxy themed power-up icons // Images (IDs are placeholders, replace with real asset IDs as needed) // Sounds // Neon pink // Deep retro blue // Neon cyan // Neon yellow // Purple // Neon cyan // Neon pink // Neon yellow // Neon cyan // Purple // Neon pink // Neon yellow // Deep retro blue // Neon cyan // Neon pink // Neon yellow // Purple // Deep retro blue // Neon cyan // Neon cyan // Neon pink // Neon yellow // Purple // Neon pink // Neon cyan // Neon yellow // Neon pink // Deep retro blue // Neon yellow // Purple // Neon cyan // Neon pink // Neon yellow // Neon pink // Candy pink // Pastel orange // Mint green // Candy orange // Light pink // Mint green // Candy pink // Candy orange // Mint green // Light pink // Candy pink // Candy orange // Light pink // Mint green // Candy pink // Candy orange // Light pink // Pastel orange // Mint green // Pastel blue // Pastel purple // Candy pink // Light pink // Candy pink // Mint green // Candy orange // Candy pink // Pastel orange // Pastel yellow // Light pink // Mint green // Candy pink // Candy orange // Candy pink // Forest green ball // Light moss cell // Fern green hover // Deep green pressed // Pale green // Deep green border // Sunlight confetti // Light brown confetti // Fern green // Pale green // Forest green // Sunlight free space // Pale green bg // Fern swirl // Forest green // Deep green // Pale green overlay // Light brown // Deep green // Blue pond // Forest flower // Mushroom cap // Pale green // Forest green // Fern green // Light brown // Sunlight // Light moss // Sunlight // Pale green // Fern green // Forest green // Sunlight // Deep green // Ses assets for ses1 to ses40 function kaydetOyunu() { // Prepare save data var saveData = { calledNumbers: calledNumbers.slice(), cardNumbers: [cardNumbers[0] ? cardNumbers[0].map(function (col) { return col.slice(); }) : [], cardNumbers[1] ? cardNumbers[1].map(function (col) { return col.slice(); }) : []], marked: [bingoCells[0] ? bingoCells[0].map(function (cell) { return cell.marked; }) : [], bingoCells[1] ? bingoCells[1].map(function (cell) { return cell.marked; }) : []], timeLeft: timeLeft.slice(), streak: streak.slice(), currentPlayer: currentPlayer, gameOver: gameOver, state: game.state, availableNumbers: availableNumbers.slice(), currentNumber: game.currentNumber }; storage['bingo_save'] = saveData; } // Load the saved game state (if any) function yukleOyunu() { var saveData = storage['bingo_save']; if (!saveData) return false; // Restore state calledNumbers = saveData.calledNumbers || []; cardNumbers = [saveData.cardNumbers[0] ? saveData.cardNumbers[0].map(function (col) { return col.slice(); }) : [], saveData.cardNumbers[1] ? saveData.cardNumbers[1].map(function (col) { return col.slice(); }) : []]; availableNumbers = saveData.availableNumbers ? saveData.availableNumbers.slice() : []; timeLeft = saveData.timeLeft ? saveData.timeLeft.slice() : [gameDuration, gameDuration]; streak = saveData.streak ? saveData.streak.slice() : [0, 0]; currentPlayer = typeof saveData.currentPlayer === "number" ? saveData.currentPlayer : 0; gameOver = !!saveData.gameOver; game.state = saveData.state || 'playing'; game.currentNumber = typeof saveData.currentNumber === "number" ? saveData.currentNumber : null; // Re-create cards and marked cells for (var p = 0; p < playerCount; p++) { if (!cardNumbers[p] || cardNumbers[p].length === 0) continue; if (!bingoCells[p]) bingoCells[p] = []; for (var i = 0; i < bingoCells[p].length; i++) { if (bingoCells[p][i]) { bingoCells[p][i].destroy(); } } bingoCells[p] = []; } createBingoCards(); // Restore marked cells for (var p = 0; p < playerCount; p++) { if (!saveData.marked[p]) continue; for (var i = 0; i < saveData.marked[p].length; i++) { if (bingoCells[p][i]) { bingoCells[p][i].setMarked(!!saveData.marked[p][i]); } } } // Restore timers, streaks, UI for (var p = 0; p < playerCount; p++) { if (timerInterval[p]) LK.clearInterval(timerInterval[p]); timerInterval[p] = LK.setInterval(function (playerIdx) { return function () { if (!freezeTimerActive[playerIdx]) { timeLeft[playerIdx] -= 100; if (timeLeft[playerIdx] < 0) timeLeft[playerIdx] = 0; updateTimerTextForPlayer(playerIdx); if (timeLeft[playerIdx] <= 0 && !gameOver) { endGame(false, playerIdx); } } }; }(p), 100); updateTimerTextForPlayer(p); // streakText UI removed } updateCalledBallsUI(); numberCallText.setText(game.currentNumber ? game.currentNumber : ''); return true; } // Bingo ball (yellow ellipse) // Bingo cell background (cyan box) // Mark overlay (beige box, used for marking cells) // Hint button background (green box, used for hint power-up) // Free space overlay (distinct color for center cell) // Win highlight overlay (gold ellipse for winning line) // Reveal Row button removed // Freeze Timer button and logic removed // Ses assets for ses1 to ses40 var gridSize = 5; // 5x5 bingo // Adjust cellSize and card positions for two-player mode to fit both cards on screen var cellSize = 180; // px, reduced to fit two cards side by side var cardPadding = 30; var cardWidth = gridSize * cellSize; var cardHeight = gridSize * cellSize; var cardStartX = 2048 / 4 - cardWidth / 2; // Player 1 card center at 1/4 width, Player 2 at 3/4 width var cardStartY = 500; // Lowered to fit both cards and UI var callIntervalStart = 4000; // ms (4 seconds initial call speed) var callIntervalMin = 1200; // ms (slower minimum speed) var callIntervalStep = 60; // ms, decrease per call (slower speedup) var gameDuration = 225000; // ms (3 min 45 sec) var numbersRange = 75; // 1-75 // --- State --- // Two player support var playerCount = 2; var currentPlayer = 0; // 0 or 1 var bingoCells = [[], []]; // bingoCells[0] for player 1, bingoCells[1] for player 2 var calledNumbers = []; var availableNumbers = []; var callTimer = null; var timeLeft = [gameDuration, gameDuration]; // Separate timers for each player var timerInterval = [null, null]; var cardNumbers = [[], []]; var gameOver = false; var playerNames = ["You", "AI"]; var winText = [null, null]; // Per player var streak = [0, 0]; var streakText = [null, null]; var timerText = [null, null]; // Freeze Timer state arrays removed // --- Freeze Timer compatibility: define freezeTimerActive as always-false array for each player --- var freezeTimerActive = [false, false]; // --- UI Elements --- // Container for called number balls var calledBallsContainer = new Container(); calledBallsContainer.x = 2048 / 2; calledBallsContainer.y = 2732 - 120; game.addChild(calledBallsContainer); // Show the latest called numbers as balls (max 6) function updateCalledBallsUI() { // Remove old balls while (calledBallsContainer.children.length > 0) { calledBallsContainer.removeChild(calledBallsContainer.children[0]); } var maxBalls = 6; var startIdx = Math.max(0, calledNumbers.length - maxBalls); var ballsToShow = calledNumbers.slice(startIdx); var spacing = 130; var totalWidth = (ballsToShow.length - 1) * spacing; for (var i = 0; i < ballsToShow.length; i++) { var ball = new CalledNumberBall(); ball.setNumber(ballsToShow[i]); ball.x = -totalWidth / 2 + i * spacing; ball.y = 0; // Animate in the newest ball if (i === ballsToShow.length - 1) { ball.scale.x = 0.1; ball.scale.y = 0.1; tween(ball.scale, { x: 1, y: 1 }, { duration: 180, easing: tween.easeOut }); } calledBallsContainer.addChild(ball); } } var numberCallText = new Text2('', { size: 180, fill: 0xff073a // Neon red }); numberCallText.anchor.set(0.5, 0.5); numberCallText.x = 2048 / 2; numberCallText.y = 2732 - 300; game.addChild(numberCallText); // Number left text UI removed var winText = new Text2('', { size: 120, fill: 0xfff200 // Neon yellow }); winText.anchor.set(0.5, 0.5); winText.x = 2048 / 2; winText.y = 2732 / 2; winText.visible = false; game.addChild(winText); // --- Functions --- // Example: Trigger action when a cell intersects with another object (e.g. another cell or a special marker) // Assume we have a global reference to a special object, e.g. specialMarker // (You would need to define specialMarker somewhere in your game if you want to use this for real) if (typeof specialMarker !== "undefined" && bingoCells && bingoCells[0]) { for (var i = 0; i < bingoCells[0].length; i++) { var cell = bingoCells[0][i]; if (cell.lastWasIntersecting === false && cell.intersects(specialMarker)) { // Place your action here, e.g. console.log("Cell just started intersecting with specialMarker!"); } cell.lastWasIntersecting = cell.intersects(specialMarker); } } // Generate a random bingo card (5x5, center is free) function generateCardNumbers() { var nums = []; var used = []; for (var col = 0; col < gridSize; col++) { var colNums = []; var min = col * 15 + 1; var max = min + 14; for (var row = 0; row < gridSize; row++) { if (col === 2 && row === 2) { colNums.push(0); // Free space continue; } var n; do { n = min + Math.floor(Math.random() * (max - min + 1)); } while (used.indexOf(n) !== -1); used.push(n); colNums.push(n); } nums.push(colNums); } return nums; } // Create bingo card UI for both players function createBingoCards() { for (var p = 0; p < playerCount; p++) { bingoCells[p] = []; cardNumbers[p] = generateCardNumbers(); // Center cards at 1/4 and 3/4 of the screen width var cardCenterX = p === 0 ? 2048 / 4 : 2048 * 3 / 4; var offsetX = cardCenterX - cardWidth / 2; for (var col = 0; col < gridSize; col++) { for (var row = 0; row < gridSize; row++) { var cell = new BingoCell(); var x = offsetX + col * cellSize + cellSize / 2; var y = cardStartY + row * cellSize + cellSize / 2; cell.x = x; cell.y = y; var num = cardNumbers[p][col][row]; cell.setNumber(num); if (col === 2 && row === 2) { cell.setMarked(true); // Free space } cell.playerIndex = p; game.addChild(cell); bingoCells[p].push(cell); } } // --- Ava: Add a fun idle animation to the player's bingo card for visual feedback --- if (p === 0) { // Animate the whole card with a gentle floating effect var floatT = { v: 0 }; var _floatCard = function floatCard() { tween(floatT, { v: 1 }, { duration: 2200 + Math.random() * 800, easing: tween.easeInOut, onUpdate: function onUpdate() { // Apply a gentle up-down float to all player cells for (var i = 0; i < bingoCells[0].length; i++) { var baseY = cardStartY + Math.floor(i / gridSize) * cellSize + cellSize / 2; bingoCells[0][i].y = baseY + Math.sin(floatT.v * Math.PI * 2) * 10; } }, onComplete: function onComplete() { floatT.v = 0; _floatCard(); } }); }; _floatCard(); // --- Ava: Add a 'You' indicator animation for the player side --- // Only add once per game start if (typeof youIndicatorInstance === "undefined" || !youIndicatorInstance) { var youIndicatorInstance = new Container(); // Add a glowing ellipse as a background var youBg = youIndicatorInstance.attachAsset('freeSpace', { width: 180, height: 90, color: 0xff6600, anchorX: 0.5, anchorY: 0.5 }); youBg.alpha = 0.22; // Add a white ellipse for extra glow var youGlow = youIndicatorInstance.attachAsset('freeSpace', { width: 220, height: 110, color: 0xffffff, anchorX: 0.5, anchorY: 0.5 }); youGlow.alpha = 0.09; // Add the "You" text var youText = new Text2('You', { size: 80, fill: 0xff6600, font: "Impact, Arial Black, Tahoma" }); youText.anchor.set(0.5, 0.5); youText.y = 0; youIndicatorInstance.addChild(youText); // Place above the player's card, centered horizontally youIndicatorInstance.x = 2048 / 4; youIndicatorInstance.y = cardStartY - 80; game.addChild(youIndicatorInstance); // Animate: gentle up-down float and scale pulse var youFloatT = { v: 0 }; var _youFloat = function youFloat() { tween(youFloatT, { v: 1 }, { duration: 1800 + Math.random() * 600, easing: tween.easeInOut, onUpdate: function onUpdate() { youIndicatorInstance.y = cardStartY - 80 + Math.sin(youFloatT.v * Math.PI * 2) * 18; var scalePulse = 1 + Math.sin(youFloatT.v * Math.PI * 2) * 0.07; youIndicatorInstance.scale.x = scalePulse; youIndicatorInstance.scale.y = scalePulse; }, onComplete: function onComplete() { youFloatT.v = 0; _youFloat(); } }); }; _youFloat(); } } } } // Start a new game for two players function startGame() { game.state = 'playing'; gameOver = false; calledNumbers = []; availableNumbers = []; for (var i = 1; i <= numbersRange; i++) availableNumbers.push(i); createBingoCards(); numberCallText.setText(''); // Per player UI and state for (var p = 0; p < playerCount; p++) { if (!winText[p]) { winText[p] = new Text2('', { size: 120, fill: 0xff6600 }); winText[p].anchor.set(0.5, 0.5); winText[p].x = p === 0 ? 2048 / 4 : 2048 * 3 / 4; winText[p].y = 2732 / 2; winText[p].visible = false; game.addChild(winText[p]); } // (AI robot animation and label will be handled globally after startGame) // streakText UI removed if (!timerText[p]) { timerText[p] = new Text2('', { size: 60, fill: 0xFFFFFF }); timerText[p].anchor.set(0.5, 0); if (p === 0) { // Human player timer below their board, aligned like AI timer timerText[p].x = 2048 / 4; timerText[p].y = cardStartY + cardHeight + 200 + 180; // Moved 60px further down game.addChild(timerText[p]); } else { // AI player timer below their board timerText[p].x = 2048 * 3 / 4; // Move timerText below the AI indicator image (aiIndicator.y + aiIndicator.height/2 + margin) timerText[p].y = cardStartY + cardHeight + 200 + 180; // Moved 60px further down game.addChild(timerText[p]); } } winText[p].visible = false; streak[p] = 0; // streakText UI removed // Freeze Timer state reset removed timeLeft[p] = gameDuration; updateTimerTextForPlayer(p); if (timerInterval[p]) LK.clearInterval(timerInterval[p]); timerInterval[p] = LK.setInterval(function (playerIdx) { return function () { if (!freezeTimerActive[playerIdx]) { timeLeft[playerIdx] -= 100; if (timeLeft[playerIdx] < 0) timeLeft[playerIdx] = 0; updateTimerTextForPlayer(playerIdx); if (timeLeft[playerIdx] <= 0 && !gameOver) { endGame(false, playerIdx); } } }; }(p), 100); } updateCalledBallsUI(); // Number left text UI update removed currentPlayer = 0; nextNumberCall(callIntervalStart); } // Call the next number game.currentNumber = null; function nextNumberCall(interval) { if (gameOver) return; if (availableNumbers.length === 0) { endGame(false); return; } var idx = Math.floor(Math.random() * availableNumbers.length); var num = availableNumbers[idx]; availableNumbers.splice(idx, 1); calledNumbers.push(num); game.currentNumber = num; numberCallText.setText(num); LK.effects.flashObject(numberCallText, 0xff6600, 300); // Play ses1-ses75 sound if number is in 1-75 if (num >= 1 && num <= 75) { var soundId = 'ses' + num; var sound = LK.getSound(soundId); if (sound) sound.play(); } // Update called balls UI updateCalledBallsUI(); // Animate all called balls with a gentle bounce for (var i = 0; i < calledBallsContainer.children.length; i++) { var ball = calledBallsContainer.children[i]; if (ball && ball.scale) { ball.scale.x = 1; ball.scale.y = 1; tween(ball.scale, { x: 1.15, y: 1.15 }, { duration: 120, yoyo: true, repeat: 1, easing: tween.easeOut }); } } // Number left text UI update removed // Pulse the matching cell(s) on the human player's card for (var i = 0; i < bingoCells[0].length; i++) { if (bingoCells[0][i].number === num && !bingoCells[0][i].marked) { // Flash the cell background for extra attention LK.effects.flashObject(bingoCells[0][i], 0xfff200, 220); // Pulse the cell scale tween(bingoCells[0][i].scale, { x: 1.22, y: 1.22 }, { duration: 140, yoyo: true, repeat: 1, easing: tween.easeOut }); } } // --- Enhanced Opponent AI --- if (playerCount === 2 && !gameOver) { var opponentIdx = 1; // Analyze opponent's board state var opponentScore = 0; var nearWinLines = []; var marked = []; // Build marked grid and count score for (var col = 0; col < gridSize; col++) { marked[col] = []; for (var row = 0; row < gridSize; row++) { var idx = col * gridSize + row; marked[col][row] = bingoCells[opponentIdx][idx].marked; if (marked[col][row]) opponentScore++; } } // Check for lines that are one cell away from winning // Check rows for (var row = 0; row < gridSize; row++) { var markedCount = 0; for (var col = 0; col < gridSize; col++) { if (marked[col][row]) markedCount++; } if (markedCount === gridSize - 1) nearWinLines.push({ type: 'row', index: row }); } // Check columns for (var col = 0; col < gridSize; col++) { var markedCount = 0; for (var row = 0; row < gridSize; row++) { if (marked[col][row]) markedCount++; } if (markedCount === gridSize - 1) nearWinLines.push({ type: 'col', index: col }); } // Check diagonals var diagCount1 = 0, diagCount2 = 0; for (var i = 0; i < gridSize; i++) { if (marked[i][i]) diagCount1++; if (marked[gridSize - 1 - i][i]) diagCount2++; } if (diagCount1 === gridSize - 1) nearWinLines.push({ type: 'diag1' }); if (diagCount2 === gridSize - 1) nearWinLines.push({ type: 'diag2' }); // Find the cell with the current number for (var i = 0; i < bingoCells[opponentIdx].length; i++) { var cell = bingoCells[opponentIdx][i]; if (cell.number === num && !cell.marked) { // Calculate AI response time based on selected difficulty var aiDelay = 0; var accuracyChance = 0.95; // Default fallback // Use selected difficulty if set, else fallback to old logic if (typeof game.selectedDifficulty !== "undefined") { // Use values set in overlay var aiAcc = typeof game.aiAccuracy !== "undefined" ? game.aiAccuracy : 0.95; var aiMin = typeof game.aiMinDelay !== "undefined" ? game.aiMinDelay : 200; var aiMax = typeof game.aiMaxDelay !== "undefined" ? game.aiMaxDelay : 800; aiDelay = aiMin + Math.random() * (aiMax - aiMin); accuracyChance = aiAcc; } else { // Factor 1: Score-based speed (the more marks, the faster) if (opponentScore < 5) { aiDelay = 800 + Math.random() * 600; accuracyChance = 0.7; } else if (opponentScore < 10) { aiDelay = 400 + Math.random() * 400; accuracyChance = 0.85; } else if (opponentScore < 15) { aiDelay = 200 + Math.random() * 300; accuracyChance = 0.92; } else { aiDelay = 100 + Math.random() * 200; accuracyChance = 0.98; } } // Factor 2: Priority boost if this cell completes a line var cellCol = Math.floor(i / gridSize); var cellRow = i % gridSize; var isPriority = false; for (var n = 0; n < nearWinLines.length; n++) { var line = nearWinLines[n]; if (line.type === 'row' && cellRow === line.index) isPriority = true;else if (line.type === 'col' && cellCol === line.index) isPriority = true;else if (line.type === 'diag1' && cellCol === cellRow) isPriority = true;else if (line.type === 'diag2' && cellCol === gridSize - 1 - cellRow) isPriority = true; } if (isPriority) { aiDelay = Math.min(aiDelay, 150 + Math.random() * 100); accuracyChance = 0.99; } // Factor 3: Occasional mistakes (miss a number) var makesMistake = Math.random() > accuracyChance; (function (cell, aiDelay, makesMistake) { LK.setTimeout(function () { if (!cell.marked && !gameOver && !makesMistake) { cell.setMarked(true); // Flash with AI indicator color LK.effects.flashObject(cell, 0x1565c0, 180); // Update streak for opponent streak[opponentIdx]++; // Add time bonus for streak if (streak[opponentIdx] > 1) { timeLeft[opponentIdx] += 1000; } // Check win for opponent var prevPlayer = currentPlayer; currentPlayer = opponentIdx; game.checkWin(); currentPlayer = prevPlayer; } else if (makesMistake && !gameOver) { // AI missed this number, reset streak streak[opponentIdx] = 0; } }, aiDelay); })(cell, aiDelay, makesMistake); } } } // Speed up calls as game progresses var nextInterval = Math.max(callIntervalMin, interval - callIntervalStep); if (callTimer) LK.clearTimeout(callTimer); callTimer = LK.setTimeout(function () { nextNumberCall(nextInterval); }, nextInterval); } // Update timer UI for a specific player function updateTimerTextForPlayer(p) { var sec = Math.ceil(timeLeft[p] / 1000); if (p === 0) { timerText[p].setText("Your Time: " + sec + "s"); } else { timerText[p].setText("AI Player Time: " + sec + "s"); } } // Check for win (row, col, diag) for the current player game.checkWin = function () { var p = currentPlayer; // Build marked grid var marked = []; for (var col = 0; col < gridSize; col++) { marked[col] = []; for (var row = 0; row < gridSize; row++) { var idx = col * gridSize + row; marked[col][row] = bingoCells[p][idx].marked; } } // Check rows for (var row = 0; row < gridSize; row++) { var win = true; for (var col = 0; col < gridSize; col++) { if (!marked[col][row]) win = false; } if (win) return endGame(true, p); } // Check cols for (var col = 0; col < gridSize; col++) { var win = true; for (var row = 0; row < gridSize; row++) { if (!marked[col][row]) win = false; } if (win) return endGame(true, p); } // Check diag TL-BR var win = true; for (var i = 0; i < gridSize; i++) { if (!marked[i][i]) win = false; } if (win) return endGame(true, p); // Check diag TR-BL win = true; for (var i = 0; i < gridSize; i++) { if (!marked[gridSize - 1 - i][i]) win = false; } if (win) return endGame(true, p); }; // End game: win or lose for a specific player function endGame(won, playerIdx) { gameOver = true; game.state = 'ended'; if (callTimer) LK.clearTimeout(callTimer); for (var p = 0; p < playerCount; p++) { if (timerInterval[p]) LK.clearInterval(timerInterval[p]); // Freeze Timer timeout logic removed } if (won) { // Helper to highlight a line var highlightLine = function highlightLine(indices) { for (var i = 0; i < indices.length; i++) { var idx = indices[i]; var cell = bingoCells[playerIdx][idx]; tween(cell.markOverlay, { alpha: 1 }, { duration: 300, easing: tween.easeOut }); cell.markOverlay.color = 0xff6600; } }; winText[playerIdx].setText("BINGO!\nYou Win!"); winText[playerIdx].setStyle({ fill: 0xff6600 }); LK.effects.flashScreen(0xff6600, 1000); // Highlight the winning line(s) // Rebuild marked grid var marked = []; for (var col = 0; col < gridSize; col++) { marked[col] = []; for (var row = 0; row < gridSize; row++) { var idx = col * gridSize + row; marked[col][row] = bingoCells[playerIdx][idx].marked; } } for (var row = 0; row < gridSize; row++) { var win = true; var indices = []; for (var col = 0; col < gridSize; col++) { if (!marked[col][row]) win = false; indices.push(col * gridSize + row); } if (win) highlightLine(indices); } for (var col = 0; col < gridSize; col++) { var win = true; var indices = []; for (var row = 0; row < gridSize; row++) { if (!marked[col][row]) win = false; indices.push(col * gridSize + row); } if (win) highlightLine(indices); } var win = true; var indices = []; for (var i = 0; i < gridSize; i++) { if (!marked[i][i]) win = false; indices.push(i * gridSize + i); } if (win) highlightLine(indices); win = true; indices = []; for (var i = 0; i < gridSize; i++) { if (!marked[gridSize - 1 - i][i]) win = false; indices.push((gridSize - 1 - i) * gridSize + i); } if (win) highlightLine(indices); // Confetti effect on win for (var confetti = 0; confetti < 32; confetti++) { (function () { var c = new Container(); var colorList = [0xff6600, 0xffd700, 0x76ff03, 0x1565c0, 0xffffff]; var confettiColor = colorList[Math.floor(Math.random() * colorList.length)]; var confettiShape = c.attachAsset('bingoCellBg', { width: 24 + Math.random() * 16, height: 12 + Math.random() * 8, color: confettiColor, anchorX: 0.5, anchorY: 0.5 }); c.x = (playerIdx === 0 ? 2048 / 4 : 2048 * 3 / 4) + (Math.random() - 0.5) * 200; c.y = 0; c.rotation = Math.random() * Math.PI * 2; game.addChild(c); var targetY = 2732 / 2 + 400 + Math.random() * 200; var targetX = c.x + (Math.random() - 0.5) * 400; tween(c, { x: targetX, y: targetY, rotation: c.rotation + Math.PI * 2 * (Math.random() > 0.5 ? 1 : -1) }, { duration: 1200 + Math.random() * 600, easing: tween.easeIn, onComplete: function onComplete() { if (c.parent) c.parent.removeChild(c); } }); })(); } LK.showYouWin(); } else { winText[playerIdx].setText("Time's Up!\nGame Over"); winText[playerIdx].setStyle({ fill: 0x8b0000 }); LK.effects.flashScreen(0x8b0000, 1000); LK.showGameOver(); } winText[playerIdx].visible = true; // Freeze Timer button visibility removed } // --- Input: Restart on game over/win --- game.down = function (x, y, obj) { if (game.state === 'ended') { // Wait for LK to reset game } }; // --- Start game immediately, difficulty selection deactivated --- startGame(); // --- Ava: Add a subtle AI robot idle animation to make the AI feel more alive --- // Place the robot animation slightly higher and toward the center of the screen if (typeof aiRobotInstance === "undefined") { var aiRobotInstance = new AIRobot(); // Position robot: horizontally between center and right, vertically higher up aiRobotInstance.x = 2048 * 0.74; // Move a bit more to the right aiRobotInstance.y = 370; // Move slightly higher game.addChild(aiRobotInstance); // Animate a gentle up-down float for the AI robot var aiFloatT = { v: 0 }; var _aiFloat = function aiFloat() { tween(aiFloatT, { v: 1 }, { duration: 1800 + Math.random() * 600, easing: tween.easeInOut, onUpdate: function onUpdate() { // Float around the base y position aiRobotInstance.y = 370 + Math.sin(aiFloatT.v * Math.PI * 2) * 18; }, onComplete: function onComplete() { aiFloatT.v = 0; _aiFloat(); } }); }; _aiFloat(); } // --- Add Save Button (Kaydet) --- var kaydetBtn = new Container(); var btnBg = kaydetBtn.attachAsset('buttonHover', { anchorX: 0.5, anchorY: 0.5 }); var btnText = new Text2('Kaydet', { size: 70, fill: 0xffffff }); btnText.anchor.set(0.5, 0.5); btnText.x = 0; btnText.y = 0; kaydetBtn.addChild(btnText); // Place button at top right, but not in the menu area kaydetBtn.x = 2048 - 200; kaydetBtn.y = 120; kaydetBtn.interactive = true; kaydetBtn.buttonMode = true; kaydetBtn.down = function (x, y, obj) { kaydetOyunu(); tween(btnBg, { alpha: 0.5 }, { duration: 80, yoyo: true, repeat: 1 }); }; LK.gui.top.addChild(kaydetBtn); // --- Optionally, load game if available on start --- yukleOyunu(); // --- Animated background color pulse for visual appeal --- var bgPulseColors = [0x0a0e1a, // Deep cosmic blue 0x1a1446, // Space purple 0x232b4d, // Blue-violet 0x0a0e1a, // Deep cosmic blue 0x1a1446 // Space purple ]; // Cosmic blue/purple palette var bgPulseIndex = 0; var bgPulseDuration = 3000; function pulseBackground() { var fromColor = bgPulseColors[bgPulseIndex]; var toColor = bgPulseColors[(bgPulseIndex + 1) % bgPulseColors.length]; var t = { v: 0 }; tween(t, { v: 1 }, { duration: bgPulseDuration, easing: tween.easeInOut, onUpdate: function onUpdate() { // Interpolate color var r1 = fromColor >> 16 & 0xff, g1 = fromColor >> 8 & 0xff, b1 = fromColor & 0xff; var r2 = toColor >> 16 & 0xff, g2 = toColor >> 8 & 0xff, b2 = toColor & 0xff; var r = Math.round(r1 + (r2 - r1) * t.v); var g = Math.round(g1 + (g2 - g1) * t.v); var b = Math.round(b1 + (b2 - b1) * t.v); var color = r << 16 | g << 8 | b; game.setBackgroundColor(color); }, onComplete: function onComplete() { bgPulseIndex = (bgPulseIndex + 1) % bgPulseColors.length; pulseBackground(); } }); } pulseBackground();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// AI Robot: Animated character that dances in place (no left/right movement)
var AIRobot = Container.expand(function () {
var self = Container.call(this);
// Attach a robot body (use aiIndicator image as the robot's head/body)
var robotBody = self.attachAsset('aiIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
// Add two "eyes" using small ellipses
var leftEye = self.attachAsset('freeSpace', {
width: 24,
height: 24,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5
});
var rightEye = self.attachAsset('freeSpace', {
width: 24,
height: 24,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5
});
leftEye.x = -36;
leftEye.y = -20;
rightEye.x = 36;
rightEye.y = -20;
// Animation state
self.danceTick = 0;
// Initial position
self.x = 2048 * 3 / 4;
self.y = 2732 - 180;
// Update method for in-place dance animation
self.update = function () {
// Dance in place: gentle rotation and scale pulse
self.danceTick++;
// Rotate gently back and forth
self.rotation = Math.sin(self.danceTick / 30) * 0.18;
// Scale up and down for a "bounce" effect
var scalePulse = 1 + Math.sin(self.danceTick / 18) * 0.07;
self.scale.x = scalePulse;
self.scale.y = 1 - Math.sin(self.danceTick / 18) * 0.04;
// Eyes: blink or wiggle in place
var eyeWiggle = Math.sin(self.danceTick / 10) * 2;
leftEye.x = -36 + eyeWiggle;
rightEye.x = 36 - eyeWiggle;
};
return self;
});
// BingoCell: Represents a single cell on the bingo card
var BingoCell = Container.expand(function () {
var self = Container.call(this);
// Properties
self.number = 0;
self.marked = false;
// --- Space theme: cosmic background, blue/purple glow, and star/planet decor ---
var cellBg = self.attachAsset('Background', {
width: cellSize,
height: cellSize,
color: 0x0a0e1a,
// Deep cosmic blue-black
anchorX: 0.5,
anchorY: 0.5
});
cellBg.radius = cellSize * 0.22; // Simulate rounded corners (if supported by engine)
// Add a subtle blue/purple border for cosmic effect
var border = self.attachAsset('Background', {
width: cellSize * 0.98,
height: cellSize * 0.98,
color: 0x2d1b4d,
// Deep purple/blue
anchorX: 0.5,
anchorY: 0.5
});
border.radius = cellSize * 0.19;
border.alpha = 0.7;
// --- Subtle star and planet pattern: add 2-3 faint stars and 1 planet randomly in the cell ---
self.stars = [];
for (var i = 0; i < 3; i++) {
// Use white and yellow for stars
var starColor = i % 2 === 0 ? 0xffffff : 0xf7d794;
var star = self.attachAsset(i % 2 === 0 ? 'starWhite' : 'starYellow', {
width: cellSize * (0.10 + Math.random() * 0.08),
height: cellSize * (0.10 + Math.random() * 0.08),
color: starColor,
anchorX: 0.5,
anchorY: 0.5
});
star.alpha = 0.10 + Math.random() * 0.08;
// Place stars at random positions, but not center
var angle = Math.random() * Math.PI * 2;
var dist = cellSize * (0.23 + Math.random() * 0.18);
star.x = Math.cos(angle) * dist;
star.y = Math.sin(angle) * dist;
self.stars.push(star);
}
// Add a random planet for extra space flavor
var planetTypes = ['planetBlue', 'planetPurple', 'planetRed'];
var planetType = planetTypes[Math.floor(Math.random() * planetTypes.length)];
var planet = self.attachAsset(planetType, {
width: cellSize * 0.22,
height: cellSize * 0.22,
anchorX: 0.5,
anchorY: 0.5
});
planet.alpha = 0.13 + Math.random() * 0.07;
planet.x = (Math.random() - 0.5) * cellSize * 0.5;
planet.y = (Math.random() - 0.5) * cellSize * 0.5;
self.stars.push(planet);
// Number text
var numberText = new Text2('', {
size: Math.floor(cellSize * 0.45),
fill: 0x3a6cf6 // Neon blue for space theme
});
numberText.anchor.set(0.5, 0.5);
self.addChild(numberText);
// --- Mark overlay: cosmic blue/purple ellipse, hidden by default ---
var markOverlay = self.attachAsset('winHighlight', {
width: cellSize * 0.82,
height: cellSize * 0.82,
anchorX: 0.5,
anchorY: 0.5
});
markOverlay.alpha = 0;
markOverlay.color = 0x3a6cf6; // Neon blue for space theme
self.markOverlay = markOverlay;
// --- Glow effect: subtle blue/purple glow when marked ---
var glow = self.attachAsset('freeSpace', {
width: cellSize * 1.18,
height: cellSize * 1.18,
color: 0x82589f,
// Purple glow
anchorX: 0.5,
anchorY: 0.5
});
glow.alpha = 0;
self.glow = glow;
// Set number and update text
self.setNumber = function (num) {
self.number = num;
numberText.setText(num > 0 ? num : '');
};
// Mark/unmark cell
self.setMarked = function (val) {
self.marked = val;
if (val) {
// Animate mark overlay in
tween(markOverlay, {
alpha: 0.92
}, {
duration: 200,
easing: tween.easeOut
});
// Animate glow in
tween(glow, {
alpha: 0.22
}, {
duration: 200,
easing: tween.easeOut
});
numberText.setText(self.number);
numberText.setStyle({
fill: 0x000000 // Black for contrast on blue mark
});
} else {
// Animate mark overlay out
tween(markOverlay, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
// Animate glow out
tween(glow, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
numberText.setStyle({
fill: 0x3a6cf6 // Neon blue for space theme
});
}
};
// Touch event
self.down = function (x, y, obj) {
// Play click sound on any cell tap
LK.getSound('Click').play();
if (self.marked) return;
if (game.state !== 'playing') return;
var p = self.playerIndex !== undefined ? self.playerIndex : 0;
if (self.number === game.currentNumber && p === currentPlayer) {
self.setMarked(true);
// Flash with yellow and pulse
LK.effects.flashObject(self, 0xfff200, 200);
tween(self.scale, {
x: 1.13,
y: 1.13
}, {
duration: 120,
yoyo: true,
repeat: 1,
easing: tween.easeOut
});
// Streak logic
if (typeof streak !== "undefined") {
streak[p]++;
if (streak[p] > 1) {
timeLeft[p] += 1000;
}
}
game.checkWin();
} else {
if (typeof streak !== "undefined") {
streak[p] = 0;
}
LK.effects.flashObject(self, 0x8b0000, 200);
}
};
// Example: Trigger action when cell crosses X = 1000 from left to right
if (self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) {
// Place your action here, e.g. console.log("Cell crossed X=1000!");
}
// Always update lastX at the end
self.lastX = self.x;
// Example: Trigger action when cell crosses Y = 800 from above to below
if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800) {
// Place your action here, e.g. console.log("Cell crossed Y=800!");
}
// Always update lastY at the end
self.lastY = self.y;
// Example: Trigger action when cell crosses X=1000 and Y=800 at the same frame
if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800 && self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) {
// Place your action here, e.g. console.log("Cell arrived at (1000,800)!");
}
// Always update lastX and lastY at the end
self.lastX = self.x;
self.lastY = self.y;
return self;
});
// CalledNumberBall: Shows a called number as a round ball
var CalledNumberBall = Container.expand(function () {
var self = Container.call(this);
// Ball background
var ball = self.attachAsset('bingoBall', {
anchorX: 0.5,
anchorY: 0.5
});
// Number text
var numberText = new Text2('', {
size: 60,
fill: 0x000000
});
numberText.anchor.set(0.5, 0.5);
numberText.x = 0;
numberText.y = 0;
self.addChild(numberText);
self.setNumber = function (num) {
numberText.setText(num);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0e1a // Deep cosmic blue
});
/****
* Game Code
****/
// --- Added ses41 to ses75 sound assets (IDs to be filled by asset loader) ---
// Save the current game state (called numbers, card numbers, marked cells, time left, streaks)
// --- Kaydet (Save) Functionality ---
// --- Functions ---
// --- Hint Power-Up Button ---
// Bingo game shapes
// New shapes for improved UI
// Images
// New image assets for polish (IDs are placeholders, replace with real IDs if available)
// Sounds
// Neon blue planet
// Deep space blue
// Cyan for hover
// Dark blue for pressed
// Space black
// Galaxy border
// Neon green
// Star yellow
// Light blue
// Space shadow
// Neon cyan
// Neon green
// Space black
// Space shadow
// Neon green
// Deep blue
// Star yellow
// Star yellow
// Space/Galaxy themed assets for richer visuals
// Space/galaxy decorative shapes
// Space/galaxy themed overlays for cards
// Space/galaxy themed power-up icons
// Images (IDs are placeholders, replace with real asset IDs as needed)
// Sounds
// Neon pink
// Deep retro blue
// Neon cyan
// Neon yellow
// Purple
// Neon cyan
// Neon pink
// Neon yellow
// Neon cyan
// Purple
// Neon pink
// Neon yellow
// Deep retro blue
// Neon cyan
// Neon pink
// Neon yellow
// Purple
// Deep retro blue
// Neon cyan
// Neon cyan
// Neon pink
// Neon yellow
// Purple
// Neon pink
// Neon cyan
// Neon yellow
// Neon pink
// Deep retro blue
// Neon yellow
// Purple
// Neon cyan
// Neon pink
// Neon yellow
// Neon pink
// Candy pink
// Pastel orange
// Mint green
// Candy orange
// Light pink
// Mint green
// Candy pink
// Candy orange
// Mint green
// Light pink
// Candy pink
// Candy orange
// Light pink
// Mint green
// Candy pink
// Candy orange
// Light pink
// Pastel orange
// Mint green
// Pastel blue
// Pastel purple
// Candy pink
// Light pink
// Candy pink
// Mint green
// Candy orange
// Candy pink
// Pastel orange
// Pastel yellow
// Light pink
// Mint green
// Candy pink
// Candy orange
// Candy pink
// Forest green ball
// Light moss cell
// Fern green hover
// Deep green pressed
// Pale green
// Deep green border
// Sunlight confetti
// Light brown confetti
// Fern green
// Pale green
// Forest green
// Sunlight free space
// Pale green bg
// Fern swirl
// Forest green
// Deep green
// Pale green overlay
// Light brown
// Deep green
// Blue pond
// Forest flower
// Mushroom cap
// Pale green
// Forest green
// Fern green
// Light brown
// Sunlight
// Light moss
// Sunlight
// Pale green
// Fern green
// Forest green
// Sunlight
// Deep green
// Ses assets for ses1 to ses40
function kaydetOyunu() {
// Prepare save data
var saveData = {
calledNumbers: calledNumbers.slice(),
cardNumbers: [cardNumbers[0] ? cardNumbers[0].map(function (col) {
return col.slice();
}) : [], cardNumbers[1] ? cardNumbers[1].map(function (col) {
return col.slice();
}) : []],
marked: [bingoCells[0] ? bingoCells[0].map(function (cell) {
return cell.marked;
}) : [], bingoCells[1] ? bingoCells[1].map(function (cell) {
return cell.marked;
}) : []],
timeLeft: timeLeft.slice(),
streak: streak.slice(),
currentPlayer: currentPlayer,
gameOver: gameOver,
state: game.state,
availableNumbers: availableNumbers.slice(),
currentNumber: game.currentNumber
};
storage['bingo_save'] = saveData;
}
// Load the saved game state (if any)
function yukleOyunu() {
var saveData = storage['bingo_save'];
if (!saveData) return false;
// Restore state
calledNumbers = saveData.calledNumbers || [];
cardNumbers = [saveData.cardNumbers[0] ? saveData.cardNumbers[0].map(function (col) {
return col.slice();
}) : [], saveData.cardNumbers[1] ? saveData.cardNumbers[1].map(function (col) {
return col.slice();
}) : []];
availableNumbers = saveData.availableNumbers ? saveData.availableNumbers.slice() : [];
timeLeft = saveData.timeLeft ? saveData.timeLeft.slice() : [gameDuration, gameDuration];
streak = saveData.streak ? saveData.streak.slice() : [0, 0];
currentPlayer = typeof saveData.currentPlayer === "number" ? saveData.currentPlayer : 0;
gameOver = !!saveData.gameOver;
game.state = saveData.state || 'playing';
game.currentNumber = typeof saveData.currentNumber === "number" ? saveData.currentNumber : null;
// Re-create cards and marked cells
for (var p = 0; p < playerCount; p++) {
if (!cardNumbers[p] || cardNumbers[p].length === 0) continue;
if (!bingoCells[p]) bingoCells[p] = [];
for (var i = 0; i < bingoCells[p].length; i++) {
if (bingoCells[p][i]) {
bingoCells[p][i].destroy();
}
}
bingoCells[p] = [];
}
createBingoCards();
// Restore marked cells
for (var p = 0; p < playerCount; p++) {
if (!saveData.marked[p]) continue;
for (var i = 0; i < saveData.marked[p].length; i++) {
if (bingoCells[p][i]) {
bingoCells[p][i].setMarked(!!saveData.marked[p][i]);
}
}
}
// Restore timers, streaks, UI
for (var p = 0; p < playerCount; p++) {
if (timerInterval[p]) LK.clearInterval(timerInterval[p]);
timerInterval[p] = LK.setInterval(function (playerIdx) {
return function () {
if (!freezeTimerActive[playerIdx]) {
timeLeft[playerIdx] -= 100;
if (timeLeft[playerIdx] < 0) timeLeft[playerIdx] = 0;
updateTimerTextForPlayer(playerIdx);
if (timeLeft[playerIdx] <= 0 && !gameOver) {
endGame(false, playerIdx);
}
}
};
}(p), 100);
updateTimerTextForPlayer(p);
// streakText UI removed
}
updateCalledBallsUI();
numberCallText.setText(game.currentNumber ? game.currentNumber : '');
return true;
}
// Bingo ball (yellow ellipse)
// Bingo cell background (cyan box)
// Mark overlay (beige box, used for marking cells)
// Hint button background (green box, used for hint power-up)
// Free space overlay (distinct color for center cell)
// Win highlight overlay (gold ellipse for winning line)
// Reveal Row button removed
// Freeze Timer button and logic removed
// Ses assets for ses1 to ses40
var gridSize = 5; // 5x5 bingo
// Adjust cellSize and card positions for two-player mode to fit both cards on screen
var cellSize = 180; // px, reduced to fit two cards side by side
var cardPadding = 30;
var cardWidth = gridSize * cellSize;
var cardHeight = gridSize * cellSize;
var cardStartX = 2048 / 4 - cardWidth / 2; // Player 1 card center at 1/4 width, Player 2 at 3/4 width
var cardStartY = 500; // Lowered to fit both cards and UI
var callIntervalStart = 4000; // ms (4 seconds initial call speed)
var callIntervalMin = 1200; // ms (slower minimum speed)
var callIntervalStep = 60; // ms, decrease per call (slower speedup)
var gameDuration = 225000; // ms (3 min 45 sec)
var numbersRange = 75; // 1-75
// --- State ---
// Two player support
var playerCount = 2;
var currentPlayer = 0; // 0 or 1
var bingoCells = [[], []]; // bingoCells[0] for player 1, bingoCells[1] for player 2
var calledNumbers = [];
var availableNumbers = [];
var callTimer = null;
var timeLeft = [gameDuration, gameDuration]; // Separate timers for each player
var timerInterval = [null, null];
var cardNumbers = [[], []];
var gameOver = false;
var playerNames = ["You", "AI"];
var winText = [null, null]; // Per player
var streak = [0, 0];
var streakText = [null, null];
var timerText = [null, null];
// Freeze Timer state arrays removed
// --- Freeze Timer compatibility: define freezeTimerActive as always-false array for each player ---
var freezeTimerActive = [false, false];
// --- UI Elements ---
// Container for called number balls
var calledBallsContainer = new Container();
calledBallsContainer.x = 2048 / 2;
calledBallsContainer.y = 2732 - 120;
game.addChild(calledBallsContainer);
// Show the latest called numbers as balls (max 6)
function updateCalledBallsUI() {
// Remove old balls
while (calledBallsContainer.children.length > 0) {
calledBallsContainer.removeChild(calledBallsContainer.children[0]);
}
var maxBalls = 6;
var startIdx = Math.max(0, calledNumbers.length - maxBalls);
var ballsToShow = calledNumbers.slice(startIdx);
var spacing = 130;
var totalWidth = (ballsToShow.length - 1) * spacing;
for (var i = 0; i < ballsToShow.length; i++) {
var ball = new CalledNumberBall();
ball.setNumber(ballsToShow[i]);
ball.x = -totalWidth / 2 + i * spacing;
ball.y = 0;
// Animate in the newest ball
if (i === ballsToShow.length - 1) {
ball.scale.x = 0.1;
ball.scale.y = 0.1;
tween(ball.scale, {
x: 1,
y: 1
}, {
duration: 180,
easing: tween.easeOut
});
}
calledBallsContainer.addChild(ball);
}
}
var numberCallText = new Text2('', {
size: 180,
fill: 0xff073a // Neon red
});
numberCallText.anchor.set(0.5, 0.5);
numberCallText.x = 2048 / 2;
numberCallText.y = 2732 - 300;
game.addChild(numberCallText);
// Number left text UI removed
var winText = new Text2('', {
size: 120,
fill: 0xfff200 // Neon yellow
});
winText.anchor.set(0.5, 0.5);
winText.x = 2048 / 2;
winText.y = 2732 / 2;
winText.visible = false;
game.addChild(winText);
// --- Functions ---
// Example: Trigger action when a cell intersects with another object (e.g. another cell or a special marker)
// Assume we have a global reference to a special object, e.g. specialMarker
// (You would need to define specialMarker somewhere in your game if you want to use this for real)
if (typeof specialMarker !== "undefined" && bingoCells && bingoCells[0]) {
for (var i = 0; i < bingoCells[0].length; i++) {
var cell = bingoCells[0][i];
if (cell.lastWasIntersecting === false && cell.intersects(specialMarker)) {
// Place your action here, e.g. console.log("Cell just started intersecting with specialMarker!");
}
cell.lastWasIntersecting = cell.intersects(specialMarker);
}
}
// Generate a random bingo card (5x5, center is free)
function generateCardNumbers() {
var nums = [];
var used = [];
for (var col = 0; col < gridSize; col++) {
var colNums = [];
var min = col * 15 + 1;
var max = min + 14;
for (var row = 0; row < gridSize; row++) {
if (col === 2 && row === 2) {
colNums.push(0); // Free space
continue;
}
var n;
do {
n = min + Math.floor(Math.random() * (max - min + 1));
} while (used.indexOf(n) !== -1);
used.push(n);
colNums.push(n);
}
nums.push(colNums);
}
return nums;
}
// Create bingo card UI for both players
function createBingoCards() {
for (var p = 0; p < playerCount; p++) {
bingoCells[p] = [];
cardNumbers[p] = generateCardNumbers();
// Center cards at 1/4 and 3/4 of the screen width
var cardCenterX = p === 0 ? 2048 / 4 : 2048 * 3 / 4;
var offsetX = cardCenterX - cardWidth / 2;
for (var col = 0; col < gridSize; col++) {
for (var row = 0; row < gridSize; row++) {
var cell = new BingoCell();
var x = offsetX + col * cellSize + cellSize / 2;
var y = cardStartY + row * cellSize + cellSize / 2;
cell.x = x;
cell.y = y;
var num = cardNumbers[p][col][row];
cell.setNumber(num);
if (col === 2 && row === 2) {
cell.setMarked(true); // Free space
}
cell.playerIndex = p;
game.addChild(cell);
bingoCells[p].push(cell);
}
}
// --- Ava: Add a fun idle animation to the player's bingo card for visual feedback ---
if (p === 0) {
// Animate the whole card with a gentle floating effect
var floatT = {
v: 0
};
var _floatCard = function floatCard() {
tween(floatT, {
v: 1
}, {
duration: 2200 + Math.random() * 800,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
// Apply a gentle up-down float to all player cells
for (var i = 0; i < bingoCells[0].length; i++) {
var baseY = cardStartY + Math.floor(i / gridSize) * cellSize + cellSize / 2;
bingoCells[0][i].y = baseY + Math.sin(floatT.v * Math.PI * 2) * 10;
}
},
onComplete: function onComplete() {
floatT.v = 0;
_floatCard();
}
});
};
_floatCard();
// --- Ava: Add a 'You' indicator animation for the player side ---
// Only add once per game start
if (typeof youIndicatorInstance === "undefined" || !youIndicatorInstance) {
var youIndicatorInstance = new Container();
// Add a glowing ellipse as a background
var youBg = youIndicatorInstance.attachAsset('freeSpace', {
width: 180,
height: 90,
color: 0xff6600,
anchorX: 0.5,
anchorY: 0.5
});
youBg.alpha = 0.22;
// Add a white ellipse for extra glow
var youGlow = youIndicatorInstance.attachAsset('freeSpace', {
width: 220,
height: 110,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5
});
youGlow.alpha = 0.09;
// Add the "You" text
var youText = new Text2('You', {
size: 80,
fill: 0xff6600,
font: "Impact, Arial Black, Tahoma"
});
youText.anchor.set(0.5, 0.5);
youText.y = 0;
youIndicatorInstance.addChild(youText);
// Place above the player's card, centered horizontally
youIndicatorInstance.x = 2048 / 4;
youIndicatorInstance.y = cardStartY - 80;
game.addChild(youIndicatorInstance);
// Animate: gentle up-down float and scale pulse
var youFloatT = {
v: 0
};
var _youFloat = function youFloat() {
tween(youFloatT, {
v: 1
}, {
duration: 1800 + Math.random() * 600,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
youIndicatorInstance.y = cardStartY - 80 + Math.sin(youFloatT.v * Math.PI * 2) * 18;
var scalePulse = 1 + Math.sin(youFloatT.v * Math.PI * 2) * 0.07;
youIndicatorInstance.scale.x = scalePulse;
youIndicatorInstance.scale.y = scalePulse;
},
onComplete: function onComplete() {
youFloatT.v = 0;
_youFloat();
}
});
};
_youFloat();
}
}
}
}
// Start a new game for two players
function startGame() {
game.state = 'playing';
gameOver = false;
calledNumbers = [];
availableNumbers = [];
for (var i = 1; i <= numbersRange; i++) availableNumbers.push(i);
createBingoCards();
numberCallText.setText('');
// Per player UI and state
for (var p = 0; p < playerCount; p++) {
if (!winText[p]) {
winText[p] = new Text2('', {
size: 120,
fill: 0xff6600
});
winText[p].anchor.set(0.5, 0.5);
winText[p].x = p === 0 ? 2048 / 4 : 2048 * 3 / 4;
winText[p].y = 2732 / 2;
winText[p].visible = false;
game.addChild(winText[p]);
}
// (AI robot animation and label will be handled globally after startGame)
// streakText UI removed
if (!timerText[p]) {
timerText[p] = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
timerText[p].anchor.set(0.5, 0);
if (p === 0) {
// Human player timer below their board, aligned like AI timer
timerText[p].x = 2048 / 4;
timerText[p].y = cardStartY + cardHeight + 200 + 180; // Moved 60px further down
game.addChild(timerText[p]);
} else {
// AI player timer below their board
timerText[p].x = 2048 * 3 / 4;
// Move timerText below the AI indicator image (aiIndicator.y + aiIndicator.height/2 + margin)
timerText[p].y = cardStartY + cardHeight + 200 + 180; // Moved 60px further down
game.addChild(timerText[p]);
}
}
winText[p].visible = false;
streak[p] = 0;
// streakText UI removed
// Freeze Timer state reset removed
timeLeft[p] = gameDuration;
updateTimerTextForPlayer(p);
if (timerInterval[p]) LK.clearInterval(timerInterval[p]);
timerInterval[p] = LK.setInterval(function (playerIdx) {
return function () {
if (!freezeTimerActive[playerIdx]) {
timeLeft[playerIdx] -= 100;
if (timeLeft[playerIdx] < 0) timeLeft[playerIdx] = 0;
updateTimerTextForPlayer(playerIdx);
if (timeLeft[playerIdx] <= 0 && !gameOver) {
endGame(false, playerIdx);
}
}
};
}(p), 100);
}
updateCalledBallsUI();
// Number left text UI update removed
currentPlayer = 0;
nextNumberCall(callIntervalStart);
}
// Call the next number
game.currentNumber = null;
function nextNumberCall(interval) {
if (gameOver) return;
if (availableNumbers.length === 0) {
endGame(false);
return;
}
var idx = Math.floor(Math.random() * availableNumbers.length);
var num = availableNumbers[idx];
availableNumbers.splice(idx, 1);
calledNumbers.push(num);
game.currentNumber = num;
numberCallText.setText(num);
LK.effects.flashObject(numberCallText, 0xff6600, 300);
// Play ses1-ses75 sound if number is in 1-75
if (num >= 1 && num <= 75) {
var soundId = 'ses' + num;
var sound = LK.getSound(soundId);
if (sound) sound.play();
}
// Update called balls UI
updateCalledBallsUI();
// Animate all called balls with a gentle bounce
for (var i = 0; i < calledBallsContainer.children.length; i++) {
var ball = calledBallsContainer.children[i];
if (ball && ball.scale) {
ball.scale.x = 1;
ball.scale.y = 1;
tween(ball.scale, {
x: 1.15,
y: 1.15
}, {
duration: 120,
yoyo: true,
repeat: 1,
easing: tween.easeOut
});
}
}
// Number left text UI update removed
// Pulse the matching cell(s) on the human player's card
for (var i = 0; i < bingoCells[0].length; i++) {
if (bingoCells[0][i].number === num && !bingoCells[0][i].marked) {
// Flash the cell background for extra attention
LK.effects.flashObject(bingoCells[0][i], 0xfff200, 220);
// Pulse the cell scale
tween(bingoCells[0][i].scale, {
x: 1.22,
y: 1.22
}, {
duration: 140,
yoyo: true,
repeat: 1,
easing: tween.easeOut
});
}
}
// --- Enhanced Opponent AI ---
if (playerCount === 2 && !gameOver) {
var opponentIdx = 1;
// Analyze opponent's board state
var opponentScore = 0;
var nearWinLines = [];
var marked = [];
// Build marked grid and count score
for (var col = 0; col < gridSize; col++) {
marked[col] = [];
for (var row = 0; row < gridSize; row++) {
var idx = col * gridSize + row;
marked[col][row] = bingoCells[opponentIdx][idx].marked;
if (marked[col][row]) opponentScore++;
}
}
// Check for lines that are one cell away from winning
// Check rows
for (var row = 0; row < gridSize; row++) {
var markedCount = 0;
for (var col = 0; col < gridSize; col++) {
if (marked[col][row]) markedCount++;
}
if (markedCount === gridSize - 1) nearWinLines.push({
type: 'row',
index: row
});
}
// Check columns
for (var col = 0; col < gridSize; col++) {
var markedCount = 0;
for (var row = 0; row < gridSize; row++) {
if (marked[col][row]) markedCount++;
}
if (markedCount === gridSize - 1) nearWinLines.push({
type: 'col',
index: col
});
}
// Check diagonals
var diagCount1 = 0,
diagCount2 = 0;
for (var i = 0; i < gridSize; i++) {
if (marked[i][i]) diagCount1++;
if (marked[gridSize - 1 - i][i]) diagCount2++;
}
if (diagCount1 === gridSize - 1) nearWinLines.push({
type: 'diag1'
});
if (diagCount2 === gridSize - 1) nearWinLines.push({
type: 'diag2'
});
// Find the cell with the current number
for (var i = 0; i < bingoCells[opponentIdx].length; i++) {
var cell = bingoCells[opponentIdx][i];
if (cell.number === num && !cell.marked) {
// Calculate AI response time based on selected difficulty
var aiDelay = 0;
var accuracyChance = 0.95; // Default fallback
// Use selected difficulty if set, else fallback to old logic
if (typeof game.selectedDifficulty !== "undefined") {
// Use values set in overlay
var aiAcc = typeof game.aiAccuracy !== "undefined" ? game.aiAccuracy : 0.95;
var aiMin = typeof game.aiMinDelay !== "undefined" ? game.aiMinDelay : 200;
var aiMax = typeof game.aiMaxDelay !== "undefined" ? game.aiMaxDelay : 800;
aiDelay = aiMin + Math.random() * (aiMax - aiMin);
accuracyChance = aiAcc;
} else {
// Factor 1: Score-based speed (the more marks, the faster)
if (opponentScore < 5) {
aiDelay = 800 + Math.random() * 600;
accuracyChance = 0.7;
} else if (opponentScore < 10) {
aiDelay = 400 + Math.random() * 400;
accuracyChance = 0.85;
} else if (opponentScore < 15) {
aiDelay = 200 + Math.random() * 300;
accuracyChance = 0.92;
} else {
aiDelay = 100 + Math.random() * 200;
accuracyChance = 0.98;
}
}
// Factor 2: Priority boost if this cell completes a line
var cellCol = Math.floor(i / gridSize);
var cellRow = i % gridSize;
var isPriority = false;
for (var n = 0; n < nearWinLines.length; n++) {
var line = nearWinLines[n];
if (line.type === 'row' && cellRow === line.index) isPriority = true;else if (line.type === 'col' && cellCol === line.index) isPriority = true;else if (line.type === 'diag1' && cellCol === cellRow) isPriority = true;else if (line.type === 'diag2' && cellCol === gridSize - 1 - cellRow) isPriority = true;
}
if (isPriority) {
aiDelay = Math.min(aiDelay, 150 + Math.random() * 100);
accuracyChance = 0.99;
}
// Factor 3: Occasional mistakes (miss a number)
var makesMistake = Math.random() > accuracyChance;
(function (cell, aiDelay, makesMistake) {
LK.setTimeout(function () {
if (!cell.marked && !gameOver && !makesMistake) {
cell.setMarked(true);
// Flash with AI indicator color
LK.effects.flashObject(cell, 0x1565c0, 180);
// Update streak for opponent
streak[opponentIdx]++;
// Add time bonus for streak
if (streak[opponentIdx] > 1) {
timeLeft[opponentIdx] += 1000;
}
// Check win for opponent
var prevPlayer = currentPlayer;
currentPlayer = opponentIdx;
game.checkWin();
currentPlayer = prevPlayer;
} else if (makesMistake && !gameOver) {
// AI missed this number, reset streak
streak[opponentIdx] = 0;
}
}, aiDelay);
})(cell, aiDelay, makesMistake);
}
}
}
// Speed up calls as game progresses
var nextInterval = Math.max(callIntervalMin, interval - callIntervalStep);
if (callTimer) LK.clearTimeout(callTimer);
callTimer = LK.setTimeout(function () {
nextNumberCall(nextInterval);
}, nextInterval);
}
// Update timer UI for a specific player
function updateTimerTextForPlayer(p) {
var sec = Math.ceil(timeLeft[p] / 1000);
if (p === 0) {
timerText[p].setText("Your Time: " + sec + "s");
} else {
timerText[p].setText("AI Player Time: " + sec + "s");
}
}
// Check for win (row, col, diag) for the current player
game.checkWin = function () {
var p = currentPlayer;
// Build marked grid
var marked = [];
for (var col = 0; col < gridSize; col++) {
marked[col] = [];
for (var row = 0; row < gridSize; row++) {
var idx = col * gridSize + row;
marked[col][row] = bingoCells[p][idx].marked;
}
}
// Check rows
for (var row = 0; row < gridSize; row++) {
var win = true;
for (var col = 0; col < gridSize; col++) {
if (!marked[col][row]) win = false;
}
if (win) return endGame(true, p);
}
// Check cols
for (var col = 0; col < gridSize; col++) {
var win = true;
for (var row = 0; row < gridSize; row++) {
if (!marked[col][row]) win = false;
}
if (win) return endGame(true, p);
}
// Check diag TL-BR
var win = true;
for (var i = 0; i < gridSize; i++) {
if (!marked[i][i]) win = false;
}
if (win) return endGame(true, p);
// Check diag TR-BL
win = true;
for (var i = 0; i < gridSize; i++) {
if (!marked[gridSize - 1 - i][i]) win = false;
}
if (win) return endGame(true, p);
};
// End game: win or lose for a specific player
function endGame(won, playerIdx) {
gameOver = true;
game.state = 'ended';
if (callTimer) LK.clearTimeout(callTimer);
for (var p = 0; p < playerCount; p++) {
if (timerInterval[p]) LK.clearInterval(timerInterval[p]);
// Freeze Timer timeout logic removed
}
if (won) {
// Helper to highlight a line
var highlightLine = function highlightLine(indices) {
for (var i = 0; i < indices.length; i++) {
var idx = indices[i];
var cell = bingoCells[playerIdx][idx];
tween(cell.markOverlay, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
cell.markOverlay.color = 0xff6600;
}
};
winText[playerIdx].setText("BINGO!\nYou Win!");
winText[playerIdx].setStyle({
fill: 0xff6600
});
LK.effects.flashScreen(0xff6600, 1000);
// Highlight the winning line(s)
// Rebuild marked grid
var marked = [];
for (var col = 0; col < gridSize; col++) {
marked[col] = [];
for (var row = 0; row < gridSize; row++) {
var idx = col * gridSize + row;
marked[col][row] = bingoCells[playerIdx][idx].marked;
}
}
for (var row = 0; row < gridSize; row++) {
var win = true;
var indices = [];
for (var col = 0; col < gridSize; col++) {
if (!marked[col][row]) win = false;
indices.push(col * gridSize + row);
}
if (win) highlightLine(indices);
}
for (var col = 0; col < gridSize; col++) {
var win = true;
var indices = [];
for (var row = 0; row < gridSize; row++) {
if (!marked[col][row]) win = false;
indices.push(col * gridSize + row);
}
if (win) highlightLine(indices);
}
var win = true;
var indices = [];
for (var i = 0; i < gridSize; i++) {
if (!marked[i][i]) win = false;
indices.push(i * gridSize + i);
}
if (win) highlightLine(indices);
win = true;
indices = [];
for (var i = 0; i < gridSize; i++) {
if (!marked[gridSize - 1 - i][i]) win = false;
indices.push((gridSize - 1 - i) * gridSize + i);
}
if (win) highlightLine(indices);
// Confetti effect on win
for (var confetti = 0; confetti < 32; confetti++) {
(function () {
var c = new Container();
var colorList = [0xff6600, 0xffd700, 0x76ff03, 0x1565c0, 0xffffff];
var confettiColor = colorList[Math.floor(Math.random() * colorList.length)];
var confettiShape = c.attachAsset('bingoCellBg', {
width: 24 + Math.random() * 16,
height: 12 + Math.random() * 8,
color: confettiColor,
anchorX: 0.5,
anchorY: 0.5
});
c.x = (playerIdx === 0 ? 2048 / 4 : 2048 * 3 / 4) + (Math.random() - 0.5) * 200;
c.y = 0;
c.rotation = Math.random() * Math.PI * 2;
game.addChild(c);
var targetY = 2732 / 2 + 400 + Math.random() * 200;
var targetX = c.x + (Math.random() - 0.5) * 400;
tween(c, {
x: targetX,
y: targetY,
rotation: c.rotation + Math.PI * 2 * (Math.random() > 0.5 ? 1 : -1)
}, {
duration: 1200 + Math.random() * 600,
easing: tween.easeIn,
onComplete: function onComplete() {
if (c.parent) c.parent.removeChild(c);
}
});
})();
}
LK.showYouWin();
} else {
winText[playerIdx].setText("Time's Up!\nGame Over");
winText[playerIdx].setStyle({
fill: 0x8b0000
});
LK.effects.flashScreen(0x8b0000, 1000);
LK.showGameOver();
}
winText[playerIdx].visible = true;
// Freeze Timer button visibility removed
}
// --- Input: Restart on game over/win ---
game.down = function (x, y, obj) {
if (game.state === 'ended') {
// Wait for LK to reset game
}
};
// --- Start game immediately, difficulty selection deactivated ---
startGame();
// --- Ava: Add a subtle AI robot idle animation to make the AI feel more alive ---
// Place the robot animation slightly higher and toward the center of the screen
if (typeof aiRobotInstance === "undefined") {
var aiRobotInstance = new AIRobot();
// Position robot: horizontally between center and right, vertically higher up
aiRobotInstance.x = 2048 * 0.74; // Move a bit more to the right
aiRobotInstance.y = 370; // Move slightly higher
game.addChild(aiRobotInstance);
// Animate a gentle up-down float for the AI robot
var aiFloatT = {
v: 0
};
var _aiFloat = function aiFloat() {
tween(aiFloatT, {
v: 1
}, {
duration: 1800 + Math.random() * 600,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
// Float around the base y position
aiRobotInstance.y = 370 + Math.sin(aiFloatT.v * Math.PI * 2) * 18;
},
onComplete: function onComplete() {
aiFloatT.v = 0;
_aiFloat();
}
});
};
_aiFloat();
}
// --- Add Save Button (Kaydet) ---
var kaydetBtn = new Container();
var btnBg = kaydetBtn.attachAsset('buttonHover', {
anchorX: 0.5,
anchorY: 0.5
});
var btnText = new Text2('Kaydet', {
size: 70,
fill: 0xffffff
});
btnText.anchor.set(0.5, 0.5);
btnText.x = 0;
btnText.y = 0;
kaydetBtn.addChild(btnText);
// Place button at top right, but not in the menu area
kaydetBtn.x = 2048 - 200;
kaydetBtn.y = 120;
kaydetBtn.interactive = true;
kaydetBtn.buttonMode = true;
kaydetBtn.down = function (x, y, obj) {
kaydetOyunu();
tween(btnBg, {
alpha: 0.5
}, {
duration: 80,
yoyo: true,
repeat: 1
});
};
LK.gui.top.addChild(kaydetBtn);
// --- Optionally, load game if available on start ---
yukleOyunu();
// --- Animated background color pulse for visual appeal ---
var bgPulseColors = [0x0a0e1a,
// Deep cosmic blue
0x1a1446,
// Space purple
0x232b4d,
// Blue-violet
0x0a0e1a,
// Deep cosmic blue
0x1a1446 // Space purple
]; // Cosmic blue/purple palette
var bgPulseIndex = 0;
var bgPulseDuration = 3000;
function pulseBackground() {
var fromColor = bgPulseColors[bgPulseIndex];
var toColor = bgPulseColors[(bgPulseIndex + 1) % bgPulseColors.length];
var t = {
v: 0
};
tween(t, {
v: 1
}, {
duration: bgPulseDuration,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
// Interpolate color
var r1 = fromColor >> 16 & 0xff,
g1 = fromColor >> 8 & 0xff,
b1 = fromColor & 0xff;
var r2 = toColor >> 16 & 0xff,
g2 = toColor >> 8 & 0xff,
b2 = toColor & 0xff;
var r = Math.round(r1 + (r2 - r1) * t.v);
var g = Math.round(g1 + (g2 - g1) * t.v);
var b = Math.round(b1 + (b2 - b1) * t.v);
var color = r << 16 | g << 8 | b;
game.setBackgroundColor(color);
},
onComplete: function onComplete() {
bgPulseIndex = (bgPulseIndex + 1) % bgPulseColors.length;
pulseBackground();
}
});
}
pulseBackground();
Bingo thema. In-Game asset. 2d. High contrast. No shadows
Aİ player. In-Game asset. 2d. High contrast. No shadows
Bingo Mark. In-Game asset. 2d. High contrast. No shadows
Streakbackground bingo. In-Game asset. 2d. High contrast. No shadows
Card border. In-Game asset. 2d. High contrast. No shadows
Yellow ball. In-Game asset. 2d. High contrast. No shadows
Siyah X işaretli jeton. In-Game asset. 2d. High contrast. No shadows
YOU yazısını yaz. In-Game asset. 2d. High contrast. No shadows
Click
Sound effect
Numberthree
Sound effect
ses1
Sound effect
ses2
Sound effect
ses3
Sound effect
ses4
Sound effect
ses5
Sound effect
ses6
Sound effect
ses7
Sound effect
ses8
Sound effect
ses9
Sound effect
ses10
Sound effect
ses11
Sound effect
ses12
Sound effect
ses13
Sound effect
ses14
Sound effect
ses15
Sound effect
ses16
Sound effect
ses17
Sound effect
ses18
Sound effect
ses19
Sound effect
ses20
Sound effect
ses21
Sound effect
ses22
Sound effect
ses23
Sound effect
ses24
Sound effect
ses25
Sound effect
ses26
Sound effect
ses27
Sound effect
ses28
Sound effect
ses29
Sound effect
ses30
Sound effect
ses31
Sound effect
ses32
Sound effect
ses33
Sound effect
ses34
Sound effect
ses35
Sound effect
ses36
Sound effect
ses37
Sound effect
ses38
Sound effect
ses39
Sound effect
ses40
Sound effect
ses41
Sound effect
ses42
Sound effect
ses43
Sound effect
ses44
Sound effect
ses45
Sound effect
ses46
Sound effect
ses47
Sound effect
ses48
Sound effect
ses49
Sound effect
ses50
Sound effect
ses51
Sound effect
ses52
Sound effect
ses53
Sound effect
ses54
Sound effect
ses55
Sound effect
ses56
Sound effect
ses57
Sound effect
ses58
Sound effect
ses59
Sound effect
ses60
Sound effect
ses61
Sound effect
ses62
Sound effect
ses64
Sound effect
ses65
Sound effect
ses66
Sound effect
ses67
Sound effect
ses68
Sound effect
ses69
Sound effect
ses70
Sound effect
ses71
Sound effect
ses72
Sound effect
ses75
Sound effect
Ses73
Sound effect
Ses74
Sound effect
Sonikidakika
Sound effect
Sonbirdakika
Sound effect
Oyunahosgeldin
Sound effect
oyunahosgeldin
Sound effect