/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 0, highScore: 0 }); /**** * Classes ****/ var Food = Container.expand(function () { var self = Container.call(this); self.foodGraphic = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1; // Default food value // Pulsing animation self.pulseFood = function () { tween(self.foodGraphic.scale, { x: 1.2, y: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.foodGraphic.scale, { x: 1.0, y: 1.0 }, { duration: 500, easing: tween.easeInOut, onFinish: self.pulseFood }); } }); }; self.pulseFood(); return self; }); var GameLevel = Container.expand(function (levelNum) { var self = Container.call(this); self.levelNumber = levelNum || 0; self.walls = []; self.obstacles = []; self.foods = []; self.backgroundColor = 0x88cc66; // Default jungle background self.setupLevel = function () { // Clear any existing level elements self.walls.forEach(function (wall) { wall.destroy(); }); self.obstacles.forEach(function (obstacle) { obstacle.destroy(); }); self.foods.forEach(function (food) { food.destroy(); }); self.walls = []; self.obstacles = []; self.foods = []; // Set up specific level based on level number switch (self.levelNumber) { case 0: // Jungle - Easy self.backgroundColor = 0x88cc66; self.createBorderWalls(); LK.playMusic('jungleMusic'); break; case 1: // Arctic - Medium self.backgroundColor = 0xaaddff; self.createBorderWalls(); self.createCrossObstacles(); LK.playMusic('arcticMusic'); break; case 2: // Desert - Hard self.backgroundColor = 0xddbb77; self.createBorderWalls(); self.createRandomObstacles(10); LK.playMusic('desertMusic'); break; case 3: // Cyber - Expert self.backgroundColor = 0x223355; self.createBorderWalls(); self.createMazeObstacles(); LK.playMusic('cyberMusic'); break; } game.setBackgroundColor(self.backgroundColor); self.spawnFood(); }; self.createBorderWalls = function () { // Create border walls var wallThickness = 30; var wallSpacing = 60; // Space between wall segments // Top and bottom walls for (var x = wallThickness; x < 2048; x += wallSpacing) { // Top wall var topWall = new Wall(); topWall.x = x; topWall.y = wallThickness; self.walls.push(topWall); self.addChild(topWall); // Bottom wall var bottomWall = new Wall(); bottomWall.x = x; bottomWall.y = 2732 - wallThickness; self.walls.push(bottomWall); self.addChild(bottomWall); } // Left and right walls for (var y = wallThickness; y < 2732; y += wallSpacing) { // Left wall var leftWall = new Wall(); leftWall.x = wallThickness; leftWall.y = y; self.walls.push(leftWall); self.addChild(leftWall); // Right wall var rightWall = new Wall(); rightWall.x = 2048 - wallThickness; rightWall.y = y; self.walls.push(rightWall); self.addChild(rightWall); } }; self.createCrossObstacles = function () { // Create cross-shaped obstacles for Arctic level var centerX = 2048 / 2; var centerY = 2732 / 2; var spacing = 120; // Horizontal line for (var x = centerX - 400; x <= centerX + 400; x += spacing) { var hObstacle = new Obstacle(); hObstacle.x = x; hObstacle.y = centerY; self.obstacles.push(hObstacle); self.addChild(hObstacle); } // Vertical line for (var y = centerY - 600; y <= centerY + 600; y += spacing) { if (Math.abs(y - centerY) > spacing / 2) { // Skip center to avoid overlap var vObstacle = new Obstacle(); vObstacle.x = centerX; vObstacle.y = y; self.obstacles.push(vObstacle); self.addChild(vObstacle); } } }; self.createRandomObstacles = function (count) { // Create random obstacles for Desert level var margin = 150; // Keep obstacles away from edges for (var i = 0; i < count; i++) { var obstacle = new Obstacle(); // Keep trying positions until we find one that doesn't overlap var validPosition = false; var maxTries = 20; var tries = 0; while (!validPosition && tries < maxTries) { obstacle.x = margin + Math.random() * (2048 - 2 * margin); obstacle.y = margin + Math.random() * (2732 - 2 * margin); // Check distance from other obstacles validPosition = true; for (var j = 0; j < self.obstacles.length; j++) { var existingObstacle = self.obstacles[j]; var dx = obstacle.x - existingObstacle.x; var dy = obstacle.y - existingObstacle.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { validPosition = false; break; } } tries++; } if (validPosition) { self.obstacles.push(obstacle); self.addChild(obstacle); } } }; self.createMazeObstacles = function () { // Create maze-like obstacles for Cyber level var gridSize = 150; var obstacleChance = 0.35; // Probability of placing an obstacle for (var x = gridSize * 2; x < 2048 - gridSize * 2; x += gridSize) { for (var y = gridSize * 2; y < 2732 - gridSize * 2; y += gridSize) { // Skip center area to ensure there's space to move var distFromCenter = Math.sqrt(Math.pow(x - 2048 / 2, 2) + Math.pow(y - 2732 / 2, 2)); if (distFromCenter < 400) { continue; } if (Math.random() < obstacleChance) { var obstacle = new Obstacle(); obstacle.x = x; obstacle.y = y; self.obstacles.push(obstacle); self.addChild(obstacle); } } } }; self.spawnFood = function () { var food = new Food(); var validPosition = false; var gridSize = 60; var margin = 120; // Keep food away from edges // Keep trying until we find a valid position while (!validPosition) { // Generate random position, aligned to grid var gridX = Math.floor((margin + Math.random() * (2048 - 2 * margin)) / gridSize); var gridY = Math.floor((margin + Math.random() * (2732 - 2 * margin)) / gridSize); food.x = gridX * gridSize; food.y = gridY * gridSize; // Check for collisions with walls and obstacles validPosition = true; // Check walls for (var i = 0; i < self.walls.length; i++) { if (self.isCollision(food, self.walls[i], 80)) { validPosition = false; break; } } // Check obstacles if (validPosition) { for (var j = 0; j < self.obstacles.length; j++) { if (self.isCollision(food, self.obstacles[j], 80)) { validPosition = false; break; } } } } // Set food value based on level if (self.levelNumber > 0) { food.value = self.levelNumber + 1; // Change food color based on value switch (food.value) { case 2: food.foodGraphic.tint = 0x33ccff; // Blue for level 1 break; case 3: food.foodGraphic.tint = 0xffcc33; // Orange for level 2 break; case 4: food.foodGraphic.tint = 0xff33cc; // Pink for level 3 break; } } self.foods.push(food); self.addChild(food); }; self.isCollision = function (obj1, obj2, minDistance) { var dx = obj1.x - obj2.x; var dy = obj1.y - obj2.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < minDistance; }; return self; }); var LevelSelectionScreen = Container.expand(function () { var self = Container.call(this); // Background image for level selection var background = self.attachAsset('background', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; // Level buttons var levels = [{ name: "Jungle", color: 0x88cc66 }, { name: "Arctic", color: 0xaaddff }, { name: "Desert", color: 0xddbb77 }, { name: "Cyber", color: 0x223355 }]; levels.forEach(function (level, index) { var levelBtn = new Text2('Level ' + (index + 1) + ': ' + level.name, { size: 100, fill: index === 1 ? 0xff0000 : level.color, // Bright red for Arctic align: 'center', fontWeight: 'bold' }); levelBtn.anchor.set(0.5, 0.5); levelBtn.x = 2048 / 2; levelBtn.y = 800 + index * 200; self.addChild(levelBtn); levelBtn.down = function () { currentLevel = index; storage.currentLevel = currentLevel; self.visible = false; initGame(); }; }); return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); self.obstacleGraphic = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var SnakeSegment = Container.expand(function (isHead) { var self = Container.call(this); self.assetId = isHead ? 'snakeHead' : 'snakeBody'; self.bodyGraphic = self.attachAsset(self.assetId, { anchorX: 0.5, anchorY: 0.5 }); self.nextPosition = { x: 0, y: 0 }; // Make head slightly larger if (isHead) { self.bodyGraphic.scale.set(1.2, 1.2); } return self; }); var Wall = Container.expand(function () { var self = Container.call(this); self.wallGraphic = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Always start with black background }); /**** * Game Code ****/ var levelSelectionScreen = new LevelSelectionScreen(); game.addChild(levelSelectionScreen); // Full screen mode is not supported by LK engine, removing the call. var STATE_TITLE = 0; var STATE_PLAYING = 1; var STATE_LEVEL_TRANSITION = 2; var gameState = STATE_TITLE; // Game variables var score = 0; var currentLevel = storage.currentLevel || 0; var highScore = storage.highScore || 0; var gridSize = 60; var movementSpeed = 5; // Frames per movement var speedCounter = 0; var gameLevel; // Snake variables var snake = []; var snakeDirection = 'right'; var pendingDirection = 'right'; var snakeSize = 5; // Starting snake size var snakeGrowing = 0; // Touch control variables var touchStartX = 0; var touchStartY = 0; // Create UI elements var scoreTxt = new Text2('Score: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -scoreTxt.width - 20; scoreTxt.y = 20; // Create home button var homeBtn = new Text2('Home', { size: 70, fill: 0xFF4500 // Bright red orange color }); homeBtn.anchor.set(0.5, 0.5); LK.gui.topRight.addChild(homeBtn); homeBtn.x = -homeBtn.width - 20; // Align with score text homeBtn.y = scoreTxt.y + scoreTxt.height + 20; // Position under the score text // Add event listener for home button homeBtn.down = function () { levelSelectionScreen.visible = true; // Show level selection screen gameState = STATE_TITLE; // Set game state to title }; var levelTxt = new Text2('Level: Jungle', { size: 70, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 20; var titleTxt = new Text2('SNAKE EVOLUTION\nFOUR REALMS', { size: 120, fill: 0xFFFFFF, align: 'center' }); titleTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(titleTxt); var instructionTxt = new Text2('Swipe to control the snake\nEat food to grow longer\nAvoid obstacles and yourself\n\nTap to Start', { size: 80, fill: 0xFFFFFF, align: 'center' }); instructionTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(instructionTxt); instructionTxt.y = 300; // Function to get level name from level number function getLevelName(levelNum) { switch (levelNum) { case 0: return "Jungle"; case 1: return "Arctic"; case 2: return "Desert"; case 3: return "Cyber"; default: return "Unknown"; } } // Initialize the game function initGame() { // Reset game variables score = 0; snakeSize = 5; snakeGrowing = 0; speedCounter = 0; // Update UI updateScore(); updateLevelText(); // Hide title screen elements titleTxt.visible = false; instructionTxt.visible = false; scoreTxt.visible = true; levelTxt.visible = true; // Create game level if (gameLevel) { gameLevel.destroy(); } gameLevel = new GameLevel(currentLevel); game.addChild(gameLevel); gameLevel.setupLevel(); // Create initial snake createSnake(); // Set game state to playing gameState = STATE_PLAYING; } // Create the snake with initial segments function createSnake() { // Destroy existing snake segments if any snake.forEach(function (segment) { segment.destroy(); }); snake = []; // Create new snake var centerX, centerY; if (currentLevel === 1) { // Arctic level: Start snake away from cross obstacles centerX = Math.floor(2048 / 4 / gridSize) * gridSize; // Start on the left side centerY = Math.floor(2732 / 4 / gridSize) * gridSize; // Start on the top side } else { centerX = Math.floor(2048 / 2 / gridSize) * gridSize; centerY = Math.floor(2732 / 2 / gridSize) * gridSize; } // Create head var head = new SnakeSegment(true); head.x = centerX; head.y = centerY; game.addChild(head); snake.push(head); // Create body segments for (var i = 1; i < snakeSize; i++) { var segment = new SnakeSegment(false); segment.x = centerX - i * gridSize; segment.y = centerY; game.addChild(segment); snake.push(segment); } // Set initial direction snakeDirection = 'right'; pendingDirection = 'right'; } // Move the snake function moveSnake() { // Calculate new head position var head = snake[0]; var newX = head.x; var newY = head.y; // Update direction based on pending direction snakeDirection = pendingDirection; // Calculate new position based on direction switch (snakeDirection) { case 'up': newY -= gridSize; break; case 'down': newY += gridSize; break; case 'left': newX -= gridSize; break; case 'right': newX += gridSize; break; } // Move the snake by updating the target position for each segment for (var i = snake.length - 1; i >= 0; i--) { if (i === 0) { // Head moves to new position snake[i].nextPosition = { x: newX, y: newY }; } else { // Body follows the segment in front snake[i].nextPosition = { x: snake[i - 1].x, y: snake[i - 1].y }; } } // Apply movement snake.forEach(function (segment) { segment.x = segment.nextPosition.x; segment.y = segment.nextPosition.y; }); // Add new segment if snake is growing if (snakeGrowing > 0) { var lastSegment = snake[snake.length - 1]; var newSegment = new SnakeSegment(false); newSegment.x = lastSegment.x; newSegment.y = lastSegment.y; game.addChild(newSegment); snake.push(newSegment); snakeGrowing--; } // Check for collisions checkCollisions(); } // Check for collisions with food, walls, obstacles, and self function checkCollisions() { var head = snake[0]; // Check collision with food for (var i = 0; i < gameLevel.foods.length; i++) { var food = gameLevel.foods[i]; if (distance(head, food) < gridSize * 0.8) { // Eat food LK.getSound('eat').play(); LK.getSound('powerUp').play(); // Increase score score += food.value; // Increment score by the food's value when eaten updateScore(); // Update the score display scoreTxt.setText('Score: ' + score); // Ensure score text is updated // Grow snake snakeGrowing += food.value; // Remove food food.destroy(); gameLevel.foods.splice(i, 1); // Spawn new food gameLevel.spawnFood(); // Check if we should level up if (score >= (currentLevel + 1) * 100 && currentLevel < 3) { levelUp(); return; } break; } } // Check collision with walls for (var j = 0; j < gameLevel.walls.length; j++) { if (distance(head, gameLevel.walls[j]) < gridSize * 0.8) { gameOver(); return; } } // Check collision with obstacles for (var k = 0; k < gameLevel.obstacles.length; k++) { if (distance(head, gameLevel.obstacles[k]) < gridSize * 0.8) { gameOver(); return; } } // Check collision with self (skip the first few segments) for (var l = 3; l < snake.length; l++) { if (distance(head, snake[l]) < gridSize * 0.5) { gameOver(); return; } } // Check if snake is out of bounds if (head.x < 0 || head.x > 2048 || head.y < 0 || head.y > 2732) { gameOver(); return; } } // Calculate distance between two objects function distance(obj1, obj2) { var dx = obj1.x - obj2.x; var dy = obj1.y - obj2.y; return Math.sqrt(dx * dx + dy * dy); } // Handle level up function levelUp() { // Play level up sound LK.getSound('levelUp').play(); // Save current level currentLevel++; storage.currentLevel = currentLevel; // Show transition gameState = STATE_LEVEL_TRANSITION; // Create level transition text var levelUpTxt = new Text2('LEVEL UP!\n' + getLevelName(currentLevel), { size: 120, fill: 0xFFFFFF, align: 'center' }); levelUpTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(levelUpTxt); // Fade out after 2 seconds LK.setTimeout(function () { tween(levelUpTxt, { alpha: 0 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { levelUpTxt.destroy(); initGame(); } }); }, 2000); } // Handle game over function gameOver() { // Play collision sound LK.getSound('collision').play(); LK.getSound('hitWall').play(); // Flash screen red LK.effects.flashScreen(0xff0000, 500); // Update high score if (score > highScore) { highScore = score; storage.highScore = highScore; } // Show game over LK.showGameOver(); } // Update the score display function updateScore() { scoreTxt.setText('Score: ' + score); } // Update the level text function updateLevelText() { levelTxt.setText('Level: ' + getLevelName(currentLevel)); } // Handle touch events game.down = function (x, y, obj) { if (gameState === STATE_PLAYING) { // Record start of swipe touchStartX = x; touchStartY = y; } }; game.up = function (x, y, obj) { if (gameState === STATE_PLAYING) { // Calculate swipe direction var dx = x - touchStartX; var dy = y - touchStartY; // Only change direction if the swipe is long enough if (Math.abs(dx) > 30 || Math.abs(dy) > 30) { // Determine primary direction of swipe if (Math.abs(dx) > Math.abs(dy)) { // Horizontal swipe pendingDirection = dx > 0 ? 'right' : 'left'; } else { // Vertical swipe pendingDirection = dy > 0 ? 'down' : 'up'; } // Don't allow 180-degree turns if (snakeDirection === 'up' && pendingDirection === 'down' || snakeDirection === 'down' && pendingDirection === 'up' || snakeDirection === 'left' && pendingDirection === 'right' || snakeDirection === 'right' && pendingDirection === 'left') { pendingDirection = snakeDirection; } } } }; // Game update function game.update = function () { if (gameState === STATE_PLAYING) { // Move snake at appropriate speed speedCounter++; var moveInterval = movementSpeed - Math.min(3, Math.floor(currentLevel / 2)); if (speedCounter >= moveInterval) { moveSnake(); speedCounter = 0; } } }; // Start with level selection screen titleTxt.visible = false; instructionTxt.visible = false; scoreTxt.visible = false; levelTxt.visible = false; levelSelectionScreen.visible = true; // Initialize background gameLevel = new GameLevel(currentLevel); game.addChild(gameLevel); gameLevel.setupLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentLevel: 0,
highScore: 0
});
/****
* Classes
****/
var Food = Container.expand(function () {
var self = Container.call(this);
self.foodGraphic = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1; // Default food value
// Pulsing animation
self.pulseFood = function () {
tween(self.foodGraphic.scale, {
x: 1.2,
y: 1.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.foodGraphic.scale, {
x: 1.0,
y: 1.0
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: self.pulseFood
});
}
});
};
self.pulseFood();
return self;
});
var GameLevel = Container.expand(function (levelNum) {
var self = Container.call(this);
self.levelNumber = levelNum || 0;
self.walls = [];
self.obstacles = [];
self.foods = [];
self.backgroundColor = 0x88cc66; // Default jungle background
self.setupLevel = function () {
// Clear any existing level elements
self.walls.forEach(function (wall) {
wall.destroy();
});
self.obstacles.forEach(function (obstacle) {
obstacle.destroy();
});
self.foods.forEach(function (food) {
food.destroy();
});
self.walls = [];
self.obstacles = [];
self.foods = [];
// Set up specific level based on level number
switch (self.levelNumber) {
case 0:
// Jungle - Easy
self.backgroundColor = 0x88cc66;
self.createBorderWalls();
LK.playMusic('jungleMusic');
break;
case 1:
// Arctic - Medium
self.backgroundColor = 0xaaddff;
self.createBorderWalls();
self.createCrossObstacles();
LK.playMusic('arcticMusic');
break;
case 2:
// Desert - Hard
self.backgroundColor = 0xddbb77;
self.createBorderWalls();
self.createRandomObstacles(10);
LK.playMusic('desertMusic');
break;
case 3:
// Cyber - Expert
self.backgroundColor = 0x223355;
self.createBorderWalls();
self.createMazeObstacles();
LK.playMusic('cyberMusic');
break;
}
game.setBackgroundColor(self.backgroundColor);
self.spawnFood();
};
self.createBorderWalls = function () {
// Create border walls
var wallThickness = 30;
var wallSpacing = 60; // Space between wall segments
// Top and bottom walls
for (var x = wallThickness; x < 2048; x += wallSpacing) {
// Top wall
var topWall = new Wall();
topWall.x = x;
topWall.y = wallThickness;
self.walls.push(topWall);
self.addChild(topWall);
// Bottom wall
var bottomWall = new Wall();
bottomWall.x = x;
bottomWall.y = 2732 - wallThickness;
self.walls.push(bottomWall);
self.addChild(bottomWall);
}
// Left and right walls
for (var y = wallThickness; y < 2732; y += wallSpacing) {
// Left wall
var leftWall = new Wall();
leftWall.x = wallThickness;
leftWall.y = y;
self.walls.push(leftWall);
self.addChild(leftWall);
// Right wall
var rightWall = new Wall();
rightWall.x = 2048 - wallThickness;
rightWall.y = y;
self.walls.push(rightWall);
self.addChild(rightWall);
}
};
self.createCrossObstacles = function () {
// Create cross-shaped obstacles for Arctic level
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var spacing = 120;
// Horizontal line
for (var x = centerX - 400; x <= centerX + 400; x += spacing) {
var hObstacle = new Obstacle();
hObstacle.x = x;
hObstacle.y = centerY;
self.obstacles.push(hObstacle);
self.addChild(hObstacle);
}
// Vertical line
for (var y = centerY - 600; y <= centerY + 600; y += spacing) {
if (Math.abs(y - centerY) > spacing / 2) {
// Skip center to avoid overlap
var vObstacle = new Obstacle();
vObstacle.x = centerX;
vObstacle.y = y;
self.obstacles.push(vObstacle);
self.addChild(vObstacle);
}
}
};
self.createRandomObstacles = function (count) {
// Create random obstacles for Desert level
var margin = 150; // Keep obstacles away from edges
for (var i = 0; i < count; i++) {
var obstacle = new Obstacle();
// Keep trying positions until we find one that doesn't overlap
var validPosition = false;
var maxTries = 20;
var tries = 0;
while (!validPosition && tries < maxTries) {
obstacle.x = margin + Math.random() * (2048 - 2 * margin);
obstacle.y = margin + Math.random() * (2732 - 2 * margin);
// Check distance from other obstacles
validPosition = true;
for (var j = 0; j < self.obstacles.length; j++) {
var existingObstacle = self.obstacles[j];
var dx = obstacle.x - existingObstacle.x;
var dy = obstacle.y - existingObstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
validPosition = false;
break;
}
}
tries++;
}
if (validPosition) {
self.obstacles.push(obstacle);
self.addChild(obstacle);
}
}
};
self.createMazeObstacles = function () {
// Create maze-like obstacles for Cyber level
var gridSize = 150;
var obstacleChance = 0.35; // Probability of placing an obstacle
for (var x = gridSize * 2; x < 2048 - gridSize * 2; x += gridSize) {
for (var y = gridSize * 2; y < 2732 - gridSize * 2; y += gridSize) {
// Skip center area to ensure there's space to move
var distFromCenter = Math.sqrt(Math.pow(x - 2048 / 2, 2) + Math.pow(y - 2732 / 2, 2));
if (distFromCenter < 400) {
continue;
}
if (Math.random() < obstacleChance) {
var obstacle = new Obstacle();
obstacle.x = x;
obstacle.y = y;
self.obstacles.push(obstacle);
self.addChild(obstacle);
}
}
}
};
self.spawnFood = function () {
var food = new Food();
var validPosition = false;
var gridSize = 60;
var margin = 120; // Keep food away from edges
// Keep trying until we find a valid position
while (!validPosition) {
// Generate random position, aligned to grid
var gridX = Math.floor((margin + Math.random() * (2048 - 2 * margin)) / gridSize);
var gridY = Math.floor((margin + Math.random() * (2732 - 2 * margin)) / gridSize);
food.x = gridX * gridSize;
food.y = gridY * gridSize;
// Check for collisions with walls and obstacles
validPosition = true;
// Check walls
for (var i = 0; i < self.walls.length; i++) {
if (self.isCollision(food, self.walls[i], 80)) {
validPosition = false;
break;
}
}
// Check obstacles
if (validPosition) {
for (var j = 0; j < self.obstacles.length; j++) {
if (self.isCollision(food, self.obstacles[j], 80)) {
validPosition = false;
break;
}
}
}
}
// Set food value based on level
if (self.levelNumber > 0) {
food.value = self.levelNumber + 1;
// Change food color based on value
switch (food.value) {
case 2:
food.foodGraphic.tint = 0x33ccff; // Blue for level 1
break;
case 3:
food.foodGraphic.tint = 0xffcc33; // Orange for level 2
break;
case 4:
food.foodGraphic.tint = 0xff33cc; // Pink for level 3
break;
}
}
self.foods.push(food);
self.addChild(food);
};
self.isCollision = function (obj1, obj2, minDistance) {
var dx = obj1.x - obj2.x;
var dy = obj1.y - obj2.y;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance < minDistance;
};
return self;
});
var LevelSelectionScreen = Container.expand(function () {
var self = Container.call(this);
// Background image for level selection
var background = self.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
// Level buttons
var levels = [{
name: "Jungle",
color: 0x88cc66
}, {
name: "Arctic",
color: 0xaaddff
}, {
name: "Desert",
color: 0xddbb77
}, {
name: "Cyber",
color: 0x223355
}];
levels.forEach(function (level, index) {
var levelBtn = new Text2('Level ' + (index + 1) + ': ' + level.name, {
size: 100,
fill: index === 1 ? 0xff0000 : level.color,
// Bright red for Arctic
align: 'center',
fontWeight: 'bold'
});
levelBtn.anchor.set(0.5, 0.5);
levelBtn.x = 2048 / 2;
levelBtn.y = 800 + index * 200;
self.addChild(levelBtn);
levelBtn.down = function () {
currentLevel = index;
storage.currentLevel = currentLevel;
self.visible = false;
initGame();
};
});
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
self.obstacleGraphic = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SnakeSegment = Container.expand(function (isHead) {
var self = Container.call(this);
self.assetId = isHead ? 'snakeHead' : 'snakeBody';
self.bodyGraphic = self.attachAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.nextPosition = {
x: 0,
y: 0
};
// Make head slightly larger
if (isHead) {
self.bodyGraphic.scale.set(1.2, 1.2);
}
return self;
});
var Wall = Container.expand(function () {
var self = Container.call(this);
self.wallGraphic = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Always start with black background
});
/****
* Game Code
****/
var levelSelectionScreen = new LevelSelectionScreen();
game.addChild(levelSelectionScreen);
// Full screen mode is not supported by LK engine, removing the call.
var STATE_TITLE = 0;
var STATE_PLAYING = 1;
var STATE_LEVEL_TRANSITION = 2;
var gameState = STATE_TITLE;
// Game variables
var score = 0;
var currentLevel = storage.currentLevel || 0;
var highScore = storage.highScore || 0;
var gridSize = 60;
var movementSpeed = 5; // Frames per movement
var speedCounter = 0;
var gameLevel;
// Snake variables
var snake = [];
var snakeDirection = 'right';
var pendingDirection = 'right';
var snakeSize = 5; // Starting snake size
var snakeGrowing = 0;
// Touch control variables
var touchStartX = 0;
var touchStartY = 0;
// Create UI elements
var scoreTxt = new Text2('Score: 0', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -scoreTxt.width - 20;
scoreTxt.y = 20;
// Create home button
var homeBtn = new Text2('Home', {
size: 70,
fill: 0xFF4500 // Bright red orange color
});
homeBtn.anchor.set(0.5, 0.5);
LK.gui.topRight.addChild(homeBtn);
homeBtn.x = -homeBtn.width - 20; // Align with score text
homeBtn.y = scoreTxt.y + scoreTxt.height + 20; // Position under the score text
// Add event listener for home button
homeBtn.down = function () {
levelSelectionScreen.visible = true; // Show level selection screen
gameState = STATE_TITLE; // Set game state to title
};
var levelTxt = new Text2('Level: Jungle', {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 20;
var titleTxt = new Text2('SNAKE EVOLUTION\nFOUR REALMS', {
size: 120,
fill: 0xFFFFFF,
align: 'center'
});
titleTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(titleTxt);
var instructionTxt = new Text2('Swipe to control the snake\nEat food to grow longer\nAvoid obstacles and yourself\n\nTap to Start', {
size: 80,
fill: 0xFFFFFF,
align: 'center'
});
instructionTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionTxt);
instructionTxt.y = 300;
// Function to get level name from level number
function getLevelName(levelNum) {
switch (levelNum) {
case 0:
return "Jungle";
case 1:
return "Arctic";
case 2:
return "Desert";
case 3:
return "Cyber";
default:
return "Unknown";
}
}
// Initialize the game
function initGame() {
// Reset game variables
score = 0;
snakeSize = 5;
snakeGrowing = 0;
speedCounter = 0;
// Update UI
updateScore();
updateLevelText();
// Hide title screen elements
titleTxt.visible = false;
instructionTxt.visible = false;
scoreTxt.visible = true;
levelTxt.visible = true;
// Create game level
if (gameLevel) {
gameLevel.destroy();
}
gameLevel = new GameLevel(currentLevel);
game.addChild(gameLevel);
gameLevel.setupLevel();
// Create initial snake
createSnake();
// Set game state to playing
gameState = STATE_PLAYING;
}
// Create the snake with initial segments
function createSnake() {
// Destroy existing snake segments if any
snake.forEach(function (segment) {
segment.destroy();
});
snake = [];
// Create new snake
var centerX, centerY;
if (currentLevel === 1) {
// Arctic level: Start snake away from cross obstacles
centerX = Math.floor(2048 / 4 / gridSize) * gridSize; // Start on the left side
centerY = Math.floor(2732 / 4 / gridSize) * gridSize; // Start on the top side
} else {
centerX = Math.floor(2048 / 2 / gridSize) * gridSize;
centerY = Math.floor(2732 / 2 / gridSize) * gridSize;
}
// Create head
var head = new SnakeSegment(true);
head.x = centerX;
head.y = centerY;
game.addChild(head);
snake.push(head);
// Create body segments
for (var i = 1; i < snakeSize; i++) {
var segment = new SnakeSegment(false);
segment.x = centerX - i * gridSize;
segment.y = centerY;
game.addChild(segment);
snake.push(segment);
}
// Set initial direction
snakeDirection = 'right';
pendingDirection = 'right';
}
// Move the snake
function moveSnake() {
// Calculate new head position
var head = snake[0];
var newX = head.x;
var newY = head.y;
// Update direction based on pending direction
snakeDirection = pendingDirection;
// Calculate new position based on direction
switch (snakeDirection) {
case 'up':
newY -= gridSize;
break;
case 'down':
newY += gridSize;
break;
case 'left':
newX -= gridSize;
break;
case 'right':
newX += gridSize;
break;
}
// Move the snake by updating the target position for each segment
for (var i = snake.length - 1; i >= 0; i--) {
if (i === 0) {
// Head moves to new position
snake[i].nextPosition = {
x: newX,
y: newY
};
} else {
// Body follows the segment in front
snake[i].nextPosition = {
x: snake[i - 1].x,
y: snake[i - 1].y
};
}
}
// Apply movement
snake.forEach(function (segment) {
segment.x = segment.nextPosition.x;
segment.y = segment.nextPosition.y;
});
// Add new segment if snake is growing
if (snakeGrowing > 0) {
var lastSegment = snake[snake.length - 1];
var newSegment = new SnakeSegment(false);
newSegment.x = lastSegment.x;
newSegment.y = lastSegment.y;
game.addChild(newSegment);
snake.push(newSegment);
snakeGrowing--;
}
// Check for collisions
checkCollisions();
}
// Check for collisions with food, walls, obstacles, and self
function checkCollisions() {
var head = snake[0];
// Check collision with food
for (var i = 0; i < gameLevel.foods.length; i++) {
var food = gameLevel.foods[i];
if (distance(head, food) < gridSize * 0.8) {
// Eat food
LK.getSound('eat').play();
LK.getSound('powerUp').play();
// Increase score
score += food.value; // Increment score by the food's value when eaten
updateScore(); // Update the score display
scoreTxt.setText('Score: ' + score); // Ensure score text is updated
// Grow snake
snakeGrowing += food.value;
// Remove food
food.destroy();
gameLevel.foods.splice(i, 1);
// Spawn new food
gameLevel.spawnFood();
// Check if we should level up
if (score >= (currentLevel + 1) * 100 && currentLevel < 3) {
levelUp();
return;
}
break;
}
}
// Check collision with walls
for (var j = 0; j < gameLevel.walls.length; j++) {
if (distance(head, gameLevel.walls[j]) < gridSize * 0.8) {
gameOver();
return;
}
}
// Check collision with obstacles
for (var k = 0; k < gameLevel.obstacles.length; k++) {
if (distance(head, gameLevel.obstacles[k]) < gridSize * 0.8) {
gameOver();
return;
}
}
// Check collision with self (skip the first few segments)
for (var l = 3; l < snake.length; l++) {
if (distance(head, snake[l]) < gridSize * 0.5) {
gameOver();
return;
}
}
// Check if snake is out of bounds
if (head.x < 0 || head.x > 2048 || head.y < 0 || head.y > 2732) {
gameOver();
return;
}
}
// Calculate distance between two objects
function distance(obj1, obj2) {
var dx = obj1.x - obj2.x;
var dy = obj1.y - obj2.y;
return Math.sqrt(dx * dx + dy * dy);
}
// Handle level up
function levelUp() {
// Play level up sound
LK.getSound('levelUp').play();
// Save current level
currentLevel++;
storage.currentLevel = currentLevel;
// Show transition
gameState = STATE_LEVEL_TRANSITION;
// Create level transition text
var levelUpTxt = new Text2('LEVEL UP!\n' + getLevelName(currentLevel), {
size: 120,
fill: 0xFFFFFF,
align: 'center'
});
levelUpTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelUpTxt);
// Fade out after 2 seconds
LK.setTimeout(function () {
tween(levelUpTxt, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
levelUpTxt.destroy();
initGame();
}
});
}, 2000);
}
// Handle game over
function gameOver() {
// Play collision sound
LK.getSound('collision').play();
LK.getSound('hitWall').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 500);
// Update high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
}
// Show game over
LK.showGameOver();
}
// Update the score display
function updateScore() {
scoreTxt.setText('Score: ' + score);
}
// Update the level text
function updateLevelText() {
levelTxt.setText('Level: ' + getLevelName(currentLevel));
}
// Handle touch events
game.down = function (x, y, obj) {
if (gameState === STATE_PLAYING) {
// Record start of swipe
touchStartX = x;
touchStartY = y;
}
};
game.up = function (x, y, obj) {
if (gameState === STATE_PLAYING) {
// Calculate swipe direction
var dx = x - touchStartX;
var dy = y - touchStartY;
// Only change direction if the swipe is long enough
if (Math.abs(dx) > 30 || Math.abs(dy) > 30) {
// Determine primary direction of swipe
if (Math.abs(dx) > Math.abs(dy)) {
// Horizontal swipe
pendingDirection = dx > 0 ? 'right' : 'left';
} else {
// Vertical swipe
pendingDirection = dy > 0 ? 'down' : 'up';
}
// Don't allow 180-degree turns
if (snakeDirection === 'up' && pendingDirection === 'down' || snakeDirection === 'down' && pendingDirection === 'up' || snakeDirection === 'left' && pendingDirection === 'right' || snakeDirection === 'right' && pendingDirection === 'left') {
pendingDirection = snakeDirection;
}
}
}
};
// Game update function
game.update = function () {
if (gameState === STATE_PLAYING) {
// Move snake at appropriate speed
speedCounter++;
var moveInterval = movementSpeed - Math.min(3, Math.floor(currentLevel / 2));
if (speedCounter >= moveInterval) {
moveSnake();
speedCounter = 0;
}
}
};
// Start with level selection screen
titleTxt.visible = false;
instructionTxt.visible = false;
scoreTxt.visible = false;
levelTxt.visible = false;
levelSelectionScreen.visible = true;
// Initialize background
gameLevel = new GameLevel(currentLevel);
game.addChild(gameLevel);
gameLevel.setupLevel();
Juicy or glossy ball, like a glowing apple or bouncing berry.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Two big eyes with tounge outside that is snake head with yellow and redcolors . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows