/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Apple = Container.expand(function () { var self = Container.call(this); // Glow layer var glowGraphics = self.attachAsset('appleGlow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4 }); // Main apple var appleGraphics = self.attachAsset('apple', { anchorX: 0.5, anchorY: 0.5 }); // Highlight var highlightGraphics = self.attachAsset('appleHighlight', { anchorX: 0.5, anchorY: 0.5, x: -8, y: -8, alpha: 0.9 }); // Add floating animation self.floatDirection = 1; self.baseY = 0; self.update = function () { self.y = self.baseY + Math.sin(LK.ticks * 0.05) * 3; glowGraphics.alpha = 0.4 + Math.sin(LK.ticks * 0.08) * 0.2; tween.stop(glowGraphics); tween(glowGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 1000, easing: tween.easeInOut }); tween(glowGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 1000, delay: 1000, easing: tween.easeInOut }); }; self.spawn = function () { var gridSize = 40; var padding = 100; // Better padding for modern mobile devices var maxX = Math.floor((2048 - padding * 2) / gridSize); var maxY = Math.floor((2732 - padding * 2) / gridSize); self.x = padding + Math.floor(Math.random() * maxX) * gridSize + gridSize / 2; self.baseY = padding + Math.floor(Math.random() * maxY) * gridSize + gridSize / 2; self.y = self.baseY; // Add spawn animation self.scale.set(0); tween(self.scale, { x: 1.2, y: 1.2 }, { duration: 200, easing: tween.easeOut }); tween(self.scale, { x: 1.0, y: 1.0 }, { duration: 150, delay: 200, easing: tween.easeIn }); }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); // Add sparkle effect var sparkleGraphics = self.attachAsset('sparkle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); self.vx = (Math.random() - 0.5) * 15; self.vy = (Math.random() - 0.5) * 15; self.life = 1.0; self.maxLife = 90; self.rotationSpeed = (Math.random() - 0.5) * 0.3; self.update = function () { self.x += self.vx; self.y += self.vy; self.vx *= 0.98; // Air resistance self.vy *= 0.98; self.life -= 1.0 / self.maxLife; self.alpha = self.life; self.scale.set(self.life * (1 + Math.sin(LK.ticks * 0.2) * 0.1)); self.rotation += self.rotationSpeed; // Color transition from gold to white var colorFactor = self.life; sparkleGraphics.alpha = (1 - self.life) * 0.8; if (self.life <= 0) { self.destroy(); } }; return self; }); var SnakeHead = Container.expand(function () { var self = Container.call(this); // Glow layer var glowGraphics = self.attachAsset('snakeHeadGlow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); // Main head var headGraphics = self.attachAsset('snakeHead', { anchorX: 0.5, anchorY: 0.5 }); // Add pulsing glow effect self.glowDirection = 1; self.update = function () { glowGraphics.alpha += self.glowDirection * 0.01; if (glowGraphics.alpha >= 0.6) self.glowDirection = -1; if (glowGraphics.alpha <= 0.2) self.glowDirection = 1; }; return self; }); var SnakeSegment = Container.expand(function () { var self = Container.call(this); // Outer segment var segmentGraphics = self.attachAsset('snakeSegment', { anchorX: 0.5, anchorY: 0.5 }); // Inner highlight var innerGraphics = self.attachAsset('snakeSegmentInner', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); return self; }); var TouchIndicator = Container.expand(function () { var self = Container.call(this); var indicatorGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); indicatorGraphics.width = 80; indicatorGraphics.height = 80; indicatorGraphics.alpha = 0.6; self.visible = false; self.show = function (x, y) { self.x = x; self.y = y; self.visible = true; self.scale.set(0.5); tween(self.scale, { x: 1.2, y: 1.2 }, { duration: 150, easing: tween.easeOut }); tween(self.scale, { x: 1, y: 1 }, { duration: 100, delay: 150, easing: tween.easeIn }); }; self.hide = function () { tween(self, { alpha: 0 }, { duration: 200 }); LK.setTimeout(function () { self.visible = false; self.alpha = 0.6; }, 200); }; return self; }); var TrailEffect = Container.expand(function () { var self = Container.call(this); var trailGraphics = self.attachAsset('trail', { anchorX: 0.5, anchorY: 0.5 }); self.life = 1.0; self.update = function () { self.life -= 0.02; self.alpha = self.life * 0.5; self.scale.set(self.life); if (self.life <= 0) { self.destroy(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1B5E20 }); /**** * Game Code ****/ var gridSize = 40; var snake = []; var snakeDirection = { x: 1, y: 0 }; var nextDirection = { x: 1, y: 0 }; var apple = null; var gameSpeed = 4; // Balanced modern speed var moveCounter = 0; var isMoving = false; // Track if snake is currently moving var isGameRunning = true; var particles = []; var trails = []; var combo = 0; var maxCombo = 0; var scoreTxt = new Text2('SCORE: 0', { size: 90, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var comboTxt = new Text2('', { size: 60, fill: 0xFFD700 }); comboTxt.anchor.set(1, 0); LK.gui.topRight.addChild(comboTxt); // Initialize snake with 3 segments function initializeSnake() { snake = []; var startX = 1024; var startY = 1366; // Create head var head = game.addChild(new SnakeHead()); head.x = startX; head.y = startY; snake.push(head); // Create initial body segments for (var i = 1; i < 3; i++) { var segment = game.addChild(new SnakeSegment()); segment.x = startX - i * gridSize; segment.y = startY; snake.push(segment); } } // Create apple function createApple() { if (apple) { apple.destroy(); } apple = game.addChild(new Apple()); apple.spawn(); // Make sure apple doesn't spawn on snake var appleOnSnake = true; var attempts = 0; while (appleOnSnake && attempts < 50) { appleOnSnake = false; for (var i = 0; i < snake.length; i++) { if (Math.abs(apple.x - snake[i].x) < gridSize && Math.abs(apple.y - snake[i].y) < gridSize) { appleOnSnake = true; apple.spawn(); break; } } attempts++; } } // Move snake function moveSnake() { if (!isGameRunning || isMoving) { return; } isMoving = true; snakeDirection.x = nextDirection.x; snakeDirection.y = nextDirection.y; var head = snake[0]; var newX = head.x + snakeDirection.x * gridSize; var newY = head.y + snakeDirection.y * gridSize; // Check wall collisions if (newX < 50 || newX > 1998 || newY < 50 || newY > 2682) { combo = 0; // Reset combo on collision isMoving = false; gameOver(); return; } // Check self collision for (var i = 1; i < snake.length; i++) { if (Math.abs(newX - snake[i].x) < gridSize && Math.abs(newY - snake[i].y) < gridSize) { combo = 0; // Reset combo on collision isMoving = false; gameOver(); return; } } // Check apple collision var ateApple = false; if (apple && Math.abs(newX - apple.x) < gridSize && Math.abs(newY - apple.y) < gridSize) { ateApple = true; combo++; var scoreBonus = Math.max(1, Math.floor(combo / 3)); LK.setScore(LK.getScore() + scoreBonus); scoreTxt.setText('SCORE: ' + LK.getScore()); if (combo > maxCombo) { maxCombo = combo; } if (combo > 2) { comboTxt.setText('COMBO x' + combo); tween(comboTxt, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, easing: tween.easeOut }); tween(comboTxt, { scaleX: 1, scaleY: 1 }, { duration: 200, delay: 200, easing: tween.easeIn }); } else { comboTxt.setText(''); } // Create eating particles for (var p = 0; p < 8; p++) { var particle = game.addChild(new Particle()); particle.x = apple.x; particle.y = apple.y; particles.push(particle); } // Screen shake effect tween(game, { x: 5 }, { duration: 50 }); tween(game, { x: -5 }, { duration: 50, delay: 50 }); tween(game, { x: 0 }, { duration: 50, delay: 100 }); LK.getSound('eat').play(); createApple(); } // Store old positions for smooth animation var oldPositions = []; for (var i = 0; i < snake.length; i++) { oldPositions[i] = { x: snake[i].x, y: snake[i].y }; } // Move all segments if (!ateApple) { // Remove tail if not growing var tail = snake.pop(); tail.destroy(); } // Add new head var newHead = game.addChild(new SnakeHead()); newHead.x = head.x; // Start at current position newHead.y = head.y; snake.unshift(newHead); // Convert old head to body segment if (snake.length > 1) { var oldHead = snake[1]; var newSegment = game.addChild(new SnakeSegment()); newSegment.x = oldHead.x; newSegment.y = oldHead.y; snake[1] = newSegment; oldHead.destroy(); } // Animate movement smoothly var animationDuration = 120; // Smooth modern animation tween(snake[0], { x: newX, y: newY }, { duration: animationDuration, easing: tween.easeOut }); // Animate body segments to follow with slight delay for more natural movement for (var i = 1; i < snake.length; i++) { if (i < oldPositions.length) { tween(snake[i], { x: oldPositions[i - 1].x, y: oldPositions[i - 1].y }, { duration: animationDuration, easing: tween.easeOut }); } } // Reset movement flag after animation completes LK.setTimeout(function () { isMoving = false; }, animationDuration); } function gameOver() { isGameRunning = false; LK.getSound('gameOver').play(); LK.showGameOver(); } // Touch controls var touchStartX = 0; var touchStartY = 0; var minSwipeDistance = 50; // Increased for better swipe detection var touchIndicator = game.addChild(new TouchIndicator()); var lastTouchTime = 0; var doubleTapDelay = 300; // Milliseconds for double tap detection game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; // Show touch indicator at touch position touchIndicator.show(x, y); }; game.up = function (x, y, obj) { // Hide touch indicator touchIndicator.hide(); if (!isGameRunning) { return; } var currentTime = Date.now(); var deltaX = x - touchStartX; var deltaY = y - touchStartY; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // Check for double tap (faster speed boost) if (distance < minSwipeDistance && currentTime - lastTouchTime < doubleTapDelay) { // Double tap detected - temporary speed boost if (gameSpeed > 2) { var originalSpeed = gameSpeed; gameSpeed = 2; // Flash effect to show speed boost tween(game, { tint: 0xFFFF00 }, { duration: 100 }); tween(game, { tint: 0xFFFFFF }, { duration: 100, delay: 100 }); // Reset speed after 3 seconds LK.setTimeout(function () { gameSpeed = originalSpeed; }, 3000); } lastTouchTime = currentTime; return; } // Handle single tap for direction change if (distance < minSwipeDistance) { // Enhanced tap controls - turn 90 degrees clockwise or counterclockwise based on tap position var screenCenterX = 1024; if (x > screenCenterX) { // Right side tap - turn clockwise if (snakeDirection.x === 1) { // Moving right, turn down nextDirection = { x: 0, y: 1 }; } else if (snakeDirection.x === -1) { // Moving left, turn up nextDirection = { x: 0, y: -1 }; } else if (snakeDirection.y === 1) { // Moving down, turn left nextDirection = { x: -1, y: 0 }; } else if (snakeDirection.y === -1) { // Moving up, turn right nextDirection = { x: 1, y: 0 }; } } else { // Left side tap - turn counterclockwise if (snakeDirection.x === 1) { // Moving right, turn up nextDirection = { x: 0, y: -1 }; } else if (snakeDirection.x === -1) { // Moving left, turn down nextDirection = { x: 0, y: 1 }; } else if (snakeDirection.y === 1) { // Moving down, turn right nextDirection = { x: 1, y: 0 }; } else if (snakeDirection.y === -1) { // Moving up, turn left nextDirection = { x: -1, y: 0 }; } } lastTouchTime = currentTime; return; } // Enhanced swipe detection with better sensitivity var absDeltaX = Math.abs(deltaX); var absDeltaY = Math.abs(deltaY); // Require minimum distance and clear directional preference if (distance >= minSwipeDistance) { if (absDeltaX > absDeltaY * 1.5) { // Strong horizontal swipe if (deltaX > 0 && snakeDirection.x === 0) { // Swipe right nextDirection = { x: 1, y: 0 }; // Visual feedback for swipe tween(touchIndicator, { x: touchIndicator.x + 50 }, { duration: 200 }); } else if (deltaX < 0 && snakeDirection.x === 0) { // Swipe left nextDirection = { x: -1, y: 0 }; // Visual feedback for swipe tween(touchIndicator, { x: touchIndicator.x - 50 }, { duration: 200 }); } } else if (absDeltaY > absDeltaX * 1.5) { // Strong vertical swipe if (deltaY > 0 && snakeDirection.y === 0) { // Swipe down nextDirection = { x: 0, y: 1 }; // Visual feedback for swipe tween(touchIndicator, { y: touchIndicator.y + 50 }, { duration: 200 }); } else if (deltaY < 0 && snakeDirection.y === 0) { // Swipe up nextDirection = { x: 0, y: -1 }; // Visual feedback for swipe tween(touchIndicator, { y: touchIndicator.y - 50 }, { duration: 200 }); } } } }; // Initialize game initializeSnake(); createApple(); // Add trail creation function function createTrail(x, y) { var trail = game.addChild(new TrailEffect()); trail.x = x; trail.y = y; trails.push(trail); } // Game update loop game.update = function () { if (!isGameRunning) { return; } // Update particles for (var p = particles.length - 1; p >= 0; p--) { var particle = particles[p]; if (particle.destroyed) { particles.splice(p, 1); } } // Update trails for (var t = trails.length - 1; t >= 0; t--) { var trail = trails[t]; if (trail.destroyed) { trails.splice(t, 1); } } // Create trail behind snake head if (snake.length > 0 && LK.ticks % 3 === 0) { createTrail(snake[0].x, snake[0].y); } moveCounter++; if (moveCounter >= gameSpeed && !isMoving) { moveCounter = 0; moveSnake(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Apple = Container.expand(function () {
var self = Container.call(this);
// Glow layer
var glowGraphics = self.attachAsset('appleGlow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4
});
// Main apple
var appleGraphics = self.attachAsset('apple', {
anchorX: 0.5,
anchorY: 0.5
});
// Highlight
var highlightGraphics = self.attachAsset('appleHighlight', {
anchorX: 0.5,
anchorY: 0.5,
x: -8,
y: -8,
alpha: 0.9
});
// Add floating animation
self.floatDirection = 1;
self.baseY = 0;
self.update = function () {
self.y = self.baseY + Math.sin(LK.ticks * 0.05) * 3;
glowGraphics.alpha = 0.4 + Math.sin(LK.ticks * 0.08) * 0.2;
tween.stop(glowGraphics);
tween(glowGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 1000,
easing: tween.easeInOut
});
tween(glowGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
delay: 1000,
easing: tween.easeInOut
});
};
self.spawn = function () {
var gridSize = 40;
var padding = 100; // Better padding for modern mobile devices
var maxX = Math.floor((2048 - padding * 2) / gridSize);
var maxY = Math.floor((2732 - padding * 2) / gridSize);
self.x = padding + Math.floor(Math.random() * maxX) * gridSize + gridSize / 2;
self.baseY = padding + Math.floor(Math.random() * maxY) * gridSize + gridSize / 2;
self.y = self.baseY;
// Add spawn animation
self.scale.set(0);
tween(self.scale, {
x: 1.2,
y: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
tween(self.scale, {
x: 1.0,
y: 1.0
}, {
duration: 150,
delay: 200,
easing: tween.easeIn
});
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
// Add sparkle effect
var sparkleGraphics = self.attachAsset('sparkle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.vx = (Math.random() - 0.5) * 15;
self.vy = (Math.random() - 0.5) * 15;
self.life = 1.0;
self.maxLife = 90;
self.rotationSpeed = (Math.random() - 0.5) * 0.3;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vx *= 0.98; // Air resistance
self.vy *= 0.98;
self.life -= 1.0 / self.maxLife;
self.alpha = self.life;
self.scale.set(self.life * (1 + Math.sin(LK.ticks * 0.2) * 0.1));
self.rotation += self.rotationSpeed;
// Color transition from gold to white
var colorFactor = self.life;
sparkleGraphics.alpha = (1 - self.life) * 0.8;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var SnakeHead = Container.expand(function () {
var self = Container.call(this);
// Glow layer
var glowGraphics = self.attachAsset('snakeHeadGlow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
// Main head
var headGraphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
// Add pulsing glow effect
self.glowDirection = 1;
self.update = function () {
glowGraphics.alpha += self.glowDirection * 0.01;
if (glowGraphics.alpha >= 0.6) self.glowDirection = -1;
if (glowGraphics.alpha <= 0.2) self.glowDirection = 1;
};
return self;
});
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
// Outer segment
var segmentGraphics = self.attachAsset('snakeSegment', {
anchorX: 0.5,
anchorY: 0.5
});
// Inner highlight
var innerGraphics = self.attachAsset('snakeSegmentInner', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
return self;
});
var TouchIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
indicatorGraphics.width = 80;
indicatorGraphics.height = 80;
indicatorGraphics.alpha = 0.6;
self.visible = false;
self.show = function (x, y) {
self.x = x;
self.y = y;
self.visible = true;
self.scale.set(0.5);
tween(self.scale, {
x: 1.2,
y: 1.2
}, {
duration: 150,
easing: tween.easeOut
});
tween(self.scale, {
x: 1,
y: 1
}, {
duration: 100,
delay: 150,
easing: tween.easeIn
});
};
self.hide = function () {
tween(self, {
alpha: 0
}, {
duration: 200
});
LK.setTimeout(function () {
self.visible = false;
self.alpha = 0.6;
}, 200);
};
return self;
});
var TrailEffect = Container.expand(function () {
var self = Container.call(this);
var trailGraphics = self.attachAsset('trail', {
anchorX: 0.5,
anchorY: 0.5
});
self.life = 1.0;
self.update = function () {
self.life -= 0.02;
self.alpha = self.life * 0.5;
self.scale.set(self.life);
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1B5E20
});
/****
* Game Code
****/
var gridSize = 40;
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var apple = null;
var gameSpeed = 4; // Balanced modern speed
var moveCounter = 0;
var isMoving = false; // Track if snake is currently moving
var isGameRunning = true;
var particles = [];
var trails = [];
var combo = 0;
var maxCombo = 0;
var scoreTxt = new Text2('SCORE: 0', {
size: 90,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var comboTxt = new Text2('', {
size: 60,
fill: 0xFFD700
});
comboTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(comboTxt);
// Initialize snake with 3 segments
function initializeSnake() {
snake = [];
var startX = 1024;
var startY = 1366;
// Create head
var head = game.addChild(new SnakeHead());
head.x = startX;
head.y = startY;
snake.push(head);
// Create initial body segments
for (var i = 1; i < 3; i++) {
var segment = game.addChild(new SnakeSegment());
segment.x = startX - i * gridSize;
segment.y = startY;
snake.push(segment);
}
}
// Create apple
function createApple() {
if (apple) {
apple.destroy();
}
apple = game.addChild(new Apple());
apple.spawn();
// Make sure apple doesn't spawn on snake
var appleOnSnake = true;
var attempts = 0;
while (appleOnSnake && attempts < 50) {
appleOnSnake = false;
for (var i = 0; i < snake.length; i++) {
if (Math.abs(apple.x - snake[i].x) < gridSize && Math.abs(apple.y - snake[i].y) < gridSize) {
appleOnSnake = true;
apple.spawn();
break;
}
}
attempts++;
}
}
// Move snake
function moveSnake() {
if (!isGameRunning || isMoving) {
return;
}
isMoving = true;
snakeDirection.x = nextDirection.x;
snakeDirection.y = nextDirection.y;
var head = snake[0];
var newX = head.x + snakeDirection.x * gridSize;
var newY = head.y + snakeDirection.y * gridSize;
// Check wall collisions
if (newX < 50 || newX > 1998 || newY < 50 || newY > 2682) {
combo = 0; // Reset combo on collision
isMoving = false;
gameOver();
return;
}
// Check self collision
for (var i = 1; i < snake.length; i++) {
if (Math.abs(newX - snake[i].x) < gridSize && Math.abs(newY - snake[i].y) < gridSize) {
combo = 0; // Reset combo on collision
isMoving = false;
gameOver();
return;
}
}
// Check apple collision
var ateApple = false;
if (apple && Math.abs(newX - apple.x) < gridSize && Math.abs(newY - apple.y) < gridSize) {
ateApple = true;
combo++;
var scoreBonus = Math.max(1, Math.floor(combo / 3));
LK.setScore(LK.getScore() + scoreBonus);
scoreTxt.setText('SCORE: ' + LK.getScore());
if (combo > maxCombo) {
maxCombo = combo;
}
if (combo > 2) {
comboTxt.setText('COMBO x' + combo);
tween(comboTxt, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut
});
tween(comboTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
delay: 200,
easing: tween.easeIn
});
} else {
comboTxt.setText('');
}
// Create eating particles
for (var p = 0; p < 8; p++) {
var particle = game.addChild(new Particle());
particle.x = apple.x;
particle.y = apple.y;
particles.push(particle);
}
// Screen shake effect
tween(game, {
x: 5
}, {
duration: 50
});
tween(game, {
x: -5
}, {
duration: 50,
delay: 50
});
tween(game, {
x: 0
}, {
duration: 50,
delay: 100
});
LK.getSound('eat').play();
createApple();
}
// Store old positions for smooth animation
var oldPositions = [];
for (var i = 0; i < snake.length; i++) {
oldPositions[i] = {
x: snake[i].x,
y: snake[i].y
};
}
// Move all segments
if (!ateApple) {
// Remove tail if not growing
var tail = snake.pop();
tail.destroy();
}
// Add new head
var newHead = game.addChild(new SnakeHead());
newHead.x = head.x; // Start at current position
newHead.y = head.y;
snake.unshift(newHead);
// Convert old head to body segment
if (snake.length > 1) {
var oldHead = snake[1];
var newSegment = game.addChild(new SnakeSegment());
newSegment.x = oldHead.x;
newSegment.y = oldHead.y;
snake[1] = newSegment;
oldHead.destroy();
}
// Animate movement smoothly
var animationDuration = 120; // Smooth modern animation
tween(snake[0], {
x: newX,
y: newY
}, {
duration: animationDuration,
easing: tween.easeOut
});
// Animate body segments to follow with slight delay for more natural movement
for (var i = 1; i < snake.length; i++) {
if (i < oldPositions.length) {
tween(snake[i], {
x: oldPositions[i - 1].x,
y: oldPositions[i - 1].y
}, {
duration: animationDuration,
easing: tween.easeOut
});
}
}
// Reset movement flag after animation completes
LK.setTimeout(function () {
isMoving = false;
}, animationDuration);
}
function gameOver() {
isGameRunning = false;
LK.getSound('gameOver').play();
LK.showGameOver();
}
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var minSwipeDistance = 50; // Increased for better swipe detection
var touchIndicator = game.addChild(new TouchIndicator());
var lastTouchTime = 0;
var doubleTapDelay = 300; // Milliseconds for double tap detection
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
// Show touch indicator at touch position
touchIndicator.show(x, y);
};
game.up = function (x, y, obj) {
// Hide touch indicator
touchIndicator.hide();
if (!isGameRunning) {
return;
}
var currentTime = Date.now();
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check for double tap (faster speed boost)
if (distance < minSwipeDistance && currentTime - lastTouchTime < doubleTapDelay) {
// Double tap detected - temporary speed boost
if (gameSpeed > 2) {
var originalSpeed = gameSpeed;
gameSpeed = 2;
// Flash effect to show speed boost
tween(game, {
tint: 0xFFFF00
}, {
duration: 100
});
tween(game, {
tint: 0xFFFFFF
}, {
duration: 100,
delay: 100
});
// Reset speed after 3 seconds
LK.setTimeout(function () {
gameSpeed = originalSpeed;
}, 3000);
}
lastTouchTime = currentTime;
return;
}
// Handle single tap for direction change
if (distance < minSwipeDistance) {
// Enhanced tap controls - turn 90 degrees clockwise or counterclockwise based on tap position
var screenCenterX = 1024;
if (x > screenCenterX) {
// Right side tap - turn clockwise
if (snakeDirection.x === 1) {
// Moving right, turn down
nextDirection = {
x: 0,
y: 1
};
} else if (snakeDirection.x === -1) {
// Moving left, turn up
nextDirection = {
x: 0,
y: -1
};
} else if (snakeDirection.y === 1) {
// Moving down, turn left
nextDirection = {
x: -1,
y: 0
};
} else if (snakeDirection.y === -1) {
// Moving up, turn right
nextDirection = {
x: 1,
y: 0
};
}
} else {
// Left side tap - turn counterclockwise
if (snakeDirection.x === 1) {
// Moving right, turn up
nextDirection = {
x: 0,
y: -1
};
} else if (snakeDirection.x === -1) {
// Moving left, turn down
nextDirection = {
x: 0,
y: 1
};
} else if (snakeDirection.y === 1) {
// Moving down, turn right
nextDirection = {
x: 1,
y: 0
};
} else if (snakeDirection.y === -1) {
// Moving up, turn left
nextDirection = {
x: -1,
y: 0
};
}
}
lastTouchTime = currentTime;
return;
}
// Enhanced swipe detection with better sensitivity
var absDeltaX = Math.abs(deltaX);
var absDeltaY = Math.abs(deltaY);
// Require minimum distance and clear directional preference
if (distance >= minSwipeDistance) {
if (absDeltaX > absDeltaY * 1.5) {
// Strong horizontal swipe
if (deltaX > 0 && snakeDirection.x === 0) {
// Swipe right
nextDirection = {
x: 1,
y: 0
};
// Visual feedback for swipe
tween(touchIndicator, {
x: touchIndicator.x + 50
}, {
duration: 200
});
} else if (deltaX < 0 && snakeDirection.x === 0) {
// Swipe left
nextDirection = {
x: -1,
y: 0
};
// Visual feedback for swipe
tween(touchIndicator, {
x: touchIndicator.x - 50
}, {
duration: 200
});
}
} else if (absDeltaY > absDeltaX * 1.5) {
// Strong vertical swipe
if (deltaY > 0 && snakeDirection.y === 0) {
// Swipe down
nextDirection = {
x: 0,
y: 1
};
// Visual feedback for swipe
tween(touchIndicator, {
y: touchIndicator.y + 50
}, {
duration: 200
});
} else if (deltaY < 0 && snakeDirection.y === 0) {
// Swipe up
nextDirection = {
x: 0,
y: -1
};
// Visual feedback for swipe
tween(touchIndicator, {
y: touchIndicator.y - 50
}, {
duration: 200
});
}
}
}
};
// Initialize game
initializeSnake();
createApple();
// Add trail creation function
function createTrail(x, y) {
var trail = game.addChild(new TrailEffect());
trail.x = x;
trail.y = y;
trails.push(trail);
}
// Game update loop
game.update = function () {
if (!isGameRunning) {
return;
}
// Update particles
for (var p = particles.length - 1; p >= 0; p--) {
var particle = particles[p];
if (particle.destroyed) {
particles.splice(p, 1);
}
}
// Update trails
for (var t = trails.length - 1; t >= 0; t--) {
var trail = trails[t];
if (trail.destroyed) {
trails.splice(t, 1);
}
}
// Create trail behind snake head
if (snake.length > 0 && LK.ticks % 3 === 0) {
createTrail(snake[0].x, snake[0].y);
}
moveCounter++;
if (moveCounter >= gameSpeed && !isMoving) {
moveCounter = 0;
moveSnake();
}
};