User prompt
Increase the size of all key game objects for better visibility and interaction on mobile devices. Scale up the snakehead, snakebody segments, and food items by 50%. Also increase the size of walls, background grid, and any effects to match the new scale. Ensure movement, spacing, and collision detection still function correctly after resizing. Adjust the camera or game area to fit the larger assets appropriately.
User prompt
Rotate only the snakebody segments to match the current movement direction. Keep the snakehead rotation as it is. By default, snakebody assets are horizontal. When the snake moves up or down, rotate each snakebody segment by 90 degrees accordingly. Ensure that segment spacing and alignment remain smooth. Do not affect the snakehead. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When the snake changes direction, rotate each body segment to match the movement: • Left → rotate to face left • Right → rotate to face right • Up → rotate body segments 90 degrees upward • Down → rotate body segments 90 degrees downward The snakebody assets are horizontal by default, so rotation is required to preserve proper orientation. Ensure that spacing and alignment remain smooth during movement. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'currentPos.gridX')' in or related to this line: 'var deltaX = targetPos.gridX - currentPos.gridX;' Line Number: 524
User prompt
Make each snake body segment rotate to follow the direction of movement. When the snake turns, the body segments should adjust their orientation to create a flowing, natural motion behind the head. Ensure that rotation is smooth and visually aligned with the snakehead. Keep segment spacing consistent during movement and turns. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the snake move with smooth transitions instead of grid-based step-by-step movement. The head and body segments should glide smoothly in the movement direction. Keep the classic feel, but use interpolation to animate the snake’s position. Ensure that turning and eating mechanics still work correctly. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Increase the size of the snake body segments and the snake head by 50% to improve visibility on mobile screens. Also increase the size of food items by 40%. Ensure that spacing, collisions, and movement still work correctly with the new sizes. Avoid overlapping elements or clipping.
User prompt
Make the snake head rotate to match its current movement direction. When moving: • Up → head faces upward • Down → head faces downward • Left → head faces left • Right → head faces right Ensure the head image rotates smoothly or snaps instantly to the correct direction. The snake body should follow normally. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Set the lifetime of each food item to 12 seconds before it disappears. This gives the player enough time to reach the food even if it spawns far away. If the food is eaten, it still disappears immediately as normal. Only one food should exist on the screen at a time.
User prompt
Increase the lifetime of each food item before it disappears. Set the despawn timer to 7 seconds instead of the default value. Ensure the timer resets when new food spawns. If the food is eaten before that, it should disappear immediately as usual.
User prompt
Adjust the food spawn logic to keep food items within a safe central zone. Avoid placing food too close to the screen edges or corners. Ensure all food appears within 80% of the screen’s width and height, centered. This makes food easier to reach, especially on large mobile screens.
User prompt
Add 3 types of food to the Snake game: 1. 🍏 Apple: common, gives +1 point 2. 🍇 Grape: uncommon, gives +2 points 3. 🍓 Strawberry: rare, gives +3 points Each food should: • Appear randomly and independently • Have a unique color or icon • Disappear after a few seconds if not eaten • Only one food appears on the screen at a time Make sure the score updates correctly depending on which food is eaten. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
After the player selects a game mode (Classic or Wrap), start the game immediately. Remove any overlays or menu screens, and begin snake movement and food spawning as usual. Make sure the selected mode applies correctly and that the game starts without needing any additional input.
User prompt
Add two wall modes for the Snake game: • “Classic”: If the snake hits any wall, the game ends. • “Wrap”: If the snake hits a wall, it reappears on the opposite side of the screen. Let the player choose between these two modes before starting the game. Display the selected mode during gameplay (e.g., top-left corner).
User prompt
Make the snake move faster each time it eats food. Start with a moderate speed. After every food item, increase the snake’s speed slightly (e.g., 5% faster per food). Make sure it doesn’t become unplayably fast too quickly. Cap the max speed to keep gameplay fair. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Snake Classic
Initial prompt
Create a 2D classic Snake game optimized for mobile devices. The game should include: • A snake that moves in one direction and turns when the player swipes (up, down, left, right) • A food item (dot or fruit) that appears randomly on the grid • When the snake eats the food, it grows longer and the score increases • If the snake touches itself or the screen borders, the game ends • Display the current score at the top • Use a grid-based system with smooth movement • Touchscreen swipe controls should be responsive and natural • Restart button after game over Optional: Add light sound effects for eating and game over
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Food = Container.expand(function (foodType) {
var self = Container.call(this);
self.foodType = foodType || 'apple';
var assetName = self.foodType;
var foodGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.timeLeft = 0;
self.maxTime = 0;
self.originalScale = 1.0;
self.update = function () {
if (self.timeLeft > 0) {
self.timeLeft--;
// Pulse effect when time is running low
if (self.timeLeft < 120) {
// Last 2 seconds at 60fps
var pulseScale = 0.8 + 0.4 * Math.sin(self.timeLeft * 0.3);
foodGraphics.scaleX = self.originalScale * pulseScale;
foodGraphics.scaleY = self.originalScale * pulseScale;
}
if (self.timeLeft <= 0) {
// Food expired, spawn new one
if (food === self) {
spawnFood();
}
}
}
};
return self;
});
var SnakeSegment = Container.expand(function (isHead) {
var self = Container.call(this);
var segmentGraphics = self.attachAsset(isHead ? 'snakeHead' : 'snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.isHead = isHead;
self.segmentGraphics = segmentGraphics;
self.setDirection = function (direction) {
if (self.isHead && self.segmentGraphics) {
switch (direction) {
case 'up':
self.segmentGraphics.rotation = -Math.PI / 2;
break;
case 'down':
self.segmentGraphics.rotation = Math.PI / 2;
break;
case 'left':
self.segmentGraphics.rotation = Math.PI;
break;
case 'right':
self.segmentGraphics.rotation = 0;
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2E7D32
});
/****
* Game Code
****/
// Import tween plugin for smooth speed transitions
// Game constants
var GRID_SIZE = 90;
var GRID_WIDTH = Math.floor(2048 / GRID_SIZE);
var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE);
var GAME_AREA_WIDTH = GRID_WIDTH * GRID_SIZE;
var GAME_AREA_HEIGHT = GRID_HEIGHT * GRID_SIZE;
var OFFSET_X = (2048 - GAME_AREA_WIDTH) / 2;
var OFFSET_Y = (2732 - GAME_AREA_HEIGHT) / 2 + 100;
// Speed constants
var INITIAL_MOVE_INTERVAL = 12; // Start slower for better control
var MIN_MOVE_INTERVAL = 4; // Maximum speed cap (fastest the snake can go)
var SPEED_INCREASE_FACTOR = 0.95; // Each food makes snake 5% faster (multiply interval by 0.95)
// Game variables
var snake = [];
var currentDirection = 'right';
var nextDirection = 'right';
var food = null;
var gameRunning = true;
var moveTimer = 0;
var MOVE_INTERVAL = INITIAL_MOVE_INTERVAL; // Current move interval (starts at initial speed)
var currentMoveInterval = {
value: INITIAL_MOVE_INTERVAL
}; // Object for tweening
var gameMode = 'classic'; // 'classic' or 'wrap'
var modeSelected = false;
// Food type definitions
var FOOD_TYPES = {
apple: {
points: 1,
probability: 0.7,
duration: 720
},
// 12 seconds at 60fps
grape: {
points: 2,
probability: 0.25,
duration: 720
},
// 12 seconds at 60fps
strawberry: {
points: 3,
probability: 0.05,
duration: 720
} // 12 seconds at 60fps
};
// Touch control variables
var touchStartX = 0;
var touchStartY = 0;
var MIN_SWIPE_DISTANCE = 50;
// Initialize score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize mode display
var modeTxt = new Text2('Mode: Classic', {
size: 50,
fill: 0xFFFFFF
});
modeTxt.anchor.set(1, 0);
modeTxt.x = -20; // Offset from right edge
modeTxt.y = 20; // Small offset from top
LK.gui.topRight.addChild(modeTxt);
// Convert grid coordinates to screen coordinates
function gridToScreen(gridX, gridY) {
return {
x: OFFSET_X + gridX * GRID_SIZE + GRID_SIZE / 2,
y: OFFSET_Y + gridY * GRID_SIZE + GRID_SIZE / 2
};
}
// Create mode selection UI
function createModeSelection() {
// Classic mode button
var classicButton = LK.getAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 200,
y: 2732 / 2 - 100,
scaleX: 3,
scaleY: 2
});
game.addChild(classicButton);
var classicText = new Text2('CLASSIC', {
size: 60,
fill: 0xFFFFFF
});
classicText.anchor.set(0.5, 0.5);
classicText.x = 2048 / 2 - 200;
classicText.y = 2732 / 2 - 100;
game.addChild(classicText);
// Wrap mode button
var wrapButton = LK.getAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 200,
y: 2732 / 2 - 100,
scaleX: 3,
scaleY: 2
});
game.addChild(wrapButton);
var wrapText = new Text2('WRAP', {
size: 60,
fill: 0xFFFFFF
});
wrapText.anchor.set(0.5, 0.5);
wrapText.x = 2048 / 2 + 200;
wrapText.y = 2732 / 2 - 100;
game.addChild(wrapText);
// Instructions
var instructionText = new Text2('Choose Wall Mode:', {
size: 80,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2 - 300;
game.addChild(instructionText);
// Store references for removal
game.modeSelectionElements = [classicButton, classicText, wrapButton, wrapText, instructionText];
// Handle mode selection
classicButton.interactive = true;
classicText.interactive = true;
wrapButton.interactive = true;
wrapText.interactive = true;
function selectMode(mode) {
gameMode = mode;
modeSelected = true;
modeTxt.setText('Mode: ' + (mode === 'classic' ? 'Classic' : 'Wrap'));
// Remove mode selection UI
for (var i = 0; i < game.modeSelectionElements.length; i++) {
game.modeSelectionElements[i].destroy();
}
game.modeSelectionElements = [];
// Start the game immediately
gameRunning = true;
initSnake();
spawnFood();
}
classicButton.down = function () {
selectMode('classic');
};
classicText.down = function () {
selectMode('classic');
};
wrapButton.down = function () {
selectMode('wrap');
};
wrapText.down = function () {
selectMode('wrap');
};
}
// Initialize snake
function initSnake() {
// Reset speed to initial values
MOVE_INTERVAL = INITIAL_MOVE_INTERVAL;
currentMoveInterval.value = INITIAL_MOVE_INTERVAL;
moveTimer = 0;
snake = [];
var startX = Math.floor(GRID_WIDTH / 2);
var startY = Math.floor(GRID_HEIGHT / 2);
// Create initial snake with 3 segments
for (var i = 0; i < 3; i++) {
var segment = new SnakeSegment(i === 0);
segment.gridX = startX - i;
segment.gridY = startY;
var pos = gridToScreen(segment.gridX, segment.gridY);
segment.x = pos.x;
segment.y = pos.y;
// Set initial head direction
if (i === 0) {
segment.setDirection('right');
}
snake.push(segment);
game.addChild(segment);
}
}
// Spawn food at random location
function spawnFood() {
if (food) {
food.destroy();
}
var validPositions = [];
// Calculate safe zone boundaries (80% of screen area, centered)
var safeMarginX = Math.floor(GRID_WIDTH * 0.1); // 10% margin on each side
var safeMarginY = Math.floor(GRID_HEIGHT * 0.1); // 10% margin on top/bottom
var safeStartX = safeMarginX;
var safeEndX = GRID_WIDTH - safeMarginX;
var safeStartY = safeMarginY;
var safeEndY = GRID_HEIGHT - safeMarginY;
// Find all valid positions (not occupied by snake) within safe zone
for (var x = safeStartX; x < safeEndX; x++) {
for (var y = safeStartY; y < safeEndY; y++) {
var occupied = false;
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === x && snake[i].gridY === y) {
occupied = true;
break;
}
}
if (!occupied) {
validPositions.push({
x: x,
y: y
});
}
}
}
if (validPositions.length > 0) {
// Select random food type based on probability
var rand = Math.random();
var selectedType = 'apple';
if (rand < FOOD_TYPES.strawberry.probability) {
selectedType = 'strawberry';
} else if (rand < FOOD_TYPES.strawberry.probability + FOOD_TYPES.grape.probability) {
selectedType = 'grape';
}
var randomPos = validPositions[Math.floor(Math.random() * validPositions.length)];
food = new Food(selectedType);
food.gridX = randomPos.x;
food.gridY = randomPos.y;
food.timeLeft = FOOD_TYPES[selectedType].duration;
food.maxTime = FOOD_TYPES[selectedType].duration;
var pos = gridToScreen(food.gridX, food.gridY);
food.x = pos.x;
food.y = pos.y;
game.addChild(food);
}
}
// Check if position is valid (within bounds and not hitting snake body)
function isValidPosition(x, y) {
// In wrap mode, adjust coordinates to wrap around
if (gameMode === 'wrap') {
if (x < 0) x = GRID_WIDTH - 1;
if (x >= GRID_WIDTH) x = 0;
if (y < 0) y = GRID_HEIGHT - 1;
if (y >= GRID_HEIGHT) y = 0;
} else {
// Classic mode - check bounds
if (x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) {
return false;
}
}
// Check collision with snake body (excluding head)
for (var i = 1; i < snake.length; i++) {
if (snake[i].gridX === x && snake[i].gridY === y) {
return false;
}
}
return true;
}
// Move snake
function moveSnake() {
if (!gameRunning) return;
var head = snake[0];
var newX = head.gridX;
var newY = head.gridY;
// Apply direction
currentDirection = nextDirection;
switch (currentDirection) {
case 'up':
newY--;
break;
case 'down':
newY++;
break;
case 'left':
newX--;
break;
case 'right':
newX++;
break;
}
// Handle wrapping in wrap mode
if (gameMode === 'wrap') {
if (newX < 0) newX = GRID_WIDTH - 1;
if (newX >= GRID_WIDTH) newX = 0;
if (newY < 0) newY = GRID_HEIGHT - 1;
if (newY >= GRID_HEIGHT) newY = 0;
}
// Check if new position is valid
if (!isValidPosition(newX, newY)) {
// Game over
gameRunning = false;
LK.getSound('gameOver').play();
LK.showGameOver();
return;
}
// Check if food is eaten
var ateFood = false;
if (food && newX === food.gridX && newY === food.gridY) {
ateFood = true;
var points = FOOD_TYPES[food.foodType].points;
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore());
LK.getSound('eat').play();
spawnFood();
// Increase snake speed with each food eaten
var newInterval = Math.max(MIN_MOVE_INTERVAL, MOVE_INTERVAL * SPEED_INCREASE_FACTOR);
if (newInterval !== MOVE_INTERVAL) {
// Smooth speed transition using tween
tween(currentMoveInterval, {
value: newInterval
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
MOVE_INTERVAL = Math.round(currentMoveInterval.value);
}
});
}
}
// Create new head
var newHead = new SnakeSegment(true);
newHead.gridX = newX;
newHead.gridY = newY;
var pos = gridToScreen(newHead.gridX, newHead.gridY);
newHead.x = pos.x;
newHead.y = pos.y;
// Set head rotation based on movement direction
newHead.setDirection(currentDirection);
// Add new head to front
snake.unshift(newHead);
game.addChild(newHead);
// Convert old head to body
if (snake.length > 1) {
var oldHead = snake[1];
oldHead.removeChildren();
var bodyGraphics = oldHead.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Remove tail if no food was eaten
if (!ateFood) {
var tail = snake.pop();
tail.destroy();
}
}
// Handle swipe input
function handleSwipe(deltaX, deltaY) {
if (!gameRunning) return;
var absX = Math.abs(deltaX);
var absY = Math.abs(deltaY);
// Determine swipe direction
if (absX > absY) {
// Horizontal swipe
if (deltaX > 0 && currentDirection !== 'left') {
nextDirection = 'right';
} else if (deltaX < 0 && currentDirection !== 'right') {
nextDirection = 'left';
}
} else {
// Vertical swipe
if (deltaY > 0 && currentDirection !== 'up') {
nextDirection = 'down';
} else if (deltaY < 0 && currentDirection !== 'down') {
nextDirection = 'up';
}
}
}
// Touch event handlers
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance >= MIN_SWIPE_DISTANCE) {
handleSwipe(deltaX, deltaY);
}
};
// Initialize game with mode selection
createModeSelection();
// Main game loop
game.update = function () {
if (!modeSelected || !gameRunning) return;
moveTimer++;
if (moveTimer >= MOVE_INTERVAL) {
moveTimer = 0;
moveSnake();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -48,59 +48,26 @@
self.gridX = 0;
self.gridY = 0;
self.isHead = isHead;
self.segmentGraphics = segmentGraphics;
- // Smooth movement properties
- self.targetX = 0;
- self.targetY = 0;
self.setDirection = function (direction) {
- // Only rotate body segments, not the head
- if (self.segmentGraphics && !self.isHead) {
- var targetRotation = 0;
+ if (self.isHead && self.segmentGraphics) {
switch (direction) {
case 'up':
- targetRotation = -Math.PI / 2;
+ self.segmentGraphics.rotation = -Math.PI / 2;
break;
case 'down':
- targetRotation = Math.PI / 2;
+ self.segmentGraphics.rotation = Math.PI / 2;
break;
case 'left':
- targetRotation = Math.PI;
+ self.segmentGraphics.rotation = Math.PI;
break;
case 'right':
- targetRotation = 0;
+ self.segmentGraphics.rotation = 0;
break;
}
- // Body segments rotate smoothly
- tween(self.segmentGraphics, {
- rotation: targetRotation
- }, {
- duration: movementDuration,
- easing: tween.easeOut
- });
}
};
- self.moveToGrid = function (gridX, gridY, duration, onComplete) {
- self.gridX = gridX;
- self.gridY = gridY;
- var pos = gridToScreen(gridX, gridY);
- self.targetX = pos.x;
- self.targetY = pos.y;
- if (smoothMovement && duration > 0) {
- tween(self, {
- x: self.targetX,
- y: self.targetY
- }, {
- duration: duration,
- easing: tween.easeOut,
- onFinish: onComplete
- });
- } else {
- self.x = self.targetX;
- self.y = self.targetY;
- if (onComplete) onComplete();
- }
- };
return self;
});
/****
@@ -114,9 +81,9 @@
* Game Code
****/
// Import tween plugin for smooth speed transitions
// Game constants
-var GRID_SIZE = 60;
+var GRID_SIZE = 90;
var GRID_WIDTH = Math.floor(2048 / GRID_SIZE);
var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE);
var GAME_AREA_WIDTH = GRID_WIDTH * GRID_SIZE;
var GAME_AREA_HEIGHT = GRID_HEIGHT * GRID_SIZE;
@@ -138,12 +105,8 @@
value: INITIAL_MOVE_INTERVAL
}; // Object for tweening
var gameMode = 'classic'; // 'classic' or 'wrap'
var modeSelected = false;
-// Smooth movement variables
-var smoothMovement = true;
-var movementDuration = 200; // Duration of smooth movement in ms
-var isMoving = false; // Track if snake is currently moving
// Food type definitions
var FOOD_TYPES = {
apple: {
points: 1,
@@ -276,16 +239,19 @@
// Reset speed to initial values
MOVE_INTERVAL = INITIAL_MOVE_INTERVAL;
currentMoveInterval.value = INITIAL_MOVE_INTERVAL;
moveTimer = 0;
- isMoving = false;
snake = [];
var startX = Math.floor(GRID_WIDTH / 2);
var startY = Math.floor(GRID_HEIGHT / 2);
// Create initial snake with 3 segments
for (var i = 0; i < 3; i++) {
var segment = new SnakeSegment(i === 0);
- segment.moveToGrid(startX - i, startY, 0); // Instant positioning for initial setup
+ segment.gridX = startX - i;
+ segment.gridY = startY;
+ var pos = gridToScreen(segment.gridX, segment.gridY);
+ segment.x = pos.x;
+ segment.y = pos.y;
// Set initial head direction
if (i === 0) {
segment.setDirection('right');
}
@@ -368,10 +334,9 @@
return true;
}
// Move snake
function moveSnake() {
- if (!gameRunning || isMoving) return;
- isMoving = true;
+ if (!gameRunning) return;
var head = snake[0];
var newX = head.gridX;
var newY = head.gridY;
// Apply direction
@@ -400,9 +365,8 @@
// Check if new position is valid
if (!isValidPosition(newX, newY)) {
// Game over
gameRunning = false;
- isMoving = false;
LK.getSound('gameOver').play();
LK.showGameOver();
return;
}
@@ -429,19 +393,15 @@
}
});
}
}
- // Store previous positions for smooth movement
- var previousPositions = [];
- for (var i = 0; i < snake.length; i++) {
- previousPositions.push({
- gridX: snake[i].gridX,
- gridY: snake[i].gridY
- });
- }
// Create new head
var newHead = new SnakeSegment(true);
- newHead.moveToGrid(newX, newY, 0); // Instant positioning for new head
+ newHead.gridX = newX;
+ newHead.gridY = newY;
+ var pos = gridToScreen(newHead.gridX, newHead.gridY);
+ newHead.x = pos.x;
+ newHead.y = pos.y;
// Set head rotation based on movement direction
newHead.setDirection(currentDirection);
// Add new head to front
snake.unshift(newHead);
@@ -455,68 +415,12 @@
anchorY: 0.5
});
}
// Remove tail if no food was eaten
- var tailToRemove = null;
if (!ateFood) {
- tailToRemove = snake.pop();
+ var tail = snake.pop();
+ tail.destroy();
}
- // Animate all segments to their new positions
- var completedMovements = 0;
- var totalMovements = snake.length;
- function onSegmentMoveComplete() {
- completedMovements++;
- if (completedMovements >= totalMovements) {
- // All segments have completed movement
- if (tailToRemove) {
- tailToRemove.destroy();
- }
- isMoving = false;
- }
- }
- // Move each segment to the position of the segment in front of it
- for (var i = 1; i < snake.length; i++) {
- var prevPos = previousPositions[i - 1];
- snake[i].moveToGrid(prevPos.gridX, prevPos.gridY, movementDuration, onSegmentMoveComplete);
- // Calculate direction for body segment rotation
- var segmentDirection = 'right'; // Default direction
- if (i === 1) {
- // First body segment follows head direction
- segmentDirection = currentDirection;
- } else {
- // Calculate direction based on movement from current position to target position
- var currentPos = {
- gridX: snake[i].gridX,
- gridY: snake[i].gridY
- };
- var targetPos = previousPositions[i - 1];
- // Ensure both positions exist and have required properties
- if (!currentPos || !targetPos || typeof currentPos.gridX === 'undefined' || typeof targetPos.gridX === 'undefined') {
- segmentDirection = 'right'; // Default fallback
- } else {
- var deltaX = targetPos.gridX - currentPos.gridX;
- var deltaY = targetPos.gridY - currentPos.gridY;
- // Handle wrapping
- if (gameMode === 'wrap') {
- if (Math.abs(deltaX) > GRID_WIDTH / 2) {
- deltaX = deltaX > 0 ? deltaX - GRID_WIDTH : deltaX + GRID_WIDTH;
- }
- if (Math.abs(deltaY) > GRID_HEIGHT / 2) {
- deltaY = deltaY > 0 ? deltaY - GRID_HEIGHT : deltaY + GRID_HEIGHT;
- }
- }
- if (Math.abs(deltaX) > Math.abs(deltaY)) {
- segmentDirection = deltaX > 0 ? 'right' : 'left';
- } else {
- segmentDirection = deltaY > 0 ? 'down' : 'up';
- }
- }
- }
- // Apply rotation to body segment
- snake[i].setDirection(segmentDirection);
- }
- // Head moves immediately (already positioned)
- onSegmentMoveComplete();
}
// Handle swipe input
function handleSwipe(deltaX, deltaY) {
if (!gameRunning) return;
@@ -557,11 +461,9 @@
// Main game loop
game.update = function () {
if (!modeSelected || !gameRunning) return;
moveTimer++;
- // Adjust movement interval to account for smooth movement duration
- var effectiveInterval = Math.max(MOVE_INTERVAL, Math.ceil(movementDuration / 16.67)); // Ensure smooth movement completes
- if (moveTimer >= effectiveInterval) {
+ if (moveTimer >= MOVE_INTERVAL) {
moveTimer = 0;
moveSnake();
}
};
\ No newline at end of file