/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Food = Container.expand(function () { var self = Container.call(this); // Create food graphics self.graphics = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); // Animation to make food more noticeable self.update = function () { self.graphics.rotation += 0.03; }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); // Create portal graphics self.graphics = self.attachAsset('portal', { anchorX: 0.5, anchorY: 0.5 }); // Animation to make portal more noticeable self.update = function () { self.graphics.rotation += 0.05; // Pulsing effect if (!self.pulseDirection) { self.pulseDirection = 1; self.pulseValue = 0; } self.pulseValue += 0.02 * self.pulseDirection; if (self.pulseValue >= 1) { self.pulseDirection = -1; } else if (self.pulseValue <= 0) { self.pulseDirection = 1; } // Scale between 0.9 and 1.1 var scale = 0.9 + self.pulseValue * 0.2; self.graphics.scale.set(scale, scale); }; return self; }); var SnakeSegment = Container.expand(function () { var self = Container.call(this); // Default to body segment self.isHead = false; // Create segment graphics self.graphics = self.attachAsset('snakeBody', { anchorX: 0.5, anchorY: 0.5 }); // Set as head segment if needed self.setAsHead = function () { self.isHead = true; self.removeChild(self.graphics); self.graphics = self.attachAsset('snakeHead', { anchorX: 0.5, anchorY: 0.5 }); }; // Store previous position for smooth movement self.prevX = 0; self.prevY = 0; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); // Create wall graphics self.graphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x202020 }); /**** * Game Code ****/ // Game constants var GRID_SIZE = 50; var GRID_WIDTH = Math.floor(2048 / GRID_SIZE); var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE); var GAME_SPEED = 200; // ms between moves var INITIAL_SNAKE_LENGTH = 3; // Game variables var snake = []; var walls = []; var foods = []; var portal = null; var direction = 'right'; var nextDirection = 'right'; var moveTimer = null; var level = storage.level || 1; var isDragging = false; var dragStartX = 0; var dragStartY = 0; var gameBoard = new Container(); var gameRunning = false; var levelText; var scoreText; // Add game board to center the maze game.addChild(gameBoard); // Initialize the game UI function initUI() { // Level display levelText = new Text2('Level: ' + level, { size: 70, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); LK.gui.topRight.addChild(levelText); // Score display scoreText = new Text2('Score: ' + LK.getScore(), { size: 70, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.top.addChild(scoreText); } // Reset the game for a new level function resetGame() { // Clear existing elements while (gameBoard.children.length > 0) { gameBoard.removeChildAt(0); } // Reset arrays snake = []; walls = []; foods = []; portal = null; // Reset direction direction = 'right'; nextDirection = 'right'; // Clear timers if (moveTimer) { LK.clearInterval(moveTimer); moveTimer = null; } // Generate level generateLevel(level); // Start the game loop moveTimer = LK.setInterval(moveSnake, GAME_SPEED); gameRunning = true; // Update UI levelText.setText('Level: ' + level); scoreText.setText('Score: ' + LK.getScore()); // Play background music LK.playMusic('bgMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); } // Generate a level with walls, food, and a snake function generateLevel(levelNum) { var difficulty = Math.min(10, Math.floor(levelNum / 2) + 1); // Calculate board size (smaller than full screen) var boardWidth = Math.min(GRID_WIDTH - 2, 20) * GRID_SIZE; var boardHeight = Math.min(GRID_HEIGHT - 6, 20) * GRID_SIZE; // Center the board gameBoard.x = (2048 - boardWidth) / 2; gameBoard.y = (2732 - boardHeight) / 2; // Generate walls around the perimeter for (var x = 0; x < boardWidth / GRID_SIZE; x++) { addWall(x * GRID_SIZE, 0); addWall(x * GRID_SIZE, boardHeight - GRID_SIZE); } for (var y = 0; y < boardHeight / GRID_SIZE; y++) { addWall(0, y * GRID_SIZE); addWall(boardWidth - GRID_SIZE, y * GRID_SIZE); } // Generate internal walls based on difficulty for (var i = 0; i < difficulty * 5; i++) { var wx = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE; var wy = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE; // Ensure we're not placing walls too close to starting position if (Math.abs(wx - 4 * GRID_SIZE) > 2 * GRID_SIZE || Math.abs(wy - 4 * GRID_SIZE) > 2 * GRID_SIZE) { addWall(wx, wy); } } // Create snake at starting position createSnake(3 * GRID_SIZE, 4 * GRID_SIZE, INITIAL_SNAKE_LENGTH); // Add food for (var f = 0; f < difficulty + 2; f++) { addRandomFood(boardWidth, boardHeight); } // Add exit portal var px = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE; var py = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE; // Make sure portal isn't too close to snake start while (Math.abs(px - 4 * GRID_SIZE) < 5 * GRID_SIZE && Math.abs(py - 4 * GRID_SIZE) < 5 * GRID_SIZE) { px = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE; py = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE; } addPortal(px, py); } // Create the initial snake function createSnake(x, y, length) { for (var i = 0; i < length; i++) { var segment = new SnakeSegment(); // Place segment with head at (x,y) and body extending to the left segment.x = x - i * GRID_SIZE; segment.y = y; segment.prevX = segment.x; segment.prevY = segment.y; // Make the first segment the head if (i === 0) { segment.setAsHead(); } snake.push(segment); gameBoard.addChild(segment); } } // Add a wall at the specified position function addWall(x, y) { var wall = new Wall(); wall.x = x; wall.y = y; walls.push(wall); gameBoard.addChild(wall); } // Add food at a random position function addRandomFood(boardWidth, boardHeight) { var validPosition = false; var fx, fy; while (!validPosition) { fx = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 2) + 1) * GRID_SIZE; fy = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 2) + 1) * GRID_SIZE; validPosition = true; // Check if position overlaps with walls for (var i = 0; i < walls.length; i++) { if (walls[i].x === fx && walls[i].y === fy) { validPosition = false; break; } } // Check if position overlaps with snake if (validPosition) { for (var j = 0; j < snake.length; j++) { if (Math.abs(snake[j].x - fx) < GRID_SIZE && Math.abs(snake[j].y - fy) < GRID_SIZE) { validPosition = false; break; } } } // Check if position overlaps with portal if (validPosition && portal && Math.abs(portal.x - fx) < GRID_SIZE && Math.abs(portal.y - fy) < GRID_SIZE) { validPosition = false; } } var food = new Food(); food.x = fx; food.y = fy; foods.push(food); gameBoard.addChild(food); } // Add exit portal function addPortal(x, y) { portal = new Portal(); portal.x = x; portal.y = y; gameBoard.addChild(portal); } // Move the snake based on current direction function moveSnake() { if (!gameRunning) return; // Update direction direction = nextDirection; // Store previous positions for smooth movement for (var i = 0; i < snake.length; i++) { snake[i].prevX = snake[i].x; snake[i].prevY = snake[i].y; } // Calculate new head position var head = snake[0]; var newHeadX = head.x; var newHeadY = head.y; switch (direction) { case 'up': newHeadY -= GRID_SIZE; break; case 'down': newHeadY += GRID_SIZE; break; case 'left': newHeadX -= GRID_SIZE; break; case 'right': newHeadX += GRID_SIZE; break; } // Check for collisions if (checkCollision(newHeadX, newHeadY)) { // Game over LK.getSound('hit').play(); gameRunning = false; // Flash red and show game over LK.effects.flashScreen(0xFF0000, 500); LK.setTimeout(function () { LK.showGameOver(); }, 600); return; } // Move body segments for (var i = snake.length - 1; i > 0; i--) { snake[i].x = snake[i - 1].x; snake[i].y = snake[i - 1].y; } // Move head to new position head.x = newHeadX; head.y = newHeadY; // Check for food collision for (var i = 0; i < foods.length; i++) { if (Math.abs(head.x - foods[i].x) < GRID_SIZE / 2 && Math.abs(head.y - foods[i].y) < GRID_SIZE / 2) { // Remove the food gameBoard.removeChild(foods[i]); foods.splice(i, 1); // Play eat sound LK.getSound('eat').play(); // Add score LK.setScore(LK.getScore() + 10); scoreText.setText('Score: ' + LK.getScore()); // Add a new segment var tail = snake[snake.length - 1]; var newSegment = new SnakeSegment(); newSegment.x = tail.x; newSegment.y = tail.y; newSegment.prevX = newSegment.x; newSegment.prevY = newSegment.y; snake.push(newSegment); gameBoard.addChild(newSegment); // Add a new food var boardWidth = Math.min(GRID_WIDTH - 2, 20) * GRID_SIZE; var boardHeight = Math.min(GRID_HEIGHT - 6, 20) * GRID_SIZE; addRandomFood(boardWidth, boardHeight); break; } } // Check for portal collision if (portal && Math.abs(head.x - portal.x) < GRID_SIZE / 2 && Math.abs(head.y - portal.y) < GRID_SIZE / 2) { // Play portal sound LK.getSound('portal').play(); // Level completed gameRunning = false; // Flash screen and advance to next level LK.effects.flashScreen(0x9966FF, 500); // Store level progress level++; storage.level = level; LK.setTimeout(function () { resetGame(); }, 1000); } } // Check if the given position collides with walls or snake body function checkCollision(x, y) { // Check wall collision for (var i = 0; i < walls.length; i++) { if (Math.abs(x - walls[i].x) < GRID_SIZE / 2 && Math.abs(y - walls[i].y) < GRID_SIZE / 2) { return true; } } // Check self collision (skip head) for (var i = 1; i < snake.length; i++) { if (Math.abs(x - snake[i].x) < GRID_SIZE / 2 && Math.abs(y - snake[i].y) < GRID_SIZE / 2) { return true; } } return false; } // Handle touch/mouse down on game game.down = function (x, y, obj) { if (!gameRunning) return; isDragging = true; dragStartX = x; dragStartY = y; }; // Handle touch/mouse move game.move = function (x, y, obj) { if (!isDragging || !gameRunning) return; // Calculate the difference from start position var dx = x - dragStartX; var dy = y - dragStartY; // Only change direction if the drag is significant if (Math.abs(dx) > 20 || Math.abs(dy) > 20) { // Determine direction based on which axis has the larger change if (Math.abs(dx) > Math.abs(dy)) { // Horizontal movement if (dx > 0 && direction !== 'left') { nextDirection = 'right'; } else if (dx < 0 && direction !== 'right') { nextDirection = 'left'; } } else { // Vertical movement if (dy > 0 && direction !== 'up') { nextDirection = 'down'; } else if (dy < 0 && direction !== 'down') { nextDirection = 'up'; } } // Reset drag start dragStartX = x; dragStartY = y; } }; // Handle touch/mouse up game.up = function (x, y, obj) { isDragging = false; }; // Update game state each tick game.update = function () { // Update all elements with update methods for (var i = 0; i < foods.length; i++) { foods[i].update(); } if (portal) { portal.update(); } }; // Initialize UI and start the game initUI(); resetGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,439 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Food = Container.expand(function () {
+ var self = Container.call(this);
+ // Create food graphics
+ self.graphics = self.attachAsset('food', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Animation to make food more noticeable
+ self.update = function () {
+ self.graphics.rotation += 0.03;
+ };
+ return self;
+});
+var Portal = Container.expand(function () {
+ var self = Container.call(this);
+ // Create portal graphics
+ self.graphics = self.attachAsset('portal', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Animation to make portal more noticeable
+ self.update = function () {
+ self.graphics.rotation += 0.05;
+ // Pulsing effect
+ if (!self.pulseDirection) {
+ self.pulseDirection = 1;
+ self.pulseValue = 0;
+ }
+ self.pulseValue += 0.02 * self.pulseDirection;
+ if (self.pulseValue >= 1) {
+ self.pulseDirection = -1;
+ } else if (self.pulseValue <= 0) {
+ self.pulseDirection = 1;
+ }
+ // Scale between 0.9 and 1.1
+ var scale = 0.9 + self.pulseValue * 0.2;
+ self.graphics.scale.set(scale, scale);
+ };
+ return self;
+});
+var SnakeSegment = Container.expand(function () {
+ var self = Container.call(this);
+ // Default to body segment
+ self.isHead = false;
+ // Create segment graphics
+ self.graphics = self.attachAsset('snakeBody', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Set as head segment if needed
+ self.setAsHead = function () {
+ self.isHead = true;
+ self.removeChild(self.graphics);
+ self.graphics = self.attachAsset('snakeHead', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ };
+ // Store previous position for smooth movement
+ self.prevX = 0;
+ self.prevY = 0;
+ return self;
+});
+var Wall = Container.expand(function () {
+ var self = Container.call(this);
+ // Create wall graphics
+ self.graphics = self.attachAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x202020
+});
+
+/****
+* Game Code
+****/
+// Game constants
+var GRID_SIZE = 50;
+var GRID_WIDTH = Math.floor(2048 / GRID_SIZE);
+var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE);
+var GAME_SPEED = 200; // ms between moves
+var INITIAL_SNAKE_LENGTH = 3;
+// Game variables
+var snake = [];
+var walls = [];
+var foods = [];
+var portal = null;
+var direction = 'right';
+var nextDirection = 'right';
+var moveTimer = null;
+var level = storage.level || 1;
+var isDragging = false;
+var dragStartX = 0;
+var dragStartY = 0;
+var gameBoard = new Container();
+var gameRunning = false;
+var levelText;
+var scoreText;
+// Add game board to center the maze
+game.addChild(gameBoard);
+// Initialize the game UI
+function initUI() {
+ // Level display
+ levelText = new Text2('Level: ' + level, {
+ size: 70,
+ fill: 0xFFFFFF
+ });
+ levelText.anchor.set(0, 0);
+ LK.gui.topRight.addChild(levelText);
+ // Score display
+ scoreText = new Text2('Score: ' + LK.getScore(), {
+ size: 70,
+ fill: 0xFFFFFF
+ });
+ scoreText.anchor.set(0, 0);
+ LK.gui.top.addChild(scoreText);
+}
+// Reset the game for a new level
+function resetGame() {
+ // Clear existing elements
+ while (gameBoard.children.length > 0) {
+ gameBoard.removeChildAt(0);
+ }
+ // Reset arrays
+ snake = [];
+ walls = [];
+ foods = [];
+ portal = null;
+ // Reset direction
+ direction = 'right';
+ nextDirection = 'right';
+ // Clear timers
+ if (moveTimer) {
+ LK.clearInterval(moveTimer);
+ moveTimer = null;
+ }
+ // Generate level
+ generateLevel(level);
+ // Start the game loop
+ moveTimer = LK.setInterval(moveSnake, GAME_SPEED);
+ gameRunning = true;
+ // Update UI
+ levelText.setText('Level: ' + level);
+ scoreText.setText('Score: ' + LK.getScore());
+ // Play background music
+ LK.playMusic('bgMusic', {
+ fade: {
+ start: 0,
+ end: 0.4,
+ duration: 1000
+ }
+ });
+}
+// Generate a level with walls, food, and a snake
+function generateLevel(levelNum) {
+ var difficulty = Math.min(10, Math.floor(levelNum / 2) + 1);
+ // Calculate board size (smaller than full screen)
+ var boardWidth = Math.min(GRID_WIDTH - 2, 20) * GRID_SIZE;
+ var boardHeight = Math.min(GRID_HEIGHT - 6, 20) * GRID_SIZE;
+ // Center the board
+ gameBoard.x = (2048 - boardWidth) / 2;
+ gameBoard.y = (2732 - boardHeight) / 2;
+ // Generate walls around the perimeter
+ for (var x = 0; x < boardWidth / GRID_SIZE; x++) {
+ addWall(x * GRID_SIZE, 0);
+ addWall(x * GRID_SIZE, boardHeight - GRID_SIZE);
+ }
+ for (var y = 0; y < boardHeight / GRID_SIZE; y++) {
+ addWall(0, y * GRID_SIZE);
+ addWall(boardWidth - GRID_SIZE, y * GRID_SIZE);
+ }
+ // Generate internal walls based on difficulty
+ for (var i = 0; i < difficulty * 5; i++) {
+ var wx = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ var wy = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ // Ensure we're not placing walls too close to starting position
+ if (Math.abs(wx - 4 * GRID_SIZE) > 2 * GRID_SIZE || Math.abs(wy - 4 * GRID_SIZE) > 2 * GRID_SIZE) {
+ addWall(wx, wy);
+ }
+ }
+ // Create snake at starting position
+ createSnake(3 * GRID_SIZE, 4 * GRID_SIZE, INITIAL_SNAKE_LENGTH);
+ // Add food
+ for (var f = 0; f < difficulty + 2; f++) {
+ addRandomFood(boardWidth, boardHeight);
+ }
+ // Add exit portal
+ var px = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ var py = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ // Make sure portal isn't too close to snake start
+ while (Math.abs(px - 4 * GRID_SIZE) < 5 * GRID_SIZE && Math.abs(py - 4 * GRID_SIZE) < 5 * GRID_SIZE) {
+ px = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ py = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 4) + 2) * GRID_SIZE;
+ }
+ addPortal(px, py);
+}
+// Create the initial snake
+function createSnake(x, y, length) {
+ for (var i = 0; i < length; i++) {
+ var segment = new SnakeSegment();
+ // Place segment with head at (x,y) and body extending to the left
+ segment.x = x - i * GRID_SIZE;
+ segment.y = y;
+ segment.prevX = segment.x;
+ segment.prevY = segment.y;
+ // Make the first segment the head
+ if (i === 0) {
+ segment.setAsHead();
+ }
+ snake.push(segment);
+ gameBoard.addChild(segment);
+ }
+}
+// Add a wall at the specified position
+function addWall(x, y) {
+ var wall = new Wall();
+ wall.x = x;
+ wall.y = y;
+ walls.push(wall);
+ gameBoard.addChild(wall);
+}
+// Add food at a random position
+function addRandomFood(boardWidth, boardHeight) {
+ var validPosition = false;
+ var fx, fy;
+ while (!validPosition) {
+ fx = Math.floor(Math.random() * (boardWidth / GRID_SIZE - 2) + 1) * GRID_SIZE;
+ fy = Math.floor(Math.random() * (boardHeight / GRID_SIZE - 2) + 1) * GRID_SIZE;
+ validPosition = true;
+ // Check if position overlaps with walls
+ for (var i = 0; i < walls.length; i++) {
+ if (walls[i].x === fx && walls[i].y === fy) {
+ validPosition = false;
+ break;
+ }
+ }
+ // Check if position overlaps with snake
+ if (validPosition) {
+ for (var j = 0; j < snake.length; j++) {
+ if (Math.abs(snake[j].x - fx) < GRID_SIZE && Math.abs(snake[j].y - fy) < GRID_SIZE) {
+ validPosition = false;
+ break;
+ }
+ }
+ }
+ // Check if position overlaps with portal
+ if (validPosition && portal && Math.abs(portal.x - fx) < GRID_SIZE && Math.abs(portal.y - fy) < GRID_SIZE) {
+ validPosition = false;
+ }
+ }
+ var food = new Food();
+ food.x = fx;
+ food.y = fy;
+ foods.push(food);
+ gameBoard.addChild(food);
+}
+// Add exit portal
+function addPortal(x, y) {
+ portal = new Portal();
+ portal.x = x;
+ portal.y = y;
+ gameBoard.addChild(portal);
+}
+// Move the snake based on current direction
+function moveSnake() {
+ if (!gameRunning) return;
+ // Update direction
+ direction = nextDirection;
+ // Store previous positions for smooth movement
+ for (var i = 0; i < snake.length; i++) {
+ snake[i].prevX = snake[i].x;
+ snake[i].prevY = snake[i].y;
+ }
+ // Calculate new head position
+ var head = snake[0];
+ var newHeadX = head.x;
+ var newHeadY = head.y;
+ switch (direction) {
+ case 'up':
+ newHeadY -= GRID_SIZE;
+ break;
+ case 'down':
+ newHeadY += GRID_SIZE;
+ break;
+ case 'left':
+ newHeadX -= GRID_SIZE;
+ break;
+ case 'right':
+ newHeadX += GRID_SIZE;
+ break;
+ }
+ // Check for collisions
+ if (checkCollision(newHeadX, newHeadY)) {
+ // Game over
+ LK.getSound('hit').play();
+ gameRunning = false;
+ // Flash red and show game over
+ LK.effects.flashScreen(0xFF0000, 500);
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 600);
+ return;
+ }
+ // Move body segments
+ for (var i = snake.length - 1; i > 0; i--) {
+ snake[i].x = snake[i - 1].x;
+ snake[i].y = snake[i - 1].y;
+ }
+ // Move head to new position
+ head.x = newHeadX;
+ head.y = newHeadY;
+ // Check for food collision
+ for (var i = 0; i < foods.length; i++) {
+ if (Math.abs(head.x - foods[i].x) < GRID_SIZE / 2 && Math.abs(head.y - foods[i].y) < GRID_SIZE / 2) {
+ // Remove the food
+ gameBoard.removeChild(foods[i]);
+ foods.splice(i, 1);
+ // Play eat sound
+ LK.getSound('eat').play();
+ // Add score
+ LK.setScore(LK.getScore() + 10);
+ scoreText.setText('Score: ' + LK.getScore());
+ // Add a new segment
+ var tail = snake[snake.length - 1];
+ var newSegment = new SnakeSegment();
+ newSegment.x = tail.x;
+ newSegment.y = tail.y;
+ newSegment.prevX = newSegment.x;
+ newSegment.prevY = newSegment.y;
+ snake.push(newSegment);
+ gameBoard.addChild(newSegment);
+ // Add a new food
+ var boardWidth = Math.min(GRID_WIDTH - 2, 20) * GRID_SIZE;
+ var boardHeight = Math.min(GRID_HEIGHT - 6, 20) * GRID_SIZE;
+ addRandomFood(boardWidth, boardHeight);
+ break;
+ }
+ }
+ // Check for portal collision
+ if (portal && Math.abs(head.x - portal.x) < GRID_SIZE / 2 && Math.abs(head.y - portal.y) < GRID_SIZE / 2) {
+ // Play portal sound
+ LK.getSound('portal').play();
+ // Level completed
+ gameRunning = false;
+ // Flash screen and advance to next level
+ LK.effects.flashScreen(0x9966FF, 500);
+ // Store level progress
+ level++;
+ storage.level = level;
+ LK.setTimeout(function () {
+ resetGame();
+ }, 1000);
+ }
+}
+// Check if the given position collides with walls or snake body
+function checkCollision(x, y) {
+ // Check wall collision
+ for (var i = 0; i < walls.length; i++) {
+ if (Math.abs(x - walls[i].x) < GRID_SIZE / 2 && Math.abs(y - walls[i].y) < GRID_SIZE / 2) {
+ return true;
+ }
+ }
+ // Check self collision (skip head)
+ for (var i = 1; i < snake.length; i++) {
+ if (Math.abs(x - snake[i].x) < GRID_SIZE / 2 && Math.abs(y - snake[i].y) < GRID_SIZE / 2) {
+ return true;
+ }
+ }
+ return false;
+}
+// Handle touch/mouse down on game
+game.down = function (x, y, obj) {
+ if (!gameRunning) return;
+ isDragging = true;
+ dragStartX = x;
+ dragStartY = y;
+};
+// Handle touch/mouse move
+game.move = function (x, y, obj) {
+ if (!isDragging || !gameRunning) return;
+ // Calculate the difference from start position
+ var dx = x - dragStartX;
+ var dy = y - dragStartY;
+ // Only change direction if the drag is significant
+ if (Math.abs(dx) > 20 || Math.abs(dy) > 20) {
+ // Determine direction based on which axis has the larger change
+ if (Math.abs(dx) > Math.abs(dy)) {
+ // Horizontal movement
+ if (dx > 0 && direction !== 'left') {
+ nextDirection = 'right';
+ } else if (dx < 0 && direction !== 'right') {
+ nextDirection = 'left';
+ }
+ } else {
+ // Vertical movement
+ if (dy > 0 && direction !== 'up') {
+ nextDirection = 'down';
+ } else if (dy < 0 && direction !== 'down') {
+ nextDirection = 'up';
+ }
+ }
+ // Reset drag start
+ dragStartX = x;
+ dragStartY = y;
+ }
+};
+// Handle touch/mouse up
+game.up = function (x, y, obj) {
+ isDragging = false;
+};
+// Update game state each tick
+game.update = function () {
+ // Update all elements with update methods
+ for (var i = 0; i < foods.length; i++) {
+ foods[i].update();
+ }
+ if (portal) {
+ portal.update();
+ }
+};
+// Initialize UI and start the game
+initUI();
+resetGame();
\ No newline at end of file