User prompt
Remove nick selection at game start ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.rankings = storageRankings;' Line Number: 378 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.rankings = storageRankings;' Line Number: 380
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.rankings = storageRankings;' Line Number: 375 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.rankings = rankings;' Line Number: 360 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Create a ranking tab. There should be a ranking button on the right side of the screen and open the ranking tab. Write the highest scores in the ranking tab. Before the game starts, ask the player for their nickname, and if this nickname has a score in the ranking list, write it next to that score. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Write the highest score made at the top of the game. Even if you exit the game and re-enter, the highest score made with that device should be written there. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Let the game have a dark gray background
User prompt
Let the game have a gray background
Code edit (2 edits merged)
Please save this source code
User prompt
Let the snake's body move more smoothly ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The life number of the apples should be written under the apples.
User prompt
undo what you did last
User prompt
Let the snake's body be one piece. Let the life number of the apples be written under the apples. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let the snake's body be united ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
increase the size of apples
Code edit (1 edits merged)
Please save this source code
User prompt
After the snake eats the apple, its speed remains the same
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game configuration var segmentLength = 40, startingSegments = 10, spawn = { x: 1024, y: 1366 }, snakeSpeed = 2000, baseSnakeSpeed = 2, speedIncrement = 2000, maxApples = 5, appleLife = 300, segmentsPerApple = 2, snakeWidth = 30, appleWidth = 50, cursorSize = 20, snake, target, apples, score, gameState, deathMeans, smoothMovement = true, movementQueue = []; function distance(p1, p2) { var dx = p2.x - p1.x; var dy = p2.y - p1.y; return Math.sqrt(dx * dx + dy * dy); } function lineIntersect(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) { var s1_x = p1_x - p0_x, s1_y = p1_y - p0_y, s2_x = p3_x - p2_x, s2_y = p3_y - p2_y, s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y), t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y); if (s >= 0 && s <= 1 && t >= 0 && t <= 1) { return true; } return false; } function SGM(angle, x, y) { this.x = x || 0; this.y = y || 0; this.angle = angle || 0; this.parent = null; } ; SGM.prototype.endX = function () { return this.x + Math.cos(this.angle) * segmentLength; }; SGM.prototype.endY = function () { return this.y + Math.sin(this.angle) * segmentLength; }; SGM.prototype.pointAt = function (x, y) { var dx = x - this.x, dy = y - this.y; this.angle = Math.atan2(dy, dx); }; SGM.prototype.target = function (x, y) { this.targetX = x; this.targetY = y; this.arrived = false; this.totalDist = distance({ x: this.endX(), y: this.endY() }, { x: this.targetX, y: this.targetY }); this.currentDist = parseInt(this.totalDist); }; SGM.prototype.gotoTarget = function () { if (!this.arrived) { if (this.targetX > this.x + segmentLength || this.targetX < this.x - segmentLength || this.targetY > this.y + segmentLength || this.targetY < this.y - segmentLength) { this.pointAt(this.targetX, this.targetY); } else { this.arrived = true; } this.currentDist = distance({ x: this.endX(), y: this.endY() }, { x: this.targetX, y: this.targetY }); } this.x += (this.endX() - this.x) / snakeSpeed; this.y += (this.endY() - this.y) / snakeSpeed; if (this.parent) { this.parent.drag(this.x, this.y); } }; SGM.prototype.drag = function (x, y) { this.pointAt(x, y); var newX = x - Math.cos(this.angle) * segmentLength; var newY = y - Math.sin(this.angle) * segmentLength; this.x = newX; this.y = newY; if (this.parent) { this.parent.drag(this.x, this.y); } }; SGM.prototype.render = function (context) { context.lineTo(this.endX(), this.endY()); }; function IKR(x, y) { this.ix = x || 0; this.iy = y || 0; this.sgms = []; this.lastArm = null; } ; IKR.prototype.addSeg = function (angle) { var arm = new SGM(angle); if (this.lastArm !== null) { arm.x = this.lastArm.endX(); arm.y = this.lastArm.endY(); arm.parent = this.lastArm; } else { arm.x = this.ix; arm.y = this.iy; } this.sgms.push(arm); this.lastArm = arm; }; IKR.prototype.grow = function () { var tail = this.sgms[0], arm = new SGM(tail.angle); arm.x = tail.x - Math.cos(tail.angle) * segmentLength; arm.y = tail.y - Math.sin(tail.angle) * segmentLength; tail.parent = arm; this.sgms.unshift(arm); }; IKR.prototype.drag = function (x, y) { this.lastArm.drag(x, y); }; function CUR(x, y) { this.x = x; this.y = y; this.rotation = 0; } ; CUR.prototype.render = function (context) { context.save(); context.translate(this.x, this.y); context.rotate(this.rotation); context.beginPath(); context.moveTo(0, -cursorSize); context.lineTo(0, -cursorSize / 2); context.moveTo(0, cursorSize / 2); context.lineTo(0, cursorSize); context.moveTo(-cursorSize, 0); context.lineTo(-cursorSize / 2, 0); context.moveTo(cursorSize / 2, 0); context.lineTo(cursorSize, 0); context.stroke(); context.restore(); this.rotation = (this.rotation + cursorSpin) % 360; }; function Apple(x, y) { this.x = x; this.y = y; this.life = appleLife; this.rotation = 0; } Apple.prototype.update = function () { this.life--; }; Apple.prototype.render = function (context) { context.beginPath(); context.arc(this.x, this.y, appleWidth, 0, Math.PI * 2); context.fill(); if (gameState !== 'dead') { context.save(); context.fillStyle = 'white'; context.font = '8px sans-serif'; context.fillText(this.life, this.x + 10, this.y + 10); context.restore(); CUR.prototype.render.call(this, context); } }; function init() { snake = new IKR(spawn.x, spawn.y); cursor = new CUR(-20, -20); target = new CUR(spawn.x + segmentLength * (startingSegments + 5), spawn.y); apples = []; score = 0; snakeSpeed = baseSnakeSpeed; // Reset speed to base value for (var i = 0; i < startingSegments; i++) { snake.addSeg(); } snake.lastArm.target(target.x, target.y); gameState = 'play'; } init(); // Touch events handled by game object game.down = function (x, y, obj) { switch (gameState) { case 'play': target.x = x; target.y = y; snake.lastArm.target(target.x, target.y); break; case 'dead': init(); break; } }; function badPlacement(apple) { for (var s = 0; s < snake.sgms.length; s++) { var seg = snake.sgms[s]; if (Math.min(distance(apple, { x: seg.endX(), y: seg.endY() }), distance(apple, { x: seg.x, y: seg.y })) < appleWidth * 2) { return true; } } return false; } function addScoreSegments() { for (var i = 0; i < segmentsPerApple; i++) { snake.grow(); } // Keep snake speed constant - reset to base speed snakeSpeed = baseSnakeSpeed; } function update() { if (gameState !== 'dead') { snake.lastArm.gotoTarget(); if (snake.lastArm.endX() > 2048 - 50 || snake.lastArm.endX() < 50 || snake.lastArm.endY() > 2732 - 50 || snake.lastArm.endY() < 50) { gameState = 'dead'; deathMeans = 'Hit the wall!'; LK.showGameOver(); return; } for (var s = 0; s < snake.sgms.length - 2; s++) { var seg = snake.sgms[s]; if (lineIntersect(snake.lastArm.x, snake.lastArm.y, snake.lastArm.endX(), snake.lastArm.endY(), seg.x, seg.y, seg.endX(), seg.endY())) { gameState = 'dead'; deathMeans = 'You bit yourself'; LK.showGameOver(); return; } for (var a in apples) { var apple = apples[a]; if (Math.min(distance(apple, { x: seg.endX(), y: seg.endY() }), distance(apple, { x: seg.x, y: seg.y })) < appleWidth * 2) { score += Math.round(apple.life / 2); // half score if absorbed by the tail apples.splice(a, 1); addScoreSegments(); } } } for (var a in apples) { var apple = apples[a]; apple.update(); if (apple.life <= 0) { apples.splice(a, 1); continue; } if (distance(apple, { x: snake.lastArm.endX(), y: snake.lastArm.endY() }) < appleWidth * 2) { score += apple.life; apples.splice(a, 1); addScoreSegments(); } } if (apples.length < maxApples && Math.random() < 0.02) { var offset = appleWidth * 4, apple = new Apple(offset + Math.floor(Math.random() * (2048 - offset * 2)), offset + Math.floor(Math.random() * (2732 - offset * 2))); while (badPlacement(apple)) { apple.x = offset + Math.floor(Math.random() * (2048 - offset * 2)); apple.y = offset + Math.floor(Math.random() * (2732 - offset * 2)); } apples.push(apple); // Create visual apple var appleVisual = LK.getAsset('apple', { width: appleWidth * 2, height: appleWidth * 2, color: 0x00ff00, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); appleVisual.x = apple.x; appleVisual.y = apple.y; game.addChild(appleVisual); // Create life text under apple var lifeText = new Text2(apple.life.toString(), { size: 40, fill: 0xFFFFFF }); lifeText.anchor.set(0.5, 0); lifeText.x = apple.x; lifeText.y = apple.y + appleWidth; game.addChild(lifeText); appleVisual.lifeText = lifeText; appleObjects.push(appleVisual); } } } // LK rendering system - visual elements handled by game objects var snakeSegments = []; var appleObjects = []; var targetObject = null; var scoreText = null; // Initialize visual elements function initVisuals() { // Clear existing visuals for (var i = 0; i < snakeSegments.length; i++) { snakeSegments[i].destroy(); } for (var i = 0; i < appleObjects.length; i++) { appleObjects[i].destroy(); } if (targetObject) { targetObject.destroy(); } if (scoreText) { scoreText.destroy(); } snakeSegments = []; appleObjects = []; // Create score text scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topLeft.addChild(scoreText); scoreText.x = 120; scoreText.y = 20; // Create target indicator targetObject = LK.getAsset('target', { width: 30, height: 30, color: 0x0000ff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); game.addChild(targetObject); } // Initialize the game init(); initVisuals(); // LK game update loop game.update = function () { if (gameState === 'play') { update(); // Update score display if (scoreText) { scoreText.setText('Score: ' + score); } // Update target position if (targetObject && !snake.lastArm.arrived) { targetObject.x = target.x; targetObject.y = target.y; targetObject.visible = true; } else if (targetObject) { targetObject.visible = false; } // Update snake visual segments updateSnakeVisuals(); // Update apple visuals updateAppleVisuals(); } }; function updateSnakeVisuals() { // Only update positions if we have existing segments, otherwise recreate if (snakeSegments.length !== snake.sgms.length + 1) { // Clear existing snake segments for (var i = 0; i < snakeSegments.length; i++) { snakeSegments[i].destroy(); } snakeSegments = []; // Create new snake segments for (var s = 0; s < snake.sgms.length; s++) { var seg = snake.sgms[s]; var segmentVisual = LK.getAsset('snakeSegment', { width: snakeWidth, height: segmentLength, color: 0x64ff64, shape: 'box', anchorX: 0.5, anchorY: 0 }); segmentVisual.x = seg.x; segmentVisual.y = seg.y; segmentVisual.rotation = seg.angle + Math.PI / 2; game.addChild(segmentVisual); snakeSegments.push(segmentVisual); } // Create snake head with proper sizing var head = LK.getAsset('snakeHead', { width: 60, height: 60, anchorX: 0.5, anchorY: 0.5 }); head.x = snake.lastArm.endX(); head.y = snake.lastArm.endY(); game.addChild(head); snakeSegments.push(head); } else { // Update all segments as one unified body with synchronized movement var targetPositions = []; var targetRotations = []; // Calculate all target positions first for (var s = 0; s < snake.sgms.length; s++) { var seg = snake.sgms[s]; targetPositions[s] = { x: seg.x, y: seg.y }; targetRotations[s] = seg.angle + Math.PI / 2; } targetPositions[snake.sgms.length] = { x: snake.lastArm.endX(), y: snake.lastArm.endY() }; // Apply unified movement to all segments simultaneously for (var s = 0; s < snakeSegments.length; s++) { var segmentVisual = snakeSegments[s]; var targetPos = targetPositions[s]; var targetRot = targetRotations[s] || segmentVisual.rotation; // Unified smooth movement for entire snake body tween(segmentVisual, { x: targetPos.x, y: targetPos.y, rotation: targetRot }, { duration: 50, easing: tween.easeInOut }); } } } function updateAppleVisuals() { // Remove apples that no longer exist for (var i = appleObjects.length - 1; i >= 0; i--) { var found = false; for (var a = 0; a < apples.length; a++) { if (Math.abs(appleObjects[i].x - apples[a].x) < 5 && Math.abs(appleObjects[i].y - apples[a].y) < 5) { found = true; break; } } if (!found) { appleObjects[i].destroy(); if (appleObjects[i].lifeText) { appleObjects[i].lifeText.destroy(); } appleObjects.splice(i, 1); } } // Update life text for existing apples for (var i = 0; i < appleObjects.length; i++) { for (var a = 0; a < apples.length; a++) { if (Math.abs(appleObjects[i].x - apples[a].x) < 5 && Math.abs(appleObjects[i].y - apples[a].y) < 5) { if (appleObjects[i].lifeText) { appleObjects[i].lifeText.setText(apples[a].life.toString()); } break; } } } } ; ;
===================================================================
--- original.js
+++ change.js
@@ -311,8 +311,18 @@
});
appleVisual.x = apple.x;
appleVisual.y = apple.y;
game.addChild(appleVisual);
+ // Create life text under apple
+ var lifeText = new Text2(apple.life.toString(), {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ lifeText.anchor.set(0.5, 0);
+ lifeText.x = apple.x;
+ lifeText.y = apple.y + appleWidth;
+ game.addChild(lifeText);
+ appleVisual.lifeText = lifeText;
appleObjects.push(appleVisual);
}
}
}
@@ -383,41 +393,76 @@
updateAppleVisuals();
}
};
function updateSnakeVisuals() {
- // Create or update snake segments
- while (snakeSegments.length < snake.sgms.length) {
- var segment = snakeSegments.length === 0 ? LK.getAsset('snakeHead', {
- width: snakeWidth * 2,
- height: snakeWidth * 2,
- color: 0xafbfcb,
- shape: 'box',
+ // Only update positions if we have existing segments, otherwise recreate
+ if (snakeSegments.length !== snake.sgms.length + 1) {
+ // Clear existing snake segments
+ for (var i = 0; i < snakeSegments.length; i++) {
+ snakeSegments[i].destroy();
+ }
+ snakeSegments = [];
+ // Create new snake segments
+ for (var s = 0; s < snake.sgms.length; s++) {
+ var seg = snake.sgms[s];
+ var segmentVisual = LK.getAsset('snakeSegment', {
+ width: snakeWidth,
+ height: segmentLength,
+ color: 0x64ff64,
+ shape: 'box',
+ anchorX: 0.5,
+ anchorY: 0
+ });
+ segmentVisual.x = seg.x;
+ segmentVisual.y = seg.y;
+ segmentVisual.rotation = seg.angle + Math.PI / 2;
+ game.addChild(segmentVisual);
+ snakeSegments.push(segmentVisual);
+ }
+ // Create snake head with proper sizing
+ var head = LK.getAsset('snakeHead', {
+ width: 60,
+ height: 60,
anchorX: 0.5,
anchorY: 0.5
- }) : LK.getAsset('snakeSegment', {
- width: snakeWidth,
- height: snakeWidth,
- color: 0x66ff66,
- shape: 'box',
- anchorX: 0.5,
- anchorY: 0.5
});
- game.addChild(segment);
- snakeSegments.push(segment);
+ head.x = snake.lastArm.endX();
+ head.y = snake.lastArm.endY();
+ game.addChild(head);
+ snakeSegments.push(head);
+ } else {
+ // Update all segments as one unified body with synchronized movement
+ var targetPositions = [];
+ var targetRotations = [];
+ // Calculate all target positions first
+ for (var s = 0; s < snake.sgms.length; s++) {
+ var seg = snake.sgms[s];
+ targetPositions[s] = {
+ x: seg.x,
+ y: seg.y
+ };
+ targetRotations[s] = seg.angle + Math.PI / 2;
+ }
+ targetPositions[snake.sgms.length] = {
+ x: snake.lastArm.endX(),
+ y: snake.lastArm.endY()
+ };
+ // Apply unified movement to all segments simultaneously
+ for (var s = 0; s < snakeSegments.length; s++) {
+ var segmentVisual = snakeSegments[s];
+ var targetPos = targetPositions[s];
+ var targetRot = targetRotations[s] || segmentVisual.rotation;
+ // Unified smooth movement for entire snake body
+ tween(segmentVisual, {
+ x: targetPos.x,
+ y: targetPos.y,
+ rotation: targetRot
+ }, {
+ duration: 50,
+ easing: tween.easeInOut
+ });
+ }
}
- // Update segment positions with smooth tweening
- for (var s = 0; s < snake.sgms.length && s < snakeSegments.length; s++) {
- var seg = snake.sgms[s];
- var segment = snakeSegments[s];
- tween(segment, {
- x: seg.x + Math.cos(seg.angle) * segmentLength / 2,
- y: seg.y + Math.sin(seg.angle) * segmentLength / 2,
- rotation: seg.angle + Math.PI / 2
- }, {
- duration: 50,
- easing: tween.easeInOut
- });
- }
}
function updateAppleVisuals() {
// Remove apples that no longer exist
for (var i = appleObjects.length - 1; i >= 0; i--) {
@@ -429,10 +474,24 @@
}
}
if (!found) {
appleObjects[i].destroy();
+ if (appleObjects[i].lifeText) {
+ appleObjects[i].lifeText.destroy();
+ }
appleObjects.splice(i, 1);
}
}
+ // Update life text for existing apples
+ for (var i = 0; i < appleObjects.length; i++) {
+ for (var a = 0; a < apples.length; a++) {
+ if (Math.abs(appleObjects[i].x - apples[a].x) < 5 && Math.abs(appleObjects[i].y - apples[a].y) < 5) {
+ if (appleObjects[i].lifeText) {
+ appleObjects[i].lifeText.setText(apples[a].life.toString());
+ }
+ break;
+ }
+ }
+ }
}
;
;
\ No newline at end of file