User prompt
Add background music based on level theme: tribal drums for Jungle, icy winds for Arctic, desert winds, and sci-fi synths for Cyber. Add sound effects for eating food, hitting walls, and collecting power-ups.
User prompt
Display two text labels at the top center of the screen. The first label should say “Level: Jungle” and be aligned at the top center, with white text and a large font size. Below it, add a second label that says “Score: 0” also in white and slightly smaller font. Both labels should be placed above the game area, not overlapping with buttons. Use padding or positioning to ensure they are clearly visible and centered horizontally.
User prompt
> Add two labels at the top center of the screen. The first label should display "Level: Jungle" and be positioned at the top center with white text. Below that, add another label displaying "Score: 0" also centered and in white. Both texts should be clearly visible, with "Level: Jungle" slightly above "Score: 0". Make sure they don't overlap with any UI elements like the pause button or home button.
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'y')' in or related to this line: 'scoreTxt.y = homeBtn.y + homeBtn.height + 20; // Position under the home button' Line Number: 399
User prompt
Score text placed under the home button
/**** * 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();
===================================================================
--- original.js
+++ change.js
@@ -73,20 +73,23 @@
// 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();
@@ -397,23 +400,14 @@
levelSelectionScreen.visible = true; // Show level selection screen
gameState = STATE_TITLE; // Set game state to title
};
var levelTxt = new Text2('Level: Jungle', {
- size: 100,
+ size: 70,
fill: 0xFFFFFF
});
-levelTxt.anchor.set(0.5, 0); // Center horizontally
+levelTxt.anchor.set(0, 0);
LK.gui.top.addChild(levelTxt);
-levelTxt.x = 2048 / 2; // Center horizontally
levelTxt.y = 20;
-var scoreTxtCenter = new Text2('Score: 0', {
- size: 80,
- fill: 0xFFFFFF
-});
-scoreTxtCenter.anchor.set(0.5, 0); // Center horizontally
-LK.gui.top.addChild(scoreTxtCenter);
-scoreTxtCenter.x = 2048 / 2; // Center horizontally
-scoreTxtCenter.y = levelTxt.y + levelTxt.height + 10; // Position below levelTxt
var titleTxt = new Text2('SNAKE EVOLUTION\nFOUR REALMS', {
size: 120,
fill: 0xFFFFFF,
align: 'center'
@@ -570,8 +564,9 @@
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
@@ -657,8 +652,9 @@
// 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) {
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