User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.users[username] = newUserData;' Line Number: 2033 βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.users[username] = newUserData;' Line Number: 2029 βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
After you create a account you unlock leaderboards only works if ur logged in βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
Now it's not working on create account fix it so it works on both
User prompt
When your in log in the keyboard should also pop up
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'storage.users[username] = {' Line Number: 1966 βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make it so when you log in you must enter the correct password for your account and username βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
When you leave the game it should always auto save your account and your accounts progress βͺπ‘ Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make the keyboard easier to use bye spacing out keys a Lil bit βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make it so when you type in username or password text buttons make sure it shows the letters u have entered
User prompt
When your keyboard pops up get rid of the light black background
User prompt
Please fix the bug: 'Uncaught ReferenceError: usernameDisplayText is not defined' in or related to this line: 'if (usernameDisplayText) {' Line Number: 343
User prompt
Make it so u can see what letters u have entered while using keyboard
User prompt
Make the keyboard bigger and pop up from the bottom βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught ReferenceError: addCharacter is not defined' in or related to this line: 'addCharacter(letter);' Line Number: 263
User prompt
Please fix the bug: 'Uncaught ReferenceError: createSpecialKey is not defined' in or related to this line: 'createSpecialKey('SPACE', 2048 / 2, startY + 3 * keySpacing, 4, function () {' Line Number: 208
User prompt
Please fix the bug: 'Uncaught ReferenceError: createKey is not defined' in or related to this line: 'createKey(rowKeys[col], startX + col * keySpacing, startY + row * keySpacing);' Line Number: 196
User prompt
Please fix the bug: 'Uncaught ReferenceError: getInputText is not defined' in or related to this line: 'inputDisplayText = new Text2(getInputText(), {' Line Number: 164
User prompt
Please fix the bug: 'Uncaught ReferenceError: showKeyboard is not defined' in or related to this line: 'showKeyboard('username');' Line Number: 1719
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var FoodItem = Container.expand(function (foodType) {
var self = Container.call(this);
self.foodType = foodType;
self.gridX = -1;
self.gridY = -1;
self.isMatched = false;
self.isAnimating = false;
var foodGraphics = self.attachAsset(foodType, {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, callback) {
self.isAnimating = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (callback) callback();
}
});
};
self.animateMatch = function (callback) {
self.isMatched = true;
// First make it bigger and sparkly
tween(self, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFD700
}, {
duration: 150,
easing: tween.bounceOut
});
// Then shrink away with stars effect
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: callback
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var CELL_SIZE = 240;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = 300;
var FOOD_TYPES = ['apple', 'banana', 'orange', 'grape', 'lemon', 'hamburger', 'hotdog', 'pizza'];
var grid = [];
var selectedFood = null;
var isProcessingMatches = false;
var movesLeft = 30;
var currentScore = 0;
var targetMatches = 10;
var matchesCleared = 0;
var swipeStartX = 0;
var swipeStartY = 0;
var swipeFood = null;
var isSwipeActive = false;
var SWIPE_THRESHOLD = 50;
var currentLevel = 1;
var maxUnlockedLevel = 1;
var totalScore = 0;
var gameState = 'playing';
var levelCompleteShown = false;
// Text input variables
var currentInputField = null;
var usernameText = '';
var passwordText = '';
var keyboardContainer = null;
var inputDisplayText = null;
var isKeyboardVisible = false;
var usernameDisplayText = null;
var passwordDisplayText = null;
var createUsernameDisplayText = null;
var createPasswordDisplayText = null;
// Initialize grid array
function getInputText() {
if (currentInputField === 'username') {
return usernameText;
} else if (currentInputField === 'password') {
// Show asterisks for password
var asterisks = '';
for (var i = 0; i < passwordText.length; i++) {
asterisks += '*';
}
return asterisks;
}
return '';
}
function showKeyboard(inputType) {
if (isKeyboardVisible) return;
isKeyboardVisible = true;
currentInputField = inputType;
// Create keyboard container
keyboardContainer = new Container();
game.addChild(keyboardContainer);
// Keyboard popup without background
// Create input display
var inputBg = LK.getAsset('inputField', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 2
});
inputBg.x = 2048 / 2;
inputBg.y = 1600;
keyboardContainer.addChild(inputBg);
// Create input text display
inputDisplayText = new Text2(getInputText(), {
size: 80,
fill: 0xFFFFFF
});
inputDisplayText.anchor.set(0.5, 0.5);
inputDisplayText.x = 2048 / 2;
inputDisplayText.y = 1600;
keyboardContainer.addChild(inputDisplayText);
// Create keyboard layout
var keys = [['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M']];
var startY = 1800;
var keySize = 160;
var keySpacing = 200;
// Create letter keys
for (var row = 0; row < keys.length; row++) {
var rowKeys = keys[row];
var totalWidth = rowKeys.length * keySpacing;
var startX = (2048 - totalWidth) / 2 + keySpacing / 2;
for (var col = 0; col < rowKeys.length; col++) {
createKey(rowKeys[col], startX + col * keySpacing, startY + row * keySpacing);
}
}
// Create number row
var numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
var numberStartY = startY - keySpacing;
var numberTotalWidth = numbers.length * keySpacing;
var numberStartX = (2048 - numberTotalWidth) / 2 + keySpacing / 2;
for (var i = 0; i < numbers.length; i++) {
createKey(numbers[i], numberStartX + i * keySpacing, numberStartY);
}
// Create special keys
createSpecialKey('SPACE', 2048 / 2, startY + 3 * keySpacing, 4, function () {
addCharacter(' ');
});
createSpecialKey('DELETE', 2048 / 2 - 400, startY + 3 * keySpacing, 2, function () {
deleteCharacter();
});
createSpecialKey('DONE', 2048 / 2 + 400, startY + 3 * keySpacing, 2, function () {
hideKeyboard();
});
// Create close button
var closeButton = LK.getAsset('xButton', {
anchorX: 0.5,
anchorY: 0.5
});
closeButton.x = 2048 / 2 + 500;
closeButton.y = 1500;
closeButton.down = function () {
hideKeyboard();
};
keyboardContainer.addChild(closeButton);
// Start keyboard below screen and animate up
keyboardContainer.y = 800;
tween(keyboardContainer, {
y: 0
}, {
duration: 300,
easing: tween.easeOut
});
}
function createKey(letter, x, y) {
var keyButton = new Container();
var keyBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
keyBg.tint = 0x4CAF50;
keyButton.addChild(keyBg);
var keyText = new Text2(letter, {
size: 70,
fill: 0xFFFFFF
});
keyText.anchor.set(0.5, 0.5);
keyButton.addChild(keyText);
keyButton.x = x;
keyButton.y = y;
keyButton.down = function () {
LK.getSound('buttonClick').play();
tween(keyButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(keyButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
addCharacter(letter);
};
keyboardContainer.addChild(keyButton);
}
function createSpecialKey(text, x, y, widthScale, action) {
var keyButton = new Container();
var keyBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: widthScale * 0.8,
scaleY: 1.2
});
keyBg.tint = 0xFF9800;
keyButton.addChild(keyBg);
var keyText = new Text2(text, {
size: 60,
fill: 0xFFFFFF
});
keyText.anchor.set(0.5, 0.5);
keyButton.addChild(keyText);
keyButton.x = x;
keyButton.y = y;
keyButton.down = function () {
LK.getSound('buttonClick').play();
tween(keyButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(keyButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
action();
};
keyboardContainer.addChild(keyButton);
}
function addCharacter(_char) {
if (currentInputField === 'username') {
if (usernameText.length < 15) {
usernameText += _char;
}
} else if (currentInputField === 'password') {
if (passwordText.length < 15) {
passwordText += _char;
}
}
updateInputDisplay();
}
function deleteCharacter() {
if (currentInputField === 'username') {
if (usernameText.length > 0) {
usernameText = usernameText.slice(0, -1);
}
} else if (currentInputField === 'password') {
if (passwordText.length > 0) {
passwordText = passwordText.slice(0, -1);
}
}
updateInputDisplay();
}
function updateInputDisplay() {
if (inputDisplayText) {
inputDisplayText.setText(getInputText());
}
// Update field displays on login screen
if (gameState === 'loginScreen') {
if (usernameDisplayText) {
usernameDisplayText.setText(usernameText);
}
if (passwordDisplayText) {
var asterisks = '';
for (var i = 0; i < passwordText.length; i++) {
asterisks += '*';
}
passwordDisplayText.setText(asterisks);
}
}
// Update field displays on create account screen
if (gameState === 'createAccountScreen') {
if (createUsernameDisplayText) {
createUsernameDisplayText.setText(usernameText);
}
if (createPasswordDisplayText) {
var asterisks = '';
for (var i = 0; i < passwordText.length; i++) {
asterisks += '*';
}
createPasswordDisplayText.setText(asterisks);
}
}
}
function hideKeyboard() {
if (keyboardContainer) {
tween(keyboardContainer, {
y: 800
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
keyboardContainer.destroy();
keyboardContainer = null;
inputDisplayText = null;
isKeyboardVisible = false;
currentInputField = null;
}
});
}
}
var _loop = function _loop() {
grid[x] = [];
for (y = 0; y < GRID_SIZE; y++) {
grid[x][y] = null;
}
},
y;
for (var x = 0; x < GRID_SIZE; x++) {
_loop();
}
// Create grid background
var gridBackground = new Container();
game.addChild(gridBackground);
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var cell = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
cell.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
cell.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
cell.alpha = 0.3;
gridBackground.addChild(cell);
}
}
// Create UI
var scoreText = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 120;
var movesText = new Text2('Moves: 30', {
size: 80,
fill: 0xFFFFFF
});
movesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(movesText);
movesText.x = 150;
movesText.y = 50;
var tutorialText = new Text2('Lvl' + currentLevel, {
size: 120,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0);
LK.gui.top.addChild(tutorialText);
tutorialText.y = 20;
var targetText = new Text2('Target: ' + targetMatches, {
size: 100,
fill: 0xFFFFFF
});
targetText.anchor.set(0, 0);
LK.gui.top.addChild(targetText);
targetText.x = tutorialText.x + tutorialText.width / 2 + 50;
targetText.y = tutorialText.y;
function getRandomFoodType(x, y) {
// If position is provided, try to create squares by matching nearby foods
if (x !== undefined && y !== undefined) {
// Collect nearby food types that could form squares
var nearbyTypes = [];
// Check adjacent positions for potential square formation
var positions = [{
dx: -1,
dy: 0
}, {
dx: 1,
dy: 0
}, {
dx: 0,
dy: -1
}, {
dx: 0,
dy: 1
},
// Adjacent
{
dx: -1,
dy: -1
}, {
dx: 1,
dy: -1
}, {
dx: -1,
dy: 1
}, {
dx: 1,
dy: 1
} // Diagonal
];
for (var i = 0; i < positions.length; i++) {
var checkX = x + positions[i].dx;
var checkY = y + positions[i].dy;
if (isValidPosition(checkX, checkY) && grid[checkX] && grid[checkX][checkY]) {
nearbyTypes.push(grid[checkX][checkY].foodType);
}
}
// 40% chance to match a nearby type if any exist
if (nearbyTypes.length > 0 && Math.random() < 0.4) {
return nearbyTypes[Math.floor(Math.random() * nearbyTypes.length)];
}
}
return FOOD_TYPES[Math.floor(Math.random() * FOOD_TYPES.length)];
}
function createFoodItem(x, y) {
var foodType = getRandomFoodType(x, y);
var food = new FoodItem(foodType);
food.setGridPosition(x, y);
grid[x][y] = food;
game.addChild(food);
// Add fun spawn animation with rainbow colors
food.scaleX = 0;
food.scaleY = 0;
food.alpha = 0;
var rainbowColors = [0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xFECA57, 0xFF9FF3, 0x54A0FF];
var randomColor = rainbowColors[Math.floor(Math.random() * rainbowColors.length)];
food.tint = randomColor;
tween(food, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500,
easing: tween.bounceOut
});
// Reset to normal color after spawn
tween(food, {
tint: 0xFFFFFF
}, {
duration: 800,
easing: tween.easeOut
});
return food;
}
function initializeGrid() {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
createFoodItem(x, y);
}
}
// Remove initial matches
var foundMatches = true;
while (foundMatches) {
var matches = findAllMatches();
if (matches.length > 0) {
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (grid[match.x] && grid[match.x][match.y]) {
grid[match.x][match.y].destroy();
grid[match.x][match.y] = null;
}
}
fillEmptySpaces();
} else {
foundMatches = false;
}
}
}
function isValidPosition(x, y) {
return x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE;
}
function isAdjacent(x1, y1, x2, y2) {
var dx = Math.abs(x1 - x2);
var dy = Math.abs(y1 - y2);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapFoods(food1, food2) {
if (!food1 || !food2) return false;
var x1 = food1.gridX;
var y1 = food1.gridY;
var x2 = food2.gridX;
var y2 = food2.gridY;
// Swap in grid
grid[x1][y1] = food2;
grid[x2][y2] = food1;
// Update grid positions
food1.setGridPosition(x2, y2);
food2.setGridPosition(x1, y1);
// Animate swap
var targetX1 = GRID_START_X + x2 * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = GRID_START_Y + y2 * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = GRID_START_X + x1 * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = GRID_START_Y + y1 * CELL_SIZE + CELL_SIZE / 2;
food1.animateToPosition(targetX1, targetY1);
food2.animateToPosition(targetX2, targetY2);
return true;
}
function findMatches(x, y) {
var matches = [];
if (!grid[x] || !grid[x][y]) return matches;
var foodType = grid[x][y].foodType;
// Check horizontal matches
var horizontalMatches = [{
x: x,
y: y
}];
// Check left
for (var i = x - 1; i >= 0; i--) {
if (grid[i] && grid[i][y] && grid[i][y].foodType === foodType) {
horizontalMatches.push({
x: i,
y: y
});
} else {
break;
}
}
// Check right
for (var i = x + 1; i < GRID_SIZE; i++) {
if (grid[i] && grid[i][y] && grid[i][y].foodType === foodType) {
horizontalMatches.push({
x: i,
y: y
});
} else {
break;
}
}
if (horizontalMatches.length >= 3) {
matches = matches.concat(horizontalMatches);
}
// Check vertical matches
var verticalMatches = [{
x: x,
y: y
}];
// Check up
for (var i = y - 1; i >= 0; i--) {
if (grid[x] && grid[x][i] && grid[x][i].foodType === foodType) {
verticalMatches.push({
x: x,
y: i
});
} else {
break;
}
}
// Check down
for (var i = y + 1; i < GRID_SIZE; i++) {
if (grid[x] && grid[x][i] && grid[x][i].foodType === foodType) {
verticalMatches.push({
x: x,
y: i
});
} else {
break;
}
}
if (verticalMatches.length >= 3) {
matches = matches.concat(verticalMatches);
}
return matches;
}
function findSquares() {
var allSquares = [];
// Check for 2x2 squares
for (var x = 0; x < GRID_SIZE - 1; x++) {
for (var y = 0; y < GRID_SIZE - 1; y++) {
// Check if all positions have valid food items
if (grid[x] && grid[x][y] && grid[x + 1] && grid[x + 1][y] && grid[x] && grid[x][y + 1] && grid[x + 1] && grid[x + 1][y + 1]) {
var topLeft = grid[x][y];
var topRight = grid[x + 1][y];
var bottomLeft = grid[x][y + 1];
var bottomRight = grid[x + 1][y + 1];
// Check if all 4 foods exist, are the same type and not already matched
if (topLeft && topRight && bottomLeft && bottomRight && topLeft.foodType === topRight.foodType && topLeft.foodType === bottomLeft.foodType && topLeft.foodType === bottomRight.foodType && !topLeft.isMatched && !topRight.isMatched && !bottomLeft.isMatched && !bottomRight.isMatched) {
allSquares.push([{
x: x,
y: y
}, {
x: x + 1,
y: y
}, {
x: x,
y: y + 1
}, {
x: x + 1,
y: y + 1
}]);
}
}
}
}
return allSquares;
}
function findAllMatches() {
var allMatches = [];
var processed = {};
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x] && grid[x][y] && !processed[x + ',' + y]) {
var matches = findMatches(x, y);
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var key = match.x + ',' + match.y;
if (!processed[key]) {
allMatches.push(match);
processed[key] = true;
}
}
}
}
}
return allMatches;
}
function processMatches() {
if (isProcessingMatches) return;
// First check for squares
var squares = findSquares();
var matches = findAllMatches();
if (squares.length === 0 && matches.length === 0) return;
isProcessingMatches = true;
LK.getSound('match').play();
var totalClearedCount = 0;
var finalMatches = [];
// Process squares first - clear entire rows
if (squares.length > 0) {
var rowsToClear = [];
// Collect all unique rows that contain squares
for (var s = 0; s < squares.length; s++) {
var square = squares[s];
for (var p = 0; p < square.length; p++) {
var rowY = square[p].y;
if (rowsToClear.indexOf(rowY) === -1) {
rowsToClear.push(rowY);
}
}
}
// Clear all foods in the identified rows
for (var r = 0; r < rowsToClear.length; r++) {
var row = rowsToClear[r];
for (var x = 0; x < GRID_SIZE; x++) {
if (grid[x] && grid[x][row] && !grid[x][row].isMatched) {
finalMatches.push({
x: x,
y: row
});
grid[x][row].isMatched = true; // Mark as matched immediately
}
}
}
totalClearedCount = finalMatches.length;
// Special celebration for square clearing
LK.effects.flashScreen(0x00FF00, 800);
currentScore += totalClearedCount * 20; // Bonus points for row clearing
} else {
// Regular match processing
finalMatches = matches;
totalClearedCount = matches.length;
currentScore += totalClearedCount * 10;
}
matchesCleared += totalClearedCount;
targetMatches = Math.max(0, targetMatches - Math.floor(totalClearedCount / 3));
updateUI();
// Update total score
totalScore += squares.length > 0 ? totalClearedCount * 20 : totalClearedCount * 10;
// Save high score to storage
var highScore = storage.highScore || 0;
if (totalScore > highScore) {
storage.highScore = totalScore;
}
// Auto-save user progress
saveUserProgress();
// Play squeaky voice when getting points
LK.getSound('goodJobBooby').play();
// Add celebration effects for bigger matches
if (totalClearedCount >= 4 || squares.length > 0) {
// Big match celebration!
if (squares.length === 0) {
LK.effects.flashScreen(0xFFD700, 500);
}
// Make score text dance
tween(scoreText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 300,
easing: tween.bounceOut
});
tween(scoreText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.bounceOut
});
}
var animationsCompleted = 0;
for (var i = 0; i < finalMatches.length; i++) {
var match = finalMatches[i];
if (grid[match.x] && grid[match.x][match.y]) {
// Mark as matched before animation
grid[match.x][match.y].isMatched = true;
grid[match.x][match.y].animateMatch(function () {
animationsCompleted++;
if (animationsCompleted === totalClearedCount) {
// Remove matched foods
for (var j = 0; j < finalMatches.length; j++) {
var m = finalMatches[j];
if (grid[m.x] && grid[m.x][m.y]) {
grid[m.x][m.y].destroy();
grid[m.x][m.y] = null;
}
}
fillEmptySpaces();
LK.setTimeout(function () {
isProcessingMatches = false;
processMatches(); // Check for cascade matches
}, 300);
}
});
}
}
if (totalClearedCount === 0) {
isProcessingMatches = false;
}
}
function fillEmptySpaces() {
// Drop existing foods
for (var x = 0; x < GRID_SIZE; x++) {
var writeIndex = GRID_SIZE - 1;
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (grid[x][y] !== null) {
if (y !== writeIndex) {
grid[x][writeIndex] = grid[x][y];
grid[x][y] = null;
grid[x][writeIndex].setGridPosition(x, writeIndex);
var targetY = GRID_START_Y + writeIndex * CELL_SIZE + CELL_SIZE / 2;
grid[x][writeIndex].animateToPosition(grid[x][writeIndex].x, targetY);
}
writeIndex--;
}
}
// Create new foods for empty spaces at top
for (var y = 0; y <= writeIndex; y++) {
var food = new FoodItem(getRandomFoodType(x, y));
food.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
food.y = GRID_START_Y - (writeIndex - y + 1) * CELL_SIZE + CELL_SIZE / 2;
food.gridX = x;
food.gridY = y;
grid[x][y] = food;
game.addChild(food);
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
food.animateToPosition(food.x, targetY);
}
}
}
function updateUI() {
if (scoreText) {
scoreText.setText('Score: ' + currentScore);
}
if (movesText) {
movesText.setText('Moves: ' + movesLeft);
}
if (targetText) {
targetText.setText('Target: ' + targetMatches);
}
}
function checkGameEnd() {
if (targetMatches <= 1 && targetMatches > 0) {
// Create guaranteed 2x2 square at front of board
createGuaranteedSquare();
}
if (targetMatches <= 0) {
if (currentLevel === 1 && !levelCompleteShown) {
showLevelComplete();
} else {
completeLevel();
}
} else if (movesLeft <= 0) {
LK.showGameOver();
}
}
function createGuaranteedSquare() {
// Choose a random food type for the square
var squareFoodType = FOOD_TYPES[Math.floor(Math.random() * FOOD_TYPES.length)];
// Find the best 2x2 position at the front (top rows) of the board
var bestX = 0;
var bestY = 0;
// Try to place in top-left area first for visibility
for (var x = 0; x <= GRID_SIZE - 2; x++) {
for (var y = 0; y <= 2; y++) {
// Focus on top 3 rows
if (isValidPosition(x, y) && isValidPosition(x + 1, y) && isValidPosition(x, y + 1) && isValidPosition(x + 1, y + 1)) {
bestX = x;
bestY = y;
break;
}
}
if (bestY <= 2) break;
}
// Create the 2x2 square by replacing existing foods
var positions = [{
x: bestX,
y: bestY
}, {
x: bestX + 1,
y: bestY
}, {
x: bestX,
y: bestY + 1
}, {
x: bestX + 1,
y: bestY + 1
}];
for (var i = 0; i < positions.length; i++) {
var pos = positions[i];
// Remove existing food if any
if (grid[pos.x] && grid[pos.x][pos.y]) {
grid[pos.x][pos.y].destroy();
}
// Create new food of the same type
var newFood = new FoodItem(squareFoodType);
newFood.setGridPosition(pos.x, pos.y);
grid[pos.x][pos.y] = newFood;
game.addChild(newFood);
// Add special visual effect to highlight the square
newFood.tint = 0xFFD700; // Gold tint
// Add pulsing animation to make it obvious
tween(newFood, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOut
});
tween(newFood, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
// Flash screen to draw attention
LK.effects.flashScreen(0xFFD700, 1000);
}
function showLevelComplete() {
levelCompleteShown = true;
gameState = 'levelComplete';
// Play celebration music
LK.playMusic('celebrationMusic', {
loop: false
});
// Play level complete sound
LK.getSound('levelComplete').play();
// Add celebration effects
LK.effects.flashScreen(0xFFD700, 1000);
// Make all UI elements dance
tween(scoreText, {
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.2
}, {
duration: 500,
easing: tween.bounceOut
});
tween(tutorialText, {
scaleX: 1.3,
scaleY: 1.3,
rotation: -0.1
}, {
duration: 600,
easing: tween.bounceOut
});
tween(targetText, {
scaleX: 1.2,
scaleY: 1.2,
rotation: 0.15
}, {
duration: 700,
easing: tween.bounceOut
});
LK.setTimeout(function () {
showWhiteScreen();
}, 3000);
}
function showWhiteScreen() {
gameState = 'whiteScreen';
// Clear all game elements
game.removeChildren();
// Clear tutorial UI elements
if (tutorialText && tutorialText.parent) {
tutorialText.destroy();
tutorialText = null;
}
if (targetText && targetText.parent) {
targetText.destroy();
targetText = null;
}
if (scoreText && scoreText.parent) {
scoreText.destroy();
scoreText = null;
}
if (movesText && movesText.parent) {
movesText.destroy();
movesText = null;
}
// Set white background
game.setBackgroundColor(0xFFFFFF);
// Show white screen for 2 seconds then show home screen
LK.setTimeout(function () {
showHomeScreen();
}, 2000);
}
function showHomeScreen() {
gameState = 'homeScreen';
// Load user progress from storage
loadUserProgress();
// Clear all game elements
game.removeChildren();
// Set game background color
game.setBackgroundColor(0x87CEEB);
// Start playing happy background music
LK.playMusic('happyBgMusic', {
loop: true
});
// Clear all UI elements from the screen
if (tutorialText && tutorialText.parent) {
tutorialText.destroy();
tutorialText = null;
}
if (targetText && targetText.parent) {
targetText.destroy();
targetText = null;
}
if (scoreText && scoreText.parent) {
scoreText.destroy();
scoreText = null;
}
if (movesText && movesText.parent) {
movesText.destroy();
movesText = null;
}
// Get user data from storage
var currentUser = storage.currentUser || null;
var isLoggedIn = currentUser !== null;
// Create home screen UI
var titleText = new Text2('FOOD MATCH', {
size: 200,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 300;
game.addChild(titleText);
// Show user status
if (isLoggedIn) {
var welcomeText = new Text2('Welcome back, ' + currentUser + '!', {
size: 80,
fill: 0xFFD700
});
welcomeText.anchor.set(0.5, 0.5);
welcomeText.x = 2048 / 2;
welcomeText.y = 450;
game.addChild(welcomeText);
} else {
var guestText = new Text2('Playing as Guest', {
size: 80,
fill: 0xFFFFFF
});
guestText.anchor.set(0.5, 0.5);
guestText.x = 2048 / 2;
guestText.y = 450;
game.addChild(guestText);
}
// Create play button
var playButton = new Container();
var playBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.8
});
playBg.tint = 0x4CAF50; // Green tint for play button
playButton.addChild(playBg);
var playText = new Text2('PLAY', {
size: 80,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playButton.addChild(playText);
playButton.x = 2048 / 2;
playButton.y = 800;
playButton.down = function () {
// Play button click sound
LK.getSound('buttonClick').play();
// Add button press animation
tween(playButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
// Start the game
startLevel(1);
};
game.addChild(playButton);
// Create leaderboard button
var leaderboardButton = new Container();
var leaderboardBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.8
});
leaderboardBg.tint = isLoggedIn ? 0x2196F3 : 0x666666; // Blue for logged in, gray for guests
leaderboardButton.addChild(leaderboardBg);
var leaderboardText = new Text2('LEADERBOARD', {
size: 60,
fill: isLoggedIn ? 0xFFFFFF : 0x999999
});
leaderboardText.anchor.set(0.5, 0.5);
leaderboardButton.addChild(leaderboardText);
leaderboardButton.x = 2048 / 2;
leaderboardButton.y = 950;
leaderboardButton.down = function () {
LK.getSound('buttonClick').play();
tween(leaderboardButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(leaderboardButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
if (isLoggedIn) {
// Show leaderboard for logged-in users
showLeaderboard();
} else {
// Show message that login is required
var loginRequiredText = new Text2('Login required for leaderboards', {
size: 60,
fill: 0xFF0000
});
loginRequiredText.anchor.set(0.5, 0.5);
loginRequiredText.x = 2048 / 2;
loginRequiredText.y = 1200;
game.addChild(loginRequiredText);
// Remove message after 3 seconds
LK.setTimeout(function () {
if (loginRequiredText && loginRequiredText.parent) {
loginRequiredText.destroy();
}
}, 3000);
}
};
game.addChild(leaderboardButton);
// Authentication buttons
if (isLoggedIn) {
// Show logout button
var logoutButton = new Container();
var logoutBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
logoutBg.tint = 0xFF9800; // Orange tint for logout button
logoutButton.addChild(logoutBg);
var logoutText = new Text2('LOGOUT', {
size: 50,
fill: 0xFFFFFF
});
logoutText.anchor.set(0.5, 0.5);
logoutButton.addChild(logoutText);
logoutButton.x = 2048 / 2;
logoutButton.y = 1100;
logoutButton.down = function () {
LK.getSound('buttonClick').play();
tween(logoutButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(logoutButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
// Save current progress before logout
saveUserProgress();
// Logout user
storage.currentUser = null;
showHomeScreen(); // Refresh home screen
};
game.addChild(logoutButton);
} else {
// Show login button
var loginButton = new Container();
var loginBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
loginBg.tint = 0x9C27B0; // Purple tint for login button
loginButton.addChild(loginBg);
var loginText = new Text2('LOGIN', {
size: 50,
fill: 0xFFFFFF
});
loginText.anchor.set(0.5, 0.5);
loginButton.addChild(loginText);
loginButton.x = 2048 / 2 - 200;
loginButton.y = 1100;
loginButton.down = function () {
LK.getSound('buttonClick').play();
tween(loginButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(loginButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
showLoginScreen();
};
game.addChild(loginButton);
// Show create account button
var createAccountButton = new Container();
var createAccountBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
createAccountBg.tint = 0x4CAF50; // Green tint for create account button
createAccountButton.addChild(createAccountBg);
var createAccountText = new Text2('SIGN UP', {
size: 50,
fill: 0xFFFFFF
});
createAccountText.anchor.set(0.5, 0.5);
createAccountButton.addChild(createAccountText);
createAccountButton.x = 2048 / 2 + 200;
createAccountButton.y = 1100;
createAccountButton.down = function () {
LK.getSound('buttonClick').play();
tween(createAccountButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(createAccountButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
showCreateAccountScreen();
};
game.addChild(createAccountButton);
}
// Show high score if available
var highScore = storage.highScore || 0;
if (highScore > 0) {
var highScoreText = new Text2('High Score: ' + highScore, {
size: 80,
fill: 0xFFFFFF
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 2048 / 2;
highScoreText.y = 600;
game.addChild(highScoreText);
}
}
function completeLevel() {
// Add current score to total score
totalScore += currentScore;
// Save high score to storage
var highScore = storage.highScore || 0;
if (totalScore > highScore) {
storage.highScore = totalScore;
}
// Auto-save user progress
saveUserProgress();
// Show leaderboard
showLeaderboard();
// Show home screen to restart the game
showHomeScreen();
}
function startLevel(levelNum) {
currentLevel = levelNum;
gameState = 'playing';
levelCompleteShown = false;
// Auto-save progress when starting level
saveUserProgress();
// Continue playing background music during gameplay
LK.playMusic('happyBgMusic', {
loop: true
});
// Adjust difficulty based on level
targetMatches = Math.min(10 + (levelNum - 1) * 5, 100);
movesLeft = Math.max(30 - Math.floor((levelNum - 1) / 3), 15);
currentScore = 0;
matchesCleared = 0;
// Clear existing UI
game.removeChildren();
// Recreate game
setupGame();
}
function setupGame() {
// Recreate grid background
gridBackground = new Container();
game.addChild(gridBackground);
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var cell = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
cell.x = GRID_START_X + x * CELL_SIZE + CELL_SIZE / 2;
cell.y = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
cell.alpha = 0.3;
gridBackground.addChild(cell);
}
}
// Clear existing UI elements
if (tutorialText && tutorialText.parent) {
tutorialText.destroy();
}
if (targetText && targetText.parent) {
targetText.destroy();
}
// Recreate UI elements if they don't exist
if (!scoreText) {
scoreText = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 120;
}
if (!movesText) {
movesText = new Text2('Moves: ' + movesLeft, {
size: 80,
fill: 0xFFFFFF
});
movesText.anchor.set(0, 0);
LK.gui.topLeft.addChild(movesText);
movesText.x = 150;
movesText.y = 50;
}
// Update UI
scoreText.setText('Score: 0');
movesText.setText('Moves: ' + movesLeft);
tutorialText = new Text2('Lvl' + currentLevel, {
size: 120,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0);
LK.gui.top.addChild(tutorialText);
tutorialText.y = 20;
targetText = new Text2('Target: ' + targetMatches, {
size: 100,
fill: 0xFFFFFF
});
targetText.anchor.set(0, 0);
LK.gui.top.addChild(targetText);
targetText.x = tutorialText.x + tutorialText.width / 2 + 50;
targetText.y = tutorialText.y;
// Add exit button below the game grid
var exitButton = new Container();
var exitBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
exitBg.tint = 0xFF4444; // Red tint for exit button
exitButton.addChild(exitBg);
var exitText = new Text2('EXIT', {
size: 60,
fill: 0xFFFFFF
});
exitText.anchor.set(0.5, 0.5);
exitButton.addChild(exitText);
// Position button below the game grid, centered
exitButton.x = 2048 / 2;
exitButton.y = GRID_START_Y + GRID_SIZE * CELL_SIZE + 100;
exitButton.down = function () {
// Play button click sound
LK.getSound('buttonClick').play();
// Add button press animation
tween(exitButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(exitButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
// Teleport to home screen
showHomeScreen();
};
game.addChild(exitButton);
// Initialize grid
initializeGrid();
updateUI();
}
function getFoodAtPosition(x, y) {
var gridX = Math.floor((x - GRID_START_X) / CELL_SIZE);
var gridY = Math.floor((y - GRID_START_Y) / CELL_SIZE);
if (isValidPosition(gridX, gridY) && grid[gridX] && grid[gridX][gridY]) {
return grid[gridX][gridY];
}
return null;
}
game.down = function (x, y, obj) {
if (isProcessingMatches) return;
var food = getFoodAtPosition(x, y);
if (food && !food.isAnimating) {
swipeStartX = x;
swipeStartY = y;
swipeFood = food;
isSwipeActive = true;
swipeFood.alpha = 0.7;
// Add fun wobble animation when selected
tween(swipeFood, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.bounceOut
});
}
};
game.up = function (x, y, obj) {
if (!isSwipeActive || !swipeFood) return;
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (swipeDistance < SWIPE_THRESHOLD) {
// Not a swipe, reset
swipeFood.alpha = 1;
isSwipeActive = false;
swipeFood = null;
return;
}
// Determine swipe direction
var targetGridX = swipeFood.gridX;
var targetGridY = swipeFood.gridY;
var absDeltaX = Math.abs(deltaX);
var absDeltaY = Math.abs(deltaY);
if (absDeltaX > absDeltaY) {
// Horizontal swipe
if (deltaX > 0) {
targetGridX++; // Swipe right
} else {
targetGridX--; // Swipe left
}
} else {
// Vertical swipe
if (deltaY > 0) {
targetGridY++; // Swipe down
} else {
targetGridY--; // Swipe up
}
}
// Check if target position is valid
if (isValidPosition(targetGridX, targetGridY) && grid[targetGridX] && grid[targetGridX][targetGridY]) {
var targetFood = grid[targetGridX][targetGridY];
if (!targetFood.isAnimating) {
LK.getSound('swap').play();
// Store original positions BEFORE any swap
var tempFood1 = swipeFood;
var tempFood2 = targetFood;
var originalX1 = tempFood1.gridX;
var originalY1 = tempFood1.gridY;
var originalX2 = tempFood2.gridX;
var originalY2 = tempFood2.gridY;
// Try swap
swapFoods(tempFood1, tempFood2);
LK.setTimeout(function () {
var matches = findAllMatches();
if (matches.length === 0) {
// Invalid move, animate swap back to original positions
var targetX1 = GRID_START_X + originalX1 * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = GRID_START_Y + originalY1 * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = GRID_START_X + originalX2 * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = GRID_START_Y + originalY2 * CELL_SIZE + CELL_SIZE / 2;
tempFood1.animateToPosition(targetX1, targetY1);
tempFood2.animateToPosition(targetX2, targetY2);
// Restore original grid positions
grid[originalX1][originalY1] = tempFood1;
grid[originalX2][originalY2] = tempFood2;
tempFood1.gridX = originalX1;
tempFood1.gridY = originalY1;
tempFood2.gridX = originalX2;
tempFood2.gridY = originalY2;
} else {
// Valid move
movesLeft--;
updateUI();
processMatches();
checkGameEnd();
}
}, 350);
}
}
// Reset swipe state with fun bounce back animation
tween(swipeFood, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
isSwipeActive = false;
swipeFood = null;
};
// Start background music when game loads
LK.playMusic('happyBgMusic', {
loop: true
});
// Initialize the game - start with home screen
showHomeScreen();
function showLoginScreen() {
gameState = 'loginScreen';
// Clear all game elements
game.removeChildren();
// Set game background color
game.setBackgroundColor(0x87CEEB);
// Create login screen UI
var titleText = new Text2('LOGIN', {
size: 150,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 300;
game.addChild(titleText);
// Username input field
var usernameField = LK.getAsset('inputField', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.2
});
usernameField.x = 2048 / 2;
usernameField.y = 600;
usernameField.down = function () {
showKeyboard('username');
};
game.addChild(usernameField);
usernameDisplayText = new Text2('', {
size: 50,
fill: 0x000000
});
usernameDisplayText.anchor.set(0.5, 0.5);
usernameDisplayText.x = 2048 / 2;
usernameDisplayText.y = 600;
game.addChild(usernameDisplayText);
var usernameLabel = new Text2('Username', {
size: 60,
fill: 0xFFFFFF
});
usernameLabel.anchor.set(0.5, 0.5);
usernameLabel.x = 2048 / 2;
usernameLabel.y = 550;
game.addChild(usernameLabel);
// Password input field
var passwordField = LK.getAsset('passwordField', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.2
});
passwordField.x = 2048 / 2;
passwordField.y = 800;
passwordField.down = function () {
showKeyboard('password');
};
game.addChild(passwordField);
passwordDisplayText = new Text2('', {
size: 50,
fill: 0x000000
});
passwordDisplayText.anchor.set(0.5, 0.5);
passwordDisplayText.x = 2048 / 2;
passwordDisplayText.y = 800;
game.addChild(passwordDisplayText);
var passwordLabel = new Text2('Password', {
size: 60,
fill: 0xFFFFFF
});
passwordLabel.anchor.set(0.5, 0.5);
passwordLabel.x = 2048 / 2;
passwordLabel.y = 750;
game.addChild(passwordLabel);
// Show keyboard automatically for username input
showKeyboard('username');
// Login button
var loginButton = new Container();
var loginBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.8
});
loginBg.tint = 0x4CAF50; // Green tint for login button
loginButton.addChild(loginBg);
var loginText = new Text2('LOGIN', {
size: 80,
fill: 0xFFFFFF
});
loginText.anchor.set(0.5, 0.5);
loginButton.addChild(loginText);
loginButton.x = 2048 / 2;
loginButton.y = 1000;
loginButton.down = function () {
LK.getSound('buttonClick').play();
tween(loginButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(loginButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
// Validate input fields
if (usernameText.length === 0 || passwordText.length === 0) {
// Show error message for empty fields
var errorText = new Text2('Please fill all fields', {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 900;
game.addChild(errorText);
// Remove error message after 2 seconds
LK.setTimeout(function () {
if (errorText && errorText.parent) {
errorText.destroy();
}
}, 2000);
return;
}
// Validate credentials
var existingUsers = storage.users || {};
var username = usernameText;
if (!existingUsers[username]) {
// Username doesn't exist
var errorText = new Text2('Username not found', {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 900;
game.addChild(errorText);
// Remove error message after 2 seconds
LK.setTimeout(function () {
if (errorText && errorText.parent) {
errorText.destroy();
}
}, 2000);
return;
}
if (existingUsers[username].password !== passwordText) {
// Wrong password
var errorText = new Text2('Incorrect password', {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 900;
game.addChild(errorText);
// Remove error message after 2 seconds
LK.setTimeout(function () {
if (errorText && errorText.parent) {
errorText.destroy();
}
}, 2000);
return;
}
// Valid credentials - login successful
storage.currentUser = username;
// Auto-save user data on login
saveUserProgress();
// Clear input fields
usernameText = '';
passwordText = '';
showHomeScreen();
};
game.addChild(loginButton);
// Back button
var backButton = new Container();
var backBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
backBg.tint = 0xFF4444; // Red tint for back button
backButton.addChild(backBg);
var backText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
backButton.x = 2048 / 2;
backButton.y = 1150;
backButton.down = function () {
LK.getSound('buttonClick').play();
tween(backButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(backButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
showHomeScreen();
};
game.addChild(backButton);
}
function showLeaderboard() {
gameState = 'leaderboard';
// Clear all game elements
game.removeChildren();
// Set game background color
game.setBackgroundColor(0x87CEEB);
// Create leaderboard screen UI
var titleText = new Text2('LEADERBOARD', {
size: 150,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 300;
game.addChild(titleText);
// Get user-specific high score from storage
var currentUser = storage.currentUser || 'Guest';
var highScore = 0;
if (currentUser !== 'Guest' && storage.users && storage.users[currentUser]) {
highScore = storage.users[currentUser].highScore || 0;
} else {
highScore = storage.highScore || 0;
}
// Display high score
var highScoreText = new Text2('High Score: ' + highScore, {
size: 120,
fill: 0xFFD700
});
highScoreText.anchor.set(0.5, 0.5);
highScoreText.x = 2048 / 2;
highScoreText.y = 600;
game.addChild(highScoreText);
// Display current user
var userText = new Text2('Player: ' + currentUser, {
size: 80,
fill: 0xFFFFFF
});
userText.anchor.set(0.5, 0.5);
userText.x = 2048 / 2;
userText.y = 750;
game.addChild(userText);
// Show additional user stats for logged-in users
if (currentUser !== 'Guest' && storage.users && storage.users[currentUser]) {
var userData = storage.users[currentUser];
var levelText = new Text2('Level Reached: ' + (userData.level || 1), {
size: 70,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = 2048 / 2;
levelText.y = 850;
game.addChild(levelText);
var totalScoreText = new Text2('Total Score: ' + (userData.totalScore || 0), {
size: 70,
fill: 0xFFFFFF
});
totalScoreText.anchor.set(0.5, 0.5);
totalScoreText.x = 2048 / 2;
totalScoreText.y = 920;
game.addChild(totalScoreText);
} else {
var loginPromptText = new Text2('Login to track your progress!', {
size: 60,
fill: 0xFFD700
});
loginPromptText.anchor.set(0.5, 0.5);
loginPromptText.x = 2048 / 2;
loginPromptText.y = 850;
game.addChild(loginPromptText);
}
// Back button
var backButton = new Container();
var backBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.8
});
backBg.tint = 0xFF4444; // Red tint for back button
backButton.addChild(backBg);
var backText = new Text2('BACK', {
size: 80,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
backButton.x = 2048 / 2;
backButton.y = 1000;
backButton.down = function () {
LK.getSound('buttonClick').play();
tween(backButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(backButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
showHomeScreen();
};
game.addChild(backButton);
}
function showCreateAccountScreen() {
gameState = 'createAccountScreen';
// Clear all game elements
game.removeChildren();
// Set game background color
game.setBackgroundColor(0x87CEEB);
// Create account screen UI
var titleText = new Text2('CREATE ACCOUNT', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 300;
game.addChild(titleText);
// Username input field
var usernameField = LK.getAsset('inputField', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.2
});
usernameField.x = 2048 / 2;
usernameField.y = 600;
usernameField.down = function () {
showKeyboard('username');
};
game.addChild(usernameField);
createUsernameDisplayText = new Text2('', {
size: 50,
fill: 0x000000
});
createUsernameDisplayText.anchor.set(0.5, 0.5);
createUsernameDisplayText.x = 2048 / 2;
createUsernameDisplayText.y = 600;
game.addChild(createUsernameDisplayText);
var usernameLabel = new Text2('Choose Username', {
size: 60,
fill: 0xFFFFFF
});
usernameLabel.anchor.set(0.5, 0.5);
usernameLabel.x = 2048 / 2;
usernameLabel.y = 550;
game.addChild(usernameLabel);
// Password input field
var passwordField = LK.getAsset('passwordField', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
scaleY: 1.2
});
passwordField.x = 2048 / 2;
passwordField.y = 800;
passwordField.down = function () {
showKeyboard('password');
};
game.addChild(passwordField);
createPasswordDisplayText = new Text2('', {
size: 50,
fill: 0x000000
});
createPasswordDisplayText.anchor.set(0.5, 0.5);
createPasswordDisplayText.x = 2048 / 2;
createPasswordDisplayText.y = 800;
game.addChild(createPasswordDisplayText);
var passwordLabel = new Text2('Choose Password', {
size: 60,
fill: 0xFFFFFF
});
passwordLabel.anchor.set(0.5, 0.5);
passwordLabel.x = 2048 / 2;
passwordLabel.y = 750;
game.addChild(passwordLabel);
// Show keyboard automatically for username input
showKeyboard('username');
// Create account button
var createButton = new Container();
var createBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 0.8
});
createBg.tint = 0x4CAF50; // Green tint for create button
createButton.addChild(createBg);
var createText = new Text2('CREATE', {
size: 70,
fill: 0xFFFFFF
});
createText.anchor.set(0.5, 0.5);
createButton.addChild(createText);
createButton.x = 2048 / 2;
createButton.y = 1000;
createButton.down = function () {
LK.getSound('buttonClick').play();
tween(createButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(createButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
// Validate input fields
if (usernameText.length === 0 || passwordText.length === 0) {
// Show error message for empty fields
var errorText = new Text2('Please fill all fields', {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 900;
game.addChild(errorText);
// Remove error message after 2 seconds
LK.setTimeout(function () {
if (errorText && errorText.parent) {
errorText.destroy();
}
}, 2000);
return;
}
// Check if username already exists
var existingUsers = storage.users || {};
if (existingUsers[usernameText]) {
// Show error message for existing username
var errorText = new Text2('Username already exists', {
size: 60,
fill: 0xFF0000
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 900;
game.addChild(errorText);
// Remove error message after 2 seconds
LK.setTimeout(function () {
if (errorText && errorText.parent) {
errorText.destroy();
}
}, 2000);
return;
}
// Create account with password
var username = usernameText;
// Store user credentials in storage
if (!storage.users) {
storage.users = {};
}
// Ensure the storage.users object is properly initialized before assignment
var newUserData = {
password: passwordText,
level: 1,
totalScore: 0,
highScore: 0
};
// Double-check storage.users exists before assignment
if (!storage.users) {
storage.users = {};
}
// Ensure storage.users is properly initialized before assignment
if (!storage.users) {
storage.users = {};
}
storage.users[username] = newUserData;
storage.currentUser = username;
// Auto-save new user data
saveUserProgress();
// Clear input fields
usernameText = '';
passwordText = '';
showHomeScreen();
};
game.addChild(createButton);
// Back button
var backButton = new Container();
var backBg = LK.getAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 0.6
});
backBg.tint = 0xFF4444; // Red tint for back button
backButton.addChild(backBg);
var backText = new Text2('BACK', {
size: 50,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backButton.addChild(backText);
backButton.x = 2048 / 2;
backButton.y = 1150;
backButton.down = function () {
LK.getSound('buttonClick').play();
tween(backButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
tween(backButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
showHomeScreen();
};
game.addChild(backButton);
}
function saveUserProgress() {
// Save current user data
if (storage.currentUser) {
// Initialize users storage if it doesn't exist
if (!storage.users) {
storage.users = {};
}
// Initialize user data if it doesn't exist
if (!storage.users[storage.currentUser]) {
storage.users[storage.currentUser] = {
password: '',
level: 1,
totalScore: 0,
highScore: 0
};
}
// Update user-specific progress
storage.users[storage.currentUser].level = currentLevel;
storage.users[storage.currentUser].totalScore = totalScore;
storage.users[storage.currentUser].currentScore = currentScore;
storage.users[storage.currentUser].movesLeft = movesLeft;
storage.users[storage.currentUser].targetMatches = targetMatches;
storage.users[storage.currentUser].matchesCleared = matchesCleared;
storage.users[storage.currentUser].maxUnlockedLevel = maxUnlockedLevel;
storage.users[storage.currentUser].gameState = gameState;
// Update high score if current total score is higher
var userHighScore = storage.users[storage.currentUser].highScore || 0;
if (totalScore > userHighScore) {
storage.users[storage.currentUser].highScore = totalScore;
}
// Also save to legacy storage locations for backward compatibility
storage.userLevel = currentLevel;
storage.userTotalScore = totalScore;
storage.userCurrentScore = currentScore;
storage.userMovesLeft = movesLeft;
storage.userTargetMatches = targetMatches;
storage.userMatchesCleared = matchesCleared;
storage.userMaxUnlockedLevel = maxUnlockedLevel;
storage.gameState = gameState;
}
// Save general game progress
storage.lastPlayedLevel = currentLevel;
storage.lastTotalScore = totalScore;
}
function loadUserProgress() {
// Load user-specific progress if logged in
if (storage.currentUser) {
// Initialize users storage if it doesn't exist
if (!storage.users) {
storage.users = {};
}
// Load from user account if it exists
if (storage.users[storage.currentUser]) {
var userData = storage.users[storage.currentUser];
currentLevel = userData.level || 1;
totalScore = userData.totalScore || 0;
currentScore = userData.currentScore || 0;
movesLeft = userData.movesLeft || 30;
targetMatches = userData.targetMatches || 10;
matchesCleared = userData.matchesCleared || 0;
maxUnlockedLevel = userData.maxUnlockedLevel || 1;
} else {
// Fallback to legacy storage for existing users
currentLevel = storage.userLevel || 1;
totalScore = storage.userTotalScore || 0;
currentScore = storage.userCurrentScore || 0;
movesLeft = storage.userMovesLeft || 30;
targetMatches = storage.userTargetMatches || 10;
matchesCleared = storage.userMatchesCleared || 0;
maxUnlockedLevel = storage.userMaxUnlockedLevel || 1;
}
} else {
// Load general progress for guests
currentLevel = storage.lastPlayedLevel || 1;
totalScore = storage.lastTotalScore || 0;
}
} ===================================================================
--- original.js
+++ change.js
@@ -1988,8 +1988,12 @@
// Double-check storage.users exists before assignment
if (!storage.users) {
storage.users = {};
}
+ // Ensure storage.users is properly initialized before assignment
+ if (!storage.users) {
+ storage.users = {};
+ }
storage.users[username] = newUserData;
storage.currentUser = username;
// Auto-save new user data
saveUserProgress();