/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Orb class var Orb = Container.expand(function () { var self = Container.call(this); // Randomize orb color and size var orbColors = [0xffe066, 0x66e0ff, 0xff66b3, 0x8cf58c, 0xffb366, 0xc299fc, 0xfff266]; var color = orbColors[Math.floor(Math.random() * orbColors.length)]; var minSize = 55, maxSize = 90; var size = minSize + Math.random() * (maxSize - minSize); var orb = self.attachAsset('orb', { anchorX: 0.5, anchorY: 0.5, width: size, height: size, color: color }); // Animate orb with a pulsing effect tween(orb, { scaleX: 1.2, scaleY: 1.2 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(orb, { scaleX: 1, scaleY: 1 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { // Loop if (self.parent) { orb.scaleX = 1; orb.scaleY = 1; tween(orb, { scaleX: 1.2, scaleY: 1.2 }, { duration: 600, easing: tween.easeInOut, onFinish: arguments.callee }); } } }); } }); return self; }); // Snake Segment (body or head) var SnakeSegment = Container.expand(function () { var self = Container.call(this); // By default, body segment var assetId = self.isHead ? 'snakeHead' : 'snakeBody'; var seg = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181c2c }); /**** * Game Code ****/ // Orb: glowing yellow // Snake body: ellipse, lighter green // Snake head: ellipse, bright green // Game constants var GAME_W = 2048; var GAME_H = 2732; var ARENA_MARGIN = 60; // px, keep snake/orbs away from edge var SNAKE_INIT_LEN = 6; var SNAKE_SPEED = 13; // px per tick var SNAKE_TURN_SPEED = 0.16; // radians per tick var ORB_COUNT = 3; // State var snake = []; var snakeDirs = []; // Array of directions (radians) for each segment var snakeTargetDir = 0; // radians, where the head is steering var snakeCurDir = 0; // radians, current head direction var snakePendingGrowth = 0; var orbs = []; var dragging = false; var dragTarget = { x: 0, y: 0 }; var score = 0; var gameOver = false; // GUI var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Helper: clamp function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Helper: distance function dist(ax, ay, bx, by) { var dx = ax - bx; var dy = ay - by; return Math.sqrt(dx * dx + dy * dy); } // Helper: angle between two points function angleTo(ax, ay, bx, by) { return Math.atan2(by - ay, bx - ax); } // Helper: wrap angle to [-PI, PI] function wrapAngle(a) { while (a > Math.PI) a -= Math.PI * 2; while (a < -Math.PI) a += Math.PI * 2; return a; } // Helper: random position inside arena function randomArenaPos() { var x = ARENA_MARGIN + Math.random() * (GAME_W - 2 * ARENA_MARGIN); var y = ARENA_MARGIN + Math.random() * (GAME_H - 2 * ARENA_MARGIN); return { x: x, y: y }; } // Place orbs, avoiding snake function placeOrb(orb) { var tries = 0; while (tries < 20) { var pos = randomArenaPos(); var ok = true; for (var i = 0; i < snake.length; ++i) { if (dist(pos.x, pos.y, snake[i].x, snake[i].y) < 180) { ok = false; break; } } if (ok) { orb.x = pos.x; orb.y = pos.y; return; } tries++; } // fallback orb.x = ARENA_MARGIN + Math.random() * (GAME_W - 2 * ARENA_MARGIN); orb.y = ARENA_MARGIN + Math.random() * (GAME_H - 2 * ARENA_MARGIN); } // Initialize snake function initSnake() { // Remove old for (var i = 0; i < snake.length; ++i) { snake[i].destroy(); } snake = []; snakeDirs = []; // Center start var startX = GAME_W / 2; var startY = GAME_H / 2; var dir = -Math.PI / 2; // Up for (var i = 0; i < SNAKE_INIT_LEN; ++i) { var seg = new SnakeSegment(); seg.isHead = i === 0; // Re-attach correct asset for head if (seg.isHead) { seg.removeChildren(); seg.attachAsset('snakeHead', { anchorX: 0.5, anchorY: 0.5 }); } seg.x = startX - Math.cos(dir) * i * 85; seg.y = startY - Math.sin(dir) * i * 85; game.addChild(seg); snake.push(seg); snakeDirs.push(dir); } snakeCurDir = dir; snakeTargetDir = dir; snakePendingGrowth = 0; } // Initialize orbs function initOrbs() { for (var i = 0; i < orbs.length; ++i) { orbs[i].destroy(); } orbs = []; for (var i = 0; i < ORB_COUNT; ++i) { var orb = new Orb(); placeOrb(orb); game.addChild(orb); orbs.push(orb); } } // Reset game state function resetGame() { score = 0; scoreTxt.setText(score); gameOver = false; initSnake(); initOrbs(); window._orbsEaten = 0; } // Start game resetGame(); // Touch/drag controls game.down = function (x, y, obj) { // Don't allow drag in top left 100x100 if (x < 100 && y < 100) return; dragging = true; dragTarget.x = x; dragTarget.y = y; // Set target direction immediately var head = snake[0]; snakeTargetDir = angleTo(head.x, head.y, x, y); }; game.move = function (x, y, obj) { if (!dragging) return; dragTarget.x = x; dragTarget.y = y; var head = snake[0]; snakeTargetDir = angleTo(head.x, head.y, x, y); }; game.up = function (x, y, obj) { dragging = false; }; // Main update loop game.update = function () { if (gameOver) return; // Move snake head var head = snake[0]; var angleDiff = wrapAngle(snakeTargetDir - snakeCurDir); // Limit turn speed if (Math.abs(angleDiff) > SNAKE_TURN_SPEED) { snakeCurDir += SNAKE_TURN_SPEED * (angleDiff > 0 ? 1 : -1); } else { snakeCurDir = snakeTargetDir; } // Move head forward var newHeadX = head.x + Math.cos(snakeCurDir) * SNAKE_SPEED; var newHeadY = head.y + Math.sin(snakeCurDir) * SNAKE_SPEED; // Check wall collision if (newHeadX < ARENA_MARGIN || newHeadX > GAME_W - ARENA_MARGIN || newHeadY < ARENA_MARGIN || newHeadY > GAME_H - ARENA_MARGIN) { // Game over LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); gameOver = true; return; } // Move body: each segment follows the previous var prevX = head.x, prevY = head.y; var prevDir = snakeCurDir; // Move head head.x = newHeadX; head.y = newHeadY; snakeDirs[0] = snakeCurDir; // Rotate head to face direction if (head.children && head.children.length > 0) { head.children[0].rotation = snakeCurDir; } for (var i = 1; i < snake.length; ++i) { var seg = snake[i]; var dx = prevX - seg.x; var dy = prevY - seg.y; var d = Math.sqrt(dx * dx + dy * dy); var desiredDist = 85; if (d > 1) { var moveDist = clamp(d - desiredDist, 0, SNAKE_SPEED * 1.2); if (moveDist > 0) { var moveX = seg.x + dx / d * moveDist; var moveY = seg.y + dy / d * moveDist; seg.x = moveX; seg.y = moveY; } } // Face the direction of movement with smooth turning var targetDir = Math.atan2(seg.y - prevY, seg.x - prevX); var curDir = snakeDirs[i]; var diff = wrapAngle(targetDir - curDir); if (Math.abs(diff) > SNAKE_TURN_SPEED) { curDir += SNAKE_TURN_SPEED * (diff > 0 ? 1 : -1); } else { curDir = targetDir; } snakeDirs[i] = curDir; // Rotate segment to face movement direction if (seg.children && seg.children.length > 0) { seg.children[0].rotation = curDir; } prevX = seg.x; prevY = seg.y; prevDir = snakeDirs[i]; } // Check self-collision (head with body, skip first 3 segments for leniency) for (var i = 3; i < snake.length; ++i) { var seg = snake[i]; if (dist(head.x, head.y, seg.x, seg.y) < 60) { // Game over LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); gameOver = true; return; } } // Check orb collision for (var i = 0; i < orbs.length; ++i) { var orb = orbs[i]; if (dist(head.x, head.y, orb.x, orb.y) < 80) { // Eat orb score += 1; scoreTxt.setText(score); // Grow much slower: require 5 orbs per new segment if (!window._orbsEaten) window._orbsEaten = 0; window._orbsEaten += 1; if (window._orbsEaten >= 5) { snakePendingGrowth += 1; window._orbsEaten = 0; } // Animate orb tween(orb, { scaleX: 1.7, scaleY: 1.7, alpha: 0 }, { duration: 180, easing: tween.easeOut, onFinish: function (orb, i) { return function () { orb.scaleX = 1; orb.scaleY = 1; orb.alpha = 1; placeOrb(orb); }; }(orb, i) }); } } // Grow snake if needed while (snakePendingGrowth > 0) { var last = snake[snake.length - 1]; var dir = snakeDirs[snake.length - 1]; var seg = new SnakeSegment(); seg.isHead = false; seg.removeChildren(); seg.attachAsset('snakeBody', { anchorX: 0.5, anchorY: 0.5 }); // Place at last segment's position, trailing behind seg.x = last.x - Math.cos(dir) * 85; seg.y = last.y - Math.sin(dir) * 85; // Rotate new segment to match direction if (seg.children && seg.children.length > 0) { seg.children[0].rotation = dir; } game.addChild(seg); snake.push(seg); snakeDirs.push(dir); snakePendingGrowth--; } }; // On game over, reset state for replay LK.on('gameover', function () { resetGame(); }); LK.on('youWin', function () { resetGame(); });
===================================================================
--- original.js
+++ change.js
@@ -8,11 +8,20 @@
****/
// Orb class
var Orb = Container.expand(function () {
var self = Container.call(this);
+ // Randomize orb color and size
+ var orbColors = [0xffe066, 0x66e0ff, 0xff66b3, 0x8cf58c, 0xffb366, 0xc299fc, 0xfff266];
+ var color = orbColors[Math.floor(Math.random() * orbColors.length)];
+ var minSize = 55,
+ maxSize = 90;
+ var size = minSize + Math.random() * (maxSize - minSize);
var orb = self.attachAsset('orb', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ width: size,
+ height: size,
+ color: color
});
// Animate orb with a pulsing effect
tween(orb, {
scaleX: 1.2,