Code edit (1 edits merged)
Please save this source code
User prompt
Add a circle to player snake head. Its indicate player shooting range. It shuld be slightly visiable
User prompt
Snake lenght must be increase only 1 after eatign and kill enemy.
User prompt
background image size is 1020x1065,8 . Fix tiling Fix left top corner tiling issue
User prompt
background image size is 1024x928 . Fix tiling
User prompt
- add a gorund image it should be like hexagonal tilemap (sliter io like)
User prompt
Speed up fart nuke effects. It must disappear faster.
User prompt
Those nuke farts must be an asset. So i can change their visuals.
User prompt
Enemy nuke fart need to be differnt from player snake nuke fart. Dont change the players nuke fart. Change enemy snake nuke fart visual
User prompt
add a nuke fart to enemy snake. I trigger when take hit
User prompt
incrase firerate %50
User prompt
Dont destroy enemy snake use pooling system. When enemy snake is dead it need to return to pool. When i need new snake system need to fetch from pool an initialize that snake
User prompt
-Enemies need to spawn every 2 seconds. - Reduce player firerate - player bullet must be faced to enemy(rotate)
User prompt
enemies must be spawn outsides ıof the screen. When i reach the 1000 score i need to win. Enemi
User prompt
add longer enemys. They will come after get 100 score. Every 100 score pass enemies come longer and longer
User prompt
snake can be move only mouse button is holding.
User prompt
when snake reach the last mouse position dont change the face rotation
User prompt
when snake is not moving its head are shaking fix this
User prompt
Scale ratio isint working properly Fix this. It must be like triangle lookalike
User prompt
When player eating First segments are going to be bigger. For example if head scale is end tail scale is 0.2 and middle segments must be ratio scale in these two numbers. (The numbers is example use active scalse)
User prompt
Make a player snake tail more smaller than head. The segment scales are rated whit its positions
User prompt
add rotation to enemy head and segments like a players.
User prompt
Oh c onn. Use snake head asset for snake head. Use snake body asset for snake body. Fix immediately.
User prompt
I change the snake parts whit square. So you need to fix like its need to rotate when following the mouse.
User prompt
Add mega fart to player. This is like a nuke particle. It will be shown when player eat something
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet var Bullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.owner = null; // 'player' or 'enemy' self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Enemy Snake Head var EnemyHead = Container.expand(function () { var self = Container.call(this); var head = self.attachAsset('enemyHead', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Enemy Snake Segment var EnemySegment = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('enemyBody', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Enemy Snake var EnemySnake = Container.expand(function () { var self = Container.call(this); self.segments = []; self.head = new EnemyHead(); self.addChild(self.head); self.segments.push(self.head); self.length = 4 + Math.floor(Math.random() * 3); self.speed = 13 + Math.random() * 4; self.targetX = 1024 + (Math.random() - 0.5) * 800; self.targetY = 1366 + (Math.random() - 0.5) * 1200; self.lastMoveX = 0; self.lastMoveY = 1; self.alive = true; // Initialize body for (var i = 1; i < self.length; i++) { var seg = new EnemySegment(); seg.x = self.head.x; seg.y = self.head.y + i * 80; self.addChild(seg); self.segments.push(seg); } // Move snake self.moveSnake = function (playerPos) { // Move toward player, but with some randomness var dx = 0, dy = 0; if (playerPos && typeof playerPos.x === "number" && typeof playerPos.y === "number" && self.head && typeof self.head.x === "number" && typeof self.head.y === "number") { dx = playerPos.x - self.head.x + (Math.random() - 0.5) * 200; dy = playerPos.y - self.head.y + (Math.random() - 0.5) * 200; } else { // fallback: move randomly if playerPos or self.head is not valid dx = (Math.random() - 0.5) * 200; dy = (Math.random() - 0.5) * 200; } var dist = Math.sqrt(dx * dx + dy * dy); var moveX = 0, moveY = 0; if (dist > 10) { moveX = dx / dist; moveY = dy / dist; self.lastMoveX = moveX; self.lastMoveY = moveY; } else { moveX = self.lastMoveX; moveY = self.lastMoveY; } self.head.x += moveX * self.speed; self.head.y += moveY * self.speed; // Move body for (var i = self.segments.length - 1; i > 0; i--) { var prev = self.segments[i - 1]; var seg = self.segments[i]; var pdx = prev.x - seg.x; var pdy = prev.y - seg.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); if (pdist > 80) { seg.x += pdx / pdist * Math.min(self.speed, pdist - 80); seg.y += pdy / pdist * Math.min(self.speed, pdist - 80); } } }; // Update self.update = function (playerPos) { if (!self.alive) return; self.moveSnake(playerPos); }; // Get head position self.getHeadPos = function () { return { x: self.head.x, y: self.head.y }; }; // Get direction vector self.getDirection = function () { return { x: self.lastMoveX, y: self.lastMoveY }; }; // Die self.die = function () { self.alive = false; // Fade out for (var i = 0; i < self.segments.length; i++) { tween(self.segments[i], { alpha: 0 }, { duration: 400, easing: tween.linear, onFinish: function onFinish() { self.destroy(); } }); } }; return self; }); // (Flame Fart Burst removed) // Food var Food = Container.expand(function () { var self = Container.call(this); var food = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // MegaFart effect (nuke particle) var MegaFart = Container.expand(function () { var self = Container.call(this); // Create a big, semi-transparent ellipse as the nuke core var core = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5, scaleX: 6, scaleY: 6 }); core.alpha = 0.35; core.tint = 0x00ffcc; // Add a second, larger, colored ellipse for the outer glow var glow = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10 }); glow.alpha = 0.18; glow.tint = 0x00ffff; // Animate: expand and fade out, then destroy self.play = function () { // Animate both core and glow tween(core, { scaleX: 10, scaleY: 10, alpha: 0 }, { duration: 700, easing: tween.easeOutCubic }); tween(glow, { scaleX: 16, scaleY: 16, alpha: 0 }, { duration: 700, easing: tween.easeOutCubic }); // Fade out and destroy container after animation tween(self, {}, { duration: 700, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Player Snake var PlayerSnake = Container.expand(function () { var self = Container.call(this); self.segments = []; self.directions = []; self.head = new SnakeHead(); self.addChild(self.head); self.segments.push(self.head); self.length = 5; self.speed = 12; self.targetX = 1024; self.targetY = 1366; self.lastMoveX = 0; self.lastMoveY = -1; self.growPending = 0; self.lastFireTick = 0; // Initialize body for (var i = 1; i < self.length; i++) { var seg = new SnakeSegment(); seg.x = self.head.x; seg.y = self.head.y + i * 80; self.addChild(seg); self.segments.push(seg); } // Move snake self.moveSnake = function () { // Calculate direction to target var dx = self.targetX - self.head.x; var dy = self.targetY - self.head.y; var dist = Math.sqrt(dx * dx + dy * dy); var moveX = 0, moveY = 0; if (dist > 10) { moveX = dx / dist; moveY = dy / dist; self.lastMoveX = moveX; self.lastMoveY = moveY; } else { moveX = self.lastMoveX; moveY = self.lastMoveY; } // Move head self.head.x += moveX * self.speed; self.head.y += moveY * self.speed; // Move body for (var i = self.segments.length - 1; i > 0; i--) { var prev = self.segments[i - 1]; var seg = self.segments[i]; var pdx = prev.x - seg.x; var pdy = prev.y - seg.y; var pdist = Math.sqrt(pdx * pdx + pdy * pdy); if (pdist > 80) { seg.x += pdx / pdist * Math.min(self.speed, pdist - 80); seg.y += pdy / pdist * Math.min(self.speed, pdist - 80); } } }; // Grow snake self.grow = function (n) { self.growPending += n; }; // Update self.update = function () { self.moveSnake(); // Handle growth if (self.growPending > 0) { var last = self.segments[self.segments.length - 1]; var seg = new SnakeSegment(); seg.x = last.x; seg.y = last.y; self.addChild(seg); self.segments.push(seg); self.growPending--; } }; // Get head position self.getHeadPos = function () { return { x: self.head.x, y: self.head.y }; }; // Get direction vector self.getDirection = function () { return { x: self.lastMoveX, y: self.lastMoveY }; }; return self; }); // Player Snake Head var SnakeHead = Container.expand(function () { var self = Container.call(this); var head = self.attachAsset('snakeHead', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Player Snake Segment var SnakeSegment = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('snakeBody', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Game variables // Snake body segment (player) // Snake head (player) // Enemy snake body // Enemy snake head // Food // Bullet // Flame fart burst // (flame asset removed) var playerSnake; var enemySnakes = []; var foods = []; var bullets = []; // (flames array removed) var scoreTxt; var dragNode = null; var lastFireTick = 0; var spawnFoodTick = 0; var spawnEnemyTick = 0; var gameArea = { x: 120, y: 120, w: 2048 - 240, h: 2732 - 240 }; // leave margin for UI // Score display scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Initialize player snake playerSnake = new PlayerSnake(); playerSnake.head.x = 1024; playerSnake.head.y = 1800; for (var i = 0; i < playerSnake.segments.length; i++) { playerSnake.segments[i].x = 1024; playerSnake.segments[i].y = 1800 + i * 80; } game.addChild(playerSnake); // Spawn initial food function spawnFood() { var f = new Food(); f.x = gameArea.x + 100 + Math.random() * (gameArea.w - 200); f.y = gameArea.y + 100 + Math.random() * (gameArea.h - 200); foods.push(f); game.addChild(f); } for (var i = 0; i < 8; i++) { spawnFood(); } // Spawn enemy snake function spawnEnemy() { var e = new EnemySnake(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top e.head.x = gameArea.x + Math.random() * gameArea.w; e.head.y = gameArea.y - 120; } else if (edge === 1) { // bottom e.head.x = gameArea.x + Math.random() * gameArea.w; e.head.y = gameArea.y + gameArea.h + 120; } else if (edge === 2) { // left e.head.x = gameArea.x - 120; e.head.y = gameArea.y + Math.random() * gameArea.h; } else { // right e.head.x = gameArea.x + gameArea.w + 120; e.head.y = gameArea.y + Math.random() * gameArea.h; } for (var i = 1; i < e.segments.length; i++) { e.segments[i].x = e.head.x; e.segments[i].y = e.head.y + i * 80; } enemySnakes.push(e); game.addChild(e); } for (var i = 0; i < 2; i++) { spawnEnemy(); } // Handle dragging game.down = function (x, y, obj) { dragNode = playerSnake; playerSnake.targetX = x; playerSnake.targetY = y; }; game.move = function (x, y, obj) { if (dragNode) { playerSnake.targetX = x; playerSnake.targetY = y; } }; game.up = function (x, y, obj) { dragNode = null; }; // Helper: check collision between two containers (circle-based) function circlesIntersect(a, b, rA, rB) { var dx = a.x - b.x; var dy = a.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); return dist < (rA + rB) * 0.5; } // Helper: clamp to game area function clampToArea(x, y) { x = Math.max(gameArea.x + 50, Math.min(gameArea.x + gameArea.w - 50, x)); y = Math.max(gameArea.y + 50, Math.min(gameArea.y + gameArea.h - 50, y)); return { x: x, y: y }; } // Main game update game.update = function () { // Update player snake playerSnake.update(); // Clamp player head to area var clamped = clampToArea(playerSnake.head.x, playerSnake.head.y); playerSnake.head.x = clamped.x; playerSnake.head.y = clamped.y; // Update enemy snakes for (var i = enemySnakes.length - 1; i >= 0; i--) { var e = enemySnakes[i]; if (!e.alive) continue; e.update(playerSnake.getHeadPos()); // Clamp enemy head to area var ce = clampToArea(e.head.x, e.head.y); e.head.x = ce.x; e.head.y = ce.y; } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); // Remove if out of bounds if (b.x < gameArea.x - 60 || b.x > gameArea.x + gameArea.w + 60 || b.y < gameArea.y - 60 || b.y > gameArea.y + gameArea.h + 60) { b.destroy(); bullets.splice(i, 1); continue; } // Bullet hits enemy snake if (b.owner === 'player') { for (var j = 0; j < enemySnakes.length; j++) { var e = enemySnakes[j]; if (!e.alive) continue; if (circlesIntersect(b, e.head, 60, 60)) { // Hit! b.destroy(); bullets.splice(i, 1); // Shorten enemy snake or kill var killed = false; if (e.segments.length > 2) { var seg = e.segments.pop(); seg.destroy(); } else { e.die(); killed = true; } LK.setScore(LK.getScore() + 5); scoreTxt.setText(LK.getScore()); // Player fart effect when enemy is killed if (killed) { // Flash the head and all body segments for a more visible fart effect for (var f = 0; f < playerSnake.segments.length; f++) { LK.effects.flashObject(playerSnake.segments[f], 0xcccc00, 600); } } break; } } } // Bullet hits player (if we add enemy bullets in future) } // Player eats food for (var i = foods.length - 1; i >= 0; i--) { var food = foods[i]; if (circlesIntersect(playerSnake.head, food, 60, 35)) { food.destroy(); foods.splice(i, 1); playerSnake.grow(2); LK.setScore(LK.getScore() + 1); scoreTxt.setText(LK.getScore()); // MegaFart effect: nuke particle at player head var megaFart = new MegaFart(); megaFart.x = playerSnake.head.x; megaFart.y = playerSnake.head.y; game.addChild(megaFart); megaFart.play(); // Win condition removed } } // Player collides with enemy snake head or body for (var i = 0; i < enemySnakes.length; i++) { var e = enemySnakes[i]; if (!e.alive) continue; // Head to head if (circlesIntersect(playerSnake.head, e.head, 60, 60)) { LK.effects.flashScreen(0xff3300, 800); LK.showGameOver(); return; } // Head to body for (var j = 1; j < e.segments.length; j++) { if (circlesIntersect(playerSnake.head, e.segments[j], 60, 40)) { LK.effects.flashScreen(0xff3300, 800); LK.showGameOver(); return; } } } // Player collides with self (not head) for (var i = 2; i < playerSnake.segments.length; i++) { if (circlesIntersect(playerSnake.head, playerSnake.segments[i], 60, 40)) { LK.effects.flashScreen(0xff3300, 800); LK.showGameOver(); return; } } // Spawn food spawnFoodTick++; if (spawnFoodTick > 40 && foods.length < 12) { spawnFood(); spawnFoodTick = 0; } // Spawn enemy spawnEnemyTick++; if (spawnEnemyTick > 80 && enemySnakes.length < 8) { spawnEnemy(); spawnEnemyTick = 0; } // Minigun: auto-fire at nearest enemy in range if (LK.ticks - lastFireTick > 4) { // ~15 shots/sec var nearest = null; var minDist = 99999; for (var i = 0; i < enemySnakes.length; i++) { var e = enemySnakes[i]; if (!e.alive) continue; var dx = e.head.x - playerSnake.head.x; var dy = e.head.y - playerSnake.head.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 600 && dist < minDist) { minDist = dist; nearest = e; } } if (nearest) { fireBulletAt(playerSnake.head.x, playerSnake.head.y, nearest.head.x, nearest.head.y, 'player'); lastFireTick = LK.ticks; } } }; // Fire bullet from (x0,y0) to (x1,y1) function fireBulletAt(x0, y0, x1, y1, owner) { var b = new Bullet(); b.x = x0; b.y = y0; var dx = x1 - x0; var dy = y1 - y0; var dist = Math.sqrt(dx * dx + dy * dy); var speed = 38; b.vx = dx / dist * speed; b.vy = dy / dist * speed; b.owner = owner; bullets.push(b); game.addChild(b); } // (spawnFlameBurst removed) // Center score text scoreTxt.setText(LK.getScore()); scoreTxt.anchor.set(0.5, 0); // No music or sound for MVP
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.owner = null; // 'player' or 'enemy'
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Enemy Snake Head
var EnemyHead = Container.expand(function () {
var self = Container.call(this);
var head = self.attachAsset('enemyHead', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Enemy Snake Segment
var EnemySegment = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('enemyBody', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Enemy Snake
var EnemySnake = Container.expand(function () {
var self = Container.call(this);
self.segments = [];
self.head = new EnemyHead();
self.addChild(self.head);
self.segments.push(self.head);
self.length = 4 + Math.floor(Math.random() * 3);
self.speed = 13 + Math.random() * 4;
self.targetX = 1024 + (Math.random() - 0.5) * 800;
self.targetY = 1366 + (Math.random() - 0.5) * 1200;
self.lastMoveX = 0;
self.lastMoveY = 1;
self.alive = true;
// Initialize body
for (var i = 1; i < self.length; i++) {
var seg = new EnemySegment();
seg.x = self.head.x;
seg.y = self.head.y + i * 80;
self.addChild(seg);
self.segments.push(seg);
}
// Move snake
self.moveSnake = function (playerPos) {
// Move toward player, but with some randomness
var dx = 0,
dy = 0;
if (playerPos && typeof playerPos.x === "number" && typeof playerPos.y === "number" && self.head && typeof self.head.x === "number" && typeof self.head.y === "number") {
dx = playerPos.x - self.head.x + (Math.random() - 0.5) * 200;
dy = playerPos.y - self.head.y + (Math.random() - 0.5) * 200;
} else {
// fallback: move randomly if playerPos or self.head is not valid
dx = (Math.random() - 0.5) * 200;
dy = (Math.random() - 0.5) * 200;
}
var dist = Math.sqrt(dx * dx + dy * dy);
var moveX = 0,
moveY = 0;
if (dist > 10) {
moveX = dx / dist;
moveY = dy / dist;
self.lastMoveX = moveX;
self.lastMoveY = moveY;
} else {
moveX = self.lastMoveX;
moveY = self.lastMoveY;
}
self.head.x += moveX * self.speed;
self.head.y += moveY * self.speed;
// Move body
for (var i = self.segments.length - 1; i > 0; i--) {
var prev = self.segments[i - 1];
var seg = self.segments[i];
var pdx = prev.x - seg.x;
var pdy = prev.y - seg.y;
var pdist = Math.sqrt(pdx * pdx + pdy * pdy);
if (pdist > 80) {
seg.x += pdx / pdist * Math.min(self.speed, pdist - 80);
seg.y += pdy / pdist * Math.min(self.speed, pdist - 80);
}
}
};
// Update
self.update = function (playerPos) {
if (!self.alive) return;
self.moveSnake(playerPos);
};
// Get head position
self.getHeadPos = function () {
return {
x: self.head.x,
y: self.head.y
};
};
// Get direction vector
self.getDirection = function () {
return {
x: self.lastMoveX,
y: self.lastMoveY
};
};
// Die
self.die = function () {
self.alive = false;
// Fade out
for (var i = 0; i < self.segments.length; i++) {
tween(self.segments[i], {
alpha: 0
}, {
duration: 400,
easing: tween.linear,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
// (Flame Fart Burst removed)
// Food
var Food = Container.expand(function () {
var self = Container.call(this);
var food = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// MegaFart effect (nuke particle)
var MegaFart = Container.expand(function () {
var self = Container.call(this);
// Create a big, semi-transparent ellipse as the nuke core
var core = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 6,
scaleY: 6
});
core.alpha = 0.35;
core.tint = 0x00ffcc;
// Add a second, larger, colored ellipse for the outer glow
var glow = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 10
});
glow.alpha = 0.18;
glow.tint = 0x00ffff;
// Animate: expand and fade out, then destroy
self.play = function () {
// Animate both core and glow
tween(core, {
scaleX: 10,
scaleY: 10,
alpha: 0
}, {
duration: 700,
easing: tween.easeOutCubic
});
tween(glow, {
scaleX: 16,
scaleY: 16,
alpha: 0
}, {
duration: 700,
easing: tween.easeOutCubic
});
// Fade out and destroy container after animation
tween(self, {}, {
duration: 700,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
// Player Snake
var PlayerSnake = Container.expand(function () {
var self = Container.call(this);
self.segments = [];
self.directions = [];
self.head = new SnakeHead();
self.addChild(self.head);
self.segments.push(self.head);
self.length = 5;
self.speed = 12;
self.targetX = 1024;
self.targetY = 1366;
self.lastMoveX = 0;
self.lastMoveY = -1;
self.growPending = 0;
self.lastFireTick = 0;
// Initialize body
for (var i = 1; i < self.length; i++) {
var seg = new SnakeSegment();
seg.x = self.head.x;
seg.y = self.head.y + i * 80;
self.addChild(seg);
self.segments.push(seg);
}
// Move snake
self.moveSnake = function () {
// Calculate direction to target
var dx = self.targetX - self.head.x;
var dy = self.targetY - self.head.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var moveX = 0,
moveY = 0;
if (dist > 10) {
moveX = dx / dist;
moveY = dy / dist;
self.lastMoveX = moveX;
self.lastMoveY = moveY;
} else {
moveX = self.lastMoveX;
moveY = self.lastMoveY;
}
// Move head
self.head.x += moveX * self.speed;
self.head.y += moveY * self.speed;
// Move body
for (var i = self.segments.length - 1; i > 0; i--) {
var prev = self.segments[i - 1];
var seg = self.segments[i];
var pdx = prev.x - seg.x;
var pdy = prev.y - seg.y;
var pdist = Math.sqrt(pdx * pdx + pdy * pdy);
if (pdist > 80) {
seg.x += pdx / pdist * Math.min(self.speed, pdist - 80);
seg.y += pdy / pdist * Math.min(self.speed, pdist - 80);
}
}
};
// Grow snake
self.grow = function (n) {
self.growPending += n;
};
// Update
self.update = function () {
self.moveSnake();
// Handle growth
if (self.growPending > 0) {
var last = self.segments[self.segments.length - 1];
var seg = new SnakeSegment();
seg.x = last.x;
seg.y = last.y;
self.addChild(seg);
self.segments.push(seg);
self.growPending--;
}
};
// Get head position
self.getHeadPos = function () {
return {
x: self.head.x,
y: self.head.y
};
};
// Get direction vector
self.getDirection = function () {
return {
x: self.lastMoveX,
y: self.lastMoveY
};
};
return self;
});
// Player Snake Head
var SnakeHead = Container.expand(function () {
var self = Container.call(this);
var head = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Player Snake Segment
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Game variables
// Snake body segment (player)
// Snake head (player)
// Enemy snake body
// Enemy snake head
// Food
// Bullet
// Flame fart burst
// (flame asset removed)
var playerSnake;
var enemySnakes = [];
var foods = [];
var bullets = [];
// (flames array removed)
var scoreTxt;
var dragNode = null;
var lastFireTick = 0;
var spawnFoodTick = 0;
var spawnEnemyTick = 0;
var gameArea = {
x: 120,
y: 120,
w: 2048 - 240,
h: 2732 - 240
}; // leave margin for UI
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize player snake
playerSnake = new PlayerSnake();
playerSnake.head.x = 1024;
playerSnake.head.y = 1800;
for (var i = 0; i < playerSnake.segments.length; i++) {
playerSnake.segments[i].x = 1024;
playerSnake.segments[i].y = 1800 + i * 80;
}
game.addChild(playerSnake);
// Spawn initial food
function spawnFood() {
var f = new Food();
f.x = gameArea.x + 100 + Math.random() * (gameArea.w - 200);
f.y = gameArea.y + 100 + Math.random() * (gameArea.h - 200);
foods.push(f);
game.addChild(f);
}
for (var i = 0; i < 8; i++) {
spawnFood();
}
// Spawn enemy snake
function spawnEnemy() {
var e = new EnemySnake();
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
e.head.x = gameArea.x + Math.random() * gameArea.w;
e.head.y = gameArea.y - 120;
} else if (edge === 1) {
// bottom
e.head.x = gameArea.x + Math.random() * gameArea.w;
e.head.y = gameArea.y + gameArea.h + 120;
} else if (edge === 2) {
// left
e.head.x = gameArea.x - 120;
e.head.y = gameArea.y + Math.random() * gameArea.h;
} else {
// right
e.head.x = gameArea.x + gameArea.w + 120;
e.head.y = gameArea.y + Math.random() * gameArea.h;
}
for (var i = 1; i < e.segments.length; i++) {
e.segments[i].x = e.head.x;
e.segments[i].y = e.head.y + i * 80;
}
enemySnakes.push(e);
game.addChild(e);
}
for (var i = 0; i < 2; i++) {
spawnEnemy();
}
// Handle dragging
game.down = function (x, y, obj) {
dragNode = playerSnake;
playerSnake.targetX = x;
playerSnake.targetY = y;
};
game.move = function (x, y, obj) {
if (dragNode) {
playerSnake.targetX = x;
playerSnake.targetY = y;
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Helper: check collision between two containers (circle-based)
function circlesIntersect(a, b, rA, rB) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var dist = Math.sqrt(dx * dx + dy * dy);
return dist < (rA + rB) * 0.5;
}
// Helper: clamp to game area
function clampToArea(x, y) {
x = Math.max(gameArea.x + 50, Math.min(gameArea.x + gameArea.w - 50, x));
y = Math.max(gameArea.y + 50, Math.min(gameArea.y + gameArea.h - 50, y));
return {
x: x,
y: y
};
}
// Main game update
game.update = function () {
// Update player snake
playerSnake.update();
// Clamp player head to area
var clamped = clampToArea(playerSnake.head.x, playerSnake.head.y);
playerSnake.head.x = clamped.x;
playerSnake.head.y = clamped.y;
// Update enemy snakes
for (var i = enemySnakes.length - 1; i >= 0; i--) {
var e = enemySnakes[i];
if (!e.alive) continue;
e.update(playerSnake.getHeadPos());
// Clamp enemy head to area
var ce = clampToArea(e.head.x, e.head.y);
e.head.x = ce.x;
e.head.y = ce.y;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
b.update();
// Remove if out of bounds
if (b.x < gameArea.x - 60 || b.x > gameArea.x + gameArea.w + 60 || b.y < gameArea.y - 60 || b.y > gameArea.y + gameArea.h + 60) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// Bullet hits enemy snake
if (b.owner === 'player') {
for (var j = 0; j < enemySnakes.length; j++) {
var e = enemySnakes[j];
if (!e.alive) continue;
if (circlesIntersect(b, e.head, 60, 60)) {
// Hit!
b.destroy();
bullets.splice(i, 1);
// Shorten enemy snake or kill
var killed = false;
if (e.segments.length > 2) {
var seg = e.segments.pop();
seg.destroy();
} else {
e.die();
killed = true;
}
LK.setScore(LK.getScore() + 5);
scoreTxt.setText(LK.getScore());
// Player fart effect when enemy is killed
if (killed) {
// Flash the head and all body segments for a more visible fart effect
for (var f = 0; f < playerSnake.segments.length; f++) {
LK.effects.flashObject(playerSnake.segments[f], 0xcccc00, 600);
}
}
break;
}
}
}
// Bullet hits player (if we add enemy bullets in future)
}
// Player eats food
for (var i = foods.length - 1; i >= 0; i--) {
var food = foods[i];
if (circlesIntersect(playerSnake.head, food, 60, 35)) {
food.destroy();
foods.splice(i, 1);
playerSnake.grow(2);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
// MegaFart effect: nuke particle at player head
var megaFart = new MegaFart();
megaFart.x = playerSnake.head.x;
megaFart.y = playerSnake.head.y;
game.addChild(megaFart);
megaFart.play();
// Win condition removed
}
}
// Player collides with enemy snake head or body
for (var i = 0; i < enemySnakes.length; i++) {
var e = enemySnakes[i];
if (!e.alive) continue;
// Head to head
if (circlesIntersect(playerSnake.head, e.head, 60, 60)) {
LK.effects.flashScreen(0xff3300, 800);
LK.showGameOver();
return;
}
// Head to body
for (var j = 1; j < e.segments.length; j++) {
if (circlesIntersect(playerSnake.head, e.segments[j], 60, 40)) {
LK.effects.flashScreen(0xff3300, 800);
LK.showGameOver();
return;
}
}
}
// Player collides with self (not head)
for (var i = 2; i < playerSnake.segments.length; i++) {
if (circlesIntersect(playerSnake.head, playerSnake.segments[i], 60, 40)) {
LK.effects.flashScreen(0xff3300, 800);
LK.showGameOver();
return;
}
}
// Spawn food
spawnFoodTick++;
if (spawnFoodTick > 40 && foods.length < 12) {
spawnFood();
spawnFoodTick = 0;
}
// Spawn enemy
spawnEnemyTick++;
if (spawnEnemyTick > 80 && enemySnakes.length < 8) {
spawnEnemy();
spawnEnemyTick = 0;
}
// Minigun: auto-fire at nearest enemy in range
if (LK.ticks - lastFireTick > 4) {
// ~15 shots/sec
var nearest = null;
var minDist = 99999;
for (var i = 0; i < enemySnakes.length; i++) {
var e = enemySnakes[i];
if (!e.alive) continue;
var dx = e.head.x - playerSnake.head.x;
var dy = e.head.y - playerSnake.head.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 600 && dist < minDist) {
minDist = dist;
nearest = e;
}
}
if (nearest) {
fireBulletAt(playerSnake.head.x, playerSnake.head.y, nearest.head.x, nearest.head.y, 'player');
lastFireTick = LK.ticks;
}
}
};
// Fire bullet from (x0,y0) to (x1,y1)
function fireBulletAt(x0, y0, x1, y1, owner) {
var b = new Bullet();
b.x = x0;
b.y = y0;
var dx = x1 - x0;
var dy = y1 - y0;
var dist = Math.sqrt(dx * dx + dy * dy);
var speed = 38;
b.vx = dx / dist * speed;
b.vy = dy / dist * speed;
b.owner = owner;
bullets.push(b);
game.addChild(b);
}
// (spawnFlameBurst removed)
// Center score text
scoreTxt.setText(LK.getScore());
scoreTxt.anchor.set(0.5, 0);
// No music or sound for MVP