User prompt
The two fruits are spawning in the same place.
User prompt
If we click behind while the snake is looking forward, it will go back.
User prompt
Let it go where I stepped, but don't go diagonally.
User prompt
make the game's map grid-like
User prompt
Make a separate accessory for the snake's head and prepare 5 different foods. Each one should give a different score and display the score they gave on the screen.
Code edit (1 edits merged)
Please save this source code
User prompt
Snake Classic
Initial prompt
make a snake game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Food Class var Food = Container.expand(function () { var self = Container.call(this); // Food is a red ellipse var foodAsset = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Snake Segment Class var SnakeSegment = Container.expand(function () { var self = Container.call(this); // Each segment is a green box var segmentAsset = self.attachAsset('snakeSegment', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // --- Game Constants --- // --- Asset Initialization --- var GRID_SIZE = 80; // Each cell is 80x80 px var GRID_WIDTH = Math.floor(2048 / GRID_SIZE); var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE); var MOVE_INTERVAL = 120; // ms between snake moves // --- Game State --- var snake = []; // Array of SnakeSegment var snakeDir = { x: 1, y: 0 }; // Initial direction: right var nextDir = { x: 1, y: 0 }; // Next direction to turn to var food = null; var foodPos = { x: 0, y: 0 }; var moveTimer = null; var isAlive = true; var pendingGrowth = 0; // --- Score UI --- var score = 0; var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Helper Functions --- function gridToPos(gx, gy) { // Center the grid in the game area var offsetX = Math.floor((2048 - GRID_WIDTH * GRID_SIZE) / 2); var offsetY = Math.floor((2732 - GRID_HEIGHT * GRID_SIZE) / 2); return { x: offsetX + gx * GRID_SIZE + GRID_SIZE / 2, y: offsetY + gy * GRID_SIZE + GRID_SIZE / 2 }; } function posToGrid(x, y) { var offsetX = Math.floor((2048 - GRID_WIDTH * GRID_SIZE) / 2); var offsetY = Math.floor((2732 - GRID_HEIGHT * GRID_SIZE) / 2); return { x: Math.floor((x - offsetX) / GRID_SIZE), y: Math.floor((y - offsetY) / GRID_SIZE) }; } function spawnFood() { // Remove old food if exists if (food) { food.destroy(); food = null; } // Find empty cell var emptyCells = []; for (var gx = 0; gx < GRID_WIDTH; gx++) { for (var gy = 0; gy < GRID_HEIGHT; gy++) { var occupied = false; for (var i = 0; i < snake.length; i++) { if (snake[i].gx === gx && snake[i].gy === gy) { occupied = true; break; } } if (!occupied) { emptyCells.push({ x: gx, y: gy }); } } } if (emptyCells.length === 0) { // No space left, player wins! LK.showYouWin(); return; } var idx = Math.floor(Math.random() * emptyCells.length); foodPos = emptyCells[idx]; food = new Food(); var pos = gridToPos(foodPos.x, foodPos.y); food.x = pos.x; food.y = pos.y; food.gx = foodPos.x; food.gy = foodPos.y; game.addChild(food); } // --- Snake Initialization --- function resetGame() { // Remove old snake for (var i = 0; i < snake.length; i++) { snake[i].destroy(); } snake = []; // Remove food if (food) { food.destroy(); food = null; } // Reset state isAlive = true; score = 0; scoreTxt.setText(score); snakeDir = { x: 1, y: 0 }; nextDir = { x: 1, y: 0 }; pendingGrowth = 2; // Start with 3 segments // Place snake in center var startX = Math.floor(GRID_WIDTH / 2); var startY = Math.floor(GRID_HEIGHT / 2); for (var i = 0; i < 3; i++) { var seg = new SnakeSegment(); seg.gx = startX - i; seg.gy = startY; var pos = gridToPos(seg.gx, seg.gy); seg.x = pos.x; seg.y = pos.y; game.addChild(seg); snake.push(seg); } spawnFood(); // Start move timer if (moveTimer) LK.clearInterval(moveTimer); moveTimer = LK.setInterval(moveSnake, MOVE_INTERVAL); } // --- Snake Movement --- function moveSnake() { if (!isAlive) return; // Update direction if ((nextDir.x !== -snakeDir.x || nextDir.y !== -snakeDir.y // Prevent 180 turns ) && (nextDir.x !== snakeDir.x || nextDir.y !== snakeDir.y)) { snakeDir.x = nextDir.x; snakeDir.y = nextDir.y; } // Calculate new head position var head = snake[0]; var newGX = head.gx + snakeDir.x; var newGY = head.gy + snakeDir.y; // Check wall collision if (newGX < 0 || newGX >= GRID_WIDTH || newGY < 0 || newGY >= GRID_HEIGHT) { gameOver(); return; } // Check self collision for (var i = 0; i < snake.length; i++) { if (snake[i].gx === newGX && snake[i].gy === newGY) { gameOver(); return; } } // Move segments var prevGX = head.gx; var prevGY = head.gy; var prevPos = gridToPos(prevGX, prevGY); // Move head head.gx = newGX; head.gy = newGY; var newPos = gridToPos(newGX, newGY); tween(head, { x: newPos.x, y: newPos.y }, { duration: MOVE_INTERVAL - 10, easing: tween.linear }); // Move body for (var i = 1; i < snake.length; i++) { var seg = snake[i]; var tmpGX = seg.gx; var tmpGY = seg.gy; var tmpPos = gridToPos(tmpGX, tmpGY); seg.gx = prevGX; seg.gy = prevGY; tween(seg, { x: prevPos.x, y: prevPos.y }, { duration: MOVE_INTERVAL - 10, easing: tween.linear }); prevGX = tmpGX; prevGY = tmpGY; prevPos = tmpPos; } // Growth if (pendingGrowth > 0) { var tail = snake[snake.length - 1]; var newSeg = new SnakeSegment(); newSeg.gx = prevGX; newSeg.gy = prevGY; var tailPos = gridToPos(prevGX, prevGY); newSeg.x = tailPos.x; newSeg.y = tailPos.y; game.addChild(newSeg); snake.push(newSeg); pendingGrowth--; } // Check food collision if (head.gx === food.gx && head.gy === food.gy) { score++; scoreTxt.setText(score); pendingGrowth++; spawnFood(); } } // --- Game Over --- function gameOver() { isAlive = false; LK.effects.flashScreen(0xff0000, 800); if (moveTimer) LK.clearInterval(moveTimer); LK.setTimeout(function () { LK.showGameOver(); }, 800); } // --- Input Handling --- // Touch/drag/swipe: change direction var dragStart = null; var dragLast = null; var dragThreshold = 40; // px function handleDirectionInput(x, y) { // Convert to grid var head = snake[0]; var pos = gridToPos(head.gx, head.gy); var dx = x - pos.x; var dy = y - pos.y; if (Math.abs(dx) > Math.abs(dy)) { // Horizontal if (dx > dragThreshold && snakeDir.x !== -1) { nextDir = { x: 1, y: 0 }; } else if (dx < -dragThreshold && snakeDir.x !== 1) { nextDir = { x: -1, y: 0 }; } } else { // Vertical if (dy > dragThreshold && snakeDir.y !== -1) { nextDir = { x: 0, y: 1 }; } else if (dy < -dragThreshold && snakeDir.y !== 1) { nextDir = { x: 0, y: -1 }; } } } // Touch down: start drag game.down = function (x, y, obj) { dragStart = { x: x, y: y }; dragLast = { x: x, y: y }; }; // Touch move: detect swipe game.move = function (x, y, obj) { if (!dragStart) return; var dx = x - dragStart.x; var dy = y - dragStart.y; if (Math.abs(dx) > dragThreshold || Math.abs(dy) > dragThreshold) { handleDirectionInput(x, y); dragStart = { x: x, y: y }; // Reset for next swipe } dragLast = { x: x, y: y }; }; // Touch up: tap to turn (if no swipe) game.up = function (x, y, obj) { if (!dragStart) return; var dx = x - dragStart.x; var dy = y - dragStart.y; if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) { // Tap: turn clockwise if (snakeDir.x === 1 && snakeDir.y === 0) nextDir = { x: 0, y: 1 };else if (snakeDir.x === 0 && snakeDir.y === 1) nextDir = { x: -1, y: 0 };else if (snakeDir.x === -1 && snakeDir.y === 0) nextDir = { x: 0, y: -1 };else if (snakeDir.x === 0 && snakeDir.y === -1) nextDir = { x: 1, y: 0 }; } dragStart = null; dragLast = null; }; // --- Game Update (not used for movement, but could be used for future features) --- game.update = function () { // No per-frame logic needed for MVP }; // --- Start Game --- resetGame();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,358 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Food Class
+var Food = Container.expand(function () {
+ var self = Container.call(this);
+ // Food is a red ellipse
+ var foodAsset = self.attachAsset('food', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+// Snake Segment Class
+var SnakeSegment = Container.expand(function () {
+ var self = Container.call(this);
+ // Each segment is a green box
+ var segmentAsset = self.attachAsset('snakeSegment', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x222222
+});
+
+/****
+* Game Code
+****/
+// --- Game Constants ---
+// --- Asset Initialization ---
+var GRID_SIZE = 80; // Each cell is 80x80 px
+var GRID_WIDTH = Math.floor(2048 / GRID_SIZE);
+var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE);
+var MOVE_INTERVAL = 120; // ms between snake moves
+// --- Game State ---
+var snake = []; // Array of SnakeSegment
+var snakeDir = {
+ x: 1,
+ y: 0
+}; // Initial direction: right
+var nextDir = {
+ x: 1,
+ y: 0
+}; // Next direction to turn to
+var food = null;
+var foodPos = {
+ x: 0,
+ y: 0
+};
+var moveTimer = null;
+var isAlive = true;
+var pendingGrowth = 0;
+// --- Score UI ---
+var score = 0;
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+// --- Helper Functions ---
+function gridToPos(gx, gy) {
+ // Center the grid in the game area
+ var offsetX = Math.floor((2048 - GRID_WIDTH * GRID_SIZE) / 2);
+ var offsetY = Math.floor((2732 - GRID_HEIGHT * GRID_SIZE) / 2);
+ return {
+ x: offsetX + gx * GRID_SIZE + GRID_SIZE / 2,
+ y: offsetY + gy * GRID_SIZE + GRID_SIZE / 2
+ };
+}
+function posToGrid(x, y) {
+ var offsetX = Math.floor((2048 - GRID_WIDTH * GRID_SIZE) / 2);
+ var offsetY = Math.floor((2732 - GRID_HEIGHT * GRID_SIZE) / 2);
+ return {
+ x: Math.floor((x - offsetX) / GRID_SIZE),
+ y: Math.floor((y - offsetY) / GRID_SIZE)
+ };
+}
+function spawnFood() {
+ // Remove old food if exists
+ if (food) {
+ food.destroy();
+ food = null;
+ }
+ // Find empty cell
+ var emptyCells = [];
+ for (var gx = 0; gx < GRID_WIDTH; gx++) {
+ for (var gy = 0; gy < GRID_HEIGHT; gy++) {
+ var occupied = false;
+ for (var i = 0; i < snake.length; i++) {
+ if (snake[i].gx === gx && snake[i].gy === gy) {
+ occupied = true;
+ break;
+ }
+ }
+ if (!occupied) {
+ emptyCells.push({
+ x: gx,
+ y: gy
+ });
+ }
+ }
+ }
+ if (emptyCells.length === 0) {
+ // No space left, player wins!
+ LK.showYouWin();
+ return;
+ }
+ var idx = Math.floor(Math.random() * emptyCells.length);
+ foodPos = emptyCells[idx];
+ food = new Food();
+ var pos = gridToPos(foodPos.x, foodPos.y);
+ food.x = pos.x;
+ food.y = pos.y;
+ food.gx = foodPos.x;
+ food.gy = foodPos.y;
+ game.addChild(food);
+}
+// --- Snake Initialization ---
+function resetGame() {
+ // Remove old snake
+ for (var i = 0; i < snake.length; i++) {
+ snake[i].destroy();
+ }
+ snake = [];
+ // Remove food
+ if (food) {
+ food.destroy();
+ food = null;
+ }
+ // Reset state
+ isAlive = true;
+ score = 0;
+ scoreTxt.setText(score);
+ snakeDir = {
+ x: 1,
+ y: 0
+ };
+ nextDir = {
+ x: 1,
+ y: 0
+ };
+ pendingGrowth = 2; // Start with 3 segments
+ // Place snake in center
+ var startX = Math.floor(GRID_WIDTH / 2);
+ var startY = Math.floor(GRID_HEIGHT / 2);
+ for (var i = 0; i < 3; i++) {
+ var seg = new SnakeSegment();
+ seg.gx = startX - i;
+ seg.gy = startY;
+ var pos = gridToPos(seg.gx, seg.gy);
+ seg.x = pos.x;
+ seg.y = pos.y;
+ game.addChild(seg);
+ snake.push(seg);
+ }
+ spawnFood();
+ // Start move timer
+ if (moveTimer) LK.clearInterval(moveTimer);
+ moveTimer = LK.setInterval(moveSnake, MOVE_INTERVAL);
+}
+// --- Snake Movement ---
+function moveSnake() {
+ if (!isAlive) return;
+ // Update direction
+ if ((nextDir.x !== -snakeDir.x || nextDir.y !== -snakeDir.y // Prevent 180 turns
+ ) && (nextDir.x !== snakeDir.x || nextDir.y !== snakeDir.y)) {
+ snakeDir.x = nextDir.x;
+ snakeDir.y = nextDir.y;
+ }
+ // Calculate new head position
+ var head = snake[0];
+ var newGX = head.gx + snakeDir.x;
+ var newGY = head.gy + snakeDir.y;
+ // Check wall collision
+ if (newGX < 0 || newGX >= GRID_WIDTH || newGY < 0 || newGY >= GRID_HEIGHT) {
+ gameOver();
+ return;
+ }
+ // Check self collision
+ for (var i = 0; i < snake.length; i++) {
+ if (snake[i].gx === newGX && snake[i].gy === newGY) {
+ gameOver();
+ return;
+ }
+ }
+ // Move segments
+ var prevGX = head.gx;
+ var prevGY = head.gy;
+ var prevPos = gridToPos(prevGX, prevGY);
+ // Move head
+ head.gx = newGX;
+ head.gy = newGY;
+ var newPos = gridToPos(newGX, newGY);
+ tween(head, {
+ x: newPos.x,
+ y: newPos.y
+ }, {
+ duration: MOVE_INTERVAL - 10,
+ easing: tween.linear
+ });
+ // Move body
+ for (var i = 1; i < snake.length; i++) {
+ var seg = snake[i];
+ var tmpGX = seg.gx;
+ var tmpGY = seg.gy;
+ var tmpPos = gridToPos(tmpGX, tmpGY);
+ seg.gx = prevGX;
+ seg.gy = prevGY;
+ tween(seg, {
+ x: prevPos.x,
+ y: prevPos.y
+ }, {
+ duration: MOVE_INTERVAL - 10,
+ easing: tween.linear
+ });
+ prevGX = tmpGX;
+ prevGY = tmpGY;
+ prevPos = tmpPos;
+ }
+ // Growth
+ if (pendingGrowth > 0) {
+ var tail = snake[snake.length - 1];
+ var newSeg = new SnakeSegment();
+ newSeg.gx = prevGX;
+ newSeg.gy = prevGY;
+ var tailPos = gridToPos(prevGX, prevGY);
+ newSeg.x = tailPos.x;
+ newSeg.y = tailPos.y;
+ game.addChild(newSeg);
+ snake.push(newSeg);
+ pendingGrowth--;
+ }
+ // Check food collision
+ if (head.gx === food.gx && head.gy === food.gy) {
+ score++;
+ scoreTxt.setText(score);
+ pendingGrowth++;
+ spawnFood();
+ }
+}
+// --- Game Over ---
+function gameOver() {
+ isAlive = false;
+ LK.effects.flashScreen(0xff0000, 800);
+ if (moveTimer) LK.clearInterval(moveTimer);
+ LK.setTimeout(function () {
+ LK.showGameOver();
+ }, 800);
+}
+// --- Input Handling ---
+// Touch/drag/swipe: change direction
+var dragStart = null;
+var dragLast = null;
+var dragThreshold = 40; // px
+function handleDirectionInput(x, y) {
+ // Convert to grid
+ var head = snake[0];
+ var pos = gridToPos(head.gx, head.gy);
+ var dx = x - pos.x;
+ var dy = y - pos.y;
+ if (Math.abs(dx) > Math.abs(dy)) {
+ // Horizontal
+ if (dx > dragThreshold && snakeDir.x !== -1) {
+ nextDir = {
+ x: 1,
+ y: 0
+ };
+ } else if (dx < -dragThreshold && snakeDir.x !== 1) {
+ nextDir = {
+ x: -1,
+ y: 0
+ };
+ }
+ } else {
+ // Vertical
+ if (dy > dragThreshold && snakeDir.y !== -1) {
+ nextDir = {
+ x: 0,
+ y: 1
+ };
+ } else if (dy < -dragThreshold && snakeDir.y !== 1) {
+ nextDir = {
+ x: 0,
+ y: -1
+ };
+ }
+ }
+}
+// Touch down: start drag
+game.down = function (x, y, obj) {
+ dragStart = {
+ x: x,
+ y: y
+ };
+ dragLast = {
+ x: x,
+ y: y
+ };
+};
+// Touch move: detect swipe
+game.move = function (x, y, obj) {
+ if (!dragStart) return;
+ var dx = x - dragStart.x;
+ var dy = y - dragStart.y;
+ if (Math.abs(dx) > dragThreshold || Math.abs(dy) > dragThreshold) {
+ handleDirectionInput(x, y);
+ dragStart = {
+ x: x,
+ y: y
+ }; // Reset for next swipe
+ }
+ dragLast = {
+ x: x,
+ y: y
+ };
+};
+// Touch up: tap to turn (if no swipe)
+game.up = function (x, y, obj) {
+ if (!dragStart) return;
+ var dx = x - dragStart.x;
+ var dy = y - dragStart.y;
+ if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) {
+ // Tap: turn clockwise
+ if (snakeDir.x === 1 && snakeDir.y === 0) nextDir = {
+ x: 0,
+ y: 1
+ };else if (snakeDir.x === 0 && snakeDir.y === 1) nextDir = {
+ x: -1,
+ y: 0
+ };else if (snakeDir.x === -1 && snakeDir.y === 0) nextDir = {
+ x: 0,
+ y: -1
+ };else if (snakeDir.x === 0 && snakeDir.y === -1) nextDir = {
+ x: 1,
+ y: 0
+ };
+ }
+ dragStart = null;
+ dragLast = null;
+};
+// --- Game Update (not used for movement, but could be used for future features) ---
+game.update = function () {
+ // No per-frame logic needed for MVP
+};
+// --- Start Game ---
+resetGame();
\ No newline at end of file
ultra realistic apple. In-Game asset. 2d. High contrast. No shadows
create ultra realistic pear. In-Game asset. 2d. High contrast. No shadows
ultra realistic strawberry. In-Game asset. 2d. High contrast. No shadows
ultra realistic orange fruit. In-Game asset. 2d. High contrast. No shadows
snake head 16x16. In-Game asset. 2d. High contrast. No shadows