/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Animal class var Animal = Container.expand(function () { var self = Container.call(this); self.type = null; self.asset = null; self.setType = function (type) { self.type = type; if (self.asset) { self.removeChild(self.asset); } self.asset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); }; return self; }); // Snake Segment (body or head) var SnakeSegment = Container.expand(function () { var self = Container.call(this); self.asset = null; self.setType = function (type) { if (self.asset) { self.removeChild(self.asset); } var assetId = type === 'head' ? 'snakeHead' : 'snakeBody'; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; self.setType('body'); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // Animal assets: pig, cat, bee, frog (box/ellipse with different colors) // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var SNAKE_START_LENGTH = 3; var SNAKE_START_SPEED = 8; // pixels per tick var SNAKE_SPEED_INCREMENT = 1.5; // speed up per sequence var SNAKE_MAX_SPEED = 32; var SEGMENT_SPACING = 90; // px between segments var ANIMAL_TYPES = ['pig', 'cat', 'bee', 'frog']; var ANIMAL_NAMES = { pig: "Pig", cat: "Cat", bee: "Bee", frog: "Frog" }; // Game state var snake = []; var snakeDir = { x: 0, y: -1 }; // start moving up var snakeNextDir = { x: 0, y: -1 }; var snakeSpeed = SNAKE_START_SPEED; var snakePositions = []; // for body following var animals = []; var currentTargetIndex = 0; // which animal in sequence to eat next var score = 0; var sequenceCount = 0; var isGameOver = false; var moveCooldown = 0; // for swipe input var dragStart = null; // GUI var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var orderTxt = new Text2('', { size: 70, fill: "#fff" }); orderTxt.anchor.set(0.5, 0); LK.gui.top.addChild(orderTxt); orderTxt.y = 130; // Helper: get random position for animal, not too close to snake head function getRandomAnimalPos() { var margin = 180; var tries = 0; while (tries < 20) { var x = margin + Math.random() * (GAME_WIDTH - 2 * margin); var y = margin + Math.random() * (GAME_HEIGHT - 2 * margin); // Avoid spawning too close to snake head var dx = x - snake[0].x; var dy = y - snake[0].y; if (dx * dx + dy * dy > 400 * 400) { return { x: x, y: y }; } tries++; } // fallback return { x: margin + Math.random() * (GAME_WIDTH - 2 * margin), y: margin + Math.random() * (GAME_HEIGHT - 2 * margin) }; } // Helper: update order text function updateOrderText() { var s = ''; for (var i = 0; i < ANIMAL_TYPES.length; i++) { if (i === currentTargetIndex) { s += '[b]' + ANIMAL_NAMES[ANIMAL_TYPES[i]] + '[/b] '; } else { s += ANIMAL_NAMES[ANIMAL_TYPES[i]] + ' '; } } orderTxt.setText(s.trim()); } // Helper: spawn all animals function spawnAnimals() { // Remove old for (var i = 0; i < animals.length; i++) { animals[i].destroy(); } animals = []; for (var i = 0; i < ANIMAL_TYPES.length; i++) { var animal = new Animal(); animal.setType(ANIMAL_TYPES[i]); var pos = getRandomAnimalPos(); animal.x = pos.x; animal.y = pos.y; animals.push(animal); game.addChild(animal); } } // Helper: reset snake function resetSnake() { for (var i = 0; i < snake.length; i++) { snake[i].destroy(); } snake = []; snakePositions = []; var startX = GAME_WIDTH / 2; var startY = GAME_HEIGHT / 2 + 300; for (var i = 0; i < SNAKE_START_LENGTH; i++) { var seg = new SnakeSegment(); seg.setType(i === 0 ? 'head' : 'body'); seg.x = startX; seg.y = startY + i * SEGMENT_SPACING; snake.push(seg); game.addChild(seg); snakePositions.push({ x: seg.x, y: seg.y }); } snakeDir = { x: 0, y: -1 }; snakeNextDir = { x: 0, y: -1 }; } // Helper: grow snake function growSnake() { var last = snake[snake.length - 1]; var seg = new SnakeSegment(); seg.setType('body'); seg.x = last.x; seg.y = last.y; snake.push(seg); game.addChild(seg); snakePositions.push({ x: seg.x, y: seg.y }); } // Helper: check self collision function checkSelfCollision() { var head = snake[0]; for (var i = 2; i < snake.length; i++) { var seg = snake[i]; var dx = head.x - seg.x; var dy = head.y - seg.y; if (dx * dx + dy * dy < 60 * 60) { return true; } } return false; } // Helper: check wall collision function checkWallCollision() { var head = snake[0]; var margin = 40; if (head.x < margin || head.x > GAME_WIDTH - margin || head.y < margin || head.y > GAME_HEIGHT - margin) { return true; } return false; } // Helper: check animal collision function checkAnimalCollision() { var head = snake[0]; for (var i = 0; i < animals.length; i++) { var animal = animals[i]; var dx = head.x - animal.x; var dy = head.y - animal.y; if (dx * dx + dy * dy < 80 * 80) { return i; } } return -1; } // Helper: handle eating animal function eatAnimal(idx) { var animal = animals[idx]; if (animal.type === ANIMAL_TYPES[currentTargetIndex]) { // Correct animal growSnake(); score++; scoreTxt.setText(score); // Remove and respawn this animal animal.destroy(); animals.splice(idx, 1); // Next in sequence currentTargetIndex++; if (currentTargetIndex >= ANIMAL_TYPES.length) { // Sequence complete sequenceCount++; currentTargetIndex = 0; // Speed up snakeSpeed = Math.min(snakeSpeed + SNAKE_SPEED_INCREMENT, SNAKE_MAX_SPEED); // Respawn all animals spawnAnimals(); // Flash green LK.effects.flashScreen(0x00ff00, 400); } else { // Only respawn this animal var newAnimal = new Animal(); newAnimal.setType(animal.type); var pos = getRandomAnimalPos(); newAnimal.x = pos.x; newAnimal.y = pos.y; animals.push(newAnimal); game.addChild(newAnimal); } updateOrderText(); } else { // Wrong animal: game over LK.effects.flashScreen(0xff0000, 800); isGameOver = true; LK.showGameOver(); } } // Helper: handle game over function handleGameOver() { isGameOver = true; // LK.showGameOver() already called } // Input: swipe to change direction function getSwipeDir(dx, dy) { if (Math.abs(dx) > Math.abs(dy)) { return { x: dx > 0 ? 1 : -1, y: 0 }; } else { return { x: 0, y: dy > 0 ? 1 : -1 }; } } // Input: touch/drag game.down = function (x, y, obj) { dragStart = { x: x, y: y }; }; game.up = function (x, y, obj) { dragStart = null; }; game.move = function (x, y, obj) { if (dragStart && !isGameOver) { var dx = x - dragStart.x; var dy = y - dragStart.y; if (dx * dx + dy * dy > 80 * 80) { var dir = getSwipeDir(dx, dy); // Prevent reversing if (!(dir.x === -snakeDir.x && dir.y === -snakeDir.y)) { snakeNextDir = dir; } dragStart = null; } } }; // Main update loop game.update = function () { if (isGameOver) return; // Move snake // Update direction if (snakeNextDir.x !== snakeDir.x || snakeNextDir.y !== snakeDir.y) { snakeDir = { x: snakeNextDir.x, y: snakeNextDir.y }; } // Calculate new head position var head = snake[0]; var newX = head.x + snakeDir.x * snakeSpeed; var newY = head.y + snakeDir.y * snakeSpeed; // Store previous positions snakePositions.unshift({ x: newX, y: newY }); if (snakePositions.length > snake.length * SEGMENT_SPACING / snakeSpeed + 2) { snakePositions.pop(); } // Move segments for (var i = 0; i < snake.length; i++) { var posIdx = Math.min(i * Math.floor(SEGMENT_SPACING / snakeSpeed), snakePositions.length - 1); var pos = snakePositions[posIdx]; snake[i].x = pos.x; snake[i].y = pos.y; } // Check wall collision if (checkWallCollision()) { LK.effects.flashScreen(0xff0000, 800); handleGameOver(); LK.showGameOver(); return; } // Check self collision if (checkSelfCollision()) { LK.effects.flashScreen(0xff0000, 800); handleGameOver(); LK.showGameOver(); return; } // Check animal collision var animalIdx = checkAnimalCollision(); if (animalIdx !== -1) { eatAnimal(animalIdx); } }; // Game start/reset function startGame() { isGameOver = false; score = 0; sequenceCount = 0; snakeSpeed = SNAKE_START_SPEED; currentTargetIndex = 0; scoreTxt.setText(score); updateOrderText(); resetSnake(); spawnAnimals(); } startGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Animal class
var Animal = Container.expand(function () {
var self = Container.call(this);
self.type = null;
self.asset = null;
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
self.asset = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
};
return self;
});
// Snake Segment (body or head)
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
self.asset = null;
self.setType = function (type) {
if (self.asset) {
self.removeChild(self.asset);
}
var assetId = type === 'head' ? 'snakeHead' : 'snakeBody';
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.setType('body');
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Animal assets: pig, cat, bee, frog (box/ellipse with different colors)
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var SNAKE_START_LENGTH = 3;
var SNAKE_START_SPEED = 8; // pixels per tick
var SNAKE_SPEED_INCREMENT = 1.5; // speed up per sequence
var SNAKE_MAX_SPEED = 32;
var SEGMENT_SPACING = 90; // px between segments
var ANIMAL_TYPES = ['pig', 'cat', 'bee', 'frog'];
var ANIMAL_NAMES = {
pig: "Pig",
cat: "Cat",
bee: "Bee",
frog: "Frog"
};
// Game state
var snake = [];
var snakeDir = {
x: 0,
y: -1
}; // start moving up
var snakeNextDir = {
x: 0,
y: -1
};
var snakeSpeed = SNAKE_START_SPEED;
var snakePositions = []; // for body following
var animals = [];
var currentTargetIndex = 0; // which animal in sequence to eat next
var score = 0;
var sequenceCount = 0;
var isGameOver = false;
var moveCooldown = 0; // for swipe input
var dragStart = null;
// GUI
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var orderTxt = new Text2('', {
size: 70,
fill: "#fff"
});
orderTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(orderTxt);
orderTxt.y = 130;
// Helper: get random position for animal, not too close to snake head
function getRandomAnimalPos() {
var margin = 180;
var tries = 0;
while (tries < 20) {
var x = margin + Math.random() * (GAME_WIDTH - 2 * margin);
var y = margin + Math.random() * (GAME_HEIGHT - 2 * margin);
// Avoid spawning too close to snake head
var dx = x - snake[0].x;
var dy = y - snake[0].y;
if (dx * dx + dy * dy > 400 * 400) {
return {
x: x,
y: y
};
}
tries++;
}
// fallback
return {
x: margin + Math.random() * (GAME_WIDTH - 2 * margin),
y: margin + Math.random() * (GAME_HEIGHT - 2 * margin)
};
}
// Helper: update order text
function updateOrderText() {
var s = '';
for (var i = 0; i < ANIMAL_TYPES.length; i++) {
if (i === currentTargetIndex) {
s += '[b]' + ANIMAL_NAMES[ANIMAL_TYPES[i]] + '[/b] ';
} else {
s += ANIMAL_NAMES[ANIMAL_TYPES[i]] + ' ';
}
}
orderTxt.setText(s.trim());
}
// Helper: spawn all animals
function spawnAnimals() {
// Remove old
for (var i = 0; i < animals.length; i++) {
animals[i].destroy();
}
animals = [];
for (var i = 0; i < ANIMAL_TYPES.length; i++) {
var animal = new Animal();
animal.setType(ANIMAL_TYPES[i]);
var pos = getRandomAnimalPos();
animal.x = pos.x;
animal.y = pos.y;
animals.push(animal);
game.addChild(animal);
}
}
// Helper: reset snake
function resetSnake() {
for (var i = 0; i < snake.length; i++) {
snake[i].destroy();
}
snake = [];
snakePositions = [];
var startX = GAME_WIDTH / 2;
var startY = GAME_HEIGHT / 2 + 300;
for (var i = 0; i < SNAKE_START_LENGTH; i++) {
var seg = new SnakeSegment();
seg.setType(i === 0 ? 'head' : 'body');
seg.x = startX;
seg.y = startY + i * SEGMENT_SPACING;
snake.push(seg);
game.addChild(seg);
snakePositions.push({
x: seg.x,
y: seg.y
});
}
snakeDir = {
x: 0,
y: -1
};
snakeNextDir = {
x: 0,
y: -1
};
}
// Helper: grow snake
function growSnake() {
var last = snake[snake.length - 1];
var seg = new SnakeSegment();
seg.setType('body');
seg.x = last.x;
seg.y = last.y;
snake.push(seg);
game.addChild(seg);
snakePositions.push({
x: seg.x,
y: seg.y
});
}
// Helper: check self collision
function checkSelfCollision() {
var head = snake[0];
for (var i = 2; i < snake.length; i++) {
var seg = snake[i];
var dx = head.x - seg.x;
var dy = head.y - seg.y;
if (dx * dx + dy * dy < 60 * 60) {
return true;
}
}
return false;
}
// Helper: check wall collision
function checkWallCollision() {
var head = snake[0];
var margin = 40;
if (head.x < margin || head.x > GAME_WIDTH - margin || head.y < margin || head.y > GAME_HEIGHT - margin) {
return true;
}
return false;
}
// Helper: check animal collision
function checkAnimalCollision() {
var head = snake[0];
for (var i = 0; i < animals.length; i++) {
var animal = animals[i];
var dx = head.x - animal.x;
var dy = head.y - animal.y;
if (dx * dx + dy * dy < 80 * 80) {
return i;
}
}
return -1;
}
// Helper: handle eating animal
function eatAnimal(idx) {
var animal = animals[idx];
if (animal.type === ANIMAL_TYPES[currentTargetIndex]) {
// Correct animal
growSnake();
score++;
scoreTxt.setText(score);
// Remove and respawn this animal
animal.destroy();
animals.splice(idx, 1);
// Next in sequence
currentTargetIndex++;
if (currentTargetIndex >= ANIMAL_TYPES.length) {
// Sequence complete
sequenceCount++;
currentTargetIndex = 0;
// Speed up
snakeSpeed = Math.min(snakeSpeed + SNAKE_SPEED_INCREMENT, SNAKE_MAX_SPEED);
// Respawn all animals
spawnAnimals();
// Flash green
LK.effects.flashScreen(0x00ff00, 400);
} else {
// Only respawn this animal
var newAnimal = new Animal();
newAnimal.setType(animal.type);
var pos = getRandomAnimalPos();
newAnimal.x = pos.x;
newAnimal.y = pos.y;
animals.push(newAnimal);
game.addChild(newAnimal);
}
updateOrderText();
} else {
// Wrong animal: game over
LK.effects.flashScreen(0xff0000, 800);
isGameOver = true;
LK.showGameOver();
}
}
// Helper: handle game over
function handleGameOver() {
isGameOver = true;
// LK.showGameOver() already called
}
// Input: swipe to change direction
function getSwipeDir(dx, dy) {
if (Math.abs(dx) > Math.abs(dy)) {
return {
x: dx > 0 ? 1 : -1,
y: 0
};
} else {
return {
x: 0,
y: dy > 0 ? 1 : -1
};
}
}
// Input: touch/drag
game.down = function (x, y, obj) {
dragStart = {
x: x,
y: y
};
};
game.up = function (x, y, obj) {
dragStart = null;
};
game.move = function (x, y, obj) {
if (dragStart && !isGameOver) {
var dx = x - dragStart.x;
var dy = y - dragStart.y;
if (dx * dx + dy * dy > 80 * 80) {
var dir = getSwipeDir(dx, dy);
// Prevent reversing
if (!(dir.x === -snakeDir.x && dir.y === -snakeDir.y)) {
snakeNextDir = dir;
}
dragStart = null;
}
}
};
// Main update loop
game.update = function () {
if (isGameOver) return;
// Move snake
// Update direction
if (snakeNextDir.x !== snakeDir.x || snakeNextDir.y !== snakeDir.y) {
snakeDir = {
x: snakeNextDir.x,
y: snakeNextDir.y
};
}
// Calculate new head position
var head = snake[0];
var newX = head.x + snakeDir.x * snakeSpeed;
var newY = head.y + snakeDir.y * snakeSpeed;
// Store previous positions
snakePositions.unshift({
x: newX,
y: newY
});
if (snakePositions.length > snake.length * SEGMENT_SPACING / snakeSpeed + 2) {
snakePositions.pop();
}
// Move segments
for (var i = 0; i < snake.length; i++) {
var posIdx = Math.min(i * Math.floor(SEGMENT_SPACING / snakeSpeed), snakePositions.length - 1);
var pos = snakePositions[posIdx];
snake[i].x = pos.x;
snake[i].y = pos.y;
}
// Check wall collision
if (checkWallCollision()) {
LK.effects.flashScreen(0xff0000, 800);
handleGameOver();
LK.showGameOver();
return;
}
// Check self collision
if (checkSelfCollision()) {
LK.effects.flashScreen(0xff0000, 800);
handleGameOver();
LK.showGameOver();
return;
}
// Check animal collision
var animalIdx = checkAnimalCollision();
if (animalIdx !== -1) {
eatAnimal(animalIdx);
}
};
// Game start/reset
function startGame() {
isGameOver = false;
score = 0;
sequenceCount = 0;
snakeSpeed = SNAKE_START_SPEED;
currentTargetIndex = 0;
scoreTxt.setText(score);
updateOrderText();
resetSnake();
spawnAnimals();
}
startGame();