/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var DirectionalButton = Container.expand(function (direction, assetId) { var self = Container.call(this); var graphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.direction = direction; // Add visual feedback when pressed self.down = function (x, y, obj) { if (!isGameRunning) { return; } // Prevent multiple rapid presses if (self.isPressed) { return; } self.isPressed = true; // Visual feedback - make button slightly smaller tween(self, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); // Change snake direction immediately changeDirection(self.direction); }; self.up = function (x, y, obj) { // Reset pressed state self.isPressed = false; // Return button to normal size tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); }; return self; }); var EnemySnake = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('enemySnake', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0xff4444; // Red tint for enemy self.moveSpeed = 1.5; self.direction = Math.random() * Math.PI * 2; self.chaseTimer = 0; self.isBeingRepelled = false; self.repelTimer = 0; self.update = function () { // Check if being repelled by friendly snakes self.isBeingRepelled = false; for (var i = 0; i < friendlySnakes.length; i++) { var friendlySnake = friendlySnakes[i]; var dist = Math.sqrt(Math.pow(self.x - friendlySnake.x, 2) + Math.pow(self.y - friendlySnake.y, 2)); if (dist < 150) { // Repel range self.isBeingRepelled = true; // Move away from friendly snake var angle = Math.atan2(self.y - friendlySnake.y, self.x - friendlySnake.x); self.direction = angle; break; } } // If not being repelled, chase the player if (!self.isBeingRepelled && snake.length > 0) { self.chaseTimer++; if (self.chaseTimer >= 30) { // Update chase direction every 0.5 seconds var playerHead = snake[0]; var playerScreenPos = gridToScreen(playerHead.x, playerHead.y); var angle = Math.atan2(playerScreenPos.y - self.y, playerScreenPos.x - self.x); self.direction = angle; self.chaseTimer = 0; } } // Move in current direction self.x += Math.cos(self.direction) * self.moveSpeed; self.y += Math.sin(self.direction) * self.moveSpeed; // Bounce off walls if (self.x < boardOffsetX || self.x > boardOffsetX + BOARD_WIDTH * GRID_SIZE) { self.direction = Math.PI - self.direction; } if (self.y < boardOffsetY || self.y > boardOffsetY + BOARD_HEIGHT * GRID_SIZE) { self.direction = -self.direction; } // Keep within bounds self.x = Math.max(boardOffsetX, Math.min(boardOffsetX + BOARD_WIDTH * GRID_SIZE, self.x)); self.y = Math.max(boardOffsetY, Math.min(boardOffsetY + BOARD_HEIGHT * GRID_SIZE, self.y)); }; return self; }); var Food = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Simple pulsing animation var scale = 1 + Math.sin(LK.ticks * 0.1) * 0.1; self.scaleX = scale; self.scaleY = scale; }; return self; }); var FriendlySnake = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('friendlySnake', { anchorX: 0.5, anchorY: 0.5 }); self.moveSpeed = 2; self.direction = Math.random() * Math.PI * 2; self.dropTimer = 0; self.maxDrops = 3; self.dropsLeft = 3; self.hasKilledEnemy = false; self.update = function () { // Check for nearby enemy snakes to chase var isChasing = false; var closestEnemy = null; var closestDistance = Infinity; for (var i = 0; i < enemySnakes.length; i++) { var enemySnake = enemySnakes[i]; var dist = Math.sqrt(Math.pow(self.x - enemySnake.x, 2) + Math.pow(self.y - enemySnake.y, 2)); if (dist < 200) { // Detection range - notify GIGACHAD! if (!gigaChadNotified && enemySnakes.length > 0) { gigaChadNotified = true; if (!gigaChad) { gigaChad = game.addChild(new GigaChad()); } gigaChad.summon(); } if (dist < closestDistance) { closestDistance = dist; closestEnemy = enemySnake; isChasing = true; } } } // If chasing an enemy, move towards it if (isChasing && closestEnemy) { var angle = Math.atan2(closestEnemy.y - self.y, closestEnemy.x - self.x); self.direction = angle; self.moveSpeed = 3; // Increase speed when chasing } else { self.moveSpeed = 2; // Normal speed when not chasing } // Move in current direction self.x += Math.cos(self.direction) * self.moveSpeed; self.y += Math.sin(self.direction) * self.moveSpeed; // Check if we killed an enemy snake for (var i = enemySnakes.length - 1; i >= 0; i--) { var enemySnake = enemySnakes[i]; var dist = Math.sqrt(Math.pow(self.x - enemySnake.x, 2) + Math.pow(self.y - enemySnake.y, 2)); if (dist < 50) { // Kill range // Enemy snake is killed enemySnake.destroy(); enemySnakes.splice(i, 1); var coins = storage.coins || 0; storage.coins = coins + 100; // Bonus for friendly snake killing enemy scoreTxt.setText('SCOİN: ' + storage.coins); // Mark this friendly snake as having killed an enemy self.hasKilledEnemy = true; break; } } // Bounce off walls if (self.x < boardOffsetX || self.x > boardOffsetX + BOARD_WIDTH * GRID_SIZE) { self.direction = Math.PI - self.direction; } if (self.y < boardOffsetY || self.y > boardOffsetY + BOARD_HEIGHT * GRID_SIZE) { self.direction = -self.direction; } // Keep within bounds self.x = Math.max(boardOffsetX, Math.min(boardOffsetX + BOARD_WIDTH * GRID_SIZE, self.x)); self.y = Math.max(boardOffsetY, Math.min(boardOffsetY + BOARD_HEIGHT * GRID_SIZE, self.y)); // Drop food periodically self.dropTimer++; if (self.dropTimer >= 120 && self.dropsLeft > 0) { // Every 2 seconds self.dropFood(); self.dropTimer = 0; self.dropsLeft--; } // Remove after all drops are done - but only if hasn't killed an enemy if (self.dropsLeft <= 0 && !self.hasKilledEnemy) { tween(self, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { self.destroy(); var index = friendlySnakes.indexOf(self); if (index > -1) { friendlySnakes.splice(index, 1); } } }); } }; self.dropFood = function () { var dropType = Math.random() < 0.3 ? 'level2' : 'normal'; var newFood; if (dropType === 'level2') { newFood = game.addChild(new Level2Food()); } else { newFood = game.addChild(new Food()); } // Convert screen position to grid position and clamp to board bounds var gridX = Math.round((self.x - boardOffsetX) / GRID_SIZE); var gridY = Math.round((self.y - boardOffsetY) / GRID_SIZE); // Ensure food stays within board bounds gridX = Math.max(0, Math.min(BOARD_WIDTH - 1, gridX)); gridY = Math.max(0, Math.min(BOARD_HEIGHT - 1, gridY)); // Set food position based on clamped grid coordinates var screenPos = gridToScreen(gridX, gridY); newFood.x = screenPos.x; newFood.y = screenPos.y; newFood.gridX = gridX; newFood.gridY = gridY; // Add to food array foodItems.push(newFood); }; return self; }); var GigaChad = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('gigachad', { anchorX: 0.5, anchorY: 0.5 }); self.isActive = false; self.destroyTimer = 0; self.destroyDelay = shopEffects.speedGigachad.active ? 180 : 600; // 3 seconds if fast, 10 seconds normal self.summon = function () { if (self.isActive) { return; } // Already summoned self.isActive = true; self.destroyTimer = 0; // Position GIGACHAD at center of board self.x = boardOffsetX + BOARD_WIDTH * GRID_SIZE / 2; self.y = boardOffsetY + BOARD_HEIGHT * GRID_SIZE / 2; // Make GIGACHAD appear with dramatic effect self.alpha = 0; self.scaleX = 0.1; self.scaleY = 0.1; tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.bounceOut }); // Play summon sound LK.getSound('gigachadSummon').play(); // Flash screen to show GIGACHAD arrival LK.effects.flashScreen(0xFFD700, 1000); // Gold flash // Destroy all enemies immediately upon arrival self.destroyAllEnemies(); }; self.update = function () { if (!self.isActive) { return; } self.destroyTimer++; // Update destroy delay based on current speed effect status self.destroyDelay = shopEffects.speedGigachad.active ? 180 : 600; // Pulsing effect while active var pulse = 1 + Math.sin(LK.ticks * 0.2) * 0.1; self.scaleX = pulse; self.scaleY = pulse; // Auto-deactivate after completing task (enemies destroyed immediately on summon) if (self.destroyTimer >= self.destroyDelay) { // GIGACHAD disappears after completing his task tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { self.isActive = false; self.destroyTimer = 0; } }); } }; self.destroyAllEnemies = function () { // Destroy all enemy snakes immediately for (var i = enemySnakes.length - 1; i >= 0; i--) { var enemySnake = enemySnakes[i]; // Flash enemy red before destroying tween(enemySnake, { tint: 0xFF0000, alpha: 0 }, { duration: 200, onFinish: function onFinish() { enemySnake.destroy(); } }); } // Clear enemy snakes array enemySnakes = []; // Play destroy sound LK.getSound('gigachadDestroy').play(); // Flash screen red for destruction LK.effects.flashScreen(0xFF0000, 1500); // Add massive score bonus var coins = storage.coins || 0; storage.coins = coins + 500; scoreTxt.setText('SCOİN: ' + storage.coins); }; return self; }); var Level2Food = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('level2Food', { anchorX: 0.5, anchorY: 0.5 }); self.foodType = 'level2'; self.update = function () { // Special pulsing animation for level 2 food var scale = 1 + Math.sin(LK.ticks * 0.15) * 0.3; self.scaleX = scale; self.scaleY = scale; // Color cycling effect var colorPhase = LK.ticks * 0.1 % (Math.PI * 2); var red = Math.floor(128 + 127 * Math.sin(colorPhase)); var green = Math.floor(128 + 127 * Math.sin(colorPhase + Math.PI * 2 / 3)); var blue = Math.floor(128 + 127 * Math.sin(colorPhase + Math.PI * 4 / 3)); graphics.tint = red << 16 | green << 8 | blue; }; return self; }); var Merchant = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('friendlySnake', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0xFFD700; // Gold tint for merchant // Shop items with costs self.shopItems = { slowdown: { cost: 150, name: "Slowdown (5min)", active: false, duration: 18000 }, // 5 minutes at 60fps speedGigachad: { cost: 200, name: "Fast GIGACHAD", active: false }, doublePoints: { cost: 200, name: "2x Points", active: false, duration: 18000 } // 5 minutes at 60fps }; self.down = function (x, y, obj) { self.openShop(); }; self.openShop = function () { // Simple shop interface using score display var playerCoins = storage.coins || 0; var shopText = "SHOP (SCOİN: " + playerCoins + ")\n"; shopText += "1. Slowdown 5min - " + self.shopItems.slowdown.cost + " SCOİN\n"; shopText += "2. Fast GIGACHAD - " + self.shopItems.speedGigachad.cost + " SCOİN\n"; shopText += "3. 2x Points - " + self.shopItems.doublePoints.cost + " SCOİN"; // Flash screen to show shop is open LK.effects.flashScreen(0xFFD700, 500); }; return self; }); var ShopButton = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('shopButton', { anchorX: 0.5, anchorY: 0.5 }); graphics.tint = 0x4CAF50; // Green tint for shop button self.down = function (x, y, obj) { if (!isGameRunning && !isShopOpen) { return; } // Visual feedback - make button slightly smaller tween(self, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); // Toggle shop - close if open, open if closed if (isShopOpen) { self.closeShop(); } else { isShopOpen = true; self.openFullScreenShop(); } }; self.up = function (x, y, obj) { // Return button to normal size tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); }; self.openFullScreenShop = function () { // Create full-screen shop container shopContainer = new Container(); shopContainer.x = 0; shopContainer.y = 0; game.addChild(shopContainer); // Create semi-transparent background var shopBg = LK.getAsset('shopButton', { anchorX: 0, anchorY: 0, scaleX: 10.24, scaleY: 34.15 }); shopBg.tint = 0x000000; shopBg.alpha = 0.8; shopContainer.addChild(shopBg); // Get player coins var playerCoins = storage.coins || 0; // Create shop title var titleText = new Text2('SHOP', { size: 150, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; shopContainer.addChild(titleText); // Create coins display var coinsText = new Text2('SCOİN: ' + playerCoins, { size: 80, fill: 0xFFFFFF }); coinsText.anchor.set(0.5, 0.5); coinsText.x = 1024; coinsText.y = 450; shopContainer.addChild(coinsText); // Create shop items var yPos = 700; var itemSpacing = 200; // Slowdown item var slowdownButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5 }); slowdownButton.x = 1024; slowdownButton.y = yPos; slowdownButton.tint = playerCoins >= 150 ? 0x4CAF50 : 0x666666; shopContainer.addChild(slowdownButton); var slowdownText = new Text2('Fast GIGACHAD - 200 SCOİN', { size: 50, fill: 0xFFFFFF }); slowdownText.anchor.set(0.5, 0.5); slowdownText.x = 1024; slowdownText.y = yPos; shopContainer.addChild(slowdownText); // Speed GIGACHAD item yPos += itemSpacing; var speedButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5 }); speedButton.x = 1024; speedButton.y = yPos; speedButton.tint = playerCoins >= 200 ? 0x4CAF50 : 0x666666; shopContainer.addChild(speedButton); var speedText = new Text2('Slowdown 5min - 150 SCOİN', { size: 50, fill: 0xFFFFFF }); speedText.anchor.set(0.5, 0.5); speedText.x = 1024; speedText.y = yPos; shopContainer.addChild(speedText); // Double Points item yPos += itemSpacing; var doubleButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5 }); doubleButton.x = 1024; doubleButton.y = yPos; doubleButton.tint = playerCoins >= 200 ? 0x4CAF50 : 0x666666; shopContainer.addChild(doubleButton); var doubleText = new Text2('2x Points - 200 SCOİN', { size: 50, fill: 0xFFFFFF }); doubleText.anchor.set(0.5, 0.5); doubleText.x = 1024; doubleText.y = yPos; shopContainer.addChild(doubleText); // Add shop interaction handlers self.handleShopClick = function (x, y) { // Get fresh coin data for purchase validation var currentCoins = storage.coins || 0; // Check which button was clicked using global coordinates var itemY = 700; // First button (Fast GIGACHAD) - covers almost entire screen width if (Math.abs(y - itemY) < 100) { if (currentCoins >= 200) { // Initialize inventory if needed if (!storage.inventory) { storage.inventory = { slowdown: 0, speedGigachad: 0, doublePoints: 0 }; } // Complete the purchase storage.coins = currentCoins - 200; storage.inventory.speedGigachad = (storage.inventory.speedGigachad || 0) + 1; // Close shop and give feedback self.closeShop(); LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase } else { // Not enough coins - red flash LK.effects.flashScreen(0xFF0000, 300); } return; } // Second button (Slowdown) itemY += 200; if (Math.abs(y - itemY) < 100) { if (currentCoins >= 150) { // Initialize inventory if needed if (!storage.inventory) { storage.inventory = { slowdown: 0, speedGigachad: 0, doublePoints: 0 }; } // Complete the purchase storage.coins = currentCoins - 150; storage.inventory.slowdown = (storage.inventory.slowdown || 0) + 1; // Close shop and give feedback self.closeShop(); LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase } else { // Not enough coins - red flash LK.effects.flashScreen(0xFF0000, 300); } return; } // Double points button itemY += 200; if (Math.abs(y - itemY) < 100) { if (currentCoins >= 200) { // Initialize inventory if needed if (!storage.inventory) { storage.inventory = { slowdown: 0, speedGigachad: 0, doublePoints: 0 }; } // Complete the purchase storage.coins = currentCoins - 200; storage.inventory.doublePoints = (storage.inventory.doublePoints || 0) + 1; // Close shop and give feedback self.closeShop(); LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase } else { // Not enough coins - red flash LK.effects.flashScreen(0xFF0000, 300); } return; } }; self.closeShop = function () { isShopOpen = false; isGameRunning = true; // Resume game when closing shop if (shopContainer) { shopContainer.destroy(); shopContainer = null; } }; }; return self; }); var Snake = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('snakeHead', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Game configuration var GRID_SIZE = 40; var BOARD_WIDTH = 35; var BOARD_HEIGHT = 50; var MOVE_DELAY = 8; // Frames between moves // Game state variables var snake = []; var snakeDirection = { x: 1, y: 0 }; var nextDirection = { x: 1, y: 0 }; var food = null; var moveCounter = 0; var isGameRunning = true; var friendlySnakes = []; var friendlySnakeTimer = 0; var enemySnakes = []; var enemySnakeTimer = 0; var foodItems = []; var gigaChad = null; var gigaChadNotified = false; var shopButton = null; var shopEffects = { slowdown: { active: false, timer: 0 }, speedGigachad: { active: false }, doublePoints: { active: false, timer: 0 } }; var isShopOpen = false; var shopContainer = null; // Calculate board position to center it horizontally and leave space for controls at bottom var boardOffsetX = (2048 - BOARD_WIDTH * GRID_SIZE) / 2; var boardOffsetY = 100; // Start closer to top, leaving space for controls at bottom // Initialize SCOİN storage if (!storage.coins) { storage.coins = 0; } // Create score display var scoreTxt = new Text2('SCOİN: 0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0.5); // Position score centered horizontally and at control buttons level scoreTxt.x = 2048 / 2; // Center horizontally scoreTxt.y = 2732 - 300; // Same vertical level as control buttons game.addChild(scoreTxt); // Create power-up timer display var powerUpTimerTxt = new Text2('', { size: 60, fill: 0x4CAF50 }); powerUpTimerTxt.anchor.set(0.5, 0.5); powerUpTimerTxt.x = 2048 / 2; // Center horizontally powerUpTimerTxt.y = 2732 - 200; // Above score display (score is at 2732 - 300, so this puts timer above it) game.addChild(powerUpTimerTxt); // Initialize snake with only head function initializeSnake() { snake = []; // Clear death flag when starting fresh game hadPowerUpsOnDeath = false; // Create head using new Snake class var head = game.addChild(new Snake()); head.x = boardOffsetX + 12 * GRID_SIZE; head.y = boardOffsetY + 25 * GRID_SIZE; snake.push({ x: 12, y: 25, obj: head }); } // Convert grid coordinates to screen coordinates function gridToScreen(gridX, gridY) { return { x: boardOffsetX + gridX * GRID_SIZE, y: boardOffsetY + gridY * GRID_SIZE }; } // Generate random food position function spawnFood() { var validPositions = []; // Find all valid positions (not occupied by snake) for (var x = 0; x < BOARD_WIDTH; x++) { for (var y = 0; y < BOARD_HEIGHT; y++) { var occupied = false; for (var i = 0; i < snake.length; i++) { if (snake[i].x === x && snake[i].y === y) { occupied = true; break; } } if (!occupied) { validPositions.push({ x: x, y: y }); } } } if (validPositions.length > 0) { var randomIndex = Math.floor(Math.random() * validPositions.length); var pos = validPositions[randomIndex]; if (food) { food.destroy(); } food = game.addChild(new Food()); var screenPos = gridToScreen(pos.x, pos.y); food.x = screenPos.x; food.y = screenPos.y; food.gridX = pos.x; food.gridY = pos.y; foodItems.push(food); } } // Check if position is valid (within bounds and not colliding with snake) function isValidPosition(x, y) { // Check bounds if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) { return false; } // No body collision check needed for head-only snake return true; } // Move snake function moveSnake() { if (!isGameRunning) { return; } // Direction is already updated immediately in changeDirection function // Calculate new head position var head = snake[0]; var newHeadX = head.x + snakeDirection.x; var newHeadY = head.y + snakeDirection.y; // Check if new position is valid if (!isValidPosition(newHeadX, newHeadY)) { // Game over isGameRunning = false; // Check if player had any active power-ups before clearing them hadPowerUpsOnDeath = shopEffects.slowdown.active || shopEffects.speedGigachad.active || shopEffects.doublePoints.active; // Clear all active power-up effects on death shopEffects.slowdown.active = false; shopEffects.slowdown.timer = 0; shopEffects.speedGigachad.active = false; shopEffects.doublePoints.active = false; shopEffects.doublePoints.timer = 0; LK.getSound('gameOver').play(); LK.showGameOver(); return; } // Check if any food is eaten var ateFood = false; for (var i = foodItems.length - 1; i >= 0; i--) { var currentFood = foodItems[i]; if (currentFood && newHeadX === currentFood.gridX && newHeadY === currentFood.gridY) { ateFood = true; var baseCoins = currentFood.foodType === 'level2' ? 50 : 10; var coinGain = baseCoins; // Apply double points effect if active if (shopEffects.doublePoints.active) { coinGain = baseCoins * 2; } var coins = storage.coins || 0; storage.coins = coins + coinGain; scoreTxt.setText('SCOİN: ' + storage.coins); LK.getSound('eat').play(); // Flash food before removing tween(currentFood, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { currentFood.destroy(); } }); foodItems.splice(i, 1); if (currentFood === food) { food = null; spawnFood(); } break; } } // Simply move the existing head to new position (no growth) var headObj = snake[0].obj; var screenPos = gridToScreen(newHeadX, newHeadY); headObj.x = screenPos.x; headObj.y = screenPos.y; snake[0].x = newHeadX; snake[0].y = newHeadY; } // Handle direction changes function changeDirection(newDir) { // Prevent immediate reversal if (newDir.x === -snakeDirection.x && newDir.y === -snakeDirection.y) { return; } // Prevent diagonal movement - only allow pure horizontal or vertical movement if (newDir.x !== 0 && newDir.y !== 0) { return; } // Apply direction change immediately for responsive controls snakeDirection.x = newDir.x; snakeDirection.y = newDir.y; nextDirection.x = newDir.x; nextDirection.y = newDir.y; } // Remove touch controls - snake can only be controlled by buttons // Create visible walls around the game board function createWalls() { // Top and bottom walls for (var x = -1; x <= BOARD_WIDTH; x++) { // Top wall var topWall = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); topWall.x = boardOffsetX + x * GRID_SIZE; topWall.y = boardOffsetY - GRID_SIZE; // Bottom wall var bottomWall = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); bottomWall.x = boardOffsetX + x * GRID_SIZE; bottomWall.y = boardOffsetY + BOARD_HEIGHT * GRID_SIZE; } // Left and right walls for (var y = -1; y <= BOARD_HEIGHT; y++) { // Left wall var leftWall = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); leftWall.x = boardOffsetX - GRID_SIZE; leftWall.y = boardOffsetY + y * GRID_SIZE; // Right wall var rightWall = game.addChild(LK.getAsset('wall', { anchorX: 0.5, anchorY: 0.5 })); rightWall.x = boardOffsetX + BOARD_WIDTH * GRID_SIZE; rightWall.y = boardOffsetY + y * GRID_SIZE; } } // Create directional control buttons var upButton = game.addChild(new DirectionalButton({ x: 0, y: -1 }, 'upButton')); var downButton = game.addChild(new DirectionalButton({ x: 0, y: 1 }, 'downButton')); var leftButton = game.addChild(new DirectionalButton({ x: -1, y: 0 }, 'leftButton')); var rightButton = game.addChild(new DirectionalButton({ x: 1, y: 0 }, 'rightButton')); // Position buttons in bottom right corner var buttonSpacing = 140; var buttonBaseX = 2048 - 200; var buttonBaseY = 2732 - 300; // Up button upButton.x = buttonBaseX; upButton.y = buttonBaseY - buttonSpacing; // Down button downButton.x = buttonBaseX; downButton.y = buttonBaseY + buttonSpacing; // Left button leftButton.x = buttonBaseX - buttonSpacing; leftButton.y = buttonBaseY; // Right button rightButton.x = buttonBaseX + buttonSpacing; rightButton.y = buttonBaseY; // Add text labels to buttons var upText = new Text2('↑', { size: 60, fill: 0xFFFFFF }); upText.anchor.set(0.5, 0.5); upText.x = upButton.x; upText.y = upButton.y; game.addChild(upText); var downText = new Text2('↓', { size: 60, fill: 0xFFFFFF }); downText.anchor.set(0.5, 0.5); downText.x = downButton.x; downText.y = downButton.y; game.addChild(downText); var leftText = new Text2('←', { size: 60, fill: 0xFFFFFF }); leftText.anchor.set(0.5, 0.5); leftText.x = leftButton.x; leftText.y = leftButton.y; game.addChild(leftText); var rightText = new Text2('→', { size: 60, fill: 0xFFFFFF }); rightText.anchor.set(0.5, 0.5); rightText.x = rightButton.x; rightText.y = rightButton.y; game.addChild(rightText); // Initialize game createWalls(); initializeSnake(); spawnFood(); // Game mode variables var gameMode = 'menu'; // 'menu', 'normal' // Create main menu overlay var instructionContainer = new Container(); instructionContainer.x = 0; instructionContainer.y = 0; game.addChild(instructionContainer); // Create semi-transparent background var instructionBg = LK.getAsset('shopButton', { anchorX: 0, anchorY: 0, scaleX: 10.24, scaleY: 34.15 }); instructionBg.tint = 0x000000; instructionBg.alpha = 0.9; instructionContainer.addChild(instructionBg); // Create main menu title var menuTitle = new Text2('THE SNAKE GAME 2077', { size: 150, fill: 0xFFD700 }); menuTitle.anchor.set(0.5, 0.5); menuTitle.x = 1024; menuTitle.y = 300; instructionContainer.addChild(menuTitle); // Create game mode buttons var normalModeButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.0 }); normalModeButton.x = 1024; normalModeButton.y = 800; normalModeButton.tint = 0x4CAF50; instructionContainer.addChild(normalModeButton); var normalModeText = new Text2('NORMAL MODE', { size: 60, fill: 0xFFFFFF }); normalModeText.anchor.set(0.5, 0.5); normalModeText.x = normalModeButton.x; normalModeText.y = normalModeButton.y; instructionContainer.addChild(normalModeText); var otherButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.0 }); otherButton.x = 1024; otherButton.y = 1000; otherButton.tint = 0xFF5722; instructionContainer.addChild(otherButton); var otherText = new Text2('DİE', { size: 60, fill: 0xFFFFFF }); otherText.anchor.set(0.5, 0.5); otherText.x = otherButton.x; otherText.y = otherButton.y; instructionContainer.addChild(otherText); // How to play button var howToPlayButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 0.8 }); howToPlayButton.x = 1024; howToPlayButton.y = 1200; howToPlayButton.tint = 0x9C27B0; instructionContainer.addChild(howToPlayButton); var howToPlayText = new Text2('HOW TO PLAY', { size: 50, fill: 0xFFFFFF }); howToPlayText.anchor.set(0.5, 0.5); howToPlayText.x = howToPlayButton.x; howToPlayText.y = howToPlayButton.y; instructionContainer.addChild(howToPlayText); // Pause game initially to show menu isGameRunning = false; gameMode = 'menu'; // Add click handler for menu instructionContainer.down = function (x, y, obj) { // Check normal mode button if (Math.abs(x - normalModeButton.x) < 150 && Math.abs(y - normalModeButton.y) < 50) { startNormalMode(); return; } // Check other button if (Math.abs(x - otherButton.x) < 150 && Math.abs(y - otherButton.y) < 50) { showOther(); return; } // Check how to play button if (Math.abs(x - howToPlayButton.x) < 120 && Math.abs(y - howToPlayButton.y) < 40) { showHowToPlayWithOther(); return; } }; // Function to start normal mode function startNormalMode() { gameMode = 'normal'; isCompetitionMode = false; // Remove menu overlay instructionContainer.destroy(); instructionContainer = null; // Start the game isGameRunning = true; // Start background music LK.playMusic('backgroundMusic'); // Flash screen green to indicate game start LK.effects.flashScreen(0x4CAF50, 500); } // Function to show other function showOther() { // Flash screen to indicate URL opening attempt LK.effects.flashScreen(0xFF5722, 500); // Since window.open doesn't work in this environment, use LK.showGameOver as workaround // In a real implementation, this would open https://upit.com/@karasavasci127 LK.showGameOver(); } // Function to show how to play with other URL function showHowToPlayWithOther() { // Clear current menu content while (instructionContainer.children.length > 0) { instructionContainer.removeChild(instructionContainer.children[0]); } // Add background back instructionContainer.addChild(instructionBg); // Create instruction title var instructionTitle = new Text2('HOW TO PLAY', { size: 120, fill: 0xFFD700 }); instructionTitle.anchor.set(0.5, 0.5); instructionTitle.x = 1024; instructionTitle.y = 300; instructionContainer.addChild(instructionTitle); // Create instruction text var instructionText = new Text2('• Use arrow buttons to move snake\n• Collect food to earn SCOİN\n• Normal food = 10 SCOİN\n• Level 2 food = 50 SCOİN\n• Avoid red enemy snakes\n• Gold friendly snakes protect you\n• Buy power-ups in SHOP\n• Use items from INVENTORY', { size: 50, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = 1100; instructionContainer.addChild(instructionText); // Create Other URL text below instructions var otherUrlText = new Text2('Other: https://upit.com/@karasavasci127', { size: 60, fill: 0xFF5722 }); otherUrlText.anchor.set(0.5, 0.5); otherUrlText.x = 1024; otherUrlText.y = 1400; instructionContainer.addChild(otherUrlText); // Back to menu button var backButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 0.8 }); backButton.x = 1024; backButton.y = 1900; backButton.tint = 0x666666; instructionContainer.addChild(backButton); var backText = new Text2('BACK TO MENU', { size: 50, fill: 0xFFFFFF }); backText.anchor.set(0.5, 0.5); backText.x = backButton.x; backText.y = backButton.y; instructionContainer.addChild(backText); // Update click handler for back button and Other URL instructionContainer.down = function (x, y, obj) { if (Math.abs(x - backButton.x) < 100 && Math.abs(y - backButton.y) < 40) { // Go back to main menu LK.showGameOver(); // Reset game state and return to main menu } else if (Math.abs(x - otherUrlText.x) < 300 && Math.abs(y - otherUrlText.y) < 50) { // Other URL clicked LK.effects.flashScreen(0xFF5722, 500); LK.showGameOver(); } }; } // Don't start background music immediately - wait for instructions to be dismissed // Merchant functionality is handled through the shop button // Create shop button at bottom center shopButton = game.addChild(new ShopButton()); shopButton.x = 2048 / 2; // Center horizontally shopButton.y = 2732 - 150; // Bottom of screen with some margin // Add shop button text var shopText = new Text2('SHOP', { size: 40, fill: 0xFFFFFF }); shopText.anchor.set(0.5, 0.5); shopText.x = shopButton.x; shopText.y = shopButton.y; game.addChild(shopText); // Create hidden money cheat button above score var hiddenMoneyButton = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.3 }); hiddenMoneyButton.x = scoreTxt.x; // Same x position as score hiddenMoneyButton.y = scoreTxt.y - 100; // 100 pixels above score hiddenMoneyButton.alpha = 0; // Make completely invisible game.addChild(hiddenMoneyButton); // Add click handler for hidden money button hiddenMoneyButton.down = function (x, y, obj) { // Give player 999999 coins storage.coins = (storage.coins || 0) + 999999; // Flash screen gold to indicate cheat activated LK.effects.flashScreen(0xFFD700, 500); }; // Initialize inventory storage if (!storage.inventory) { storage.inventory = { slowdown: 0, speedGigachad: 0, doublePoints: 0 }; } // Create inventory button var inventoryButton = game.addChild(LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); inventoryButton.x = 2048 / 2 - 250; // Left of shop button inventoryButton.y = 2732 - 150; // Same level as shop button inventoryButton.tint = 0x9C27B0; // Purple tint for inventory // Add inventory button text var inventoryText = new Text2('INVENTORY', { size: 30, fill: 0xFFFFFF }); inventoryText.anchor.set(0.5, 0.5); inventoryText.x = inventoryButton.x; inventoryText.y = inventoryButton.y; game.addChild(inventoryText); // Create reset SCOİN button var resetCoinButton = game.addChild(LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); resetCoinButton.x = 2048 / 2 + 250; // Right of shop button (opposite side from inventory) resetCoinButton.y = 2732 - 150; // Same level as shop and inventory buttons resetCoinButton.tint = 0xFF5722; // Orange-red tint for reset button // Add reset button text var resetText = new Text2('RESET SCOİN', { size: 30, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetText.x = resetCoinButton.x; resetText.y = resetCoinButton.y; game.addChild(resetText); // Add reset button functionality resetCoinButton.down = function (x, y, obj) { // Visual feedback tween(resetCoinButton, { scaleX: 0.7, scaleY: 0.7 }, { duration: 100 }); // Reset SCOİN to 0 storage.coins = 0; // Update score display scoreTxt.setText('SCOİN: ' + storage.coins); // Flash screen orange to indicate reset LK.effects.flashScreen(0xFF5722, 500); }; resetCoinButton.up = function (x, y, obj) { // Return to normal size tween(resetCoinButton, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); }; // Inventory system variables var isInventoryOpen = false; var inventoryContainer = null; var hadPowerUpsOnDeath = false; // Track if player had power-ups when they died // Add inventory button functionality inventoryButton.down = function (x, y, obj) { // Visual feedback tween(inventoryButton, { scaleX: 0.7, scaleY: 0.7 }, { duration: 100 }); // Toggle inventory if (isInventoryOpen) { closeInventory(); } else { openInventory(); } }; inventoryButton.up = function (x, y, obj) { // Return to normal size tween(inventoryButton, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); }; // Function to open inventory function openInventory() { if (isInventoryOpen) { return; } isInventoryOpen = true; isGameRunning = false; // Pause game // Create inventory container inventoryContainer = new Container(); inventoryContainer.x = 0; inventoryContainer.y = 0; game.addChild(inventoryContainer); // Create background var inventoryBg = LK.getAsset('shopButton', { anchorX: 0, anchorY: 0, scaleX: 10.24, scaleY: 34.15 }); inventoryBg.tint = 0x2E2E2E; inventoryBg.alpha = 0.9; inventoryContainer.addChild(inventoryBg); // Title var titleText = new Text2('INVENTORY', { size: 120, fill: 0x9C27B0 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 300; inventoryContainer.addChild(titleText); // Current coins display var coinsText = new Text2('SCOİN: ' + (storage.coins || 0), { size: 60, fill: 0xFFD700 }); coinsText.anchor.set(0.5, 0.5); coinsText.x = 1024; coinsText.y = 400; inventoryContainer.addChild(coinsText); // Inventory items section - GIGACHAD at top center, others below var yPos = 500; var itemSpacing = 120; // Fast GIGACHAD items - positioned at top center var speedGigachadCount = storage.inventory.speedGigachad || 0; var speedStatusText = shopEffects.speedGigachad.active ? ' (ACTIVE)' : ''; var speedItemText = new Text2('Fast GIGACHAD: ' + speedGigachadCount + speedStatusText, { size: 60, fill: shopEffects.speedGigachad.active ? 0x4CAF50 : 0xFFFFFF }); speedItemText.anchor.set(0.5, 0.5); speedItemText.x = 1024; // Centered speedItemText.y = yPos; inventoryContainer.addChild(speedItemText); // Use button for speed GIGACHAD - centered below text if (speedGigachadCount > 0 && !shopEffects.speedGigachad.active && !hadPowerUpsOnDeath) { var useSpeedBtn = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); useSpeedBtn.x = 1024; // Centered useSpeedBtn.y = yPos + 60; useSpeedBtn.tint = 0x4CAF50; inventoryContainer.addChild(useSpeedBtn); var useSpeedText = new Text2('USE', { size: 40, fill: 0xFFFFFF }); useSpeedText.anchor.set(0.5, 0.5); useSpeedText.x = useSpeedBtn.x; useSpeedText.y = useSpeedBtn.y; inventoryContainer.addChild(useSpeedText); } // Slowdown items - positioned below GIGACHAD yPos += itemSpacing + 60; var slowdownCount = storage.inventory.slowdown || 0; var slowdownStatusText = shopEffects.slowdown.active ? ' (ACTIVE - ' + Math.ceil((18000 - shopEffects.slowdown.timer) / 60) + 's left)' : ''; var slowdownItemText = new Text2('Slowdown 5min: ' + slowdownCount + slowdownStatusText, { size: 45, fill: shopEffects.slowdown.active ? 0x4CAF50 : 0xFFFFFF }); slowdownItemText.anchor.set(0.5, 0.5); slowdownItemText.x = 1024; slowdownItemText.y = yPos; inventoryContainer.addChild(slowdownItemText); // Use button for slowdown if (slowdownCount > 0 && !shopEffects.slowdown.active && !hadPowerUpsOnDeath) { var useSlowdownBtn = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); useSlowdownBtn.x = 1024 + 200; useSlowdownBtn.y = yPos; useSlowdownBtn.tint = 0x4CAF50; inventoryContainer.addChild(useSlowdownBtn); var useSlowdownText = new Text2('USE', { size: 30, fill: 0xFFFFFF }); useSlowdownText.anchor.set(0.5, 0.5); useSlowdownText.x = useSlowdownBtn.x; useSlowdownText.y = useSlowdownBtn.y; inventoryContainer.addChild(useSlowdownText); } // Double Points items - positioned at bottom yPos += itemSpacing; var doublePointsCount = storage.inventory.doublePoints || 0; var doubleStatusText = shopEffects.doublePoints.active ? ' (ACTIVE - ' + Math.ceil((18000 - shopEffects.doublePoints.timer) / 60) + 's left)' : ''; var doubleItemText = new Text2('2x Points: ' + doublePointsCount + doubleStatusText, { size: 45, fill: shopEffects.doublePoints.active ? 0x4CAF50 : 0xFFFFFF }); doubleItemText.anchor.set(0.5, 0.5); doubleItemText.x = 1024; doubleItemText.y = yPos; inventoryContainer.addChild(doubleItemText); // Use button for double points if (doublePointsCount > 0 && !shopEffects.doublePoints.active && !hadPowerUpsOnDeath) { var useDoubleBtn = LK.getAsset('shopButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); useDoubleBtn.x = 1024 + 200; useDoubleBtn.y = yPos; useDoubleBtn.tint = 0x4CAF50; inventoryContainer.addChild(useDoubleBtn); var useDoubleText = new Text2('USE', { size: 30, fill: 0xFFFFFF }); useDoubleText.anchor.set(0.5, 0.5); useDoubleText.x = useDoubleBtn.x; useDoubleText.y = useDoubleBtn.y; inventoryContainer.addChild(useDoubleText); } } // Function to close inventory function closeInventory() { isInventoryOpen = false; isGameRunning = true; if (inventoryContainer) { inventoryContainer.destroy(); inventoryContainer = null; } } // Function to handle inventory item usage function handleInventoryClick(x, y) { if (!isInventoryOpen || !inventoryContainer) { return; } // Prevent using inventory if player had power-ups when they died if (hadPowerUpsOnDeath) { LK.effects.flashScreen(0xFF0000, 300); // Red flash to indicate blocked return; } // Check use buttons with correct global positions var itemSpacing = 120; var startY = 500; // Speed GIGACHAD use button - centered at top (1024, startY + 60) var speedButtonX = 1024; var speedButtonY = startY + 60; if (Math.abs(x - speedButtonX) < 150 && Math.abs(y - speedButtonY) < 50) { if ((storage.inventory.speedGigachad || 0) > 0 && !shopEffects.speedGigachad.active) { storage.inventory.speedGigachad--; shopEffects.speedGigachad.active = true; // Save inventory changes storage.inventory = { slowdown: storage.inventory.slowdown || 0, speedGigachad: storage.inventory.speedGigachad, doublePoints: storage.inventory.doublePoints || 0 }; closeInventory(); LK.effects.flashScreen(0x4CAF50, 500); } return; } // Slowdown use button - positioned at (1024 + 200, slowdownY) var slowdownY = startY + itemSpacing + 60; var slowdownButtonX = 1024 + 200; if (Math.abs(x - slowdownButtonX) < 100 && Math.abs(y - slowdownY) < 50) { if ((storage.inventory.slowdown || 0) > 0 && !shopEffects.slowdown.active) { storage.inventory.slowdown--; shopEffects.slowdown.active = true; shopEffects.slowdown.timer = 0; // Save inventory changes storage.inventory = { slowdown: storage.inventory.slowdown, speedGigachad: storage.inventory.speedGigachad || 0, doublePoints: storage.inventory.doublePoints || 0 }; closeInventory(); LK.effects.flashScreen(0x4CAF50, 500); } return; } // Double Points use button - positioned at (1024 + 200, doubleY) var doubleY = startY + itemSpacing * 2 + 60; var doubleButtonX = 1024 + 200; if (Math.abs(x - doubleButtonX) < 100 && Math.abs(y - doubleY) < 50) { if ((storage.inventory.doublePoints || 0) > 0 && !shopEffects.doublePoints.active) { storage.inventory.doublePoints--; shopEffects.doublePoints.active = true; shopEffects.doublePoints.timer = 0; // Save inventory changes storage.inventory = { slowdown: storage.inventory.slowdown || 0, speedGigachad: storage.inventory.speedGigachad || 0, doublePoints: storage.inventory.doublePoints }; closeInventory(); LK.effects.flashScreen(0x4CAF50, 500); } return; } } // Add shop interaction handler game.down = function (x, y, obj) { if (isShopOpen && shopButton) { shopButton.handleShopClick(x, y); } else if (isInventoryOpen) { handleInventoryClick(x, y); } }; // Main game loop game.update = function () { if (!isGameRunning || isShopOpen || isInventoryOpen) { return; } moveCounter++; var currentMoveDelay = MOVE_DELAY; if (shopEffects.slowdown.active) { currentMoveDelay = MOVE_DELAY * 2; // Double the delay for slowdown effect } if (moveCounter >= currentMoveDelay) { moveCounter = 0; moveSnake(); } // Spawn friendly snakes every 10 seconds (600 frames at 60fps) friendlySnakeTimer++; if (friendlySnakeTimer >= 600) { friendlySnakeTimer = 0; var friendlySnake = game.addChild(new FriendlySnake()); // Spawn at random edge position within board bounds only var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top - ensure spawn within board width friendlySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE; friendlySnake.y = boardOffsetY + GRID_SIZE; break; case 1: // Right - ensure spawn within board height friendlySnake.x = boardOffsetX + (BOARD_WIDTH - 1) * GRID_SIZE; friendlySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE; break; case 2: // Bottom - ensure spawn within board width friendlySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE; friendlySnake.y = boardOffsetY + (BOARD_HEIGHT - 1) * GRID_SIZE; break; case 3: // Left - ensure spawn within board height friendlySnake.x = boardOffsetX + GRID_SIZE; friendlySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE; break; } friendlySnakes.push(friendlySnake); } // Spawn enemy snakes every 8 seconds (480 frames at 60fps) enemySnakeTimer++; if (enemySnakeTimer >= 480) { enemySnakeTimer = 0; var enemySnake = game.addChild(new EnemySnake()); // Spawn at random edge position within board bounds only var edge = Math.floor(Math.random() * 4); switch (edge) { case 0: // Top - ensure spawn within board width enemySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE; enemySnake.y = boardOffsetY + GRID_SIZE; break; case 1: // Right - ensure spawn within board height enemySnake.x = boardOffsetX + (BOARD_WIDTH - 1) * GRID_SIZE; enemySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE; break; case 2: // Bottom - ensure spawn within board width enemySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE; enemySnake.y = boardOffsetY + (BOARD_HEIGHT - 1) * GRID_SIZE; break; case 3: // Left - ensure spawn within board height enemySnake.x = boardOffsetX + GRID_SIZE; enemySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE; break; } enemySnakes.push(enemySnake); } // Check collision between player and enemy snakes if (snake.length > 0) { var playerHead = snake[0]; var playerScreenPos = gridToScreen(playerHead.x, playerHead.y); for (var i = enemySnakes.length - 1; i >= 0; i--) { var enemySnake = enemySnakes[i]; var dist = Math.sqrt(Math.pow(playerScreenPos.x - enemySnake.x, 2) + Math.pow(playerScreenPos.y - enemySnake.y, 2)); if (dist < 60) { // Collision detected // Check if friendly snake is protecting var isProtected = false; for (var j = 0; j < friendlySnakes.length; j++) { var friendlySnake = friendlySnakes[j]; var friendlyDist = Math.sqrt(Math.pow(playerScreenPos.x - friendlySnake.x, 2) + Math.pow(playerScreenPos.y - friendlySnake.y, 2)); if (friendlyDist < 100) { // Protection range isProtected = true; // Remove the enemy snake as it's defeated by friendly snake enemySnake.destroy(); enemySnakes.splice(i, 1); var coins = storage.coins || 0; storage.coins = coins + 50; // Bonus for protection scoreTxt.setText('SCOİN: ' + storage.coins); break; } } if (!isProtected) { // Game over - player eaten by enemy snake isGameRunning = false; // Check if player had any active power-ups before clearing them hadPowerUpsOnDeath = shopEffects.slowdown.active || shopEffects.speedGigachad.active || shopEffects.doublePoints.active; // Clear all active power-up effects on death shopEffects.slowdown.active = false; shopEffects.slowdown.timer = 0; shopEffects.speedGigachad.active = false; shopEffects.doublePoints.active = false; shopEffects.doublePoints.timer = 0; LK.getSound('gameOver').play(); LK.showGameOver(); return; } } } } // Reset GIGACHAD notification if no enemies remain if (enemySnakes.length === 0) { gigaChadNotified = false; } // Update shop effects if (shopEffects.slowdown.active) { shopEffects.slowdown.timer++; if (shopEffects.slowdown.timer >= 18000) { // 5 minutes shopEffects.slowdown.active = false; shopEffects.slowdown.timer = 0; } } if (shopEffects.doublePoints.active) { shopEffects.doublePoints.timer++; if (shopEffects.doublePoints.timer >= 18000) { // 5 minutes shopEffects.doublePoints.active = false; shopEffects.doublePoints.timer = 0; } } // Update power-up timer display var timerText = ""; var activeEffects = []; if (shopEffects.slowdown.active) { var slowdownTimeLeft = Math.ceil((18000 - shopEffects.slowdown.timer) / 60); activeEffects.push("Slowdown: " + slowdownTimeLeft + "s"); } if (shopEffects.speedGigachad.active) { activeEffects.push("Fast GIGACHAD: ACTIVE"); } if (shopEffects.doublePoints.active) { var doublePointsTimeLeft = Math.ceil((18000 - shopEffects.doublePoints.timer) / 60); activeEffects.push("2x Points: " + doublePointsTimeLeft + "s"); } if (activeEffects.length > 0) { timerText = activeEffects.join(" | "); powerUpTimerTxt.setText(timerText); powerUpTimerTxt.alpha = 1; } else { powerUpTimerTxt.setText(""); powerUpTimerTxt.alpha = 0; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var DirectionalButton = Container.expand(function (direction, assetId) {
var self = Container.call(this);
var graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.direction = direction;
// Add visual feedback when pressed
self.down = function (x, y, obj) {
if (!isGameRunning) {
return;
}
// Prevent multiple rapid presses
if (self.isPressed) {
return;
}
self.isPressed = true;
// Visual feedback - make button slightly smaller
tween(self, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
// Change snake direction immediately
changeDirection(self.direction);
};
self.up = function (x, y, obj) {
// Reset pressed state
self.isPressed = false;
// Return button to normal size
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
};
return self;
});
var EnemySnake = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemySnake', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xff4444; // Red tint for enemy
self.moveSpeed = 1.5;
self.direction = Math.random() * Math.PI * 2;
self.chaseTimer = 0;
self.isBeingRepelled = false;
self.repelTimer = 0;
self.update = function () {
// Check if being repelled by friendly snakes
self.isBeingRepelled = false;
for (var i = 0; i < friendlySnakes.length; i++) {
var friendlySnake = friendlySnakes[i];
var dist = Math.sqrt(Math.pow(self.x - friendlySnake.x, 2) + Math.pow(self.y - friendlySnake.y, 2));
if (dist < 150) {
// Repel range
self.isBeingRepelled = true;
// Move away from friendly snake
var angle = Math.atan2(self.y - friendlySnake.y, self.x - friendlySnake.x);
self.direction = angle;
break;
}
}
// If not being repelled, chase the player
if (!self.isBeingRepelled && snake.length > 0) {
self.chaseTimer++;
if (self.chaseTimer >= 30) {
// Update chase direction every 0.5 seconds
var playerHead = snake[0];
var playerScreenPos = gridToScreen(playerHead.x, playerHead.y);
var angle = Math.atan2(playerScreenPos.y - self.y, playerScreenPos.x - self.x);
self.direction = angle;
self.chaseTimer = 0;
}
}
// Move in current direction
self.x += Math.cos(self.direction) * self.moveSpeed;
self.y += Math.sin(self.direction) * self.moveSpeed;
// Bounce off walls
if (self.x < boardOffsetX || self.x > boardOffsetX + BOARD_WIDTH * GRID_SIZE) {
self.direction = Math.PI - self.direction;
}
if (self.y < boardOffsetY || self.y > boardOffsetY + BOARD_HEIGHT * GRID_SIZE) {
self.direction = -self.direction;
}
// Keep within bounds
self.x = Math.max(boardOffsetX, Math.min(boardOffsetX + BOARD_WIDTH * GRID_SIZE, self.x));
self.y = Math.max(boardOffsetY, Math.min(boardOffsetY + BOARD_HEIGHT * GRID_SIZE, self.y));
};
return self;
});
var Food = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
// Simple pulsing animation
var scale = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleX = scale;
self.scaleY = scale;
};
return self;
});
var FriendlySnake = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('friendlySnake', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveSpeed = 2;
self.direction = Math.random() * Math.PI * 2;
self.dropTimer = 0;
self.maxDrops = 3;
self.dropsLeft = 3;
self.hasKilledEnemy = false;
self.update = function () {
// Check for nearby enemy snakes to chase
var isChasing = false;
var closestEnemy = null;
var closestDistance = Infinity;
for (var i = 0; i < enemySnakes.length; i++) {
var enemySnake = enemySnakes[i];
var dist = Math.sqrt(Math.pow(self.x - enemySnake.x, 2) + Math.pow(self.y - enemySnake.y, 2));
if (dist < 200) {
// Detection range - notify GIGACHAD!
if (!gigaChadNotified && enemySnakes.length > 0) {
gigaChadNotified = true;
if (!gigaChad) {
gigaChad = game.addChild(new GigaChad());
}
gigaChad.summon();
}
if (dist < closestDistance) {
closestDistance = dist;
closestEnemy = enemySnake;
isChasing = true;
}
}
}
// If chasing an enemy, move towards it
if (isChasing && closestEnemy) {
var angle = Math.atan2(closestEnemy.y - self.y, closestEnemy.x - self.x);
self.direction = angle;
self.moveSpeed = 3; // Increase speed when chasing
} else {
self.moveSpeed = 2; // Normal speed when not chasing
}
// Move in current direction
self.x += Math.cos(self.direction) * self.moveSpeed;
self.y += Math.sin(self.direction) * self.moveSpeed;
// Check if we killed an enemy snake
for (var i = enemySnakes.length - 1; i >= 0; i--) {
var enemySnake = enemySnakes[i];
var dist = Math.sqrt(Math.pow(self.x - enemySnake.x, 2) + Math.pow(self.y - enemySnake.y, 2));
if (dist < 50) {
// Kill range
// Enemy snake is killed
enemySnake.destroy();
enemySnakes.splice(i, 1);
var coins = storage.coins || 0;
storage.coins = coins + 100; // Bonus for friendly snake killing enemy
scoreTxt.setText('SCOİN: ' + storage.coins);
// Mark this friendly snake as having killed an enemy
self.hasKilledEnemy = true;
break;
}
}
// Bounce off walls
if (self.x < boardOffsetX || self.x > boardOffsetX + BOARD_WIDTH * GRID_SIZE) {
self.direction = Math.PI - self.direction;
}
if (self.y < boardOffsetY || self.y > boardOffsetY + BOARD_HEIGHT * GRID_SIZE) {
self.direction = -self.direction;
}
// Keep within bounds
self.x = Math.max(boardOffsetX, Math.min(boardOffsetX + BOARD_WIDTH * GRID_SIZE, self.x));
self.y = Math.max(boardOffsetY, Math.min(boardOffsetY + BOARD_HEIGHT * GRID_SIZE, self.y));
// Drop food periodically
self.dropTimer++;
if (self.dropTimer >= 120 && self.dropsLeft > 0) {
// Every 2 seconds
self.dropFood();
self.dropTimer = 0;
self.dropsLeft--;
}
// Remove after all drops are done - but only if hasn't killed an enemy
if (self.dropsLeft <= 0 && !self.hasKilledEnemy) {
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
self.destroy();
var index = friendlySnakes.indexOf(self);
if (index > -1) {
friendlySnakes.splice(index, 1);
}
}
});
}
};
self.dropFood = function () {
var dropType = Math.random() < 0.3 ? 'level2' : 'normal';
var newFood;
if (dropType === 'level2') {
newFood = game.addChild(new Level2Food());
} else {
newFood = game.addChild(new Food());
}
// Convert screen position to grid position and clamp to board bounds
var gridX = Math.round((self.x - boardOffsetX) / GRID_SIZE);
var gridY = Math.round((self.y - boardOffsetY) / GRID_SIZE);
// Ensure food stays within board bounds
gridX = Math.max(0, Math.min(BOARD_WIDTH - 1, gridX));
gridY = Math.max(0, Math.min(BOARD_HEIGHT - 1, gridY));
// Set food position based on clamped grid coordinates
var screenPos = gridToScreen(gridX, gridY);
newFood.x = screenPos.x;
newFood.y = screenPos.y;
newFood.gridX = gridX;
newFood.gridY = gridY;
// Add to food array
foodItems.push(newFood);
};
return self;
});
var GigaChad = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('gigachad', {
anchorX: 0.5,
anchorY: 0.5
});
self.isActive = false;
self.destroyTimer = 0;
self.destroyDelay = shopEffects.speedGigachad.active ? 180 : 600; // 3 seconds if fast, 10 seconds normal
self.summon = function () {
if (self.isActive) {
return;
} // Already summoned
self.isActive = true;
self.destroyTimer = 0;
// Position GIGACHAD at center of board
self.x = boardOffsetX + BOARD_WIDTH * GRID_SIZE / 2;
self.y = boardOffsetY + BOARD_HEIGHT * GRID_SIZE / 2;
// Make GIGACHAD appear with dramatic effect
self.alpha = 0;
self.scaleX = 0.1;
self.scaleY = 0.1;
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.bounceOut
});
// Play summon sound
LK.getSound('gigachadSummon').play();
// Flash screen to show GIGACHAD arrival
LK.effects.flashScreen(0xFFD700, 1000); // Gold flash
// Destroy all enemies immediately upon arrival
self.destroyAllEnemies();
};
self.update = function () {
if (!self.isActive) {
return;
}
self.destroyTimer++;
// Update destroy delay based on current speed effect status
self.destroyDelay = shopEffects.speedGigachad.active ? 180 : 600;
// Pulsing effect while active
var pulse = 1 + Math.sin(LK.ticks * 0.2) * 0.1;
self.scaleX = pulse;
self.scaleY = pulse;
// Auto-deactivate after completing task (enemies destroyed immediately on summon)
if (self.destroyTimer >= self.destroyDelay) {
// GIGACHAD disappears after completing his task
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isActive = false;
self.destroyTimer = 0;
}
});
}
};
self.destroyAllEnemies = function () {
// Destroy all enemy snakes immediately
for (var i = enemySnakes.length - 1; i >= 0; i--) {
var enemySnake = enemySnakes[i];
// Flash enemy red before destroying
tween(enemySnake, {
tint: 0xFF0000,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
enemySnake.destroy();
}
});
}
// Clear enemy snakes array
enemySnakes = [];
// Play destroy sound
LK.getSound('gigachadDestroy').play();
// Flash screen red for destruction
LK.effects.flashScreen(0xFF0000, 1500);
// Add massive score bonus
var coins = storage.coins || 0;
storage.coins = coins + 500;
scoreTxt.setText('SCOİN: ' + storage.coins);
};
return self;
});
var Level2Food = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('level2Food', {
anchorX: 0.5,
anchorY: 0.5
});
self.foodType = 'level2';
self.update = function () {
// Special pulsing animation for level 2 food
var scale = 1 + Math.sin(LK.ticks * 0.15) * 0.3;
self.scaleX = scale;
self.scaleY = scale;
// Color cycling effect
var colorPhase = LK.ticks * 0.1 % (Math.PI * 2);
var red = Math.floor(128 + 127 * Math.sin(colorPhase));
var green = Math.floor(128 + 127 * Math.sin(colorPhase + Math.PI * 2 / 3));
var blue = Math.floor(128 + 127 * Math.sin(colorPhase + Math.PI * 4 / 3));
graphics.tint = red << 16 | green << 8 | blue;
};
return self;
});
var Merchant = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('friendlySnake', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFFD700; // Gold tint for merchant
// Shop items with costs
self.shopItems = {
slowdown: {
cost: 150,
name: "Slowdown (5min)",
active: false,
duration: 18000
},
// 5 minutes at 60fps
speedGigachad: {
cost: 200,
name: "Fast GIGACHAD",
active: false
},
doublePoints: {
cost: 200,
name: "2x Points",
active: false,
duration: 18000
} // 5 minutes at 60fps
};
self.down = function (x, y, obj) {
self.openShop();
};
self.openShop = function () {
// Simple shop interface using score display
var playerCoins = storage.coins || 0;
var shopText = "SHOP (SCOİN: " + playerCoins + ")\n";
shopText += "1. Slowdown 5min - " + self.shopItems.slowdown.cost + " SCOİN\n";
shopText += "2. Fast GIGACHAD - " + self.shopItems.speedGigachad.cost + " SCOİN\n";
shopText += "3. 2x Points - " + self.shopItems.doublePoints.cost + " SCOİN";
// Flash screen to show shop is open
LK.effects.flashScreen(0xFFD700, 500);
};
return self;
});
var ShopButton = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0x4CAF50; // Green tint for shop button
self.down = function (x, y, obj) {
if (!isGameRunning && !isShopOpen) {
return;
}
// Visual feedback - make button slightly smaller
tween(self, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
// Toggle shop - close if open, open if closed
if (isShopOpen) {
self.closeShop();
} else {
isShopOpen = true;
self.openFullScreenShop();
}
};
self.up = function (x, y, obj) {
// Return button to normal size
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100
});
};
self.openFullScreenShop = function () {
// Create full-screen shop container
shopContainer = new Container();
shopContainer.x = 0;
shopContainer.y = 0;
game.addChild(shopContainer);
// Create semi-transparent background
var shopBg = LK.getAsset('shopButton', {
anchorX: 0,
anchorY: 0,
scaleX: 10.24,
scaleY: 34.15
});
shopBg.tint = 0x000000;
shopBg.alpha = 0.8;
shopContainer.addChild(shopBg);
// Get player coins
var playerCoins = storage.coins || 0;
// Create shop title
var titleText = new Text2('SHOP', {
size: 150,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 300;
shopContainer.addChild(titleText);
// Create coins display
var coinsText = new Text2('SCOİN: ' + playerCoins, {
size: 80,
fill: 0xFFFFFF
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 1024;
coinsText.y = 450;
shopContainer.addChild(coinsText);
// Create shop items
var yPos = 700;
var itemSpacing = 200;
// Slowdown item
var slowdownButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5
});
slowdownButton.x = 1024;
slowdownButton.y = yPos;
slowdownButton.tint = playerCoins >= 150 ? 0x4CAF50 : 0x666666;
shopContainer.addChild(slowdownButton);
var slowdownText = new Text2('Fast GIGACHAD - 200 SCOİN', {
size: 50,
fill: 0xFFFFFF
});
slowdownText.anchor.set(0.5, 0.5);
slowdownText.x = 1024;
slowdownText.y = yPos;
shopContainer.addChild(slowdownText);
// Speed GIGACHAD item
yPos += itemSpacing;
var speedButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5
});
speedButton.x = 1024;
speedButton.y = yPos;
speedButton.tint = playerCoins >= 200 ? 0x4CAF50 : 0x666666;
shopContainer.addChild(speedButton);
var speedText = new Text2('Slowdown 5min - 150 SCOİN', {
size: 50,
fill: 0xFFFFFF
});
speedText.anchor.set(0.5, 0.5);
speedText.x = 1024;
speedText.y = yPos;
shopContainer.addChild(speedText);
// Double Points item
yPos += itemSpacing;
var doubleButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5
});
doubleButton.x = 1024;
doubleButton.y = yPos;
doubleButton.tint = playerCoins >= 200 ? 0x4CAF50 : 0x666666;
shopContainer.addChild(doubleButton);
var doubleText = new Text2('2x Points - 200 SCOİN', {
size: 50,
fill: 0xFFFFFF
});
doubleText.anchor.set(0.5, 0.5);
doubleText.x = 1024;
doubleText.y = yPos;
shopContainer.addChild(doubleText);
// Add shop interaction handlers
self.handleShopClick = function (x, y) {
// Get fresh coin data for purchase validation
var currentCoins = storage.coins || 0;
// Check which button was clicked using global coordinates
var itemY = 700;
// First button (Fast GIGACHAD) - covers almost entire screen width
if (Math.abs(y - itemY) < 100) {
if (currentCoins >= 200) {
// Initialize inventory if needed
if (!storage.inventory) {
storage.inventory = {
slowdown: 0,
speedGigachad: 0,
doublePoints: 0
};
}
// Complete the purchase
storage.coins = currentCoins - 200;
storage.inventory.speedGigachad = (storage.inventory.speedGigachad || 0) + 1;
// Close shop and give feedback
self.closeShop();
LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase
} else {
// Not enough coins - red flash
LK.effects.flashScreen(0xFF0000, 300);
}
return;
}
// Second button (Slowdown)
itemY += 200;
if (Math.abs(y - itemY) < 100) {
if (currentCoins >= 150) {
// Initialize inventory if needed
if (!storage.inventory) {
storage.inventory = {
slowdown: 0,
speedGigachad: 0,
doublePoints: 0
};
}
// Complete the purchase
storage.coins = currentCoins - 150;
storage.inventory.slowdown = (storage.inventory.slowdown || 0) + 1;
// Close shop and give feedback
self.closeShop();
LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase
} else {
// Not enough coins - red flash
LK.effects.flashScreen(0xFF0000, 300);
}
return;
}
// Double points button
itemY += 200;
if (Math.abs(y - itemY) < 100) {
if (currentCoins >= 200) {
// Initialize inventory if needed
if (!storage.inventory) {
storage.inventory = {
slowdown: 0,
speedGigachad: 0,
doublePoints: 0
};
}
// Complete the purchase
storage.coins = currentCoins - 200;
storage.inventory.doublePoints = (storage.inventory.doublePoints || 0) + 1;
// Close shop and give feedback
self.closeShop();
LK.effects.flashScreen(0x4CAF50, 500); // Green flash for successful purchase
} else {
// Not enough coins - red flash
LK.effects.flashScreen(0xFF0000, 300);
}
return;
}
};
self.closeShop = function () {
isShopOpen = false;
isGameRunning = true; // Resume game when closing shop
if (shopContainer) {
shopContainer.destroy();
shopContainer = null;
}
};
};
return self;
});
var Snake = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game configuration
var GRID_SIZE = 40;
var BOARD_WIDTH = 35;
var BOARD_HEIGHT = 50;
var MOVE_DELAY = 8; // Frames between moves
// Game state variables
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var food = null;
var moveCounter = 0;
var isGameRunning = true;
var friendlySnakes = [];
var friendlySnakeTimer = 0;
var enemySnakes = [];
var enemySnakeTimer = 0;
var foodItems = [];
var gigaChad = null;
var gigaChadNotified = false;
var shopButton = null;
var shopEffects = {
slowdown: {
active: false,
timer: 0
},
speedGigachad: {
active: false
},
doublePoints: {
active: false,
timer: 0
}
};
var isShopOpen = false;
var shopContainer = null;
// Calculate board position to center it horizontally and leave space for controls at bottom
var boardOffsetX = (2048 - BOARD_WIDTH * GRID_SIZE) / 2;
var boardOffsetY = 100; // Start closer to top, leaving space for controls at bottom
// Initialize SCOİN storage
if (!storage.coins) {
storage.coins = 0;
}
// Create score display
var scoreTxt = new Text2('SCOİN: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0.5);
// Position score centered horizontally and at control buttons level
scoreTxt.x = 2048 / 2; // Center horizontally
scoreTxt.y = 2732 - 300; // Same vertical level as control buttons
game.addChild(scoreTxt);
// Create power-up timer display
var powerUpTimerTxt = new Text2('', {
size: 60,
fill: 0x4CAF50
});
powerUpTimerTxt.anchor.set(0.5, 0.5);
powerUpTimerTxt.x = 2048 / 2; // Center horizontally
powerUpTimerTxt.y = 2732 - 200; // Above score display (score is at 2732 - 300, so this puts timer above it)
game.addChild(powerUpTimerTxt);
// Initialize snake with only head
function initializeSnake() {
snake = [];
// Clear death flag when starting fresh game
hadPowerUpsOnDeath = false;
// Create head using new Snake class
var head = game.addChild(new Snake());
head.x = boardOffsetX + 12 * GRID_SIZE;
head.y = boardOffsetY + 25 * GRID_SIZE;
snake.push({
x: 12,
y: 25,
obj: head
});
}
// Convert grid coordinates to screen coordinates
function gridToScreen(gridX, gridY) {
return {
x: boardOffsetX + gridX * GRID_SIZE,
y: boardOffsetY + gridY * GRID_SIZE
};
}
// Generate random food position
function spawnFood() {
var validPositions = [];
// Find all valid positions (not occupied by snake)
for (var x = 0; x < BOARD_WIDTH; x++) {
for (var y = 0; y < BOARD_HEIGHT; y++) {
var occupied = false;
for (var i = 0; i < snake.length; i++) {
if (snake[i].x === x && snake[i].y === y) {
occupied = true;
break;
}
}
if (!occupied) {
validPositions.push({
x: x,
y: y
});
}
}
}
if (validPositions.length > 0) {
var randomIndex = Math.floor(Math.random() * validPositions.length);
var pos = validPositions[randomIndex];
if (food) {
food.destroy();
}
food = game.addChild(new Food());
var screenPos = gridToScreen(pos.x, pos.y);
food.x = screenPos.x;
food.y = screenPos.y;
food.gridX = pos.x;
food.gridY = pos.y;
foodItems.push(food);
}
}
// Check if position is valid (within bounds and not colliding with snake)
function isValidPosition(x, y) {
// Check bounds
if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) {
return false;
}
// No body collision check needed for head-only snake
return true;
}
// Move snake
function moveSnake() {
if (!isGameRunning) {
return;
}
// Direction is already updated immediately in changeDirection function
// Calculate new head position
var head = snake[0];
var newHeadX = head.x + snakeDirection.x;
var newHeadY = head.y + snakeDirection.y;
// Check if new position is valid
if (!isValidPosition(newHeadX, newHeadY)) {
// Game over
isGameRunning = false;
// Check if player had any active power-ups before clearing them
hadPowerUpsOnDeath = shopEffects.slowdown.active || shopEffects.speedGigachad.active || shopEffects.doublePoints.active;
// Clear all active power-up effects on death
shopEffects.slowdown.active = false;
shopEffects.slowdown.timer = 0;
shopEffects.speedGigachad.active = false;
shopEffects.doublePoints.active = false;
shopEffects.doublePoints.timer = 0;
LK.getSound('gameOver').play();
LK.showGameOver();
return;
}
// Check if any food is eaten
var ateFood = false;
for (var i = foodItems.length - 1; i >= 0; i--) {
var currentFood = foodItems[i];
if (currentFood && newHeadX === currentFood.gridX && newHeadY === currentFood.gridY) {
ateFood = true;
var baseCoins = currentFood.foodType === 'level2' ? 50 : 10;
var coinGain = baseCoins;
// Apply double points effect if active
if (shopEffects.doublePoints.active) {
coinGain = baseCoins * 2;
}
var coins = storage.coins || 0;
storage.coins = coins + coinGain;
scoreTxt.setText('SCOİN: ' + storage.coins);
LK.getSound('eat').play();
// Flash food before removing
tween(currentFood, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
currentFood.destroy();
}
});
foodItems.splice(i, 1);
if (currentFood === food) {
food = null;
spawnFood();
}
break;
}
}
// Simply move the existing head to new position (no growth)
var headObj = snake[0].obj;
var screenPos = gridToScreen(newHeadX, newHeadY);
headObj.x = screenPos.x;
headObj.y = screenPos.y;
snake[0].x = newHeadX;
snake[0].y = newHeadY;
}
// Handle direction changes
function changeDirection(newDir) {
// Prevent immediate reversal
if (newDir.x === -snakeDirection.x && newDir.y === -snakeDirection.y) {
return;
}
// Prevent diagonal movement - only allow pure horizontal or vertical movement
if (newDir.x !== 0 && newDir.y !== 0) {
return;
}
// Apply direction change immediately for responsive controls
snakeDirection.x = newDir.x;
snakeDirection.y = newDir.y;
nextDirection.x = newDir.x;
nextDirection.y = newDir.y;
}
// Remove touch controls - snake can only be controlled by buttons
// Create visible walls around the game board
function createWalls() {
// Top and bottom walls
for (var x = -1; x <= BOARD_WIDTH; x++) {
// Top wall
var topWall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
}));
topWall.x = boardOffsetX + x * GRID_SIZE;
topWall.y = boardOffsetY - GRID_SIZE;
// Bottom wall
var bottomWall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
}));
bottomWall.x = boardOffsetX + x * GRID_SIZE;
bottomWall.y = boardOffsetY + BOARD_HEIGHT * GRID_SIZE;
}
// Left and right walls
for (var y = -1; y <= BOARD_HEIGHT; y++) {
// Left wall
var leftWall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
}));
leftWall.x = boardOffsetX - GRID_SIZE;
leftWall.y = boardOffsetY + y * GRID_SIZE;
// Right wall
var rightWall = game.addChild(LK.getAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
}));
rightWall.x = boardOffsetX + BOARD_WIDTH * GRID_SIZE;
rightWall.y = boardOffsetY + y * GRID_SIZE;
}
}
// Create directional control buttons
var upButton = game.addChild(new DirectionalButton({
x: 0,
y: -1
}, 'upButton'));
var downButton = game.addChild(new DirectionalButton({
x: 0,
y: 1
}, 'downButton'));
var leftButton = game.addChild(new DirectionalButton({
x: -1,
y: 0
}, 'leftButton'));
var rightButton = game.addChild(new DirectionalButton({
x: 1,
y: 0
}, 'rightButton'));
// Position buttons in bottom right corner
var buttonSpacing = 140;
var buttonBaseX = 2048 - 200;
var buttonBaseY = 2732 - 300;
// Up button
upButton.x = buttonBaseX;
upButton.y = buttonBaseY - buttonSpacing;
// Down button
downButton.x = buttonBaseX;
downButton.y = buttonBaseY + buttonSpacing;
// Left button
leftButton.x = buttonBaseX - buttonSpacing;
leftButton.y = buttonBaseY;
// Right button
rightButton.x = buttonBaseX + buttonSpacing;
rightButton.y = buttonBaseY;
// Add text labels to buttons
var upText = new Text2('↑', {
size: 60,
fill: 0xFFFFFF
});
upText.anchor.set(0.5, 0.5);
upText.x = upButton.x;
upText.y = upButton.y;
game.addChild(upText);
var downText = new Text2('↓', {
size: 60,
fill: 0xFFFFFF
});
downText.anchor.set(0.5, 0.5);
downText.x = downButton.x;
downText.y = downButton.y;
game.addChild(downText);
var leftText = new Text2('←', {
size: 60,
fill: 0xFFFFFF
});
leftText.anchor.set(0.5, 0.5);
leftText.x = leftButton.x;
leftText.y = leftButton.y;
game.addChild(leftText);
var rightText = new Text2('→', {
size: 60,
fill: 0xFFFFFF
});
rightText.anchor.set(0.5, 0.5);
rightText.x = rightButton.x;
rightText.y = rightButton.y;
game.addChild(rightText);
// Initialize game
createWalls();
initializeSnake();
spawnFood();
// Game mode variables
var gameMode = 'menu'; // 'menu', 'normal'
// Create main menu overlay
var instructionContainer = new Container();
instructionContainer.x = 0;
instructionContainer.y = 0;
game.addChild(instructionContainer);
// Create semi-transparent background
var instructionBg = LK.getAsset('shopButton', {
anchorX: 0,
anchorY: 0,
scaleX: 10.24,
scaleY: 34.15
});
instructionBg.tint = 0x000000;
instructionBg.alpha = 0.9;
instructionContainer.addChild(instructionBg);
// Create main menu title
var menuTitle = new Text2('THE SNAKE GAME 2077', {
size: 150,
fill: 0xFFD700
});
menuTitle.anchor.set(0.5, 0.5);
menuTitle.x = 1024;
menuTitle.y = 300;
instructionContainer.addChild(menuTitle);
// Create game mode buttons
var normalModeButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.0
});
normalModeButton.x = 1024;
normalModeButton.y = 800;
normalModeButton.tint = 0x4CAF50;
instructionContainer.addChild(normalModeButton);
var normalModeText = new Text2('NORMAL MODE', {
size: 60,
fill: 0xFFFFFF
});
normalModeText.anchor.set(0.5, 0.5);
normalModeText.x = normalModeButton.x;
normalModeText.y = normalModeButton.y;
instructionContainer.addChild(normalModeText);
var otherButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.0
});
otherButton.x = 1024;
otherButton.y = 1000;
otherButton.tint = 0xFF5722;
instructionContainer.addChild(otherButton);
var otherText = new Text2('DİE', {
size: 60,
fill: 0xFFFFFF
});
otherText.anchor.set(0.5, 0.5);
otherText.x = otherButton.x;
otherText.y = otherButton.y;
instructionContainer.addChild(otherText);
// How to play button
var howToPlayButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 0.8
});
howToPlayButton.x = 1024;
howToPlayButton.y = 1200;
howToPlayButton.tint = 0x9C27B0;
instructionContainer.addChild(howToPlayButton);
var howToPlayText = new Text2('HOW TO PLAY', {
size: 50,
fill: 0xFFFFFF
});
howToPlayText.anchor.set(0.5, 0.5);
howToPlayText.x = howToPlayButton.x;
howToPlayText.y = howToPlayButton.y;
instructionContainer.addChild(howToPlayText);
// Pause game initially to show menu
isGameRunning = false;
gameMode = 'menu';
// Add click handler for menu
instructionContainer.down = function (x, y, obj) {
// Check normal mode button
if (Math.abs(x - normalModeButton.x) < 150 && Math.abs(y - normalModeButton.y) < 50) {
startNormalMode();
return;
}
// Check other button
if (Math.abs(x - otherButton.x) < 150 && Math.abs(y - otherButton.y) < 50) {
showOther();
return;
}
// Check how to play button
if (Math.abs(x - howToPlayButton.x) < 120 && Math.abs(y - howToPlayButton.y) < 40) {
showHowToPlayWithOther();
return;
}
};
// Function to start normal mode
function startNormalMode() {
gameMode = 'normal';
isCompetitionMode = false;
// Remove menu overlay
instructionContainer.destroy();
instructionContainer = null;
// Start the game
isGameRunning = true;
// Start background music
LK.playMusic('backgroundMusic');
// Flash screen green to indicate game start
LK.effects.flashScreen(0x4CAF50, 500);
}
// Function to show other
function showOther() {
// Flash screen to indicate URL opening attempt
LK.effects.flashScreen(0xFF5722, 500);
// Since window.open doesn't work in this environment, use LK.showGameOver as workaround
// In a real implementation, this would open https://upit.com/@karasavasci127
LK.showGameOver();
}
// Function to show how to play with other URL
function showHowToPlayWithOther() {
// Clear current menu content
while (instructionContainer.children.length > 0) {
instructionContainer.removeChild(instructionContainer.children[0]);
}
// Add background back
instructionContainer.addChild(instructionBg);
// Create instruction title
var instructionTitle = new Text2('HOW TO PLAY', {
size: 120,
fill: 0xFFD700
});
instructionTitle.anchor.set(0.5, 0.5);
instructionTitle.x = 1024;
instructionTitle.y = 300;
instructionContainer.addChild(instructionTitle);
// Create instruction text
var instructionText = new Text2('• Use arrow buttons to move snake\n• Collect food to earn SCOİN\n• Normal food = 10 SCOİN\n• Level 2 food = 50 SCOİN\n• Avoid red enemy snakes\n• Gold friendly snakes protect you\n• Buy power-ups in SHOP\n• Use items from INVENTORY', {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = 1100;
instructionContainer.addChild(instructionText);
// Create Other URL text below instructions
var otherUrlText = new Text2('Other: https://upit.com/@karasavasci127', {
size: 60,
fill: 0xFF5722
});
otherUrlText.anchor.set(0.5, 0.5);
otherUrlText.x = 1024;
otherUrlText.y = 1400;
instructionContainer.addChild(otherUrlText);
// Back to menu button
var backButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 0.8
});
backButton.x = 1024;
backButton.y = 1900;
backButton.tint = 0x666666;
instructionContainer.addChild(backButton);
var backText = new Text2('BACK TO MENU', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = backButton.x;
backText.y = backButton.y;
instructionContainer.addChild(backText);
// Update click handler for back button and Other URL
instructionContainer.down = function (x, y, obj) {
if (Math.abs(x - backButton.x) < 100 && Math.abs(y - backButton.y) < 40) {
// Go back to main menu
LK.showGameOver(); // Reset game state and return to main menu
} else if (Math.abs(x - otherUrlText.x) < 300 && Math.abs(y - otherUrlText.y) < 50) {
// Other URL clicked
LK.effects.flashScreen(0xFF5722, 500);
LK.showGameOver();
}
};
}
// Don't start background music immediately - wait for instructions to be dismissed
// Merchant functionality is handled through the shop button
// Create shop button at bottom center
shopButton = game.addChild(new ShopButton());
shopButton.x = 2048 / 2; // Center horizontally
shopButton.y = 2732 - 150; // Bottom of screen with some margin
// Add shop button text
var shopText = new Text2('SHOP', {
size: 40,
fill: 0xFFFFFF
});
shopText.anchor.set(0.5, 0.5);
shopText.x = shopButton.x;
shopText.y = shopButton.y;
game.addChild(shopText);
// Create hidden money cheat button above score
var hiddenMoneyButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.3
});
hiddenMoneyButton.x = scoreTxt.x; // Same x position as score
hiddenMoneyButton.y = scoreTxt.y - 100; // 100 pixels above score
hiddenMoneyButton.alpha = 0; // Make completely invisible
game.addChild(hiddenMoneyButton);
// Add click handler for hidden money button
hiddenMoneyButton.down = function (x, y, obj) {
// Give player 999999 coins
storage.coins = (storage.coins || 0) + 999999;
// Flash screen gold to indicate cheat activated
LK.effects.flashScreen(0xFFD700, 500);
};
// Initialize inventory storage
if (!storage.inventory) {
storage.inventory = {
slowdown: 0,
speedGigachad: 0,
doublePoints: 0
};
}
// Create inventory button
var inventoryButton = game.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
inventoryButton.x = 2048 / 2 - 250; // Left of shop button
inventoryButton.y = 2732 - 150; // Same level as shop button
inventoryButton.tint = 0x9C27B0; // Purple tint for inventory
// Add inventory button text
var inventoryText = new Text2('INVENTORY', {
size: 30,
fill: 0xFFFFFF
});
inventoryText.anchor.set(0.5, 0.5);
inventoryText.x = inventoryButton.x;
inventoryText.y = inventoryButton.y;
game.addChild(inventoryText);
// Create reset SCOİN button
var resetCoinButton = game.addChild(LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
resetCoinButton.x = 2048 / 2 + 250; // Right of shop button (opposite side from inventory)
resetCoinButton.y = 2732 - 150; // Same level as shop and inventory buttons
resetCoinButton.tint = 0xFF5722; // Orange-red tint for reset button
// Add reset button text
var resetText = new Text2('RESET SCOİN', {
size: 30,
fill: 0xFFFFFF
});
resetText.anchor.set(0.5, 0.5);
resetText.x = resetCoinButton.x;
resetText.y = resetCoinButton.y;
game.addChild(resetText);
// Add reset button functionality
resetCoinButton.down = function (x, y, obj) {
// Visual feedback
tween(resetCoinButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100
});
// Reset SCOİN to 0
storage.coins = 0;
// Update score display
scoreTxt.setText('SCOİN: ' + storage.coins);
// Flash screen orange to indicate reset
LK.effects.flashScreen(0xFF5722, 500);
};
resetCoinButton.up = function (x, y, obj) {
// Return to normal size
tween(resetCoinButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
};
// Inventory system variables
var isInventoryOpen = false;
var inventoryContainer = null;
var hadPowerUpsOnDeath = false; // Track if player had power-ups when they died
// Add inventory button functionality
inventoryButton.down = function (x, y, obj) {
// Visual feedback
tween(inventoryButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100
});
// Toggle inventory
if (isInventoryOpen) {
closeInventory();
} else {
openInventory();
}
};
inventoryButton.up = function (x, y, obj) {
// Return to normal size
tween(inventoryButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
};
// Function to open inventory
function openInventory() {
if (isInventoryOpen) {
return;
}
isInventoryOpen = true;
isGameRunning = false; // Pause game
// Create inventory container
inventoryContainer = new Container();
inventoryContainer.x = 0;
inventoryContainer.y = 0;
game.addChild(inventoryContainer);
// Create background
var inventoryBg = LK.getAsset('shopButton', {
anchorX: 0,
anchorY: 0,
scaleX: 10.24,
scaleY: 34.15
});
inventoryBg.tint = 0x2E2E2E;
inventoryBg.alpha = 0.9;
inventoryContainer.addChild(inventoryBg);
// Title
var titleText = new Text2('INVENTORY', {
size: 120,
fill: 0x9C27B0
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 300;
inventoryContainer.addChild(titleText);
// Current coins display
var coinsText = new Text2('SCOİN: ' + (storage.coins || 0), {
size: 60,
fill: 0xFFD700
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 1024;
coinsText.y = 400;
inventoryContainer.addChild(coinsText);
// Inventory items section - GIGACHAD at top center, others below
var yPos = 500;
var itemSpacing = 120;
// Fast GIGACHAD items - positioned at top center
var speedGigachadCount = storage.inventory.speedGigachad || 0;
var speedStatusText = shopEffects.speedGigachad.active ? ' (ACTIVE)' : '';
var speedItemText = new Text2('Fast GIGACHAD: ' + speedGigachadCount + speedStatusText, {
size: 60,
fill: shopEffects.speedGigachad.active ? 0x4CAF50 : 0xFFFFFF
});
speedItemText.anchor.set(0.5, 0.5);
speedItemText.x = 1024; // Centered
speedItemText.y = yPos;
inventoryContainer.addChild(speedItemText);
// Use button for speed GIGACHAD - centered below text
if (speedGigachadCount > 0 && !shopEffects.speedGigachad.active && !hadPowerUpsOnDeath) {
var useSpeedBtn = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
useSpeedBtn.x = 1024; // Centered
useSpeedBtn.y = yPos + 60;
useSpeedBtn.tint = 0x4CAF50;
inventoryContainer.addChild(useSpeedBtn);
var useSpeedText = new Text2('USE', {
size: 40,
fill: 0xFFFFFF
});
useSpeedText.anchor.set(0.5, 0.5);
useSpeedText.x = useSpeedBtn.x;
useSpeedText.y = useSpeedBtn.y;
inventoryContainer.addChild(useSpeedText);
}
// Slowdown items - positioned below GIGACHAD
yPos += itemSpacing + 60;
var slowdownCount = storage.inventory.slowdown || 0;
var slowdownStatusText = shopEffects.slowdown.active ? ' (ACTIVE - ' + Math.ceil((18000 - shopEffects.slowdown.timer) / 60) + 's left)' : '';
var slowdownItemText = new Text2('Slowdown 5min: ' + slowdownCount + slowdownStatusText, {
size: 45,
fill: shopEffects.slowdown.active ? 0x4CAF50 : 0xFFFFFF
});
slowdownItemText.anchor.set(0.5, 0.5);
slowdownItemText.x = 1024;
slowdownItemText.y = yPos;
inventoryContainer.addChild(slowdownItemText);
// Use button for slowdown
if (slowdownCount > 0 && !shopEffects.slowdown.active && !hadPowerUpsOnDeath) {
var useSlowdownBtn = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
useSlowdownBtn.x = 1024 + 200;
useSlowdownBtn.y = yPos;
useSlowdownBtn.tint = 0x4CAF50;
inventoryContainer.addChild(useSlowdownBtn);
var useSlowdownText = new Text2('USE', {
size: 30,
fill: 0xFFFFFF
});
useSlowdownText.anchor.set(0.5, 0.5);
useSlowdownText.x = useSlowdownBtn.x;
useSlowdownText.y = useSlowdownBtn.y;
inventoryContainer.addChild(useSlowdownText);
}
// Double Points items - positioned at bottom
yPos += itemSpacing;
var doublePointsCount = storage.inventory.doublePoints || 0;
var doubleStatusText = shopEffects.doublePoints.active ? ' (ACTIVE - ' + Math.ceil((18000 - shopEffects.doublePoints.timer) / 60) + 's left)' : '';
var doubleItemText = new Text2('2x Points: ' + doublePointsCount + doubleStatusText, {
size: 45,
fill: shopEffects.doublePoints.active ? 0x4CAF50 : 0xFFFFFF
});
doubleItemText.anchor.set(0.5, 0.5);
doubleItemText.x = 1024;
doubleItemText.y = yPos;
inventoryContainer.addChild(doubleItemText);
// Use button for double points
if (doublePointsCount > 0 && !shopEffects.doublePoints.active && !hadPowerUpsOnDeath) {
var useDoubleBtn = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
useDoubleBtn.x = 1024 + 200;
useDoubleBtn.y = yPos;
useDoubleBtn.tint = 0x4CAF50;
inventoryContainer.addChild(useDoubleBtn);
var useDoubleText = new Text2('USE', {
size: 30,
fill: 0xFFFFFF
});
useDoubleText.anchor.set(0.5, 0.5);
useDoubleText.x = useDoubleBtn.x;
useDoubleText.y = useDoubleBtn.y;
inventoryContainer.addChild(useDoubleText);
}
}
// Function to close inventory
function closeInventory() {
isInventoryOpen = false;
isGameRunning = true;
if (inventoryContainer) {
inventoryContainer.destroy();
inventoryContainer = null;
}
}
// Function to handle inventory item usage
function handleInventoryClick(x, y) {
if (!isInventoryOpen || !inventoryContainer) {
return;
}
// Prevent using inventory if player had power-ups when they died
if (hadPowerUpsOnDeath) {
LK.effects.flashScreen(0xFF0000, 300); // Red flash to indicate blocked
return;
}
// Check use buttons with correct global positions
var itemSpacing = 120;
var startY = 500;
// Speed GIGACHAD use button - centered at top (1024, startY + 60)
var speedButtonX = 1024;
var speedButtonY = startY + 60;
if (Math.abs(x - speedButtonX) < 150 && Math.abs(y - speedButtonY) < 50) {
if ((storage.inventory.speedGigachad || 0) > 0 && !shopEffects.speedGigachad.active) {
storage.inventory.speedGigachad--;
shopEffects.speedGigachad.active = true;
// Save inventory changes
storage.inventory = {
slowdown: storage.inventory.slowdown || 0,
speedGigachad: storage.inventory.speedGigachad,
doublePoints: storage.inventory.doublePoints || 0
};
closeInventory();
LK.effects.flashScreen(0x4CAF50, 500);
}
return;
}
// Slowdown use button - positioned at (1024 + 200, slowdownY)
var slowdownY = startY + itemSpacing + 60;
var slowdownButtonX = 1024 + 200;
if (Math.abs(x - slowdownButtonX) < 100 && Math.abs(y - slowdownY) < 50) {
if ((storage.inventory.slowdown || 0) > 0 && !shopEffects.slowdown.active) {
storage.inventory.slowdown--;
shopEffects.slowdown.active = true;
shopEffects.slowdown.timer = 0;
// Save inventory changes
storage.inventory = {
slowdown: storage.inventory.slowdown,
speedGigachad: storage.inventory.speedGigachad || 0,
doublePoints: storage.inventory.doublePoints || 0
};
closeInventory();
LK.effects.flashScreen(0x4CAF50, 500);
}
return;
}
// Double Points use button - positioned at (1024 + 200, doubleY)
var doubleY = startY + itemSpacing * 2 + 60;
var doubleButtonX = 1024 + 200;
if (Math.abs(x - doubleButtonX) < 100 && Math.abs(y - doubleY) < 50) {
if ((storage.inventory.doublePoints || 0) > 0 && !shopEffects.doublePoints.active) {
storage.inventory.doublePoints--;
shopEffects.doublePoints.active = true;
shopEffects.doublePoints.timer = 0;
// Save inventory changes
storage.inventory = {
slowdown: storage.inventory.slowdown || 0,
speedGigachad: storage.inventory.speedGigachad || 0,
doublePoints: storage.inventory.doublePoints
};
closeInventory();
LK.effects.flashScreen(0x4CAF50, 500);
}
return;
}
}
// Add shop interaction handler
game.down = function (x, y, obj) {
if (isShopOpen && shopButton) {
shopButton.handleShopClick(x, y);
} else if (isInventoryOpen) {
handleInventoryClick(x, y);
}
};
// Main game loop
game.update = function () {
if (!isGameRunning || isShopOpen || isInventoryOpen) {
return;
}
moveCounter++;
var currentMoveDelay = MOVE_DELAY;
if (shopEffects.slowdown.active) {
currentMoveDelay = MOVE_DELAY * 2; // Double the delay for slowdown effect
}
if (moveCounter >= currentMoveDelay) {
moveCounter = 0;
moveSnake();
}
// Spawn friendly snakes every 10 seconds (600 frames at 60fps)
friendlySnakeTimer++;
if (friendlySnakeTimer >= 600) {
friendlySnakeTimer = 0;
var friendlySnake = game.addChild(new FriendlySnake());
// Spawn at random edge position within board bounds only
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top - ensure spawn within board width
friendlySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE;
friendlySnake.y = boardOffsetY + GRID_SIZE;
break;
case 1:
// Right - ensure spawn within board height
friendlySnake.x = boardOffsetX + (BOARD_WIDTH - 1) * GRID_SIZE;
friendlySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE;
break;
case 2:
// Bottom - ensure spawn within board width
friendlySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE;
friendlySnake.y = boardOffsetY + (BOARD_HEIGHT - 1) * GRID_SIZE;
break;
case 3:
// Left - ensure spawn within board height
friendlySnake.x = boardOffsetX + GRID_SIZE;
friendlySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE;
break;
}
friendlySnakes.push(friendlySnake);
}
// Spawn enemy snakes every 8 seconds (480 frames at 60fps)
enemySnakeTimer++;
if (enemySnakeTimer >= 480) {
enemySnakeTimer = 0;
var enemySnake = game.addChild(new EnemySnake());
// Spawn at random edge position within board bounds only
var edge = Math.floor(Math.random() * 4);
switch (edge) {
case 0:
// Top - ensure spawn within board width
enemySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE;
enemySnake.y = boardOffsetY + GRID_SIZE;
break;
case 1:
// Right - ensure spawn within board height
enemySnake.x = boardOffsetX + (BOARD_WIDTH - 1) * GRID_SIZE;
enemySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE;
break;
case 2:
// Bottom - ensure spawn within board width
enemySnake.x = boardOffsetX + (Math.random() * (BOARD_WIDTH - 2) + 1) * GRID_SIZE;
enemySnake.y = boardOffsetY + (BOARD_HEIGHT - 1) * GRID_SIZE;
break;
case 3:
// Left - ensure spawn within board height
enemySnake.x = boardOffsetX + GRID_SIZE;
enemySnake.y = boardOffsetY + (Math.random() * (BOARD_HEIGHT - 2) + 1) * GRID_SIZE;
break;
}
enemySnakes.push(enemySnake);
}
// Check collision between player and enemy snakes
if (snake.length > 0) {
var playerHead = snake[0];
var playerScreenPos = gridToScreen(playerHead.x, playerHead.y);
for (var i = enemySnakes.length - 1; i >= 0; i--) {
var enemySnake = enemySnakes[i];
var dist = Math.sqrt(Math.pow(playerScreenPos.x - enemySnake.x, 2) + Math.pow(playerScreenPos.y - enemySnake.y, 2));
if (dist < 60) {
// Collision detected
// Check if friendly snake is protecting
var isProtected = false;
for (var j = 0; j < friendlySnakes.length; j++) {
var friendlySnake = friendlySnakes[j];
var friendlyDist = Math.sqrt(Math.pow(playerScreenPos.x - friendlySnake.x, 2) + Math.pow(playerScreenPos.y - friendlySnake.y, 2));
if (friendlyDist < 100) {
// Protection range
isProtected = true;
// Remove the enemy snake as it's defeated by friendly snake
enemySnake.destroy();
enemySnakes.splice(i, 1);
var coins = storage.coins || 0;
storage.coins = coins + 50; // Bonus for protection
scoreTxt.setText('SCOİN: ' + storage.coins);
break;
}
}
if (!isProtected) {
// Game over - player eaten by enemy snake
isGameRunning = false;
// Check if player had any active power-ups before clearing them
hadPowerUpsOnDeath = shopEffects.slowdown.active || shopEffects.speedGigachad.active || shopEffects.doublePoints.active;
// Clear all active power-up effects on death
shopEffects.slowdown.active = false;
shopEffects.slowdown.timer = 0;
shopEffects.speedGigachad.active = false;
shopEffects.doublePoints.active = false;
shopEffects.doublePoints.timer = 0;
LK.getSound('gameOver').play();
LK.showGameOver();
return;
}
}
}
}
// Reset GIGACHAD notification if no enemies remain
if (enemySnakes.length === 0) {
gigaChadNotified = false;
}
// Update shop effects
if (shopEffects.slowdown.active) {
shopEffects.slowdown.timer++;
if (shopEffects.slowdown.timer >= 18000) {
// 5 minutes
shopEffects.slowdown.active = false;
shopEffects.slowdown.timer = 0;
}
}
if (shopEffects.doublePoints.active) {
shopEffects.doublePoints.timer++;
if (shopEffects.doublePoints.timer >= 18000) {
// 5 minutes
shopEffects.doublePoints.active = false;
shopEffects.doublePoints.timer = 0;
}
}
// Update power-up timer display
var timerText = "";
var activeEffects = [];
if (shopEffects.slowdown.active) {
var slowdownTimeLeft = Math.ceil((18000 - shopEffects.slowdown.timer) / 60);
activeEffects.push("Slowdown: " + slowdownTimeLeft + "s");
}
if (shopEffects.speedGigachad.active) {
activeEffects.push("Fast GIGACHAD: ACTIVE");
}
if (shopEffects.doublePoints.active) {
var doublePointsTimeLeft = Math.ceil((18000 - shopEffects.doublePoints.timer) / 60);
activeEffects.push("2x Points: " + doublePointsTimeLeft + "s");
}
if (activeEffects.length > 0) {
timerText = activeEffects.join(" | ");
powerUpTimerTxt.setText(timerText);
powerUpTimerTxt.alpha = 1;
} else {
powerUpTimerTxt.setText("");
powerUpTimerTxt.alpha = 0;
}
};
robotik yap
wall block. In-Game asset. 2d. High contrast. No shadows
energy ball. In-Game asset. 2d. High contrast. No shadows
frendly robotic snake. In-Game asset. 2d. High contrast. No shadows
rainbow energy. In-Game asset. 2d. High contrast. No shadows
enemy robotic snake. In-Game asset. 2d. High contrast. No shadows
Robotic GigaChad snake. In-Game asset. 2d. High contrast. No shadows
yellow and orange cube 2d. In-Game asset. 2d. High contrast. No shadows
button red 2d. In-Game asset. 2d. High contrast. No shadows