/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Food = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.points = 10;
self.update = function () {
self.rotation += 0.05;
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var MovingWall = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.moveDirection = 1;
self.moveSpeed = 1;
self.update = function () {
if (gameMode === 'obstacle') {
self.gridX += self.moveDirection * self.moveSpeed;
if (self.gridX <= 1 || self.gridX >= gridWidth - 2) {
self.moveDirection *= -1;
}
self.x = self.gridX * cellSize + gameOffsetX + cellSize / 2;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
var assetName = type || 'speedBoost';
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.type = type;
self.duration = 5000;
self.update = function () {
self.rotation += 0.08;
self.scaleX = 1.2 + Math.sin(LK.ticks * 0.15) * 0.2;
self.scaleY = 1.2 + Math.sin(LK.ticks * 0.15) * 0.2;
};
return self;
});
var SnakeHead = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
return self;
});
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Game constants
var gridWidth = 25;
var gridHeight = 35;
var cellSize = 70;
var gameOffsetX = (2048 - gridWidth * cellSize) / 2;
var gameOffsetY = 200;
// Game state variables
var gameMode = 'classic';
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var foods = [];
var powerUps = [];
var walls = [];
var gameSpeed = 200;
var baseSpeed = 200;
var lastMoveTime = 0;
var isGameRunning = false;
var currentScore = 0;
var timeLeft = 60;
var gameStartTime = 0;
// Power-up states
var speedBoostActive = false;
var speedBoostEndTime = 0;
var ghostModeActive = false;
var ghostModeEndTime = 0;
var scoreMultiplierActive = false;
var scoreMultiplierEndTime = 0;
var multiplierValue = 1;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 60;
var modeTxt = new Text2('Classic Mode', {
size: 60,
fill: 0x00FF00
});
modeTxt.anchor.set(0, 0);
modeTxt.x = 150;
modeTxt.y = 150;
game.addChild(modeTxt);
var timeTxt = new Text2('', {
size: 60,
fill: 0xFFFF00
});
timeTxt.anchor.set(1, 0);
timeTxt.x = 1900;
timeTxt.y = 150;
game.addChild(timeTxt);
var powerUpTxt = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
powerUpTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(powerUpTxt);
powerUpTxt.y = 140;
// Game mode selection UI
var classicBtn = new Text2('Classic', {
size: 70,
fill: 0x00FF00
});
classicBtn.anchor.set(0.5, 0.5);
classicBtn.x = 2048 / 2 - 300;
classicBtn.y = 2732 / 2 - 200;
classicBtn.interactive = true;
game.addChild(classicBtn);
var timeAttackBtn = new Text2('Time Attack', {
size: 70,
fill: 0xFFFF00
});
timeAttackBtn.anchor.set(0.5, 0.5);
timeAttackBtn.x = 2048 / 2;
timeAttackBtn.y = 2732 / 2 - 200;
timeAttackBtn.interactive = true;
game.addChild(timeAttackBtn);
var obstacleBtn = new Text2('Obstacle', {
size: 70,
fill: 0xFF8800
});
obstacleBtn.anchor.set(0.5, 0.5);
obstacleBtn.x = 2048 / 2 + 300;
obstacleBtn.y = 2732 / 2 - 200;
obstacleBtn.interactive = true;
game.addChild(obstacleBtn);
var startBtn = new Text2('START GAME', {
size: 100,
fill: 0xFFFFFF
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = 2048 / 2;
startBtn.y = 2732 / 2;
startBtn.interactive = true;
game.addChild(startBtn);
// Touch controls
var lastTouchX = 0;
var lastTouchY = 0;
var minSwipeDistance = 50;
function initializeGame() {
// Clear existing game objects
for (var i = snake.length - 1; i >= 0; i--) {
snake[i].destroy();
}
snake = [];
for (var i = foods.length - 1; i >= 0; i--) {
foods[i].destroy();
}
foods = [];
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
powerUps = [];
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
// Reset game state
snakeDirection = {
x: 1,
y: 0
};
nextDirection = {
x: 1,
y: 0
};
gameSpeed = baseSpeed;
currentScore = 0;
LK.setScore(0);
timeLeft = 60;
gameStartTime = Date.now();
// Reset power-ups
speedBoostActive = false;
ghostModeActive = false;
scoreMultiplierActive = false;
multiplierValue = 1;
// Create initial snake
var head = new SnakeHead();
head.gridX = 12;
head.gridY = 17;
head.x = head.gridX * cellSize + gameOffsetX + cellSize / 2;
head.y = head.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(head);
snake.push(head);
for (var i = 1; i < 3; i++) {
var segment = new SnakeSegment();
segment.gridX = 12 - i;
segment.gridY = 17;
segment.x = segment.gridX * cellSize + gameOffsetX + cellSize / 2;
segment.y = segment.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(segment);
snake.push(segment);
}
// Create initial food
spawnFood();
// Create walls for obstacle mode
if (gameMode === 'obstacle') {
createObstacles();
}
// Hide menu UI
classicBtn.visible = false;
timeAttackBtn.visible = false;
obstacleBtn.visible = false;
startBtn.visible = false;
// Update mode text
if (gameMode === 'classic') {
modeTxt.setText('Classic Mode');
modeTxt.tint = 0x00ff00;
} else if (gameMode === 'timeAttack') {
modeTxt.setText('Time Attack');
modeTxt.tint = 0xffff00;
} else if (gameMode === 'obstacle') {
modeTxt.setText('Obstacle Course');
modeTxt.tint = 0xff8800;
}
isGameRunning = true;
lastMoveTime = Date.now();
LK.playMusic('bgmusic');
}
function spawnFood() {
var food = new Food();
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 100) {
food.gridX = Math.floor(Math.random() * gridWidth);
food.gridY = Math.floor(Math.random() * gridHeight);
validPosition = true;
// Check collision with snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === food.gridX && snake[i].gridY === food.gridY) {
validPosition = false;
break;
}
}
// Check collision with walls
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === food.gridX && walls[i].gridY === food.gridY) {
validPosition = false;
break;
}
}
attempts++;
}
food.x = food.gridX * cellSize + gameOffsetX + cellSize / 2;
food.y = food.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(food);
foods.push(food);
}
function spawnPowerUp() {
if (powerUps.length >= 2) return;
var types = ['speedBoost', 'ghostMode', 'scoreMultiplier'];
var type = types[Math.floor(Math.random() * types.length)];
var powerUp = new PowerUp(type);
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 100) {
powerUp.gridX = Math.floor(Math.random() * gridWidth);
powerUp.gridY = Math.floor(Math.random() * gridHeight);
validPosition = true;
// Check collision with snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === powerUp.gridX && snake[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
// Check collision with food
for (var i = 0; i < foods.length; i++) {
if (foods[i].gridX === powerUp.gridX && foods[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
// Check collision with walls
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === powerUp.gridX && walls[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
attempts++;
}
powerUp.x = powerUp.gridX * cellSize + gameOffsetX + cellSize / 2;
powerUp.y = powerUp.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(powerUp);
powerUps.push(powerUp);
}
function createObstacles() {
// Create moving walls
for (var i = 0; i < 3; i++) {
var wall = new MovingWall();
wall.gridX = 5 + i * 7;
wall.gridY = 10 + i * 8;
wall.x = wall.gridX * cellSize + gameOffsetX + cellSize / 2;
wall.y = wall.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(wall);
walls.push(wall);
}
}
function activatePowerUp(type) {
var currentTime = Date.now();
if (type === 'speedBoost') {
speedBoostActive = true;
speedBoostEndTime = currentTime + 5000;
gameSpeed = baseSpeed * 0.5;
} else if (type === 'ghostMode') {
ghostModeActive = true;
ghostModeEndTime = currentTime + 3000;
// Make snake semi-transparent
for (var i = 0; i < snake.length; i++) {
snake[i].alpha = 0.5;
}
} else if (type === 'scoreMultiplier') {
scoreMultiplierActive = true;
scoreMultiplierEndTime = currentTime + 8000;
multiplierValue = 2;
}
LK.getSound('powerup').play();
LK.effects.flashScreen(0x00ff00, 200);
}
function updatePowerUps() {
var currentTime = Date.now();
if (speedBoostActive && currentTime > speedBoostEndTime) {
speedBoostActive = false;
gameSpeed = Math.max(baseSpeed - Math.floor(currentScore / 100) * 20, 50);
}
if (ghostModeActive && currentTime > ghostModeEndTime) {
ghostModeActive = false;
for (var i = 0; i < snake.length; i++) {
snake[i].alpha = 1;
}
}
if (scoreMultiplierActive && currentTime > scoreMultiplierEndTime) {
scoreMultiplierActive = false;
multiplierValue = 1;
}
// Update power-up display
var powerUpText = '';
if (speedBoostActive) powerUpText += 'SPEED BOOST ';
if (ghostModeActive) powerUpText += 'GHOST MODE ';
if (scoreMultiplierActive) powerUpText += 'x2 MULTIPLIER ';
powerUpTxt.setText(powerUpText);
}
function moveSnake() {
if (!isGameRunning) return;
var currentTime = Date.now();
if (currentTime - lastMoveTime < gameSpeed) return;
snakeDirection = {
x: nextDirection.x,
y: nextDirection.y
};
var head = snake[0];
var newX = head.gridX + snakeDirection.x;
var newY = head.gridY + snakeDirection.y;
// Check wall collision (unless in ghost mode)
if (!ghostModeActive) {
if (newX < 0 || newX >= gridWidth || newY < 0 || newY >= gridHeight) {
gameOver();
return;
}
} else {
// Wrap around in ghost mode
if (newX < 0) newX = gridWidth - 1;
if (newX >= gridWidth) newX = 0;
if (newY < 0) newY = gridHeight - 1;
if (newY >= gridHeight) newY = 0;
}
// Check self collision (unless in ghost mode)
if (!ghostModeActive) {
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
gameOver();
return;
}
}
}
// Check wall obstacle collision
if (!ghostModeActive) {
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === newX && walls[i].gridY === newY) {
gameOver();
return;
}
}
}
var shouldGrow = false;
// Check food collision
for (var i = foods.length - 1; i >= 0; i--) {
if (foods[i].gridX === newX && foods[i].gridY === newY) {
var points = foods[i].points * multiplierValue;
currentScore += points;
LK.setScore(currentScore);
scoreTxt.setText('Score: ' + currentScore);
foods[i].destroy();
foods.splice(i, 1);
shouldGrow = true;
LK.getSound('eat').play();
spawnFood();
// Spawn power-ups occasionally
if (Math.random() < 0.2) {
spawnPowerUp();
}
// Increase difficulty in classic mode
if (gameMode === 'classic') {
gameSpeed = Math.max(baseSpeed - Math.floor(currentScore / 100) * 20, 50);
}
break;
}
}
// Check power-up collision
for (var i = powerUps.length - 1; i >= 0; i--) {
if (powerUps[i].gridX === newX && powerUps[i].gridY === newY) {
activatePowerUp(powerUps[i].type);
powerUps[i].destroy();
powerUps.splice(i, 1);
break;
}
}
// Move snake
if (!shouldGrow) {
var tail = snake.pop();
tail.gridX = newX;
tail.gridY = newY;
tail.x = tail.gridX * cellSize + gameOffsetX + cellSize / 2;
tail.y = tail.gridY * cellSize + gameOffsetY + cellSize / 2;
snake.unshift(tail);
} else {
var newHead = new SnakeHead();
newHead.gridX = newX;
newHead.gridY = newY;
newHead.x = newHead.gridX * cellSize + gameOffsetX + cellSize / 2;
newHead.y = newHead.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(newHead);
snake.unshift(newHead);
// Convert old head to body segment
var oldHead = snake[1];
oldHead.removeChild(oldHead.children[0]);
var bodyGraphics = oldHead.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
}
lastMoveTime = currentTime;
}
function gameOver() {
isGameRunning = false;
LK.getSound('collision').play();
LK.effects.flashScreen(0xff0000, 1000);
// Save high score
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
LK.showGameOver();
}
function handleSwipe(deltaX, deltaY) {
if (!isGameRunning) return;
var absX = Math.abs(deltaX);
var absY = Math.abs(deltaY);
if (absX > absY) {
// Horizontal swipe
if (deltaX > 0 && snakeDirection.x !== -1) {
nextDirection = {
x: 1,
y: 0
}; // Right
} else if (deltaX < 0 && snakeDirection.x !== 1) {
nextDirection = {
x: -1,
y: 0
}; // Left
}
} else {
// Vertical swipe
if (deltaY > 0 && snakeDirection.y !== -1) {
nextDirection = {
x: 0,
y: 1
}; // Down
} else if (deltaY < 0 && snakeDirection.y !== 1) {
nextDirection = {
x: 0,
y: -1
}; // Up
}
}
}
// Button event handlers
classicBtn.down = function (x, y, obj) {
gameMode = 'classic';
baseSpeed = 200;
classicBtn.tint = 0x00ff00;
timeAttackBtn.tint = 0xffffff;
obstacleBtn.tint = 0xffffff;
};
timeAttackBtn.down = function (x, y, obj) {
gameMode = 'timeAttack';
baseSpeed = 150;
classicBtn.tint = 0xffffff;
timeAttackBtn.tint = 0xffff00;
obstacleBtn.tint = 0xffffff;
};
obstacleBtn.down = function (x, y, obj) {
gameMode = 'obstacle';
baseSpeed = 180;
classicBtn.tint = 0xffffff;
timeAttackBtn.tint = 0xffffff;
obstacleBtn.tint = 0xff8800;
};
startBtn.down = function (x, y, obj) {
initializeGame();
};
game.down = function (x, y, obj) {
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > minSwipeDistance) {
handleSwipe(deltaX, deltaY);
}
};
game.update = function () {
if (isGameRunning) {
moveSnake();
updatePowerUps();
// Update time for time attack mode
if (gameMode === 'timeAttack') {
var currentTime = Date.now();
timeLeft = Math.max(0, 60 - Math.floor((currentTime - gameStartTime) / 1000));
timeTxt.setText('Time: ' + timeLeft);
if (timeLeft <= 0) {
isGameRunning = false;
LK.showGameOver();
}
// Spawn food more frequently in time attack
if (LK.ticks % 120 === 0) {
spawnFood();
}
}
// Spawn power-ups occasionally
if (LK.ticks % 600 === 0 && Math.random() < 0.3) {
spawnPowerUp();
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Food = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.points = 10;
self.update = function () {
self.rotation += 0.05;
self.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
self.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.1;
};
return self;
});
var MovingWall = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.moveDirection = 1;
self.moveSpeed = 1;
self.update = function () {
if (gameMode === 'obstacle') {
self.gridX += self.moveDirection * self.moveSpeed;
if (self.gridX <= 1 || self.gridX >= gridWidth - 2) {
self.moveDirection *= -1;
}
self.x = self.gridX * cellSize + gameOffsetX + cellSize / 2;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
var assetName = type || 'speedBoost';
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.type = type;
self.duration = 5000;
self.update = function () {
self.rotation += 0.08;
self.scaleX = 1.2 + Math.sin(LK.ticks * 0.15) * 0.2;
self.scaleY = 1.2 + Math.sin(LK.ticks * 0.15) * 0.2;
};
return self;
});
var SnakeHead = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
return self;
});
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Game constants
var gridWidth = 25;
var gridHeight = 35;
var cellSize = 70;
var gameOffsetX = (2048 - gridWidth * cellSize) / 2;
var gameOffsetY = 200;
// Game state variables
var gameMode = 'classic';
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var foods = [];
var powerUps = [];
var walls = [];
var gameSpeed = 200;
var baseSpeed = 200;
var lastMoveTime = 0;
var isGameRunning = false;
var currentScore = 0;
var timeLeft = 60;
var gameStartTime = 0;
// Power-up states
var speedBoostActive = false;
var speedBoostEndTime = 0;
var ghostModeActive = false;
var ghostModeEndTime = 0;
var scoreMultiplierActive = false;
var scoreMultiplierEndTime = 0;
var multiplierValue = 1;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 60;
var modeTxt = new Text2('Classic Mode', {
size: 60,
fill: 0x00FF00
});
modeTxt.anchor.set(0, 0);
modeTxt.x = 150;
modeTxt.y = 150;
game.addChild(modeTxt);
var timeTxt = new Text2('', {
size: 60,
fill: 0xFFFF00
});
timeTxt.anchor.set(1, 0);
timeTxt.x = 1900;
timeTxt.y = 150;
game.addChild(timeTxt);
var powerUpTxt = new Text2('', {
size: 50,
fill: 0xFFFFFF
});
powerUpTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(powerUpTxt);
powerUpTxt.y = 140;
// Game mode selection UI
var classicBtn = new Text2('Classic', {
size: 70,
fill: 0x00FF00
});
classicBtn.anchor.set(0.5, 0.5);
classicBtn.x = 2048 / 2 - 300;
classicBtn.y = 2732 / 2 - 200;
classicBtn.interactive = true;
game.addChild(classicBtn);
var timeAttackBtn = new Text2('Time Attack', {
size: 70,
fill: 0xFFFF00
});
timeAttackBtn.anchor.set(0.5, 0.5);
timeAttackBtn.x = 2048 / 2;
timeAttackBtn.y = 2732 / 2 - 200;
timeAttackBtn.interactive = true;
game.addChild(timeAttackBtn);
var obstacleBtn = new Text2('Obstacle', {
size: 70,
fill: 0xFF8800
});
obstacleBtn.anchor.set(0.5, 0.5);
obstacleBtn.x = 2048 / 2 + 300;
obstacleBtn.y = 2732 / 2 - 200;
obstacleBtn.interactive = true;
game.addChild(obstacleBtn);
var startBtn = new Text2('START GAME', {
size: 100,
fill: 0xFFFFFF
});
startBtn.anchor.set(0.5, 0.5);
startBtn.x = 2048 / 2;
startBtn.y = 2732 / 2;
startBtn.interactive = true;
game.addChild(startBtn);
// Touch controls
var lastTouchX = 0;
var lastTouchY = 0;
var minSwipeDistance = 50;
function initializeGame() {
// Clear existing game objects
for (var i = snake.length - 1; i >= 0; i--) {
snake[i].destroy();
}
snake = [];
for (var i = foods.length - 1; i >= 0; i--) {
foods[i].destroy();
}
foods = [];
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].destroy();
}
powerUps = [];
for (var i = walls.length - 1; i >= 0; i--) {
walls[i].destroy();
}
walls = [];
// Reset game state
snakeDirection = {
x: 1,
y: 0
};
nextDirection = {
x: 1,
y: 0
};
gameSpeed = baseSpeed;
currentScore = 0;
LK.setScore(0);
timeLeft = 60;
gameStartTime = Date.now();
// Reset power-ups
speedBoostActive = false;
ghostModeActive = false;
scoreMultiplierActive = false;
multiplierValue = 1;
// Create initial snake
var head = new SnakeHead();
head.gridX = 12;
head.gridY = 17;
head.x = head.gridX * cellSize + gameOffsetX + cellSize / 2;
head.y = head.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(head);
snake.push(head);
for (var i = 1; i < 3; i++) {
var segment = new SnakeSegment();
segment.gridX = 12 - i;
segment.gridY = 17;
segment.x = segment.gridX * cellSize + gameOffsetX + cellSize / 2;
segment.y = segment.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(segment);
snake.push(segment);
}
// Create initial food
spawnFood();
// Create walls for obstacle mode
if (gameMode === 'obstacle') {
createObstacles();
}
// Hide menu UI
classicBtn.visible = false;
timeAttackBtn.visible = false;
obstacleBtn.visible = false;
startBtn.visible = false;
// Update mode text
if (gameMode === 'classic') {
modeTxt.setText('Classic Mode');
modeTxt.tint = 0x00ff00;
} else if (gameMode === 'timeAttack') {
modeTxt.setText('Time Attack');
modeTxt.tint = 0xffff00;
} else if (gameMode === 'obstacle') {
modeTxt.setText('Obstacle Course');
modeTxt.tint = 0xff8800;
}
isGameRunning = true;
lastMoveTime = Date.now();
LK.playMusic('bgmusic');
}
function spawnFood() {
var food = new Food();
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 100) {
food.gridX = Math.floor(Math.random() * gridWidth);
food.gridY = Math.floor(Math.random() * gridHeight);
validPosition = true;
// Check collision with snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === food.gridX && snake[i].gridY === food.gridY) {
validPosition = false;
break;
}
}
// Check collision with walls
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === food.gridX && walls[i].gridY === food.gridY) {
validPosition = false;
break;
}
}
attempts++;
}
food.x = food.gridX * cellSize + gameOffsetX + cellSize / 2;
food.y = food.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(food);
foods.push(food);
}
function spawnPowerUp() {
if (powerUps.length >= 2) return;
var types = ['speedBoost', 'ghostMode', 'scoreMultiplier'];
var type = types[Math.floor(Math.random() * types.length)];
var powerUp = new PowerUp(type);
var validPosition = false;
var attempts = 0;
while (!validPosition && attempts < 100) {
powerUp.gridX = Math.floor(Math.random() * gridWidth);
powerUp.gridY = Math.floor(Math.random() * gridHeight);
validPosition = true;
// Check collision with snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === powerUp.gridX && snake[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
// Check collision with food
for (var i = 0; i < foods.length; i++) {
if (foods[i].gridX === powerUp.gridX && foods[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
// Check collision with walls
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === powerUp.gridX && walls[i].gridY === powerUp.gridY) {
validPosition = false;
break;
}
}
attempts++;
}
powerUp.x = powerUp.gridX * cellSize + gameOffsetX + cellSize / 2;
powerUp.y = powerUp.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(powerUp);
powerUps.push(powerUp);
}
function createObstacles() {
// Create moving walls
for (var i = 0; i < 3; i++) {
var wall = new MovingWall();
wall.gridX = 5 + i * 7;
wall.gridY = 10 + i * 8;
wall.x = wall.gridX * cellSize + gameOffsetX + cellSize / 2;
wall.y = wall.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(wall);
walls.push(wall);
}
}
function activatePowerUp(type) {
var currentTime = Date.now();
if (type === 'speedBoost') {
speedBoostActive = true;
speedBoostEndTime = currentTime + 5000;
gameSpeed = baseSpeed * 0.5;
} else if (type === 'ghostMode') {
ghostModeActive = true;
ghostModeEndTime = currentTime + 3000;
// Make snake semi-transparent
for (var i = 0; i < snake.length; i++) {
snake[i].alpha = 0.5;
}
} else if (type === 'scoreMultiplier') {
scoreMultiplierActive = true;
scoreMultiplierEndTime = currentTime + 8000;
multiplierValue = 2;
}
LK.getSound('powerup').play();
LK.effects.flashScreen(0x00ff00, 200);
}
function updatePowerUps() {
var currentTime = Date.now();
if (speedBoostActive && currentTime > speedBoostEndTime) {
speedBoostActive = false;
gameSpeed = Math.max(baseSpeed - Math.floor(currentScore / 100) * 20, 50);
}
if (ghostModeActive && currentTime > ghostModeEndTime) {
ghostModeActive = false;
for (var i = 0; i < snake.length; i++) {
snake[i].alpha = 1;
}
}
if (scoreMultiplierActive && currentTime > scoreMultiplierEndTime) {
scoreMultiplierActive = false;
multiplierValue = 1;
}
// Update power-up display
var powerUpText = '';
if (speedBoostActive) powerUpText += 'SPEED BOOST ';
if (ghostModeActive) powerUpText += 'GHOST MODE ';
if (scoreMultiplierActive) powerUpText += 'x2 MULTIPLIER ';
powerUpTxt.setText(powerUpText);
}
function moveSnake() {
if (!isGameRunning) return;
var currentTime = Date.now();
if (currentTime - lastMoveTime < gameSpeed) return;
snakeDirection = {
x: nextDirection.x,
y: nextDirection.y
};
var head = snake[0];
var newX = head.gridX + snakeDirection.x;
var newY = head.gridY + snakeDirection.y;
// Check wall collision (unless in ghost mode)
if (!ghostModeActive) {
if (newX < 0 || newX >= gridWidth || newY < 0 || newY >= gridHeight) {
gameOver();
return;
}
} else {
// Wrap around in ghost mode
if (newX < 0) newX = gridWidth - 1;
if (newX >= gridWidth) newX = 0;
if (newY < 0) newY = gridHeight - 1;
if (newY >= gridHeight) newY = 0;
}
// Check self collision (unless in ghost mode)
if (!ghostModeActive) {
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
gameOver();
return;
}
}
}
// Check wall obstacle collision
if (!ghostModeActive) {
for (var i = 0; i < walls.length; i++) {
if (walls[i].gridX === newX && walls[i].gridY === newY) {
gameOver();
return;
}
}
}
var shouldGrow = false;
// Check food collision
for (var i = foods.length - 1; i >= 0; i--) {
if (foods[i].gridX === newX && foods[i].gridY === newY) {
var points = foods[i].points * multiplierValue;
currentScore += points;
LK.setScore(currentScore);
scoreTxt.setText('Score: ' + currentScore);
foods[i].destroy();
foods.splice(i, 1);
shouldGrow = true;
LK.getSound('eat').play();
spawnFood();
// Spawn power-ups occasionally
if (Math.random() < 0.2) {
spawnPowerUp();
}
// Increase difficulty in classic mode
if (gameMode === 'classic') {
gameSpeed = Math.max(baseSpeed - Math.floor(currentScore / 100) * 20, 50);
}
break;
}
}
// Check power-up collision
for (var i = powerUps.length - 1; i >= 0; i--) {
if (powerUps[i].gridX === newX && powerUps[i].gridY === newY) {
activatePowerUp(powerUps[i].type);
powerUps[i].destroy();
powerUps.splice(i, 1);
break;
}
}
// Move snake
if (!shouldGrow) {
var tail = snake.pop();
tail.gridX = newX;
tail.gridY = newY;
tail.x = tail.gridX * cellSize + gameOffsetX + cellSize / 2;
tail.y = tail.gridY * cellSize + gameOffsetY + cellSize / 2;
snake.unshift(tail);
} else {
var newHead = new SnakeHead();
newHead.gridX = newX;
newHead.gridY = newY;
newHead.x = newHead.gridX * cellSize + gameOffsetX + cellSize / 2;
newHead.y = newHead.gridY * cellSize + gameOffsetY + cellSize / 2;
game.addChild(newHead);
snake.unshift(newHead);
// Convert old head to body segment
var oldHead = snake[1];
oldHead.removeChild(oldHead.children[0]);
var bodyGraphics = oldHead.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
}
lastMoveTime = currentTime;
}
function gameOver() {
isGameRunning = false;
LK.getSound('collision').play();
LK.effects.flashScreen(0xff0000, 1000);
// Save high score
var highScore = storage.highScore || 0;
if (currentScore > highScore) {
storage.highScore = currentScore;
}
LK.showGameOver();
}
function handleSwipe(deltaX, deltaY) {
if (!isGameRunning) return;
var absX = Math.abs(deltaX);
var absY = Math.abs(deltaY);
if (absX > absY) {
// Horizontal swipe
if (deltaX > 0 && snakeDirection.x !== -1) {
nextDirection = {
x: 1,
y: 0
}; // Right
} else if (deltaX < 0 && snakeDirection.x !== 1) {
nextDirection = {
x: -1,
y: 0
}; // Left
}
} else {
// Vertical swipe
if (deltaY > 0 && snakeDirection.y !== -1) {
nextDirection = {
x: 0,
y: 1
}; // Down
} else if (deltaY < 0 && snakeDirection.y !== 1) {
nextDirection = {
x: 0,
y: -1
}; // Up
}
}
}
// Button event handlers
classicBtn.down = function (x, y, obj) {
gameMode = 'classic';
baseSpeed = 200;
classicBtn.tint = 0x00ff00;
timeAttackBtn.tint = 0xffffff;
obstacleBtn.tint = 0xffffff;
};
timeAttackBtn.down = function (x, y, obj) {
gameMode = 'timeAttack';
baseSpeed = 150;
classicBtn.tint = 0xffffff;
timeAttackBtn.tint = 0xffff00;
obstacleBtn.tint = 0xffffff;
};
obstacleBtn.down = function (x, y, obj) {
gameMode = 'obstacle';
baseSpeed = 180;
classicBtn.tint = 0xffffff;
timeAttackBtn.tint = 0xffffff;
obstacleBtn.tint = 0xff8800;
};
startBtn.down = function (x, y, obj) {
initializeGame();
};
game.down = function (x, y, obj) {
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > minSwipeDistance) {
handleSwipe(deltaX, deltaY);
}
};
game.update = function () {
if (isGameRunning) {
moveSnake();
updatePowerUps();
// Update time for time attack mode
if (gameMode === 'timeAttack') {
var currentTime = Date.now();
timeLeft = Math.max(0, 60 - Math.floor((currentTime - gameStartTime) / 1000));
timeTxt.setText('Time: ' + timeLeft);
if (timeLeft <= 0) {
isGameRunning = false;
LK.showGameOver();
}
// Spawn food more frequently in time attack
if (LK.ticks % 120 === 0) {
spawnFood();
}
}
// Spawn power-ups occasionally
if (LK.ticks % 600 === 0 && Math.random() < 0.3) {
spawnPowerUp();
}
}
};