User prompt
If player triggers the bomb, destroy current color the bomb indicates. Don’t kill the snake, just destroy that color. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Change bomb trigger imput to double-click. For example; after snake eats a bomb explode current color if player double-clicks the screen.
User prompt
Make snake’ movement speed 2 times faster.
User prompt
Change snake controls swipe. For example; if I swipe down, snake starts goğng down. Same for the othere rotations. Cancel touching screen sides for mobement.
User prompt
Also add arrow key controls for PC.
User prompt
Add the eaten pick up en of the tail.
User prompt
Make: W = Up A = Left S = Down D = Right
User prompt
Add "WASD" control.
User prompt
Please fix the bug: 'Failed to connect to MetaMask' in or related to this line: 'if (moveTimer >= gameSpeed / 1000 * 60) {' Line Number: 378
User prompt
Please fix the bug: 'Failed to connect to MetaMask' in or related to this line: 'if (moveTimer >= gameSpeed / 60) {' Line Number: 378
User prompt
Please fix the bug: 'Failed to connect to MetaMask' in or related to this line: 'if (moveTimer >= gameSpeed / 60 * 60) {' Line Number: 378
Code edit (1 edits merged)
Please save this source code
User prompt
SnakeMatch3
Initial prompt
Create a playable prototype of a game called "SnakeMatch3". It combines classic Snake with match-3 mechanics. Core rules: - The player controls a snake that moves in 4 directions (up, down, left, right) on a grid. - The snake wraps around the screen edges (if it exits from one side, it enters from the opposite). - The snake starts with 1 segment. - When the snake eats a colored pickup (red, yellow, blue), it grows by adding a segment of that color to its tail. - Always show the "next pickup color" in the UI, similar to Tetris. - If 3 or more same-colored segments are next to each other in the tail, they explode and disappear, awarding points. - Occasionally, a bomb pickup spawns. - When the snake collects a bomb, the bomb travels along the tail segments, briefly highlighting each one in order. - The player can press a key to trigger the bomb on the highlighted segment. - The targeted segment is removed and placed at the end of the tail. If this causes 3 same-colored segments to align, they explode and the game continues. If not, the game ends. - The game also ends if the snake collides with its own body. Technical details: - Use simple placeholder graphics (colored squares for pickups and segments, a darker square for the snake head). - Show the grid-based movement clearly, with smooth snapping to the grid. - Add a score counter at the top of the screen. - Make sure the game loop is fast and responsive. Goal: The player must survive as long as possible, collect points by matching 3 segments of the same color, and use bombs strategically to manipulate the snake's body.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Pickup = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isBomb = color === 'bomb';
var assetId = self.isBomb ? 'bombPickup' : 'pickup' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x * GRID_SIZE + GRID_SIZE / 2;
self.y = y * GRID_SIZE + GRID_SIZE / 2;
return self;
});
var SnakeHead = Container.expand(function (x, y) {
var self = Container.call(this);
self.gridX = x;
self.gridY = y;
self.direction = {
x: 1,
y: 0
};
self.graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2;
};
return self;
});
var SnakeSegment = Container.expand(function (color, x, y) {
var self = Container.call(this);
self.color = color;
self.gridX = x;
self.gridY = y;
self.isHighlighted = false;
var assetId = 'snakeSegment' + color.charAt(0).toUpperCase() + color.slice(1);
self.graphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.setPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = gridY * GRID_SIZE + GRID_SIZE / 2;
};
self.highlight = function (highlight) {
self.isHighlighted = highlight;
if (highlight) {
self.graphics.alpha = 0.7;
self.graphics.scaleX = 1.2;
self.graphics.scaleY = 1.2;
} else {
self.graphics.alpha = 1.0;
self.graphics.scaleX = 1.0;
self.graphics.scaleY = 1.0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
var GRID_SIZE = 50;
var GRID_WIDTH = Math.floor(2048 / GRID_SIZE);
var GRID_HEIGHT = Math.floor(2732 / GRID_SIZE);
var snake = [];
var snakeHead = null;
var pickups = [];
var gameSpeed = 300;
var moveTimer = 0;
var colors = ['red', 'yellow', 'blue'];
var nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
var bombMode = false;
var bombIndex = 0;
var bombTimer = 0;
var gameOver = false;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var nextColorTxt = new Text2('Next: Red', {
size: 50,
fill: 0xFFFFFF
});
nextColorTxt.anchor.set(1, 0);
nextColorTxt.x = -20;
nextColorTxt.y = 20;
LK.gui.topRight.addChild(nextColorTxt);
function initializeGame() {
// Create snake head
snakeHead = new SnakeHead(Math.floor(GRID_WIDTH / 2), Math.floor(GRID_HEIGHT / 2));
game.addChild(snakeHead);
snakeHead.setPosition(snakeHead.gridX, snakeHead.gridY);
// Create initial tail segments
for (var i = 1; i <= 3; i++) {
var color = colors[Math.floor(Math.random() * colors.length)];
var segment = new SnakeSegment(color, snakeHead.gridX - i, snakeHead.gridY);
snake.push(segment);
game.addChild(segment);
segment.setPosition(segment.gridX, segment.gridY);
}
spawnRandomPickup();
updateNextColorDisplay();
}
function spawnRandomPickup() {
var attempts = 0;
var x, y;
do {
x = Math.floor(Math.random() * GRID_WIDTH);
y = Math.floor(Math.random() * GRID_HEIGHT);
attempts++;
} while (isPositionOccupied(x, y) && attempts < 100);
if (attempts < 100) {
var isBomb = Math.random() < 0.15; // 15% chance for bomb
var color = isBomb ? 'bomb' : nextPickupColor;
var pickup = new Pickup(color, x, y);
pickups.push(pickup);
game.addChild(pickup);
if (!isBomb) {
nextPickupColor = colors[Math.floor(Math.random() * colors.length)];
updateNextColorDisplay();
}
}
}
function isPositionOccupied(x, y) {
if (snakeHead.gridX === x && snakeHead.gridY === y) return true;
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === x && snake[i].gridY === y) return true;
}
for (var j = 0; j < pickups.length; j++) {
if (pickups[j].gridX === x && pickups[j].gridY === y) return true;
}
return false;
}
function updateNextColorDisplay() {
nextColorTxt.setText('Next: ' + nextPickupColor.charAt(0).toUpperCase() + nextPickupColor.slice(1));
}
function moveSnake() {
if (gameOver || bombMode) return;
var newX = snakeHead.gridX + snakeHead.direction.x;
var newY = snakeHead.gridY + snakeHead.direction.y;
// Wrap around screen edges
if (newX < 0) newX = GRID_WIDTH - 1;
if (newX >= GRID_WIDTH) newX = 0;
if (newY < 0) newY = GRID_HEIGHT - 1;
if (newY >= GRID_HEIGHT) newY = 0;
// Check for self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newX && snake[i].gridY === newY) {
gameOver = true;
LK.showGameOver();
return;
}
}
// Move tail segments
if (snake.length > 0) {
for (var j = snake.length - 1; j > 0; j--) {
snake[j].setPosition(snake[j - 1].gridX, snake[j - 1].gridY);
}
snake[0].setPosition(snakeHead.gridX, snakeHead.gridY);
}
// Move head
snakeHead.setPosition(newX, newY);
// Check for pickup collision
for (var k = pickups.length - 1; k >= 0; k--) {
var pickup = pickups[k];
if (pickup.gridX === newX && pickup.gridY === newY) {
if (pickup.isBomb) {
handleBombPickup();
} else {
handleColorPickup(pickup.color);
}
pickup.destroy();
pickups.splice(k, 1);
spawnRandomPickup();
break;
}
}
checkForMatches();
}
function handleColorPickup(color) {
LK.getSound('collect').play();
// Get the position of the last tail segment, or head if no tail exists
var lastX, lastY;
if (snake.length > 0) {
lastX = snake[snake.length - 1].gridX;
lastY = snake[snake.length - 1].gridY;
} else {
lastX = snakeHead.gridX;
lastY = snakeHead.gridY;
}
var newSegment = new SnakeSegment(color, lastX, lastY);
snake.push(newSegment);
game.addChild(newSegment);
LK.setScore(LK.getScore() + 1);
scoreTxt.setText('Score: ' + LK.getScore());
}
function handleBombPickup() {
if (snake.length === 0) return;
LK.getSound('bomb').play();
bombMode = true;
bombIndex = 0;
bombTimer = 0;
// Highlight first segment
snake[bombIndex].highlight(true);
}
function processBombMovement() {
if (!bombMode) return;
bombTimer++;
if (bombTimer >= 30) {
// Move every 30 ticks (0.5 seconds)
snake[bombIndex].highlight(false);
bombIndex++;
if (bombIndex >= snake.length) {
bombIndex = 0;
}
snake[bombIndex].highlight(true);
bombTimer = 0;
}
}
function triggerBomb() {
if (!bombMode || snake.length === 0) return;
var segmentToMove = snake[bombIndex];
segmentToMove.highlight(false);
// Remove segment from current position
snake.splice(bombIndex, 1);
// Add to end of tail
snake.push(segmentToMove);
bombMode = false;
// Check if this creates a match
var matchFound = checkForMatches();
if (!matchFound) {
gameOver = true;
LK.showGameOver();
}
}
function checkForMatches() {
var matchFound = false;
var toRemove = [];
for (var i = 0; i < snake.length - 2; i++) {
var count = 1;
var currentColor = snake[i].color;
for (var j = i + 1; j < snake.length; j++) {
if (snake[j].color === currentColor) {
count++;
} else {
break;
}
}
if (count >= 3) {
for (var k = i; k < i + count; k++) {
toRemove.push(k);
}
matchFound = true;
i += count - 1;
}
}
if (toRemove.length > 0) {
LK.getSound('explode').play();
// Remove matched segments
for (var m = toRemove.length - 1; m >= 0; m--) {
var index = toRemove[m];
snake[index].destroy();
snake.splice(index, 1);
}
// Award points
var points = toRemove.length * 10;
LK.setScore(LK.getScore() + points);
scoreTxt.setText('Score: ' + LK.getScore());
// Flash effect
LK.effects.flashScreen(0xffffff, 200);
}
return matchFound;
}
function handleInput(x, y) {
if (gameOver) return;
if (bombMode) {
triggerBomb();
return;
}
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var deltaX = x - centerX;
var deltaY = y - centerY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal movement
if (deltaX > 0 && snakeHead.direction.x !== -1) {
snakeHead.direction = {
x: 1,
y: 0
};
} else if (deltaX < 0 && snakeHead.direction.x !== 1) {
snakeHead.direction = {
x: -1,
y: 0
};
}
} else {
// Vertical movement
if (deltaY > 0 && snakeHead.direction.y !== -1) {
snakeHead.direction = {
x: 0,
y: 1
};
} else if (deltaY < 0 && snakeHead.direction.y !== 1) {
snakeHead.direction = {
x: 0,
y: -1
};
}
}
}
// Keyboard input handling for arrow keys
function handleKeyInput(key) {
if (gameOver) return;
if (bombMode) {
if (key === ' ') {
// Spacebar to trigger bomb
triggerBomb();
}
return;
}
switch (key) {
case 'ArrowUp':
if (snakeHead.direction.y !== 1) {
snakeHead.direction = {
x: 0,
y: -1
};
}
break;
case 'ArrowDown':
if (snakeHead.direction.y !== -1) {
snakeHead.direction = {
x: 0,
y: 1
};
}
break;
case 'ArrowLeft':
if (snakeHead.direction.x !== 1) {
snakeHead.direction = {
x: -1,
y: 0
};
}
break;
case 'ArrowRight':
if (snakeHead.direction.x !== -1) {
snakeHead.direction = {
x: 1,
y: 0
};
}
break;
}
}
// Add keyboard event listener
LK.on('keydown', function (event) {
handleKeyInput(event.key);
});
game.down = function (x, y, obj) {
handleInput(x, y);
};
game.update = function () {
if (gameOver) return;
processBombMovement();
moveTimer++;
if (moveTimer >= gameSpeed / 16.67) {
moveSnake();
moveTimer = 0;
}
};
// Initialize the game
initializeGame(); ===================================================================
--- original.js
+++ change.js
@@ -335,8 +335,57 @@
};
}
}
}
+// Keyboard input handling for arrow keys
+function handleKeyInput(key) {
+ if (gameOver) return;
+ if (bombMode) {
+ if (key === ' ') {
+ // Spacebar to trigger bomb
+ triggerBomb();
+ }
+ return;
+ }
+ switch (key) {
+ case 'ArrowUp':
+ if (snakeHead.direction.y !== 1) {
+ snakeHead.direction = {
+ x: 0,
+ y: -1
+ };
+ }
+ break;
+ case 'ArrowDown':
+ if (snakeHead.direction.y !== -1) {
+ snakeHead.direction = {
+ x: 0,
+ y: 1
+ };
+ }
+ break;
+ case 'ArrowLeft':
+ if (snakeHead.direction.x !== 1) {
+ snakeHead.direction = {
+ x: -1,
+ y: 0
+ };
+ }
+ break;
+ case 'ArrowRight':
+ if (snakeHead.direction.x !== -1) {
+ snakeHead.direction = {
+ x: 1,
+ y: 0
+ };
+ }
+ break;
+ }
+}
+// Add keyboard event listener
+LK.on('keydown', function (event) {
+ handleKeyInput(event.key);
+});
game.down = function (x, y, obj) {
handleInput(x, y);
};
game.update = function () {