User prompt
add new gems
User prompt
i noticed less gems bud fix it
User prompt
make the game more kid friendly even more add a target and dont change the background color
User prompt
actually change the background brown again
User prompt
make the background color different
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'scaleX')' in or related to this line: 'tween(selectedGem, {' Line Number: 445 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'scaleX')' in or related to this line: 'tween(selectedGem, {' Line Number: 445 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
im not sure that color fits good ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the game more kid friendly
User prompt
make the grid with more gems but slightly smaller
User prompt
make the grid perfectly fit the screen
User prompt
U MADE IT WORSE NOW I CANT SWIPE FIX IT ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
FOR SOME REASON WHENEVER I SWIPE AND DONT MAKE A MATCH THE GEM DOESNT GO BACK TO WHERE IT WAS FIX IT ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Gem Crush Saga
Initial prompt
U BETTER NOT MESS UP LAST TIMRE IT DID DO GOOD THIS TIME NOW MAKE A GAME LIKE CANDY CRUSH BUT GEMS AND SWIPE CONTROLS PLUS TOUCH MAKE ME START ON THE HOME SCREEN THERES A PLAY BUTTON A LEADERBOARD AND A SIGN UP LOGIN AND WHEN YOURE LOGGED IN THERES A BUTTON ON THE HOME SCREEN THAT SAYS LOGOUT
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Gem = Container.expand(function (type) { var self = Container.call(this); self.gemType = type; self.gridX = 0; self.gridY = 0; self.isAnimating = false; var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange', 'gem_cyan', 'gem_pink']; var gemGraphics = self.attachAsset(gemAssets[type], { anchorX: 0.5, anchorY: 0.5, scaleX: CELL_SIZE / 256, scaleY: CELL_SIZE / 256 }); self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = boardStartX + gridX * CELL_SIZE + CELL_SIZE / 2; self.y = boardStartY + gridY * CELL_SIZE + CELL_SIZE / 2; }; self.animateToPosition = function (targetX, targetY, duration, onComplete) { if (duration === undefined) duration = 300; self.isAnimating = true; tween(self, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut, onFinish: function onFinish() { self.isAnimating = false; if (onComplete) onComplete(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8B4513 // Brown background }); /**** * Game Code ****/ // Gold yellow // Deep pink // Medium slate blue // Bright tomato orange // Light pink board background var BOARD_SIZE = 8; // Smaller board for kids - easier to see patterns var CELL_SIZE = Math.floor(Math.min(2048, 2732 - 500) / BOARD_SIZE * 0.95); // Bigger gems, leave more space for UI var BOARD_TOTAL_SIZE = BOARD_SIZE * CELL_SIZE; var boardStartX = (2048 - BOARD_TOTAL_SIZE) / 2; var boardStartY = (2732 - BOARD_TOTAL_SIZE) / 2 + 100; // Offset for top UI var board = []; var gems = []; var selectedGem = null; var isProcessingMatches = false; var isDragging = false; var dragStartX = 0; var dragStartY = 0; var score = 0; // Create board background var boardBackground = game.addChild(LK.getAsset('boardBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: boardStartY + BOARD_TOTAL_SIZE / 2, scaleX: BOARD_TOTAL_SIZE / 960, scaleY: BOARD_TOTAL_SIZE / 960 })); // Initialize score display with bright colors var scoreTxt = new Text2('Score: 0', { size: 90, fill: 0xFF1493 // Bright pink text }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 80; // Add target score display var targetScore = 500; // Kid-friendly target var targetTxt = new Text2('Target: ' + targetScore, { size: 70, fill: 0x32CD32 // Bright green text }); targetTxt.anchor.set(0.5, 0); LK.gui.top.addChild(targetTxt); targetTxt.y = 180; // Add encouraging message display var messageTxt = new Text2('Match the colorful gems!', { size: 60, fill: 0xFFD700 // Golden yellow text }); messageTxt.anchor.set(0.5, 0); LK.gui.top.addChild(messageTxt); messageTxt.y = 250; function initializeBoard() { // Create 2D array for board for (var y = 0; y < BOARD_SIZE; y++) { board[y] = []; gems[y] = []; for (var x = 0; x < BOARD_SIZE; x++) { var gemType = Math.floor(Math.random() * 8); var gem = new Gem(gemType); gem.setGridPosition(x, y); board[y][x] = gemType; gems[y][x] = gem; game.addChild(gem); } } // Remove initial matches removeInitialMatches(); } function removeInitialMatches() { var foundMatches = true; var iterations = 0; while (foundMatches && iterations < 10) { foundMatches = false; iterations++; for (var y = 0; y < BOARD_SIZE; y++) { for (var x = 0; x < BOARD_SIZE; x++) { if (hasMatchAt(x, y)) { var newType = Math.floor(Math.random() * 8); board[y][x] = newType; gems[y][x].gemType = newType; // Update gem graphics by recreating gems[y][x].destroy(); var newGem = new Gem(newType); newGem.setGridPosition(x, y); gems[y][x] = newGem; game.addChild(newGem); foundMatches = true; } } } } } function hasMatchAt(x, y) { var gemType = board[y][x]; // Check horizontal match var horizontalCount = 1; // Check left for (var i = x - 1; i >= 0 && board[y][i] === gemType; i--) { horizontalCount++; } // Check right for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) { horizontalCount++; } // Check vertical match var verticalCount = 1; // Check up for (var i = y - 1; i >= 0 && board[i][x] === gemType; i--) { verticalCount++; } // Check down for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) { verticalCount++; } return horizontalCount >= 3 || verticalCount >= 3; } function getGemAt(gameX, gameY) { var gridX = Math.floor((gameX - boardStartX) / CELL_SIZE); var gridY = Math.floor((gameY - boardStartY) / CELL_SIZE); if (gridX >= 0 && gridX < BOARD_SIZE && gridY >= 0 && gridY < BOARD_SIZE) { return gems[gridY][gridX]; } return null; } function isAdjacent(gem1, gem2) { var dx = Math.abs(gem1.gridX - gem2.gridX); var dy = Math.abs(gem1.gridY - gem2.gridY); return dx === 1 && dy === 0 || dx === 0 && dy === 1; } function swapGems(gem1, gem2) { if (!gem1 || !gem2 || gem1.isAnimating || gem2.isAnimating) return; // Store original positions and types var originalGem1X = gem1.gridX; var originalGem1Y = gem1.gridY; var originalGem2X = gem2.gridX; var originalGem2Y = gem2.gridY; var originalGem1Type = gem1.gemType; var originalGem2Type = gem2.gemType; // Calculate original visual positions var originalGem1PosX = boardStartX + originalGem1X * CELL_SIZE + CELL_SIZE / 2; var originalGem1PosY = boardStartY + originalGem1Y * CELL_SIZE + CELL_SIZE / 2; var originalGem2PosX = boardStartX + originalGem2X * CELL_SIZE + CELL_SIZE / 2; var originalGem2PosY = boardStartY + originalGem2Y * CELL_SIZE + CELL_SIZE / 2; // Temporarily update board and gem properties to test for matches board[originalGem1Y][originalGem1X] = originalGem2Type; board[originalGem2Y][originalGem2X] = originalGem1Type; gem1.gemType = originalGem2Type; gem2.gemType = originalGem1Type; // Check if this swap creates any matches var hasMatch = hasMatchAt(originalGem1X, originalGem1Y) || hasMatchAt(originalGem2X, originalGem2Y); if (hasMatch) { // Valid swap - complete the swap gem1.setGridPosition(originalGem2X, originalGem2Y); gem2.setGridPosition(originalGem1X, originalGem1Y); // Update gems array gems[originalGem1Y][originalGem1X] = gem2; gems[originalGem2Y][originalGem2X] = gem1; // Animate to swapped positions gem1.animateToPosition(originalGem2PosX, originalGem2PosY, 200); gem2.animateToPosition(originalGem1PosX, originalGem1PosY, 200, function () { LK.getSound('swap').play(); checkForMatches(); }); } else { // Invalid swap - revert changes board[originalGem1Y][originalGem1X] = originalGem1Type; board[originalGem2Y][originalGem2X] = originalGem2Type; gem1.gemType = originalGem1Type; gem2.gemType = originalGem2Type; // Animate gems briefly toward each other then back var swapDistance = 30; var gem1SwipePosX = originalGem1PosX + (originalGem2PosX - originalGem1PosX) * 0.3; var gem1SwipePosY = originalGem1PosY + (originalGem2PosY - originalGem1PosY) * 0.3; var gem2SwipePosX = originalGem2PosX + (originalGem1PosX - originalGem2PosX) * 0.3; var gem2SwipePosY = originalGem2PosY + (originalGem1PosY - originalGem2PosY) * 0.3; // First animate toward each other gem1.animateToPosition(gem1SwipePosX, gem1SwipePosY, 150, function () { // Then animate back to original positions gem1.animateToPosition(originalGem1PosX, originalGem1PosY, 150); }); gem2.animateToPosition(gem2SwipePosX, gem2SwipePosY, 150, function () { // Then animate back to original positions gem2.animateToPosition(originalGem2PosX, originalGem2PosY, 150); }); } } function checkForMatches() { if (isProcessingMatches) return; var matchesFound = []; // Find all matches for (var y = 0; y < BOARD_SIZE; y++) { for (var x = 0; x < BOARD_SIZE; x++) { var matches = getMatchesAt(x, y); if (matches.length >= 3) { for (var i = 0; i < matches.length; i++) { var match = matches[i]; var alreadyFound = false; for (var j = 0; j < matchesFound.length; j++) { if (matchesFound[j].x === match.x && matchesFound[j].y === match.y) { alreadyFound = true; break; } } if (!alreadyFound) { matchesFound.push(match); } } } } } if (matchesFound.length > 0) { isProcessingMatches = true; removeMatches(matchesFound); } } function getMatchesAt(x, y) { var gemType = board[y][x]; var matches = [{ x: x, y: y }]; // Check horizontal var horizontalMatches = [{ x: x, y: y }]; // Check left for (var i = x - 1; i >= 0 && board[y][i] === gemType; i--) { horizontalMatches.push({ x: i, y: y }); } // Check right for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) { horizontalMatches.push({ x: i, y: y }); } // Check vertical var verticalMatches = [{ x: x, y: y }]; // Check up for (var i = y - 1; i >= 0 && board[i][x] === gemType; i--) { verticalMatches.push({ x: x, y: i }); } // Check down for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) { verticalMatches.push({ x: x, y: i }); } if (horizontalMatches.length >= 3) { matches = horizontalMatches; } if (verticalMatches.length >= 3) { if (matches.length === 1) { matches = verticalMatches; } else { // Combine both matches for (var i = 0; i < verticalMatches.length; i++) { var vMatch = verticalMatches[i]; var alreadyExists = false; for (var j = 0; j < matches.length; j++) { if (matches[j].x === vMatch.x && matches[j].y === vMatch.y) { alreadyExists = true; break; } } if (!alreadyExists) { matches.push(vMatch); } } } } return matches.length >= 3 ? matches : []; } function removeMatches(matches) { // Add score with celebration for big matches score += matches.length * 10; scoreTxt.setText('Score: ' + score); // Kid-friendly encouraging messages based on match size var encouragingMessages = ['Great job!', 'Awesome!', 'Fantastic!', 'Amazing!', 'Super cool!', 'You\'re doing great!', 'Keep going!', 'Brilliant!', 'Wonderful!']; if (matches.length >= 6) { messageTxt.setText('WOW! INCREDIBLE!'); LK.effects.flashScreen(0xFFD700, 800); // Extra long gold flash } else if (matches.length >= 5) { messageTxt.setText('SUPER COMBO!'); LK.effects.flashScreen(0xFFD700, 500); // Gold flash for 5+ matches } else if (matches.length >= 4) { messageTxt.setText('GREAT MATCH!'); LK.effects.flashScreen(0xFF69B4, 300); // Pink flash for 4+ matches } else { var randomMessage = encouragingMessages[Math.floor(Math.random() * encouragingMessages.length)]; messageTxt.setText(randomMessage); } // Update target display with progress var progress = Math.min(score / targetScore, 1.0); var progressPercent = Math.floor(progress * 100); targetTxt.setText('Target: ' + targetScore + ' (' + progressPercent + '%)'); // Encouraging messages based on progress if (progress >= 0.9) { targetTxt.fill = 0xFF6347; // Orange - almost there! } else if (progress >= 0.5) { targetTxt.fill = 0xFFD700; // Gold - halfway there! } else { targetTxt.fill = 0x32CD32; // Green - keep going! } // Check if target is reached if (score >= targetScore) { messageTxt.setText('🎉 YOU DID IT! 🎉'); LK.effects.flashScreen(0x00FF00, 1000); // Bright green celebration LK.showYouWin(); } // Flash and remove matched gems with rainbow colors var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB]; for (var i = 0; i < matches.length; i++) { var match = matches[i]; var gem = gems[match.y][match.x]; if (gem) { var flashColor = rainbowColors[i % rainbowColors.length]; LK.effects.flashObject(gem, flashColor, 300); tween(gem, { alpha: 0, scaleX: 1.5, // Make gems grow bigger before disappearing scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, // Bouncy effect onFinish: function onFinish() { // Properly destroy the gem after animation if (gem && gem.destroy) { gem.destroy(); } } }); } board[match.y][match.x] = -1; // Mark as empty gems[match.y][match.x] = null; // Clear gem reference } LK.getSound('match').play(); // Wait for animation then drop gems LK.setTimeout(function () { dropGems(); }, 350); } function dropGems() { var moved = false; // Drop existing gems for (var x = 0; x < BOARD_SIZE; x++) { var writePos = BOARD_SIZE - 1; for (var y = BOARD_SIZE - 1; y >= 0; y--) { if (board[y][x] !== -1) { if (y !== writePos) { // Move gem down board[writePos][x] = board[y][x]; gems[writePos][x] = gems[y][x]; gems[writePos][x].setGridPosition(x, writePos); gems[writePos][x].animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + writePos * CELL_SIZE + CELL_SIZE / 2, 200); board[y][x] = -1; gems[y][x] = null; moved = true; } writePos--; } } } // Fill empty spaces with new gems - ensure we fill from top to bottom for (var x = 0; x < BOARD_SIZE; x++) { for (var y = 0; y < BOARD_SIZE; y++) { if (board[y][x] === -1) { var newType = Math.floor(Math.random() * 8); var newGem = new Gem(newType); newGem.setGridPosition(x, y); newGem.y = boardStartY - (BOARD_SIZE - y) * CELL_SIZE + CELL_SIZE / 2; // Start above board newGem.animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + y * CELL_SIZE + CELL_SIZE / 2, 400); board[y][x] = newType; gems[y][x] = newGem; game.addChild(newGem); moved = true; } } } // Double check - ensure no empty spaces remain by creating additional gems if needed for (var x = 0; x < BOARD_SIZE; x++) { for (var y = 0; y < BOARD_SIZE; y++) { if (!gems[y][x] || board[y][x] === -1) { var newType = Math.floor(Math.random() * 8); var newGem = new Gem(newType); newGem.setGridPosition(x, y); board[y][x] = newType; gems[y][x] = newGem; game.addChild(newGem); moved = true; } } } if (moved) { LK.setTimeout(function () { isProcessingMatches = false; checkForMatches(); // Check for cascade matches }, 450); } else { isProcessingMatches = false; } } game.down = function (x, y, obj) { if (isProcessingMatches) return; selectedGem = getGemAt(x, y); if (selectedGem) { isDragging = true; dragStartX = x; dragStartY = y; // Fun rainbow flash and bigger bounce effect for kids var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB]; var randomColor = rainbowColors[Math.floor(Math.random() * rainbowColors.length)]; LK.effects.flashObject(selectedGem, randomColor, 300); // Store reference to selected gem for use in callbacks var gemToAnimate = selectedGem; // Check if gem exists and has valid properties before starting tween if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined) { tween(gemToAnimate, { scaleX: gemToAnimate.scaleX * 1.4, // Bigger bounce for kids scaleY: gemToAnimate.scaleY * 1.4 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { // Check if gem still exists and has valid properties before animating back if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined) { tween(gemToAnimate, { scaleX: gemToAnimate.scaleX / 1.4, scaleY: gemToAnimate.scaleY / 1.4 }, { duration: 150, easing: tween.easeIn }); } } }); } } }; game.move = function (x, y, obj) { if (!isDragging || !selectedGem || isProcessingMatches) return; var deltaX = x - dragStartX; var deltaY = y - dragStartY; var threshold = CELL_SIZE / 2; if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) { var targetGem = null; if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontal swipe if (deltaX > 0 && selectedGem.gridX < BOARD_SIZE - 1) { targetGem = gems[selectedGem.gridY][selectedGem.gridX + 1]; } else if (deltaX < 0 && selectedGem.gridX > 0) { targetGem = gems[selectedGem.gridY][selectedGem.gridX - 1]; } } else { // Vertical swipe if (deltaY > 0 && selectedGem.gridY < BOARD_SIZE - 1) { targetGem = gems[selectedGem.gridY + 1][selectedGem.gridX]; } else if (deltaY < 0 && selectedGem.gridY > 0) { targetGem = gems[selectedGem.gridY - 1][selectedGem.gridX]; } } if (targetGem) { swapGems(selectedGem, targetGem); } isDragging = false; selectedGem = null; } }; game.up = function (x, y, obj) { isDragging = false; selectedGem = null; }; // Initialize the game board initializeBoard();
===================================================================
--- original.js
+++ change.js
@@ -11,9 +11,9 @@
self.gemType = type;
self.gridX = 0;
self.gridY = 0;
self.isAnimating = false;
- var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange'];
+ var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange', 'gem_cyan', 'gem_pink'];
var gemGraphics = self.attachAsset(gemAssets[type], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: CELL_SIZE / 256,
@@ -110,9 +110,9 @@
for (var y = 0; y < BOARD_SIZE; y++) {
board[y] = [];
gems[y] = [];
for (var x = 0; x < BOARD_SIZE; x++) {
- var gemType = Math.floor(Math.random() * 6);
+ var gemType = Math.floor(Math.random() * 8);
var gem = new Gem(gemType);
gem.setGridPosition(x, y);
board[y][x] = gemType;
gems[y][x] = gem;
@@ -130,9 +130,9 @@
iterations++;
for (var y = 0; y < BOARD_SIZE; y++) {
for (var x = 0; x < BOARD_SIZE; x++) {
if (hasMatchAt(x, y)) {
- var newType = Math.floor(Math.random() * 6);
+ var newType = Math.floor(Math.random() * 8);
board[y][x] = newType;
gems[y][x].gemType = newType;
// Update gem graphics by recreating
gems[y][x].destroy();
@@ -433,9 +433,9 @@
// Fill empty spaces with new gems - ensure we fill from top to bottom
for (var x = 0; x < BOARD_SIZE; x++) {
for (var y = 0; y < BOARD_SIZE; y++) {
if (board[y][x] === -1) {
- var newType = Math.floor(Math.random() * 6);
+ var newType = Math.floor(Math.random() * 8);
var newGem = new Gem(newType);
newGem.setGridPosition(x, y);
newGem.y = boardStartY - (BOARD_SIZE - y) * CELL_SIZE + CELL_SIZE / 2; // Start above board
newGem.animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + y * CELL_SIZE + CELL_SIZE / 2, 400);
@@ -449,9 +449,9 @@
// Double check - ensure no empty spaces remain by creating additional gems if needed
for (var x = 0; x < BOARD_SIZE; x++) {
for (var y = 0; y < BOARD_SIZE; y++) {
if (!gems[y][x] || board[y][x] === -1) {
- var newType = Math.floor(Math.random() * 6);
+ var newType = Math.floor(Math.random() * 8);
var newGem = new Gem(newType);
newGem.setGridPosition(x, y);
board[y][x] = newType;
gems[y][x] = newGem;
make a orange gem realistic. In-Game asset. 2d. High contrast. No shadows
a purple gem not a diamond realistic. In-Game asset. 2d. High contrast. No shadows
a red gem realistic. In-Game asset. 2d. High contrast. No shadows
a yellow gem found from the caves of colorado make it realistic. In-Game asset. 2d. High contrast. No shadows
a cyan realistic gem. In-Game asset. 2d. High contrast. No shadows
a pink gem realistic. In-Game asset. 2d. High contrast. No shadows
a very modern pause button. In-Game asset. 2d. High contrast. No shadows
a fun play button that says play on it super modern and kid friendly. In-Game asset. 2d. High contrast. No shadows
a create account button for signing up in a game supa kid friendly and modern. In-Game asset. 2d. High contrast. No shadows