/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CartoonBoy = Container.expand(function () {
var self = Container.call(this);
// Character body
var body = self.attachAsset('characterBody', {
anchorX: 0.5,
anchorY: 1
});
// Character head
var head = self.attachAsset('characterHead', {
anchorX: 0.5,
anchorY: 1,
y: -100
});
// Eyes
var leftEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: -115
});
var rightEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 12,
y: -115
});
// Mouth
var mouth = self.attachAsset('characterMouth', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleY: 0.4
});
// Speech bubble
var speechBubble = self.attachAsset('speechBubble', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -180,
alpha: 0
});
// Speech text
var speechText = new Text2('', {
size: 24,
fill: 0x2c3e50
});
speechText.anchor.set(0.5, 0.5);
speechText.x = 0;
speechText.y = -180;
self.addChild(speechText);
self.speak = function (message) {
speechText.setText(message);
tween(speechBubble, {
alpha: 1
}, {
duration: 300
});
tween(speechText, {
alpha: 1
}, {
duration: 300
});
// Animate character excitement
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
yoyo: true,
repeat: 1
});
};
self.hideSpeech = function () {
tween(speechBubble, {
alpha: 0
}, {
duration: 300
});
tween(speechText, {
alpha: 0
}, {
duration: 300
});
};
return self;
});
var CartoonKid = Container.expand(function (bodyAsset, headAsset) {
var self = Container.call(this);
// Character body
var body = self.attachAsset(bodyAsset || 'characterBody2', {
anchorX: 0.5,
anchorY: 1
});
// Character head
var head = self.attachAsset(headAsset || 'characterHead2', {
anchorX: 0.5,
anchorY: 1,
y: -100
});
// Eyes
var leftEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: -115
});
var rightEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 12,
y: -115
});
// Mouth
var mouth = self.attachAsset('characterMouth', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleY: 0.4
});
self.cheer = function () {
// Jump animation
tween(self, {
y: self.y - 50
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 50
}, {
duration: 300,
easing: tween.bounceOut
});
}
});
// Scale animation for excitement
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Arm wave simulation by scaling
tween(head, {
rotation: 0.2
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(head, {
rotation: -0.2
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(head, {
rotation: 0
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
}
});
};
return self;
});
var Cell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.state = 0; // 0 = empty, 1 = X, 2 = O
self.isHighlighted = false;
var cellBackground = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
var cellHighlight = self.attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
var symbol = null;
self.highlight = function () {
if (!self.isHighlighted) {
self.isHighlighted = true;
tween(cellHighlight, {
alpha: 1
}, {
duration: 200
});
}
};
self.unhighlight = function () {
if (self.isHighlighted) {
self.isHighlighted = false;
tween(cellHighlight, {
alpha: 0
}, {
duration: 200
});
}
};
self.placeSymbol = function (player) {
if (self.state !== 0) return false;
self.state = player;
if (player === 1) {
var xContainer = new Container();
var xLine1 = LK.getAsset('xShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 0.25
});
var xLine2 = LK.getAsset('xShape2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 0.25
});
xContainer.addChild(xLine1);
xContainer.addChild(xLine2);
symbol = xContainer;
self.addChild(symbol);
tween(xLine1, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut
});
tween(xLine2, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut,
delay: 100
});
} else {
symbol = self.attachAsset('oShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0
});
tween(symbol, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut
});
}
LK.getSound('place').play();
return true;
};
self.down = function (x, y, obj) {
if (self.state === 0) {
self.highlight();
}
};
self.up = function (x, y, obj) {
self.unhighlight();
if (self.state === 0 && gameState === 'playing') {
if (self.placeSymbol(currentPlayer)) {
checkWin();
if (gameState === 'playing') {
switchPlayer();
}
}
}
};
return self;
});
var SnakeFood = Container.expand(function () {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
var food = self.attachAsset('snakeFood', {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
self.pulse = function () {
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
};
return self;
});
var SnakeSegment = Container.expand(function (isHead) {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.lastGridX = 0;
self.lastGridY = 0;
var segment = self.attachAsset(isHead ? 'snakeHead' : 'snakeSegment', {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.lastGridX = self.gridX;
self.lastGridY = self.gridY;
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
return self;
});
var TetrisBlock = Container.expand(function (color) {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.color = color || 0x3498db;
var block = self.attachAsset('tetrisBlock', {
anchorX: 0.5,
anchorY: 0.5
});
block.tint = self.color;
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
self.flash = function () {
tween(self, {
alpha: 0.3
}, {
duration: 100,
yoyo: true,
repeat: 3
});
};
return self;
});
var TetrisPiece = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'I';
self.rotation = 0;
self.gridX = 0;
self.gridY = 0;
self.blocks = [];
var shapes = {
I: [[1, 1, 1, 1]],
O: [[1, 1], [1, 1]],
T: [[0, 1, 0], [1, 1, 1]],
S: [[0, 1, 1], [1, 1, 0]],
Z: [[1, 1, 0], [0, 1, 1]],
J: [[1, 0, 0], [1, 1, 1]],
L: [[0, 0, 1], [1, 1, 1]]
};
var colors = {
I: 0x00f5ff,
O: 0xffff00,
T: 0x800080,
S: 0x00ff00,
Z: 0xff0000,
J: 0x0000ff,
L: 0xffa500
};
self.createBlocks = function () {
// Clear existing blocks
for (var i = 0; i < self.blocks.length; i++) {
self.blocks[i].destroy();
}
self.blocks = [];
var shape = shapes[self.type];
var color = colors[self.type];
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var block = new TetrisBlock(color);
block.setGridPosition(col, row);
self.addChild(block);
self.blocks.push(block);
}
}
}
};
self.getShape = function () {
return shapes[self.type];
};
self.rotate = function () {
var shape = shapes[self.type];
var newShape = [];
var rows = shape.length;
var cols = shape[0].length;
for (var col = 0; col < cols; col++) {
newShape[col] = [];
for (var row = rows - 1; row >= 0; row--) {
newShape[col][cols - 1 - row] = shape[row][col];
}
}
shapes[self.type] = newShape;
self.createBlocks();
};
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40;
self.y = gridY * 40;
};
self.createBlocks();
return self;
});
var WinLine = Container.expand(function () {
var self = Container.call(this);
var line = self.attachAsset('winLine', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
alpha: 0
});
self.showWinLine = function (startX, startY, endX, endY) {
self.x = (startX + endX) / 2;
self.y = (startY + endY) / 2;
var dx = endX - startX;
var dy = endY - startY;
var angle = Math.atan2(dy, dx);
var distance = Math.sqrt(dx * dx + dy * dy);
line.rotation = angle;
line.width = distance;
tween(self, {
alpha: 1
}, {
duration: 300
});
tween(line, {
scaleX: 1
}, {
duration: 500,
easing: tween.easeOut
});
LK.getSound('win').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x74b9ff
});
/****
* Game Code
****/
var cells = [];
var currentPlayer = 1; // 1 = X, 2 = O
var gameState = 'playing'; // 'playing', 'win', 'tie'
var winLine = null;
// Create grid
var gridContainer = new Container();
game.addChild(gridContainer);
// Position grid in center
gridContainer.x = 2048 / 2;
gridContainer.y = 2732 / 2;
// Create grid lines
var verticalLine1 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
y: 0
});
gridContainer.addChild(verticalLine1);
var verticalLine2 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: 0
});
gridContainer.addChild(verticalLine2);
var horizontalLine1 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
rotation: Math.PI / 2
});
gridContainer.addChild(horizontalLine1);
var horizontalLine2 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 100,
rotation: Math.PI / 2
});
gridContainer.addChild(horizontalLine2);
// Create cells
for (var row = 0; row < 3; row++) {
cells[row] = [];
for (var col = 0; col < 3; col++) {
var cell = new Cell(row, col);
cell.x = (col - 1) * 200;
cell.y = (row - 1) * 200;
gridContainer.addChild(cell);
cells[row][col] = cell;
}
}
// Create turn indicator
var turnText = new Text2('X\'s Turn', {
size: 80,
fill: 0x333333
});
turnText.anchor.set(0.5, 0.5);
turnText.x = 2048 / 2;
turnText.y = 500;
game.addChild(turnText);
// Create cartoon character
var cartoonBoy = new CartoonBoy();
cartoonBoy.x = 2048 / 2;
cartoonBoy.y = 2400;
game.addChild(cartoonBoy);
// Create additional cartoon kids
var cartoonKids = [];
// Kid 1 - Red body, orange head (left side)
var kid1 = new CartoonKid('characterBody2', 'characterHead2');
kid1.x = 2048 / 2 - 300;
kid1.y = 2450;
kid1.scaleX = 0.8;
kid1.scaleY = 0.8;
game.addChild(kid1);
cartoonKids.push(kid1);
// Kid 2 - Blue body, purple head (right side)
var kid2 = new CartoonKid('characterBody3', 'characterHead3');
kid2.x = 2048 / 2 + 300;
kid2.y = 2450;
kid2.scaleX = 0.8;
kid2.scaleY = 0.8;
game.addChild(kid2);
cartoonKids.push(kid2);
// Kid 3 - Purple body, green head (far left)
var kid3 = new CartoonKid('characterBody4', 'characterHead4');
kid3.x = 2048 / 2 - 500;
kid3.y = 2500;
kid3.scaleX = 0.7;
kid3.scaleY = 0.7;
game.addChild(kid3);
cartoonKids.push(kid3);
// Kid 4 - Teal body, peach head (far right)
var kid4 = new CartoonKid('characterBody5', 'characterHead5');
kid4.x = 2048 / 2 + 500;
kid4.y = 2500;
kid4.scaleX = 0.7;
kid4.scaleY = 0.7;
game.addChild(kid4);
cartoonKids.push(kid4);
// Kid 5 - Yellow body, default head (behind main character)
var kid5 = new CartoonKid('characterBody', 'characterHead');
kid5.x = 2048 / 2;
kid5.y = 2550;
kid5.scaleX = 0.6;
kid5.scaleY = 0.6;
game.addChild(kid5);
cartoonKids.push(kid5);
// Create game status text
var statusText = new Text2('', {
size: 100,
fill: 0xFF0000
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2200;
game.addChild(statusText);
// Create restart button text
var restartText = new Text2('Tap to Restart', {
size: 60,
fill: 0x666666
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 2350;
restartText.alpha = 0;
game.addChild(restartText);
function switchPlayer() {
currentPlayer = currentPlayer === 1 ? 2 : 1;
turnText.setText(currentPlayer === 1 ? 'X\'s Turn' : 'O\'s Turn');
turnText.tint = currentPlayer === 1 ? 0xff4444 : 0x4444ff;
}
function checkWin() {
// Check rows
for (var row = 0; row < 3; row++) {
if (cells[row][0].state !== 0 && cells[row][0].state === cells[row][1].state && cells[row][1].state === cells[row][2].state) {
showWin(cells[row][0].x + gridContainer.x, cells[row][0].y + gridContainer.y, cells[row][2].x + gridContainer.x, cells[row][2].y + gridContainer.y);
return;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (cells[0][col].state !== 0 && cells[0][col].state === cells[1][col].state && cells[1][col].state === cells[2][col].state) {
showWin(cells[0][col].x + gridContainer.x, cells[0][col].y + gridContainer.y, cells[2][col].x + gridContainer.x, cells[2][col].y + gridContainer.y);
return;
}
}
// Check diagonals
if (cells[0][0].state !== 0 && cells[0][0].state === cells[1][1].state && cells[1][1].state === cells[2][2].state) {
showWin(cells[0][0].x + gridContainer.x, cells[0][0].y + gridContainer.y, cells[2][2].x + gridContainer.x, cells[2][2].y + gridContainer.y);
return;
}
if (cells[0][2].state !== 0 && cells[0][2].state === cells[1][1].state && cells[1][1].state === cells[2][0].state) {
showWin(cells[0][2].x + gridContainer.x, cells[0][2].y + gridContainer.y, cells[2][0].x + gridContainer.x, cells[2][0].y + gridContainer.y);
return;
}
// Check for tie
var isTie = true;
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (cells[row][col].state === 0) {
isTie = false;
break;
}
}
if (!isTie) break;
}
if (isTie) {
showTie();
}
}
function showWin(startX, startY, endX, endY) {
gameState = 'win';
var winner = currentPlayer === 1 ? 'X' : 'O';
statusText.setText(winner + ' Wins!');
statusText.tint = currentPlayer === 1 ? 0x3498db : 0xe74c3c;
turnText.alpha = 0;
// Make cartoon boy announce the winner
cartoonBoy.speak(winner + ' Wins!');
// Make all cartoon kids cheer
for (var i = 0; i < cartoonKids.length; i++) {
// Add slight delay for each kid to create wave effect
(function (kid, delay) {
LK.setTimeout(function () {
kid.cheer();
}, delay);
})(cartoonKids[i], i * 100);
}
winLine = new WinLine();
game.addChild(winLine);
winLine.showWinLine(startX, startY, endX, endY);
tween(restartText, {
alpha: 1
}, {
duration: 500
});
}
function showTie() {
gameState = 'tie';
statusText.setText('It\'s a Tie!');
statusText.tint = 0x95a5a6;
turnText.alpha = 0;
// Make cartoon boy announce the tie
cartoonBoy.speak('It\'s a Tie!');
// Make all cartoon kids cheer for the tie too
for (var i = 0; i < cartoonKids.length; i++) {
// Add slight delay for each kid to create wave effect
(function (kid, delay) {
LK.setTimeout(function () {
kid.cheer();
}, delay);
})(cartoonKids[i], i * 100);
}
tween(restartText, {
alpha: 1
}, {
duration: 500
});
}
function restartGame() {
// Reset game state
gameState = 'playing';
currentPlayer = 1;
// Clear cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
cells[row][col].state = 0;
cells[row][col].removeChildren();
// Re-add cell background and highlight
var cellBackground = cells[row][col].attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
var cellHighlight = cells[row][col].attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
}
}
// Reset UI
turnText.setText('X\'s Turn');
turnText.tint = 0x3498db;
turnText.alpha = 1;
statusText.setText('');
restartText.alpha = 0;
// Hide cartoon boy speech
cartoonBoy.hideSpeech();
// Remove win line
if (winLine) {
winLine.destroy();
winLine = null;
}
}
game.down = function (x, y, obj) {
if (gameState !== 'playing' && restartText.alpha > 0) {
restartGame();
}
};
// Snake Game Variables
var snakeGameContainer = new Container();
var snakeBoard = null;
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var snakeFood = null;
var snakeScore = 0;
var snakeGameState = 'playing'; // 'playing', 'gameOver'
var snakeMoveTimer = 0;
var snakeMoveDelay = 15; // frames between moves
var boardWidth = 20; // grid cells
var boardHeight = 15; // grid cells
// Initialize Snake Game
function initSnakeGame() {
game.addChild(snakeGameContainer);
snakeGameContainer.x = 2048 / 2;
snakeGameContainer.y = 3200; // Position below Tic Tac Toe
// Create game board
snakeBoard = LK.getAsset('gameBoard', {
anchorX: 0.5,
anchorY: 0.5
});
snakeGameContainer.addChild(snakeBoard);
// Initialize snake
snake = [];
var head = new SnakeSegment(true);
head.setGridPosition(10, 7);
snakeGameContainer.addChild(head);
snake.push(head);
var body1 = new SnakeSegment(false);
body1.setGridPosition(9, 7);
snakeGameContainer.addChild(body1);
snake.push(body1);
var body2 = new SnakeSegment(false);
body2.setGridPosition(8, 7);
snakeGameContainer.addChild(body2);
snake.push(body2);
// Create food
spawnFood();
// Create snake score text
var snakeScoreText = new Text2('Snake Score: 0', {
size: 50,
fill: 0xffffff
});
snakeScoreText.anchor.set(0.5, 0.5);
snakeScoreText.x = 0;
snakeScoreText.y = -350;
snakeGameContainer.addChild(snakeScoreText);
// Create snake game title
var snakeTitleText = new Text2('SNAKE GAME', {
size: 60,
fill: 0xf39c12
});
snakeTitleText.anchor.set(0.5, 0.5);
snakeTitleText.x = 0;
snakeTitleText.y = -420;
snakeGameContainer.addChild(snakeTitleText);
// Create controls text
var controlsText = new Text2('Tap sides to turn', {
size: 40,
fill: 0xbdc3c7
});
controlsText.anchor.set(0.5, 0.5);
controlsText.x = 0;
controlsText.y = 380;
snakeGameContainer.addChild(controlsText);
}
function spawnFood() {
var foodX, foodY;
var validPosition = false;
while (!validPosition) {
foodX = Math.floor(Math.random() * boardWidth);
foodY = Math.floor(Math.random() * boardHeight);
validPosition = true;
// Check if food spawns on snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === foodX && snake[i].gridY === foodY) {
validPosition = false;
break;
}
}
}
if (snakeFood) {
snakeFood.destroy();
}
snakeFood = new SnakeFood();
snakeFood.setGridPosition(foodX, foodY);
snakeGameContainer.addChild(snakeFood);
snakeFood.pulse();
}
function moveSnake() {
if (snakeGameState !== 'playing') return;
// Update direction
snakeDirection.x = nextDirection.x;
snakeDirection.y = nextDirection.y;
// Calculate new head position
var head = snake[0];
var newX = head.gridX + snakeDirection.x;
var newY = head.gridY + snakeDirection.y;
// Check wall collision
if (newX < 0 || newX >= boardWidth || newY < 0 || newY >= boardHeight) {
snakeGameOver();
return;
}
// Check self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
snakeGameOver();
return;
}
}
// Check food collision
var ateFood = false;
if (snakeFood && newX === snakeFood.gridX && newY === snakeFood.gridY) {
ateFood = true;
snakeScore += 10;
var snakeScoreText = snakeGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Snake Score:') === 0;
});
if (snakeScoreText) {
snakeScoreText.setText('Snake Score: ' + snakeScore);
}
LK.getSound('eat').play();
spawnFood();
}
// Move snake body
for (var i = snake.length - 1; i > 0; i--) {
snake[i].setGridPosition(snake[i - 1].gridX, snake[i - 1].gridY);
}
// Move head
head.setGridPosition(newX, newY);
// Add new segment if ate food
if (ateFood) {
var newSegment = new SnakeSegment(false);
var tail = snake[snake.length - 1];
newSegment.setGridPosition(tail.lastGridX, tail.lastGridY);
snakeGameContainer.addChild(newSegment);
snake.push(newSegment);
}
}
function snakeGameOver() {
snakeGameState = 'gameOver';
LK.getSound('gameOver').play();
var gameOverText = new Text2('GAME OVER!', {
size: 80,
fill: 0xe74c3c
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = 0;
snakeGameContainer.addChild(gameOverText);
var restartSnakeText = new Text2('Tap to Restart Snake', {
size: 50,
fill: 0x95a5a6
});
restartSnakeText.anchor.set(0.5, 0.5);
restartSnakeText.x = 0;
restartSnakeText.y = 80;
snakeGameContainer.addChild(restartSnakeText);
}
function restartSnakeGame() {
// Clear existing snake game
snakeGameContainer.removeChildren();
// Reset variables
snake = [];
snakeDirection = {
x: 1,
y: 0
};
nextDirection = {
x: 1,
y: 0
};
snakeFood = null;
snakeScore = 0;
snakeGameState = 'playing';
snakeMoveTimer = 0;
// Reinitialize
initSnakeGame();
}
// Initialize Snake Game
initSnakeGame();
// Tetris Game Variables
var tetrisGameContainer = new Container();
var tetrisBoard = null;
var tetrisGrid = [];
var currentPiece = null;
var nextPiece = null;
var tetrisScore = 0;
var tetrisLevel = 1;
var tetrisLines = 0;
var tetrisGameState = 'playing'; // 'playing', 'gameOver'
var tetrisDropTimer = 0;
var tetrisDropDelay = 60; // frames between drops
var tetrisBoardWidth = 12; // grid cells
var tetrisBoardHeight = 20; // grid cells
// Initialize Tetris Game
function initTetrisGame() {
game.addChild(tetrisGameContainer);
tetrisGameContainer.x = 2048 / 2;
tetrisGameContainer.y = 4200; // Position below Snake game
// Create game board
tetrisBoard = LK.getAsset('tetrisBoard', {
anchorX: 0.5,
anchorY: 0.5
});
tetrisGameContainer.addChild(tetrisBoard);
// Initialize grid
tetrisGrid = [];
for (var row = 0; row < tetrisBoardHeight; row++) {
tetrisGrid[row] = [];
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[row][col] = null;
}
}
// Create Tetris score text
var tetrisScoreText = new Text2('Score: 0', {
size: 50,
fill: 0xffffff
});
tetrisScoreText.anchor.set(0.5, 0.5);
tetrisScoreText.x = 0;
tetrisScoreText.y = -450;
tetrisGameContainer.addChild(tetrisScoreText);
// Create level text
var tetrisLevelText = new Text2('Level: 1', {
size: 40,
fill: 0xffffff
});
tetrisLevelText.anchor.set(0.5, 0.5);
tetrisLevelText.x = -150;
tetrisLevelText.y = -450;
tetrisGameContainer.addChild(tetrisLevelText);
// Create lines text
var tetrisLinesText = new Text2('Lines: 0', {
size: 40,
fill: 0xffffff
});
tetrisLinesText.anchor.set(0.5, 0.5);
tetrisLinesText.x = 150;
tetrisLinesText.y = -450;
tetrisGameContainer.addChild(tetrisLinesText);
// Create Tetris game title
var tetrisTitleText = new Text2('TETRIS', {
size: 60,
fill: 0xe74c3c
});
tetrisTitleText.anchor.set(0.5, 0.5);
tetrisTitleText.x = 0;
tetrisTitleText.y = -520;
tetrisGameContainer.addChild(tetrisTitleText);
// Create controls text
var tetrisControlsText = new Text2('Tap: Rotate | Swipe: Move/Drop', {
size: 35,
fill: 0xbdc3c7
});
tetrisControlsText.anchor.set(0.5, 0.5);
tetrisControlsText.x = 0;
tetrisControlsText.y = 450;
tetrisGameContainer.addChild(tetrisControlsText);
// Spawn first piece
spawnNewPiece();
}
function spawnNewPiece() {
if (tetrisGameState !== 'playing') return;
var pieceTypes = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];
var randomType = pieceTypes[Math.floor(Math.random() * pieceTypes.length)];
currentPiece = new TetrisPiece(randomType);
currentPiece.setGridPosition(tetrisBoardWidth / 2 - 1, 0);
tetrisGameContainer.addChild(currentPiece);
// Check if game over
if (!canMovePiece(currentPiece, 0, 0)) {
tetrisGameOver();
}
}
function canMovePiece(piece, deltaX, deltaY) {
var shape = piece.getShape();
var newX = piece.gridX + deltaX;
var newY = piece.gridY + deltaY;
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var checkX = newX + col;
var checkY = newY + row;
// Check boundaries
if (checkX < 0 || checkX >= tetrisBoardWidth || checkY >= tetrisBoardHeight) {
return false;
}
// Check existing blocks
if (checkY >= 0 && tetrisGrid[checkY][checkX]) {
return false;
}
}
}
}
return true;
}
function movePiece(piece, deltaX, deltaY) {
if (canMovePiece(piece, deltaX, deltaY)) {
piece.setGridPosition(piece.gridX + deltaX, piece.gridY + deltaY);
return true;
}
return false;
}
function rotatePiece(piece) {
piece.rotate();
if (!canMovePiece(piece, 0, 0)) {
// Try to rotate back if invalid
piece.rotate();
piece.rotate();
piece.rotate();
}
}
function lockPiece(piece) {
var shape = piece.getShape();
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var gridX = piece.gridX + col;
var gridY = piece.gridY + row;
if (gridY >= 0) {
var block = new TetrisBlock(piece.blocks[0].color);
block.setGridPosition(gridX, gridY);
tetrisGameContainer.addChild(block);
tetrisGrid[gridY][gridX] = block;
}
}
}
}
piece.destroy();
currentPiece = null;
// Check for completed lines
checkLines();
// Spawn new piece
spawnNewPiece();
LK.getSound('tetrisDrop').play();
}
function checkLines() {
var completedLines = [];
for (var row = 0; row < tetrisBoardHeight; row++) {
var isComplete = true;
for (var col = 0; col < tetrisBoardWidth; col++) {
if (!tetrisGrid[row][col]) {
isComplete = false;
break;
}
}
if (isComplete) {
completedLines.push(row);
}
}
if (completedLines.length > 0) {
// Flash completed lines
for (var i = 0; i < completedLines.length; i++) {
var row = completedLines[i];
for (var col = 0; col < tetrisBoardWidth; col++) {
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].flash();
}
}
}
// Remove lines after flash
LK.setTimeout(function () {
clearLines(completedLines);
}, 400);
LK.getSound('tetrisLine').play();
}
}
function clearLines(completedLines) {
// Remove completed lines
for (var i = 0; i < completedLines.length; i++) {
var row = completedLines[i];
for (var col = 0; col < tetrisBoardWidth; col++) {
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].destroy();
tetrisGrid[row][col] = null;
}
}
}
// Move lines down
for (var i = completedLines.length - 1; i >= 0; i--) {
var clearedRow = completedLines[i];
for (var row = clearedRow; row > 0; row--) {
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[row][col] = tetrisGrid[row - 1][col];
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].setGridPosition(col, row);
}
}
}
// Clear top row
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[0][col] = null;
}
}
// Update score and level
tetrisLines += completedLines.length;
var points = [0, 40, 100, 300, 1200];
tetrisScore += points[completedLines.length] * tetrisLevel;
tetrisLevel = Math.floor(tetrisLines / 10) + 1;
tetrisDropDelay = Math.max(10, 60 - (tetrisLevel - 1) * 5);
// Update UI
var scoreText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Score:') === 0;
});
if (scoreText) {
scoreText.setText('Score: ' + tetrisScore);
}
var levelText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Level:') === 0;
});
if (levelText) {
levelText.setText('Level: ' + tetrisLevel);
}
var linesText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Lines:') === 0;
});
if (linesText) {
linesText.setText('Lines: ' + tetrisLines);
}
}
function tetrisGameOver() {
tetrisGameState = 'gameOver';
LK.getSound('gameOver').play();
var gameOverText = new Text2('GAME OVER!', {
size: 80,
fill: 0xe74c3c
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = 0;
tetrisGameContainer.addChild(gameOverText);
var restartTetrisText = new Text2('Tap to Restart Tetris', {
size: 50,
fill: 0x95a5a6
});
restartTetrisText.anchor.set(0.5, 0.5);
restartTetrisText.x = 0;
restartTetrisText.y = 80;
tetrisGameContainer.addChild(restartTetrisText);
}
function restartTetrisGame() {
// Clear existing tetris game
tetrisGameContainer.removeChildren();
// Reset variables
tetrisGrid = [];
currentPiece = null;
nextPiece = null;
tetrisScore = 0;
tetrisLevel = 1;
tetrisLines = 0;
tetrisGameState = 'playing';
tetrisDropTimer = 0;
tetrisDropDelay = 60;
// Reinitialize
initTetrisGame();
}
// Initialize Tetris Game
initTetrisGame();
// Camera and scrolling variables
var cameraY = 0;
var targetCameraY = 0;
var isDragging = false;
var dragStartY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gamePositions = [{
y: 0,
name: "Tic Tac Toe"
}, {
y: 3200,
name: "Snake"
}, {
y: 4200,
name: "Tetris"
}];
// Create navigation indicator
var navContainer = new Container();
LK.gui.bottom.addChild(navContainer);
var navText = new Text2('Swipe to scroll between games', {
size: 40,
fill: 0xffffff
});
navText.anchor.set(0.5, 1);
navText.y = -20;
navContainer.addChild(navText);
// Create game indicators
var indicators = [];
for (var i = 0; i < gamePositions.length; i++) {
var indicator = LK.getAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - 1) * 60,
y: -80,
scaleX: 2,
scaleY: 2
});
navContainer.addChild(indicator);
indicators.push(indicator);
}
// Update indicators based on current game
function updateNavigationIndicators() {
var currentGameIndex = 0;
var minDistance = Math.abs(cameraY - gamePositions[0].y);
for (var i = 1; i < gamePositions.length; i++) {
var distance = Math.abs(cameraY - gamePositions[i].y);
if (distance < minDistance) {
minDistance = distance;
currentGameIndex = i;
}
}
for (var i = 0; i < indicators.length; i++) {
indicators[i].tint = i === currentGameIndex ? 0x00ff00 : 0x666666;
}
}
game.down = function (x, y, obj) {
// Store touch position for swipe detection
lastTouchX = x;
lastTouchY = y;
dragStartY = y;
isDragging = false; // Start as false, will be set to true on first move
// Adjust y coordinate for camera position
var adjustedY = y + cameraY;
if (gameState !== 'playing' && restartText.alpha > 0 && adjustedY < 1000) {
restartGame();
return;
}
// Handle snake game restart
if (snakeGameState === 'gameOver' && adjustedY > 3000 && adjustedY < 4000) {
restartSnakeGame();
return;
}
// Handle tetris game restart
if (tetrisGameState === 'gameOver' && adjustedY > 4000) {
restartTetrisGame();
return;
}
// Handle snake direction change
if (snakeGameState === 'playing' && adjustedY > 2800 && adjustedY < 4000) {
var gamePos = game.toLocal({
x: x,
y: y
});
var snakeGameX = gamePos.x - snakeGameContainer.x;
if (snakeGameX < -100) {
// Turn left
if (snakeDirection.x === 0) {
nextDirection.x = -snakeDirection.y;
nextDirection.y = snakeDirection.x;
}
} else if (snakeGameX > 100) {
// Turn right
if (snakeDirection.x === 0) {
nextDirection.x = snakeDirection.y;
nextDirection.y = -snakeDirection.x;
}
} else {
// Turn up/down
if (snakeDirection.y === 0) {
if (gamePos.y < snakeGameContainer.y) {
nextDirection.x = 0;
nextDirection.y = -1;
} else {
nextDirection.x = 0;
nextDirection.y = 1;
}
}
}
}
// Handle tetris controls
if (tetrisGameState === 'playing' && adjustedY > 4000 && currentPiece) {
var gamePos = game.toLocal({
x: x,
y: y
});
var tetrisGameX = gamePos.x - tetrisGameContainer.x;
// Tap to rotate
if (Math.abs(tetrisGameX) < 100) {
rotatePiece(currentPiece);
}
}
};
game.move = function (x, y, obj) {
if (!isDragging) {
// Start dragging on first move
isDragging = true;
}
if (isDragging) {
var scrollDelta = y - lastTouchY;
targetCameraY = Math.max(0, Math.min(4200, targetCameraY + scrollDelta));
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
var adjustedY = y + cameraY;
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
var scrollDelta = dragStartY - (y + cameraY);
// Handle scrolling - snap to nearest game when drag ends
if (isDragging) {
// Find closest game position to current camera
var closestPosition = gamePositions[0];
var minDistance = Math.abs(targetCameraY - closestPosition.y);
for (var i = 1; i < gamePositions.length; i++) {
var distance = Math.abs(targetCameraY - gamePositions[i].y);
if (distance < minDistance) {
minDistance = distance;
closestPosition = gamePositions[i];
}
}
targetCameraY = closestPosition.y;
} else {
// Handle tetris swipe controls
if (tetrisGameState === 'playing' && adjustedY > 4000 && currentPiece) {
var gamePos = game.toLocal({
x: x,
y: y
});
var tetrisGameX = gamePos.x - tetrisGameContainer.x;
// Detect swipe direction
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
// Horizontal swipe
if (deltaX > 0) {
// Swipe right
movePiece(currentPiece, 1, 0);
} else {
// Swipe left
movePiece(currentPiece, -1, 0);
}
} else if (deltaY > 100) {
// Swipe down - hard drop
while (movePiece(currentPiece, 0, 1)) {
// Keep dropping
}
}
}
}
isDragging = false;
};
game.update = function () {
// Handle camera movement with smooth interpolation
var cameraDiff = targetCameraY - cameraY;
if (Math.abs(cameraDiff) > 1) {
cameraY += cameraDiff * 0.15; // Smooth interpolation
game.y = -cameraY;
} else {
cameraY = targetCameraY;
game.y = -cameraY;
}
// Update navigation indicators
updateNavigationIndicators();
// Game logic is handled by event-driven cell interactions
// Snake game logic
if (snakeGameState === 'playing') {
snakeMoveTimer++;
if (snakeMoveTimer >= snakeMoveDelay) {
moveSnake();
snakeMoveTimer = 0;
}
}
// Tetris game logic
if (tetrisGameState === 'playing' && currentPiece) {
tetrisDropTimer++;
if (tetrisDropTimer >= tetrisDropDelay) {
if (!movePiece(currentPiece, 0, 1)) {
// Can't move down, lock piece
lockPiece(currentPiece);
}
tetrisDropTimer = 0;
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var CartoonBoy = Container.expand(function () {
var self = Container.call(this);
// Character body
var body = self.attachAsset('characterBody', {
anchorX: 0.5,
anchorY: 1
});
// Character head
var head = self.attachAsset('characterHead', {
anchorX: 0.5,
anchorY: 1,
y: -100
});
// Eyes
var leftEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: -115
});
var rightEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 12,
y: -115
});
// Mouth
var mouth = self.attachAsset('characterMouth', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleY: 0.4
});
// Speech bubble
var speechBubble = self.attachAsset('speechBubble', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -180,
alpha: 0
});
// Speech text
var speechText = new Text2('', {
size: 24,
fill: 0x2c3e50
});
speechText.anchor.set(0.5, 0.5);
speechText.x = 0;
speechText.y = -180;
self.addChild(speechText);
self.speak = function (message) {
speechText.setText(message);
tween(speechBubble, {
alpha: 1
}, {
duration: 300
});
tween(speechText, {
alpha: 1
}, {
duration: 300
});
// Animate character excitement
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
yoyo: true,
repeat: 1
});
};
self.hideSpeech = function () {
tween(speechBubble, {
alpha: 0
}, {
duration: 300
});
tween(speechText, {
alpha: 0
}, {
duration: 300
});
};
return self;
});
var CartoonKid = Container.expand(function (bodyAsset, headAsset) {
var self = Container.call(this);
// Character body
var body = self.attachAsset(bodyAsset || 'characterBody2', {
anchorX: 0.5,
anchorY: 1
});
// Character head
var head = self.attachAsset(headAsset || 'characterHead2', {
anchorX: 0.5,
anchorY: 1,
y: -100
});
// Eyes
var leftEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: -115
});
var rightEye = self.attachAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 12,
y: -115
});
// Mouth
var mouth = self.attachAsset('characterMouth', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
scaleY: 0.4
});
self.cheer = function () {
// Jump animation
tween(self, {
y: self.y - 50
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 50
}, {
duration: 300,
easing: tween.bounceOut
});
}
});
// Scale animation for excitement
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Arm wave simulation by scaling
tween(head, {
rotation: 0.2
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(head, {
rotation: -0.2
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(head, {
rotation: 0
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
}
});
};
return self;
});
var Cell = Container.expand(function (row, col) {
var self = Container.call(this);
self.row = row;
self.col = col;
self.state = 0; // 0 = empty, 1 = X, 2 = O
self.isHighlighted = false;
var cellBackground = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
var cellHighlight = self.attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
var symbol = null;
self.highlight = function () {
if (!self.isHighlighted) {
self.isHighlighted = true;
tween(cellHighlight, {
alpha: 1
}, {
duration: 200
});
}
};
self.unhighlight = function () {
if (self.isHighlighted) {
self.isHighlighted = false;
tween(cellHighlight, {
alpha: 0
}, {
duration: 200
});
}
};
self.placeSymbol = function (player) {
if (self.state !== 0) return false;
self.state = player;
if (player === 1) {
var xContainer = new Container();
var xLine1 = LK.getAsset('xShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 0.25
});
var xLine2 = LK.getAsset('xShape2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0,
rotation: Math.PI * 0.25
});
xContainer.addChild(xLine1);
xContainer.addChild(xLine2);
symbol = xContainer;
self.addChild(symbol);
tween(xLine1, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut
});
tween(xLine2, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut,
delay: 100
});
} else {
symbol = self.attachAsset('oShape', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
scaleY: 0
});
tween(symbol, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.elasticOut
});
}
LK.getSound('place').play();
return true;
};
self.down = function (x, y, obj) {
if (self.state === 0) {
self.highlight();
}
};
self.up = function (x, y, obj) {
self.unhighlight();
if (self.state === 0 && gameState === 'playing') {
if (self.placeSymbol(currentPlayer)) {
checkWin();
if (gameState === 'playing') {
switchPlayer();
}
}
}
};
return self;
});
var SnakeFood = Container.expand(function () {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
var food = self.attachAsset('snakeFood', {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
self.pulse = function () {
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
};
return self;
});
var SnakeSegment = Container.expand(function (isHead) {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.lastGridX = 0;
self.lastGridY = 0;
var segment = self.attachAsset(isHead ? 'snakeHead' : 'snakeSegment', {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.lastGridX = self.gridX;
self.lastGridY = self.gridY;
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
return self;
});
var TetrisBlock = Container.expand(function (color) {
var self = Container.call(this);
self.gridX = 0;
self.gridY = 0;
self.color = color || 0x3498db;
var block = self.attachAsset('tetrisBlock', {
anchorX: 0.5,
anchorY: 0.5
});
block.tint = self.color;
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40 + 20;
self.y = gridY * 40 + 20;
};
self.flash = function () {
tween(self, {
alpha: 0.3
}, {
duration: 100,
yoyo: true,
repeat: 3
});
};
return self;
});
var TetrisPiece = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'I';
self.rotation = 0;
self.gridX = 0;
self.gridY = 0;
self.blocks = [];
var shapes = {
I: [[1, 1, 1, 1]],
O: [[1, 1], [1, 1]],
T: [[0, 1, 0], [1, 1, 1]],
S: [[0, 1, 1], [1, 1, 0]],
Z: [[1, 1, 0], [0, 1, 1]],
J: [[1, 0, 0], [1, 1, 1]],
L: [[0, 0, 1], [1, 1, 1]]
};
var colors = {
I: 0x00f5ff,
O: 0xffff00,
T: 0x800080,
S: 0x00ff00,
Z: 0xff0000,
J: 0x0000ff,
L: 0xffa500
};
self.createBlocks = function () {
// Clear existing blocks
for (var i = 0; i < self.blocks.length; i++) {
self.blocks[i].destroy();
}
self.blocks = [];
var shape = shapes[self.type];
var color = colors[self.type];
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var block = new TetrisBlock(color);
block.setGridPosition(col, row);
self.addChild(block);
self.blocks.push(block);
}
}
}
};
self.getShape = function () {
return shapes[self.type];
};
self.rotate = function () {
var shape = shapes[self.type];
var newShape = [];
var rows = shape.length;
var cols = shape[0].length;
for (var col = 0; col < cols; col++) {
newShape[col] = [];
for (var row = rows - 1; row >= 0; row--) {
newShape[col][cols - 1 - row] = shape[row][col];
}
}
shapes[self.type] = newShape;
self.createBlocks();
};
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * 40;
self.y = gridY * 40;
};
self.createBlocks();
return self;
});
var WinLine = Container.expand(function () {
var self = Container.call(this);
var line = self.attachAsset('winLine', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0,
alpha: 0
});
self.showWinLine = function (startX, startY, endX, endY) {
self.x = (startX + endX) / 2;
self.y = (startY + endY) / 2;
var dx = endX - startX;
var dy = endY - startY;
var angle = Math.atan2(dy, dx);
var distance = Math.sqrt(dx * dx + dy * dy);
line.rotation = angle;
line.width = distance;
tween(self, {
alpha: 1
}, {
duration: 300
});
tween(line, {
scaleX: 1
}, {
duration: 500,
easing: tween.easeOut
});
LK.getSound('win').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x74b9ff
});
/****
* Game Code
****/
var cells = [];
var currentPlayer = 1; // 1 = X, 2 = O
var gameState = 'playing'; // 'playing', 'win', 'tie'
var winLine = null;
// Create grid
var gridContainer = new Container();
game.addChild(gridContainer);
// Position grid in center
gridContainer.x = 2048 / 2;
gridContainer.y = 2732 / 2;
// Create grid lines
var verticalLine1 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
y: 0
});
gridContainer.addChild(verticalLine1);
var verticalLine2 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: 0
});
gridContainer.addChild(verticalLine2);
var horizontalLine1 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -100,
rotation: Math.PI / 2
});
gridContainer.addChild(horizontalLine1);
var horizontalLine2 = LK.getAsset('gridLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 100,
rotation: Math.PI / 2
});
gridContainer.addChild(horizontalLine2);
// Create cells
for (var row = 0; row < 3; row++) {
cells[row] = [];
for (var col = 0; col < 3; col++) {
var cell = new Cell(row, col);
cell.x = (col - 1) * 200;
cell.y = (row - 1) * 200;
gridContainer.addChild(cell);
cells[row][col] = cell;
}
}
// Create turn indicator
var turnText = new Text2('X\'s Turn', {
size: 80,
fill: 0x333333
});
turnText.anchor.set(0.5, 0.5);
turnText.x = 2048 / 2;
turnText.y = 500;
game.addChild(turnText);
// Create cartoon character
var cartoonBoy = new CartoonBoy();
cartoonBoy.x = 2048 / 2;
cartoonBoy.y = 2400;
game.addChild(cartoonBoy);
// Create additional cartoon kids
var cartoonKids = [];
// Kid 1 - Red body, orange head (left side)
var kid1 = new CartoonKid('characterBody2', 'characterHead2');
kid1.x = 2048 / 2 - 300;
kid1.y = 2450;
kid1.scaleX = 0.8;
kid1.scaleY = 0.8;
game.addChild(kid1);
cartoonKids.push(kid1);
// Kid 2 - Blue body, purple head (right side)
var kid2 = new CartoonKid('characterBody3', 'characterHead3');
kid2.x = 2048 / 2 + 300;
kid2.y = 2450;
kid2.scaleX = 0.8;
kid2.scaleY = 0.8;
game.addChild(kid2);
cartoonKids.push(kid2);
// Kid 3 - Purple body, green head (far left)
var kid3 = new CartoonKid('characterBody4', 'characterHead4');
kid3.x = 2048 / 2 - 500;
kid3.y = 2500;
kid3.scaleX = 0.7;
kid3.scaleY = 0.7;
game.addChild(kid3);
cartoonKids.push(kid3);
// Kid 4 - Teal body, peach head (far right)
var kid4 = new CartoonKid('characterBody5', 'characterHead5');
kid4.x = 2048 / 2 + 500;
kid4.y = 2500;
kid4.scaleX = 0.7;
kid4.scaleY = 0.7;
game.addChild(kid4);
cartoonKids.push(kid4);
// Kid 5 - Yellow body, default head (behind main character)
var kid5 = new CartoonKid('characterBody', 'characterHead');
kid5.x = 2048 / 2;
kid5.y = 2550;
kid5.scaleX = 0.6;
kid5.scaleY = 0.6;
game.addChild(kid5);
cartoonKids.push(kid5);
// Create game status text
var statusText = new Text2('', {
size: 100,
fill: 0xFF0000
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2200;
game.addChild(statusText);
// Create restart button text
var restartText = new Text2('Tap to Restart', {
size: 60,
fill: 0x666666
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 2350;
restartText.alpha = 0;
game.addChild(restartText);
function switchPlayer() {
currentPlayer = currentPlayer === 1 ? 2 : 1;
turnText.setText(currentPlayer === 1 ? 'X\'s Turn' : 'O\'s Turn');
turnText.tint = currentPlayer === 1 ? 0xff4444 : 0x4444ff;
}
function checkWin() {
// Check rows
for (var row = 0; row < 3; row++) {
if (cells[row][0].state !== 0 && cells[row][0].state === cells[row][1].state && cells[row][1].state === cells[row][2].state) {
showWin(cells[row][0].x + gridContainer.x, cells[row][0].y + gridContainer.y, cells[row][2].x + gridContainer.x, cells[row][2].y + gridContainer.y);
return;
}
}
// Check columns
for (var col = 0; col < 3; col++) {
if (cells[0][col].state !== 0 && cells[0][col].state === cells[1][col].state && cells[1][col].state === cells[2][col].state) {
showWin(cells[0][col].x + gridContainer.x, cells[0][col].y + gridContainer.y, cells[2][col].x + gridContainer.x, cells[2][col].y + gridContainer.y);
return;
}
}
// Check diagonals
if (cells[0][0].state !== 0 && cells[0][0].state === cells[1][1].state && cells[1][1].state === cells[2][2].state) {
showWin(cells[0][0].x + gridContainer.x, cells[0][0].y + gridContainer.y, cells[2][2].x + gridContainer.x, cells[2][2].y + gridContainer.y);
return;
}
if (cells[0][2].state !== 0 && cells[0][2].state === cells[1][1].state && cells[1][1].state === cells[2][0].state) {
showWin(cells[0][2].x + gridContainer.x, cells[0][2].y + gridContainer.y, cells[2][0].x + gridContainer.x, cells[2][0].y + gridContainer.y);
return;
}
// Check for tie
var isTie = true;
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
if (cells[row][col].state === 0) {
isTie = false;
break;
}
}
if (!isTie) break;
}
if (isTie) {
showTie();
}
}
function showWin(startX, startY, endX, endY) {
gameState = 'win';
var winner = currentPlayer === 1 ? 'X' : 'O';
statusText.setText(winner + ' Wins!');
statusText.tint = currentPlayer === 1 ? 0x3498db : 0xe74c3c;
turnText.alpha = 0;
// Make cartoon boy announce the winner
cartoonBoy.speak(winner + ' Wins!');
// Make all cartoon kids cheer
for (var i = 0; i < cartoonKids.length; i++) {
// Add slight delay for each kid to create wave effect
(function (kid, delay) {
LK.setTimeout(function () {
kid.cheer();
}, delay);
})(cartoonKids[i], i * 100);
}
winLine = new WinLine();
game.addChild(winLine);
winLine.showWinLine(startX, startY, endX, endY);
tween(restartText, {
alpha: 1
}, {
duration: 500
});
}
function showTie() {
gameState = 'tie';
statusText.setText('It\'s a Tie!');
statusText.tint = 0x95a5a6;
turnText.alpha = 0;
// Make cartoon boy announce the tie
cartoonBoy.speak('It\'s a Tie!');
// Make all cartoon kids cheer for the tie too
for (var i = 0; i < cartoonKids.length; i++) {
// Add slight delay for each kid to create wave effect
(function (kid, delay) {
LK.setTimeout(function () {
kid.cheer();
}, delay);
})(cartoonKids[i], i * 100);
}
tween(restartText, {
alpha: 1
}, {
duration: 500
});
}
function restartGame() {
// Reset game state
gameState = 'playing';
currentPlayer = 1;
// Clear cells
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 3; col++) {
cells[row][col].state = 0;
cells[row][col].removeChildren();
// Re-add cell background and highlight
var cellBackground = cells[row][col].attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
var cellHighlight = cells[row][col].attachAsset('cellHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
}
}
// Reset UI
turnText.setText('X\'s Turn');
turnText.tint = 0x3498db;
turnText.alpha = 1;
statusText.setText('');
restartText.alpha = 0;
// Hide cartoon boy speech
cartoonBoy.hideSpeech();
// Remove win line
if (winLine) {
winLine.destroy();
winLine = null;
}
}
game.down = function (x, y, obj) {
if (gameState !== 'playing' && restartText.alpha > 0) {
restartGame();
}
};
// Snake Game Variables
var snakeGameContainer = new Container();
var snakeBoard = null;
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var snakeFood = null;
var snakeScore = 0;
var snakeGameState = 'playing'; // 'playing', 'gameOver'
var snakeMoveTimer = 0;
var snakeMoveDelay = 15; // frames between moves
var boardWidth = 20; // grid cells
var boardHeight = 15; // grid cells
// Initialize Snake Game
function initSnakeGame() {
game.addChild(snakeGameContainer);
snakeGameContainer.x = 2048 / 2;
snakeGameContainer.y = 3200; // Position below Tic Tac Toe
// Create game board
snakeBoard = LK.getAsset('gameBoard', {
anchorX: 0.5,
anchorY: 0.5
});
snakeGameContainer.addChild(snakeBoard);
// Initialize snake
snake = [];
var head = new SnakeSegment(true);
head.setGridPosition(10, 7);
snakeGameContainer.addChild(head);
snake.push(head);
var body1 = new SnakeSegment(false);
body1.setGridPosition(9, 7);
snakeGameContainer.addChild(body1);
snake.push(body1);
var body2 = new SnakeSegment(false);
body2.setGridPosition(8, 7);
snakeGameContainer.addChild(body2);
snake.push(body2);
// Create food
spawnFood();
// Create snake score text
var snakeScoreText = new Text2('Snake Score: 0', {
size: 50,
fill: 0xffffff
});
snakeScoreText.anchor.set(0.5, 0.5);
snakeScoreText.x = 0;
snakeScoreText.y = -350;
snakeGameContainer.addChild(snakeScoreText);
// Create snake game title
var snakeTitleText = new Text2('SNAKE GAME', {
size: 60,
fill: 0xf39c12
});
snakeTitleText.anchor.set(0.5, 0.5);
snakeTitleText.x = 0;
snakeTitleText.y = -420;
snakeGameContainer.addChild(snakeTitleText);
// Create controls text
var controlsText = new Text2('Tap sides to turn', {
size: 40,
fill: 0xbdc3c7
});
controlsText.anchor.set(0.5, 0.5);
controlsText.x = 0;
controlsText.y = 380;
snakeGameContainer.addChild(controlsText);
}
function spawnFood() {
var foodX, foodY;
var validPosition = false;
while (!validPosition) {
foodX = Math.floor(Math.random() * boardWidth);
foodY = Math.floor(Math.random() * boardHeight);
validPosition = true;
// Check if food spawns on snake
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === foodX && snake[i].gridY === foodY) {
validPosition = false;
break;
}
}
}
if (snakeFood) {
snakeFood.destroy();
}
snakeFood = new SnakeFood();
snakeFood.setGridPosition(foodX, foodY);
snakeGameContainer.addChild(snakeFood);
snakeFood.pulse();
}
function moveSnake() {
if (snakeGameState !== 'playing') return;
// Update direction
snakeDirection.x = nextDirection.x;
snakeDirection.y = nextDirection.y;
// Calculate new head position
var head = snake[0];
var newX = head.gridX + snakeDirection.x;
var newY = head.gridY + snakeDirection.y;
// Check wall collision
if (newX < 0 || newX >= boardWidth || newY < 0 || newY >= boardHeight) {
snakeGameOver();
return;
}
// Check self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
snakeGameOver();
return;
}
}
// Check food collision
var ateFood = false;
if (snakeFood && newX === snakeFood.gridX && newY === snakeFood.gridY) {
ateFood = true;
snakeScore += 10;
var snakeScoreText = snakeGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Snake Score:') === 0;
});
if (snakeScoreText) {
snakeScoreText.setText('Snake Score: ' + snakeScore);
}
LK.getSound('eat').play();
spawnFood();
}
// Move snake body
for (var i = snake.length - 1; i > 0; i--) {
snake[i].setGridPosition(snake[i - 1].gridX, snake[i - 1].gridY);
}
// Move head
head.setGridPosition(newX, newY);
// Add new segment if ate food
if (ateFood) {
var newSegment = new SnakeSegment(false);
var tail = snake[snake.length - 1];
newSegment.setGridPosition(tail.lastGridX, tail.lastGridY);
snakeGameContainer.addChild(newSegment);
snake.push(newSegment);
}
}
function snakeGameOver() {
snakeGameState = 'gameOver';
LK.getSound('gameOver').play();
var gameOverText = new Text2('GAME OVER!', {
size: 80,
fill: 0xe74c3c
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = 0;
snakeGameContainer.addChild(gameOverText);
var restartSnakeText = new Text2('Tap to Restart Snake', {
size: 50,
fill: 0x95a5a6
});
restartSnakeText.anchor.set(0.5, 0.5);
restartSnakeText.x = 0;
restartSnakeText.y = 80;
snakeGameContainer.addChild(restartSnakeText);
}
function restartSnakeGame() {
// Clear existing snake game
snakeGameContainer.removeChildren();
// Reset variables
snake = [];
snakeDirection = {
x: 1,
y: 0
};
nextDirection = {
x: 1,
y: 0
};
snakeFood = null;
snakeScore = 0;
snakeGameState = 'playing';
snakeMoveTimer = 0;
// Reinitialize
initSnakeGame();
}
// Initialize Snake Game
initSnakeGame();
// Tetris Game Variables
var tetrisGameContainer = new Container();
var tetrisBoard = null;
var tetrisGrid = [];
var currentPiece = null;
var nextPiece = null;
var tetrisScore = 0;
var tetrisLevel = 1;
var tetrisLines = 0;
var tetrisGameState = 'playing'; // 'playing', 'gameOver'
var tetrisDropTimer = 0;
var tetrisDropDelay = 60; // frames between drops
var tetrisBoardWidth = 12; // grid cells
var tetrisBoardHeight = 20; // grid cells
// Initialize Tetris Game
function initTetrisGame() {
game.addChild(tetrisGameContainer);
tetrisGameContainer.x = 2048 / 2;
tetrisGameContainer.y = 4200; // Position below Snake game
// Create game board
tetrisBoard = LK.getAsset('tetrisBoard', {
anchorX: 0.5,
anchorY: 0.5
});
tetrisGameContainer.addChild(tetrisBoard);
// Initialize grid
tetrisGrid = [];
for (var row = 0; row < tetrisBoardHeight; row++) {
tetrisGrid[row] = [];
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[row][col] = null;
}
}
// Create Tetris score text
var tetrisScoreText = new Text2('Score: 0', {
size: 50,
fill: 0xffffff
});
tetrisScoreText.anchor.set(0.5, 0.5);
tetrisScoreText.x = 0;
tetrisScoreText.y = -450;
tetrisGameContainer.addChild(tetrisScoreText);
// Create level text
var tetrisLevelText = new Text2('Level: 1', {
size: 40,
fill: 0xffffff
});
tetrisLevelText.anchor.set(0.5, 0.5);
tetrisLevelText.x = -150;
tetrisLevelText.y = -450;
tetrisGameContainer.addChild(tetrisLevelText);
// Create lines text
var tetrisLinesText = new Text2('Lines: 0', {
size: 40,
fill: 0xffffff
});
tetrisLinesText.anchor.set(0.5, 0.5);
tetrisLinesText.x = 150;
tetrisLinesText.y = -450;
tetrisGameContainer.addChild(tetrisLinesText);
// Create Tetris game title
var tetrisTitleText = new Text2('TETRIS', {
size: 60,
fill: 0xe74c3c
});
tetrisTitleText.anchor.set(0.5, 0.5);
tetrisTitleText.x = 0;
tetrisTitleText.y = -520;
tetrisGameContainer.addChild(tetrisTitleText);
// Create controls text
var tetrisControlsText = new Text2('Tap: Rotate | Swipe: Move/Drop', {
size: 35,
fill: 0xbdc3c7
});
tetrisControlsText.anchor.set(0.5, 0.5);
tetrisControlsText.x = 0;
tetrisControlsText.y = 450;
tetrisGameContainer.addChild(tetrisControlsText);
// Spawn first piece
spawnNewPiece();
}
function spawnNewPiece() {
if (tetrisGameState !== 'playing') return;
var pieceTypes = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];
var randomType = pieceTypes[Math.floor(Math.random() * pieceTypes.length)];
currentPiece = new TetrisPiece(randomType);
currentPiece.setGridPosition(tetrisBoardWidth / 2 - 1, 0);
tetrisGameContainer.addChild(currentPiece);
// Check if game over
if (!canMovePiece(currentPiece, 0, 0)) {
tetrisGameOver();
}
}
function canMovePiece(piece, deltaX, deltaY) {
var shape = piece.getShape();
var newX = piece.gridX + deltaX;
var newY = piece.gridY + deltaY;
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var checkX = newX + col;
var checkY = newY + row;
// Check boundaries
if (checkX < 0 || checkX >= tetrisBoardWidth || checkY >= tetrisBoardHeight) {
return false;
}
// Check existing blocks
if (checkY >= 0 && tetrisGrid[checkY][checkX]) {
return false;
}
}
}
}
return true;
}
function movePiece(piece, deltaX, deltaY) {
if (canMovePiece(piece, deltaX, deltaY)) {
piece.setGridPosition(piece.gridX + deltaX, piece.gridY + deltaY);
return true;
}
return false;
}
function rotatePiece(piece) {
piece.rotate();
if (!canMovePiece(piece, 0, 0)) {
// Try to rotate back if invalid
piece.rotate();
piece.rotate();
piece.rotate();
}
}
function lockPiece(piece) {
var shape = piece.getShape();
for (var row = 0; row < shape.length; row++) {
for (var col = 0; col < shape[row].length; col++) {
if (shape[row][col]) {
var gridX = piece.gridX + col;
var gridY = piece.gridY + row;
if (gridY >= 0) {
var block = new TetrisBlock(piece.blocks[0].color);
block.setGridPosition(gridX, gridY);
tetrisGameContainer.addChild(block);
tetrisGrid[gridY][gridX] = block;
}
}
}
}
piece.destroy();
currentPiece = null;
// Check for completed lines
checkLines();
// Spawn new piece
spawnNewPiece();
LK.getSound('tetrisDrop').play();
}
function checkLines() {
var completedLines = [];
for (var row = 0; row < tetrisBoardHeight; row++) {
var isComplete = true;
for (var col = 0; col < tetrisBoardWidth; col++) {
if (!tetrisGrid[row][col]) {
isComplete = false;
break;
}
}
if (isComplete) {
completedLines.push(row);
}
}
if (completedLines.length > 0) {
// Flash completed lines
for (var i = 0; i < completedLines.length; i++) {
var row = completedLines[i];
for (var col = 0; col < tetrisBoardWidth; col++) {
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].flash();
}
}
}
// Remove lines after flash
LK.setTimeout(function () {
clearLines(completedLines);
}, 400);
LK.getSound('tetrisLine').play();
}
}
function clearLines(completedLines) {
// Remove completed lines
for (var i = 0; i < completedLines.length; i++) {
var row = completedLines[i];
for (var col = 0; col < tetrisBoardWidth; col++) {
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].destroy();
tetrisGrid[row][col] = null;
}
}
}
// Move lines down
for (var i = completedLines.length - 1; i >= 0; i--) {
var clearedRow = completedLines[i];
for (var row = clearedRow; row > 0; row--) {
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[row][col] = tetrisGrid[row - 1][col];
if (tetrisGrid[row][col]) {
tetrisGrid[row][col].setGridPosition(col, row);
}
}
}
// Clear top row
for (var col = 0; col < tetrisBoardWidth; col++) {
tetrisGrid[0][col] = null;
}
}
// Update score and level
tetrisLines += completedLines.length;
var points = [0, 40, 100, 300, 1200];
tetrisScore += points[completedLines.length] * tetrisLevel;
tetrisLevel = Math.floor(tetrisLines / 10) + 1;
tetrisDropDelay = Math.max(10, 60 - (tetrisLevel - 1) * 5);
// Update UI
var scoreText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Score:') === 0;
});
if (scoreText) {
scoreText.setText('Score: ' + tetrisScore);
}
var levelText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Level:') === 0;
});
if (levelText) {
levelText.setText('Level: ' + tetrisLevel);
}
var linesText = tetrisGameContainer.children.find(function (child) {
return child.getText && child.getText().indexOf('Lines:') === 0;
});
if (linesText) {
linesText.setText('Lines: ' + tetrisLines);
}
}
function tetrisGameOver() {
tetrisGameState = 'gameOver';
LK.getSound('gameOver').play();
var gameOverText = new Text2('GAME OVER!', {
size: 80,
fill: 0xe74c3c
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 0;
gameOverText.y = 0;
tetrisGameContainer.addChild(gameOverText);
var restartTetrisText = new Text2('Tap to Restart Tetris', {
size: 50,
fill: 0x95a5a6
});
restartTetrisText.anchor.set(0.5, 0.5);
restartTetrisText.x = 0;
restartTetrisText.y = 80;
tetrisGameContainer.addChild(restartTetrisText);
}
function restartTetrisGame() {
// Clear existing tetris game
tetrisGameContainer.removeChildren();
// Reset variables
tetrisGrid = [];
currentPiece = null;
nextPiece = null;
tetrisScore = 0;
tetrisLevel = 1;
tetrisLines = 0;
tetrisGameState = 'playing';
tetrisDropTimer = 0;
tetrisDropDelay = 60;
// Reinitialize
initTetrisGame();
}
// Initialize Tetris Game
initTetrisGame();
// Camera and scrolling variables
var cameraY = 0;
var targetCameraY = 0;
var isDragging = false;
var dragStartY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gamePositions = [{
y: 0,
name: "Tic Tac Toe"
}, {
y: 3200,
name: "Snake"
}, {
y: 4200,
name: "Tetris"
}];
// Create navigation indicator
var navContainer = new Container();
LK.gui.bottom.addChild(navContainer);
var navText = new Text2('Swipe to scroll between games', {
size: 40,
fill: 0xffffff
});
navText.anchor.set(0.5, 1);
navText.y = -20;
navContainer.addChild(navText);
// Create game indicators
var indicators = [];
for (var i = 0; i < gamePositions.length; i++) {
var indicator = LK.getAsset('characterEye', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - 1) * 60,
y: -80,
scaleX: 2,
scaleY: 2
});
navContainer.addChild(indicator);
indicators.push(indicator);
}
// Update indicators based on current game
function updateNavigationIndicators() {
var currentGameIndex = 0;
var minDistance = Math.abs(cameraY - gamePositions[0].y);
for (var i = 1; i < gamePositions.length; i++) {
var distance = Math.abs(cameraY - gamePositions[i].y);
if (distance < minDistance) {
minDistance = distance;
currentGameIndex = i;
}
}
for (var i = 0; i < indicators.length; i++) {
indicators[i].tint = i === currentGameIndex ? 0x00ff00 : 0x666666;
}
}
game.down = function (x, y, obj) {
// Store touch position for swipe detection
lastTouchX = x;
lastTouchY = y;
dragStartY = y;
isDragging = false; // Start as false, will be set to true on first move
// Adjust y coordinate for camera position
var adjustedY = y + cameraY;
if (gameState !== 'playing' && restartText.alpha > 0 && adjustedY < 1000) {
restartGame();
return;
}
// Handle snake game restart
if (snakeGameState === 'gameOver' && adjustedY > 3000 && adjustedY < 4000) {
restartSnakeGame();
return;
}
// Handle tetris game restart
if (tetrisGameState === 'gameOver' && adjustedY > 4000) {
restartTetrisGame();
return;
}
// Handle snake direction change
if (snakeGameState === 'playing' && adjustedY > 2800 && adjustedY < 4000) {
var gamePos = game.toLocal({
x: x,
y: y
});
var snakeGameX = gamePos.x - snakeGameContainer.x;
if (snakeGameX < -100) {
// Turn left
if (snakeDirection.x === 0) {
nextDirection.x = -snakeDirection.y;
nextDirection.y = snakeDirection.x;
}
} else if (snakeGameX > 100) {
// Turn right
if (snakeDirection.x === 0) {
nextDirection.x = snakeDirection.y;
nextDirection.y = -snakeDirection.x;
}
} else {
// Turn up/down
if (snakeDirection.y === 0) {
if (gamePos.y < snakeGameContainer.y) {
nextDirection.x = 0;
nextDirection.y = -1;
} else {
nextDirection.x = 0;
nextDirection.y = 1;
}
}
}
}
// Handle tetris controls
if (tetrisGameState === 'playing' && adjustedY > 4000 && currentPiece) {
var gamePos = game.toLocal({
x: x,
y: y
});
var tetrisGameX = gamePos.x - tetrisGameContainer.x;
// Tap to rotate
if (Math.abs(tetrisGameX) < 100) {
rotatePiece(currentPiece);
}
}
};
game.move = function (x, y, obj) {
if (!isDragging) {
// Start dragging on first move
isDragging = true;
}
if (isDragging) {
var scrollDelta = y - lastTouchY;
targetCameraY = Math.max(0, Math.min(4200, targetCameraY + scrollDelta));
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
var adjustedY = y + cameraY;
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
var scrollDelta = dragStartY - (y + cameraY);
// Handle scrolling - snap to nearest game when drag ends
if (isDragging) {
// Find closest game position to current camera
var closestPosition = gamePositions[0];
var minDistance = Math.abs(targetCameraY - closestPosition.y);
for (var i = 1; i < gamePositions.length; i++) {
var distance = Math.abs(targetCameraY - gamePositions[i].y);
if (distance < minDistance) {
minDistance = distance;
closestPosition = gamePositions[i];
}
}
targetCameraY = closestPosition.y;
} else {
// Handle tetris swipe controls
if (tetrisGameState === 'playing' && adjustedY > 4000 && currentPiece) {
var gamePos = game.toLocal({
x: x,
y: y
});
var tetrisGameX = gamePos.x - tetrisGameContainer.x;
// Detect swipe direction
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
// Horizontal swipe
if (deltaX > 0) {
// Swipe right
movePiece(currentPiece, 1, 0);
} else {
// Swipe left
movePiece(currentPiece, -1, 0);
}
} else if (deltaY > 100) {
// Swipe down - hard drop
while (movePiece(currentPiece, 0, 1)) {
// Keep dropping
}
}
}
}
isDragging = false;
};
game.update = function () {
// Handle camera movement with smooth interpolation
var cameraDiff = targetCameraY - cameraY;
if (Math.abs(cameraDiff) > 1) {
cameraY += cameraDiff * 0.15; // Smooth interpolation
game.y = -cameraY;
} else {
cameraY = targetCameraY;
game.y = -cameraY;
}
// Update navigation indicators
updateNavigationIndicators();
// Game logic is handled by event-driven cell interactions
// Snake game logic
if (snakeGameState === 'playing') {
snakeMoveTimer++;
if (snakeMoveTimer >= snakeMoveDelay) {
moveSnake();
snakeMoveTimer = 0;
}
}
// Tetris game logic
if (tetrisGameState === 'playing' && currentPiece) {
tetrisDropTimer++;
if (tetrisDropTimer >= tetrisDropDelay) {
if (!movePiece(currentPiece, 0, 1)) {
// Can't move down, lock piece
lockPiece(currentPiece);
}
tetrisDropTimer = 0;
}
}
};