/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Pickup = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isBomb = color === 'bomb';
var assetId = self.isBomb ? 'bombPickup' : 'pickup' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = PLAYABLE_START_X + x * GRID_SIZE + GRID_SIZE / 2;
self.y = y * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
return self;
});
var SnakeHead = Container.expand(function (x, y) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.direction = {
x: 1,
y: 0
};
self.graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = PLAYABLE_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
};
return self;
});
var SnakeSegment = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isHighlighted = false;
var assetId = 'snakeSegment' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = PLAYABLE_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
};
self.highlight = function (highlight) {
self.isHighlighted = highlight;
if (highlight) {
self.graphics.alpha = 0.7;
self.graphics.scaleX = 1.2;
self.graphics.scaleY = 1.2;
} else {
self.graphics.alpha = 1.0;
self.graphics.scaleX = 1.0;
self.graphics.scaleY = 1.0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
var GRID_SIZE = 100;
var UI_HEIGHT = 50; // Minimal height reserved for UI at top
var PLAYABLE_SIZE = 2048; // Full screen width playable area
var PLAYABLE_HEIGHT = 1500; // Keep original square height
var GRID_WIDTH = Math.floor(PLAYABLE_SIZE / GRID_SIZE);
var GRID_HEIGHT = Math.floor(PLAYABLE_HEIGHT / GRID_SIZE);
var PLAYABLE_START_Y = UI_HEIGHT; // Move playable area to just below UI
var PLAYABLE_START_X = 0; // Start at left edge of screen
var SWIPE_AREA_HEIGHT = 2732 - PLAYABLE_START_Y - PLAYABLE_HEIGHT - 100; // Rest for swipe area minus UI space
var snake = [];
var snakeHead = null;
var pickups = [];
var gameSpeed = 150;
var moveTimer = 0;
var colors = ['red', 'yellow', 'blue'];
var nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
var bombMode = false;
var bombIndex = 0;
var bombTimer = 0;
var gameOver = false;
var foodCounter = 0; // Track number of foods eaten
var baseSpeed = 150; // Base game speed
var bombSpawnCounter = 0; // Track number of foods eaten for bomb spawning
var bombTimers = []; // Track active bomb timers
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT + 20;
game.addChild(scoreTxt);
var nextColorTxt = new Text2('Next: Red', {
size: 70,
fill: 0xFFFFFF
});
nextColorTxt.anchor.set(1, 0);
nextColorTxt.x = 2048 - 54;
nextColorTxt.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT + 20;
game.addChild(nextColorTxt);
function initializeGame() {
// Create snake head
snakeHead = new SnakeHead(Math.floor(GRID_WIDTH / 2), Math.floor(GRID_HEIGHT / 2));
game.addChild(snakeHead);
snakeHead.setPosition(snakeHead.gridX, snakeHead.gridY);
// Create initial tail segments
for (var i = 1; i <= 3; i++) {
var color = colors[Math.floor(Math.random() * colors.length)];
var segment = new SnakeSegment(color, snakeHead.gridX - i, snakeHead.gridY);
snake.push(segment);
game.addChild(segment);
segment.setPosition(segment.gridX, segment.gridY);
}
spawnRandomPickup();
updateNextColorDisplay();
}
function spawnRandomPickup() {
var attempts = 0;
var x, y;
do {
x = Math.floor(Math.random() * GRID_WIDTH);
y = Math.floor(Math.random() * GRID_HEIGHT);
attempts++;
} while (isPositionOccupied(x, y) && attempts < 100);
if (attempts < 100) {
// Check if we should spawn a bomb every 5 foods
var shouldSpawnBomb = bombSpawnCounter >= 5;
var isBomb = shouldSpawnBomb;
var color = isBomb ? 'bomb' : nextPickupColor;
var pickup = new Pickup(color, x, y);
pickups.push(pickup);
game.addChild(pickup);
if (isBomb) {
// Reset bomb spawn counter
bombSpawnCounter = 0;
// Start 5 second timer for this bomb
var bombTimer = {
pickup: pickup,
timeLeft: 300 // 5 seconds * 60 FPS
};
bombTimers.push(bombTimer);
} else {
nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
updateNextColorDisplay();
}
}
}
function isPositionOccupied(x, y) {
if (snakeHead.gridX === x && snakeHead.gridY === y) return true;
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === x && snake[i].gridY === y) return true;
}
for (var j = 0; j < pickups.length; j++) {
if (pickups[j].gridX === x && pickups[j].gridY === y) return true;
}
return false;
}
function updateNextColorDisplay() {
nextColorTxt.setText('Next: ' + nextPickupColor.charAt(0).toUpperCase() + nextPickupColor.slice(1));
}
function moveSnake() {
if (gameOver || bombMode) return;
var newX = snakeHead.gridX + snakeHead.direction.x;
var newY = snakeHead.gridY + snakeHead.direction.y;
// Wrap around screen edges
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 for self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
gameOver = true;
LK.showGameOver();
return;
}
}
// Move tail segments
if (snake.length > 0) {
for (var j = snake.length - 1; j > 0; j--) {
snake[j].setPosition(snake[j - 1].gridX, snake[j - 1].gridY);
}
snake[0].setPosition(snakeHead.gridX, snakeHead.gridY);
}
// Move head
snakeHead.setPosition(newX, newY);
// Check for pickup collision
for (var k = pickups.length - 1; k >= 0; k--) {
var pickup = pickups[k];
if (pickup.gridX === newX && pickup.gridY === newY) {
if (pickup.isBomb) {
handleBombPickup();
// Remove bomb timer for this pickup
for (var t = bombTimers.length - 1; t >= 0; t--) {
if (bombTimers[t].pickup === pickup) {
bombTimers.splice(t, 1);
break;
}
}
} else {
handleColorPickup(pickup.color);
}
pickup.destroy();
pickups.splice(k, 1);
spawnRandomPickup();
break;
}
}
checkForMatches();
}
function handleColorPickup(color) {
LK.getSound('collect').play();
// Get the position of the last tail segment, or head if no tail exists
var lastX, lastY;
if (snake.length > 0) {
lastX = snake[snake.length - 1].gridX;
lastY = snake[snake.length - 1].gridY;
} else {
lastX = snakeHead.gridX;
lastY = snakeHead.gridY;
}
var newSegment = new SnakeSegment(color, lastX, lastY);
snake.push(newSegment);
game.addChild(newSegment);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('Score: ' + LK.getScore());
// Increment food counter and check for speed increase
foodCounter++;
bombSpawnCounter++; // Increment bomb spawn counter
if (foodCounter % 5 === 0) {
// Increase speed by reducing gameSpeed (making it 0.05x faster)
gameSpeed = Math.max(30, gameSpeed - gameSpeed * 0.05); // Prevent speed from getting too fast
}
}
function handleBombPickup() {
if (snake.length === 0) return;
LK.getSound('bomb').play();
bombMode = true;
bombIndex = 0;
bombTimer = 0;
// Highlight first segment
snake[bombIndex].highlight(true);
}
function processBombMovement() {
if (!bombMode) return;
bombTimer++;
if (bombTimer >= 30) {
// Move every 30 ticks (0.5 seconds)
snake[bombIndex].highlight(false);
bombIndex++;
if (bombIndex >= snake.length) {
bombIndex = 0;
}
snake[bombIndex].highlight(true);
bombTimer = 0;
}
}
function triggerBomb() {
if (!bombMode || snake.length === 0) return;
snake[bombIndex].highlight(false);
bombMode = false;
// Only remove the specific selected snake segment
var segmentToRemove = snake[bombIndex];
LK.getSound('explode').play();
// Create explosion effect on the selected snake segment
tween(segmentToRemove.graphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Immediately remove the segment and close the gap
segmentToRemove.destroy();
snake.splice(bombIndex, 1);
// Immediately reposition all segments after the removed one to close the gap
if (bombIndex < snake.length && snake.length > 0) {
// Get the position of the segment before the removed one (or head if removing first segment)
var previousX, previousY;
if (bombIndex === 0) {
// If we removed the first segment, connect remaining segments to head
previousX = snakeHead.gridX;
previousY = snakeHead.gridY;
} else {
// Connect to the segment before the removed one
previousX = snake[bombIndex - 1].gridX;
previousY = snake[bombIndex - 1].gridY;
}
// Reposition all segments from the removed position onwards
for (var i = bombIndex; i < snake.length; i++) {
if (i === bombIndex) {
// First segment after gap connects to previous position
snake[i].setPosition(previousX, previousY);
} else {
// Subsequent segments connect to the previous segment
snake[i].setPosition(snake[i - 1].gridX, snake[i - 1].gridY);
}
}
}
// Award points
var points = 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Flash effect
LK.effects.flashScreen(0xffffff, 300);
}
function checkForMatches() {
var matchFound = false;
var toRemove = [];
for (var i = 0; i < snake.length - 2; i++) {
var count = 1;
var currentColor = snake[i].color;
for (var j = i + 1; j < snake.length; j++) {
if (snake[j].color === currentColor) {
count++;
} else {
break;
}
}
if (count >= 3) {
for (var k = i; k < i + count; k++) {
toRemove.push(k);
}
matchFound = true;
i += count - 1;
}
}
if (toRemove.length > 0) {
LK.getSound('explode').play();
// Remove matched segments
for (var m = toRemove.length - 1; m >= 0; m--) {
var index = toRemove[m];
snake[index].destroy();
snake.splice(index, 1);
}
// Award points
var points = toRemove.length * 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Flash effect
LK.effects.flashScreen(0xffffff, 200);
}
return matchFound;
}
// Swipe detection variables
var swipeStartX = 0;
var swipeStartY = 0;
var minSwipeDistance = 50;
var isSwipeStarted = false;
function handleSwipe(startX, startY, endX, endY) {
if (gameOver) return;
if (bombMode) {
return;
}
var deltaX = endX - startX;
var deltaY = endY - startY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if swipe is long enough
if (swipeDistance < minSwipeDistance) return;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (deltaX > 0 && snakeHead.direction.x !== -1) {
// Swipe right
snakeHead.direction = {
x: 1,
y: 0
};
} else if (deltaX < 0 && snakeHead.direction.x !== 1) {
// Swipe left
snakeHead.direction = {
x: -1,
y: 0
};
}
} else {
// Vertical swipe
if (deltaY > 0 && snakeHead.direction.y !== -1) {
// Swipe down
snakeHead.direction = {
x: 0,
y: 1
};
} else if (deltaY < 0 && snakeHead.direction.y !== 1) {
// Swipe up
snakeHead.direction = {
x: 0,
y: -1
};
}
}
}
game.down = function (x, y, obj) {
// Single-click bomb trigger
if (bombMode) {
triggerBomb();
return;
}
swipeStartX = x;
swipeStartY = y;
isSwipeStarted = true;
};
game.up = function (x, y, obj) {
if (isSwipeStarted) {
handleSwipe(swipeStartX, swipeStartY, x, y);
isSwipeStarted = false;
}
};
game.update = function () {
if (gameOver) return;
processBombMovement();
// Process bomb timers
for (var i = bombTimers.length - 1; i >= 0; i--) {
var bombTimer = bombTimers[i];
bombTimer.timeLeft--;
// Visual effect - make bomb fade as time runs out
var fadeAlpha = Math.max(0.3, bombTimer.timeLeft / 300);
bombTimer.pickup.graphics.alpha = fadeAlpha;
// Scale effect to show urgency
var scaleEffect = 1 + (1 - bombTimer.timeLeft / 300) * 0.3;
bombTimer.pickup.graphics.scaleX = scaleEffect;
bombTimer.pickup.graphics.scaleY = scaleEffect;
if (bombTimer.timeLeft <= 0) {
// Remove bomb after 5 seconds
var pickupIndex = pickups.indexOf(bombTimer.pickup);
if (pickupIndex !== -1) {
// Fade out effect
tween(bombTimer.pickup.graphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (pickupIndex !== -1 && pickups[pickupIndex]) {
pickups[pickupIndex].destroy();
pickups.splice(pickupIndex, 1);
spawnRandomPickup();
}
}
});
}
bombTimers.splice(i, 1);
}
}
moveTimer++;
if (moveTimer >= gameSpeed / 16.67) {
moveSnake();
moveTimer = 0;
}
};
// Create playable area border
var playableBorder = new Container();
game.addChild(playableBorder);
// Create border lines for square centered area
var borderTop = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: PLAYABLE_SIZE / 80,
scaleY: 0.05,
tint: 0xFFFFFF
});
borderTop.x = PLAYABLE_START_X;
borderTop.y = PLAYABLE_START_Y;
playableBorder.addChild(borderTop);
var borderBottom = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: PLAYABLE_SIZE / 80,
scaleY: 0.05,
tint: 0xFFFFFF
});
borderBottom.x = PLAYABLE_START_X;
borderBottom.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT;
playableBorder.addChild(borderBottom);
var borderLeft = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: 0.05,
scaleY: PLAYABLE_HEIGHT / 80,
tint: 0xFFFFFF
});
borderLeft.x = PLAYABLE_START_X;
borderLeft.y = PLAYABLE_START_Y;
playableBorder.addChild(borderLeft);
var borderRight = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: 0.05,
scaleY: PLAYABLE_HEIGHT / 80,
tint: 0xFFFFFF
});
borderRight.x = PLAYABLE_START_X + PLAYABLE_SIZE;
borderRight.y = PLAYABLE_START_Y;
playableBorder.addChild(borderRight);
// Initialize the game
initializeGame();
; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Pickup = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isBomb = color === 'bomb';
var assetId = self.isBomb ? 'bombPickup' : 'pickup' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = PLAYABLE_START_X + x * GRID_SIZE + GRID_SIZE / 2;
self.y = y * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
return self;
});
var SnakeHead = Container.expand(function (x, y) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.direction = {
x: 1,
y: 0
};
self.graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = PLAYABLE_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
};
return self;
});
var SnakeSegment = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isHighlighted = false;
var assetId = 'snakeSegment' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = PLAYABLE_START_X + gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2 + PLAYABLE_START_Y;
};
self.highlight = function (highlight) {
self.isHighlighted = highlight;
if (highlight) {
self.graphics.alpha = 0.7;
self.graphics.scaleX = 1.2;
self.graphics.scaleY = 1.2;
} else {
self.graphics.alpha = 1.0;
self.graphics.scaleX = 1.0;
self.graphics.scaleY = 1.0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
var GRID_SIZE = 100;
var UI_HEIGHT = 50; // Minimal height reserved for UI at top
var PLAYABLE_SIZE = 2048; // Full screen width playable area
var PLAYABLE_HEIGHT = 1500; // Keep original square height
var GRID_WIDTH = Math.floor(PLAYABLE_SIZE / GRID_SIZE);
var GRID_HEIGHT = Math.floor(PLAYABLE_HEIGHT / GRID_SIZE);
var PLAYABLE_START_Y = UI_HEIGHT; // Move playable area to just below UI
var PLAYABLE_START_X = 0; // Start at left edge of screen
var SWIPE_AREA_HEIGHT = 2732 - PLAYABLE_START_Y - PLAYABLE_HEIGHT - 100; // Rest for swipe area minus UI space
var snake = [];
var snakeHead = null;
var pickups = [];
var gameSpeed = 150;
var moveTimer = 0;
var colors = ['red', 'yellow', 'blue'];
var nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
var bombMode = false;
var bombIndex = 0;
var bombTimer = 0;
var gameOver = false;
var foodCounter = 0; // Track number of foods eaten
var baseSpeed = 150; // Base game speed
var bombSpawnCounter = 0; // Track number of foods eaten for bomb spawning
var bombTimers = []; // Track active bomb timers
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 50;
scoreTxt.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT + 20;
game.addChild(scoreTxt);
var nextColorTxt = new Text2('Next: Red', {
size: 70,
fill: 0xFFFFFF
});
nextColorTxt.anchor.set(1, 0);
nextColorTxt.x = 2048 - 54;
nextColorTxt.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT + 20;
game.addChild(nextColorTxt);
function initializeGame() {
// Create snake head
snakeHead = new SnakeHead(Math.floor(GRID_WIDTH / 2), Math.floor(GRID_HEIGHT / 2));
game.addChild(snakeHead);
snakeHead.setPosition(snakeHead.gridX, snakeHead.gridY);
// Create initial tail segments
for (var i = 1; i <= 3; i++) {
var color = colors[Math.floor(Math.random() * colors.length)];
var segment = new SnakeSegment(color, snakeHead.gridX - i, snakeHead.gridY);
snake.push(segment);
game.addChild(segment);
segment.setPosition(segment.gridX, segment.gridY);
}
spawnRandomPickup();
updateNextColorDisplay();
}
function spawnRandomPickup() {
var attempts = 0;
var x, y;
do {
x = Math.floor(Math.random() * GRID_WIDTH);
y = Math.floor(Math.random() * GRID_HEIGHT);
attempts++;
} while (isPositionOccupied(x, y) && attempts < 100);
if (attempts < 100) {
// Check if we should spawn a bomb every 5 foods
var shouldSpawnBomb = bombSpawnCounter >= 5;
var isBomb = shouldSpawnBomb;
var color = isBomb ? 'bomb' : nextPickupColor;
var pickup = new Pickup(color, x, y);
pickups.push(pickup);
game.addChild(pickup);
if (isBomb) {
// Reset bomb spawn counter
bombSpawnCounter = 0;
// Start 5 second timer for this bomb
var bombTimer = {
pickup: pickup,
timeLeft: 300 // 5 seconds * 60 FPS
};
bombTimers.push(bombTimer);
} else {
nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
updateNextColorDisplay();
}
}
}
function isPositionOccupied(x, y) {
if (snakeHead.gridX === x && snakeHead.gridY === y) return true;
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === x && snake[i].gridY === y) return true;
}
for (var j = 0; j < pickups.length; j++) {
if (pickups[j].gridX === x && pickups[j].gridY === y) return true;
}
return false;
}
function updateNextColorDisplay() {
nextColorTxt.setText('Next: ' + nextPickupColor.charAt(0).toUpperCase() + nextPickupColor.slice(1));
}
function moveSnake() {
if (gameOver || bombMode) return;
var newX = snakeHead.gridX + snakeHead.direction.x;
var newY = snakeHead.gridY + snakeHead.direction.y;
// Wrap around screen edges
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 for self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
gameOver = true;
LK.showGameOver();
return;
}
}
// Move tail segments
if (snake.length > 0) {
for (var j = snake.length - 1; j > 0; j--) {
snake[j].setPosition(snake[j - 1].gridX, snake[j - 1].gridY);
}
snake[0].setPosition(snakeHead.gridX, snakeHead.gridY);
}
// Move head
snakeHead.setPosition(newX, newY);
// Check for pickup collision
for (var k = pickups.length - 1; k >= 0; k--) {
var pickup = pickups[k];
if (pickup.gridX === newX && pickup.gridY === newY) {
if (pickup.isBomb) {
handleBombPickup();
// Remove bomb timer for this pickup
for (var t = bombTimers.length - 1; t >= 0; t--) {
if (bombTimers[t].pickup === pickup) {
bombTimers.splice(t, 1);
break;
}
}
} else {
handleColorPickup(pickup.color);
}
pickup.destroy();
pickups.splice(k, 1);
spawnRandomPickup();
break;
}
}
checkForMatches();
}
function handleColorPickup(color) {
LK.getSound('collect').play();
// Get the position of the last tail segment, or head if no tail exists
var lastX, lastY;
if (snake.length > 0) {
lastX = snake[snake.length - 1].gridX;
lastY = snake[snake.length - 1].gridY;
} else {
lastX = snakeHead.gridX;
lastY = snakeHead.gridY;
}
var newSegment = new SnakeSegment(color, lastX, lastY);
snake.push(newSegment);
game.addChild(newSegment);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('Score: ' + LK.getScore());
// Increment food counter and check for speed increase
foodCounter++;
bombSpawnCounter++; // Increment bomb spawn counter
if (foodCounter % 5 === 0) {
// Increase speed by reducing gameSpeed (making it 0.05x faster)
gameSpeed = Math.max(30, gameSpeed - gameSpeed * 0.05); // Prevent speed from getting too fast
}
}
function handleBombPickup() {
if (snake.length === 0) return;
LK.getSound('bomb').play();
bombMode = true;
bombIndex = 0;
bombTimer = 0;
// Highlight first segment
snake[bombIndex].highlight(true);
}
function processBombMovement() {
if (!bombMode) return;
bombTimer++;
if (bombTimer >= 30) {
// Move every 30 ticks (0.5 seconds)
snake[bombIndex].highlight(false);
bombIndex++;
if (bombIndex >= snake.length) {
bombIndex = 0;
}
snake[bombIndex].highlight(true);
bombTimer = 0;
}
}
function triggerBomb() {
if (!bombMode || snake.length === 0) return;
snake[bombIndex].highlight(false);
bombMode = false;
// Only remove the specific selected snake segment
var segmentToRemove = snake[bombIndex];
LK.getSound('explode').play();
// Create explosion effect on the selected snake segment
tween(segmentToRemove.graphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut
});
// Immediately remove the segment and close the gap
segmentToRemove.destroy();
snake.splice(bombIndex, 1);
// Immediately reposition all segments after the removed one to close the gap
if (bombIndex < snake.length && snake.length > 0) {
// Get the position of the segment before the removed one (or head if removing first segment)
var previousX, previousY;
if (bombIndex === 0) {
// If we removed the first segment, connect remaining segments to head
previousX = snakeHead.gridX;
previousY = snakeHead.gridY;
} else {
// Connect to the segment before the removed one
previousX = snake[bombIndex - 1].gridX;
previousY = snake[bombIndex - 1].gridY;
}
// Reposition all segments from the removed position onwards
for (var i = bombIndex; i < snake.length; i++) {
if (i === bombIndex) {
// First segment after gap connects to previous position
snake[i].setPosition(previousX, previousY);
} else {
// Subsequent segments connect to the previous segment
snake[i].setPosition(snake[i - 1].gridX, snake[i - 1].gridY);
}
}
}
// Award points
var points = 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Flash effect
LK.effects.flashScreen(0xffffff, 300);
}
function checkForMatches() {
var matchFound = false;
var toRemove = [];
for (var i = 0; i < snake.length - 2; i++) {
var count = 1;
var currentColor = snake[i].color;
for (var j = i + 1; j < snake.length; j++) {
if (snake[j].color === currentColor) {
count++;
} else {
break;
}
}
if (count >= 3) {
for (var k = i; k < i + count; k++) {
toRemove.push(k);
}
matchFound = true;
i += count - 1;
}
}
if (toRemove.length > 0) {
LK.getSound('explode').play();
// Remove matched segments
for (var m = toRemove.length - 1; m >= 0; m--) {
var index = toRemove[m];
snake[index].destroy();
snake.splice(index, 1);
}
// Award points
var points = toRemove.length * 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Flash effect
LK.effects.flashScreen(0xffffff, 200);
}
return matchFound;
}
// Swipe detection variables
var swipeStartX = 0;
var swipeStartY = 0;
var minSwipeDistance = 50;
var isSwipeStarted = false;
function handleSwipe(startX, startY, endX, endY) {
if (gameOver) return;
if (bombMode) {
return;
}
var deltaX = endX - startX;
var deltaY = endY - startY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if swipe is long enough
if (swipeDistance < minSwipeDistance) return;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (deltaX > 0 && snakeHead.direction.x !== -1) {
// Swipe right
snakeHead.direction = {
x: 1,
y: 0
};
} else if (deltaX < 0 && snakeHead.direction.x !== 1) {
// Swipe left
snakeHead.direction = {
x: -1,
y: 0
};
}
} else {
// Vertical swipe
if (deltaY > 0 && snakeHead.direction.y !== -1) {
// Swipe down
snakeHead.direction = {
x: 0,
y: 1
};
} else if (deltaY < 0 && snakeHead.direction.y !== 1) {
// Swipe up
snakeHead.direction = {
x: 0,
y: -1
};
}
}
}
game.down = function (x, y, obj) {
// Single-click bomb trigger
if (bombMode) {
triggerBomb();
return;
}
swipeStartX = x;
swipeStartY = y;
isSwipeStarted = true;
};
game.up = function (x, y, obj) {
if (isSwipeStarted) {
handleSwipe(swipeStartX, swipeStartY, x, y);
isSwipeStarted = false;
}
};
game.update = function () {
if (gameOver) return;
processBombMovement();
// Process bomb timers
for (var i = bombTimers.length - 1; i >= 0; i--) {
var bombTimer = bombTimers[i];
bombTimer.timeLeft--;
// Visual effect - make bomb fade as time runs out
var fadeAlpha = Math.max(0.3, bombTimer.timeLeft / 300);
bombTimer.pickup.graphics.alpha = fadeAlpha;
// Scale effect to show urgency
var scaleEffect = 1 + (1 - bombTimer.timeLeft / 300) * 0.3;
bombTimer.pickup.graphics.scaleX = scaleEffect;
bombTimer.pickup.graphics.scaleY = scaleEffect;
if (bombTimer.timeLeft <= 0) {
// Remove bomb after 5 seconds
var pickupIndex = pickups.indexOf(bombTimer.pickup);
if (pickupIndex !== -1) {
// Fade out effect
tween(bombTimer.pickup.graphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (pickupIndex !== -1 && pickups[pickupIndex]) {
pickups[pickupIndex].destroy();
pickups.splice(pickupIndex, 1);
spawnRandomPickup();
}
}
});
}
bombTimers.splice(i, 1);
}
}
moveTimer++;
if (moveTimer >= gameSpeed / 16.67) {
moveSnake();
moveTimer = 0;
}
};
// Create playable area border
var playableBorder = new Container();
game.addChild(playableBorder);
// Create border lines for square centered area
var borderTop = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: PLAYABLE_SIZE / 80,
scaleY: 0.05,
tint: 0xFFFFFF
});
borderTop.x = PLAYABLE_START_X;
borderTop.y = PLAYABLE_START_Y;
playableBorder.addChild(borderTop);
var borderBottom = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: PLAYABLE_SIZE / 80,
scaleY: 0.05,
tint: 0xFFFFFF
});
borderBottom.x = PLAYABLE_START_X;
borderBottom.y = PLAYABLE_START_Y + PLAYABLE_HEIGHT;
playableBorder.addChild(borderBottom);
var borderLeft = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: 0.05,
scaleY: PLAYABLE_HEIGHT / 80,
tint: 0xFFFFFF
});
borderLeft.x = PLAYABLE_START_X;
borderLeft.y = PLAYABLE_START_Y;
playableBorder.addChild(borderLeft);
var borderRight = LK.getAsset('snakeHead', {
anchorX: 0,
anchorY: 0,
scaleX: 0.05,
scaleY: PLAYABLE_HEIGHT / 80,
tint: 0xFFFFFF
});
borderRight.x = PLAYABLE_START_X + PLAYABLE_SIZE;
borderRight.y = PLAYABLE_START_Y;
playableBorder.addChild(borderRight);
// Initialize the game
initializeGame();
;