/**** * Classes ****/ var Button = Container.expand(function (text, color) { var self = Container.call(this); var buttonGraphics = self.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5 }); if (color) { buttonGraphics.tint = color; } var buttonText = new Text2(text, { size: 70, fill: 0xffffff }); buttonText.anchor.set(0.5); self.addChild(buttonText); return self; }); var Confetti = Container.expand(function () { var self = Container.call(this); var confettiGraphics = self.attachAsset('confetti', { anchorX: 0.5, anchorY: 0.5 }); // Random color confettiGraphics.tint = Math.random() * 0xffffff; self.vx = (Math.random() - 0.5) * 20; self.vy = -Math.random() * 15 - 5; self.gravity = 0.5; self.rotation = Math.random() * Math.PI * 2; self.rotSpeed = (Math.random() - 0.5) * 0.2; self.lifetime = 60 + Math.random() * 60; self.update = function () { self.x += self.vx; self.y += self.vy; self.vy += self.gravity; self.rotation += self.rotSpeed; self.lifetime--; self.alpha = Math.min(1, self.lifetime / 30); if (self.lifetime <= 0) { self.destroy(); return true; } return false; }; }); var Letter = Container.expand(function (_char, index) { var self = Container.call(this); var letterGraphics = self.attachAsset('letter', { anchorX: 0.5, anchorY: 0.5 }); var letterText = new Text2(_char.toUpperCase(), { size: 70, fill: 0x000000 }); letterText.anchor.set(0.5); self.addChild(letterText); self["char"] = _char; self.slotIndex = null; self.originalIndex = index; self.isDragging = false; self.startX = 0; self.startY = 0; self.targetX = 0; self.targetY = 0; self.isMoving = false; self.setHighlight = function (isCorrect) { if (isCorrect) { letterGraphics.tint = 0x33ff33; } else if (isCorrect === false) { // explicitly check for false to differentiate from undefined letterGraphics.tint = 0xff3333; } else { letterGraphics.tint = 0xffffff; } }; self.update = function () { if (self.isMoving) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 5) { self.x = self.targetX; self.y = self.targetY; self.isMoving = false; } else { self.x += dx * 0.2; self.y += dy * 0.2; } } }; self.moveTo = function (x, y) { self.targetX = x; self.targetY = y; self.isMoving = true; }; self.returnToField = function () { self.slotIndex = null; self.moveTo(self.startX, self.startY); }; }); var Slot = Container.expand(function (index) { var self = Container.call(this); var slotGraphics = self.attachAsset('slot', { anchorX: 0.5, anchorY: 0.5 }); self.index = index; self.letter = null; self.setLetter = function (letter) { self.letter = letter; if (letter) { letter.slotIndex = self.index; } }; self.clearLetter = function () { if (self.letter) { self.letter.slotIndex = null; self.letter = null; } }; }); var TimeBar = Container.expand(function () { var self = Container.call(this); var barBg = self.attachAsset('timeBarBg', { anchorX: 0, anchorY: 0.5 }); var barFill = new Container(); var barFillGraphics = barFill.attachAsset('timeBar', { anchorX: 0, anchorY: 0.5 }); self.addChild(barFill); self.maxTime = 30 * 60; // 30 seconds at 60fps self.timeLeft = self.maxTime; self.reset = function () { self.timeLeft = self.maxTime; barFill.scale.x = 1; }; self.update = function () { if (self.timeLeft > 0) { self.timeLeft--; barFill.scale.x = self.timeLeft / self.maxTime; } return self.timeLeft <= 0; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000055 }); /**** * Game Code ****/ // Play background music in a loop var WordList = function WordList() { // A selection of 500 English words (5-9 letters) var words = ["about", "above", "actor", "adult", "after", "again", "agree", "ahead", "album", "allow", "alone", "along", "already", "always", "amount", "angry", "animal", "answer", "anyone", "anything", "appear", "apple", "argue", "around", "arrive", "artist", "assume", "attack", "attend", "author", "autumn", "awake", "award", "badge", "baggage", "bake", "balance", "balloon", "banana", "banner", "barely", "barrel", "basket", "battle", "beach", "beauty", "because", "become", "before", "begin", "behind", "belief", "belong", "beneath", "beside", "better", "between", "beyond", "bicycle", "black", "blame", "blank", "blanket", "blind", "block", "blood", "board", "boast", "bonus", "border", "borrow", "bottle", "bottom", "bounce", "brain", "branch", "brave", "bread", "break", "breath", "brick", "bridge", "brief", "bright", "broad", "broken", "brother", "brown", "brush", "budget", "build", "bumpy", "bunch", "burden", "butter", "button", "cable", "camel", "camera", "cancel", "candy", "cannon", "canoe", "canvas", "canyon", "capable", "capital", "captain", "carbon", "career", "careful", "carpet", "carrot", "carry", "carton", "castle", "cattle", "caught", "cause", "caution", "cease", "ceiling", "celery", "cellar", "century", "certain", "chain", "chair", "chalk", "channel", "chapter", "charge", "charm", "chart", "chase", "cheap", "check", "cheer", "cheese", "cherry", "chicken", "chief", "child", "chill", "choice", "choose", "church", "circle", "claim", "class", "clean", "clear", "clerk", "clever", "cliff", "climb", "clock", "close", "cloth", "cloud", "clown", "coach", "coast", "coffee", "collar", "colony", "color", "column", "combat", "combine", "comedy", "coming", "common", "compass", "complex", "compute", "conceal", "concept", "concern", "concert", "conduct", "confirm", "connect", "consent", "contain", "content", "contest", "control", "convert", "cookie", "copper", "corner", "correct", "cotton", "couch", "cough", "council", "count", "country", "county", "couple", "course", "cousin", "cover", "crack", "craft", "crash", "crawl", "crazy", "cream", "create", "credit", "creek", "crime", "crisp", "critic", "cross", "crowd", "crown", "cruel", "crush", "crystal", "culture", "cunning", "curious", "current", "curtain", "curve", "cushion", "custom", "cutting", "cycle", "daily", "damage", "dance", "danger", "daring", "darken", "dazzle", "dealer", "debate", "debris", "decade", "decay", "decent", "decide", "declare", "decorate", "decrease", "dedicate", "defeat", "defend", "define", "degree", "delay", "delete", "delight", "deliver", "demand", "demise", "denial", "dense", "dental", "depart", "depend", "depict", "deposit", "depth", "deputy", "derive", "describe", "desert", "design", "desire", "despair", "destroy", "detail", "detect", "develop", "device", "devote", "diagnose", "diamond", "diary", "dictate", "differ", "digest", "digital", "dignity", "dilemma", "diminish", "dinner", "direct", "disable", "disagree", "disclose", "discover", "discuss", "disease", "disgust", "dismiss", "display", "dispose", "distance", "distort", "disturb", "divide", "divine", "dizzy", "doctor", "document", "domain", "domestic", "dominate", "donate", "donor", "double", "doubt", "dozen", "draft", "dragon", "drama", "dream", "dress", "drift", "drink", "drive", "drone", "drown", "drunk", "dryer", "duckling", "dumb", "dusk", "dust", "duty", "dwarf", "dwell", "eager", "eagle", "early", "earth", "easily", "easter", "eastern", "eating", "eclipse", "ecology", "economy", "edition", "editor", "educate", "effect", "effort", "eight", "either", "elbow", "elder", "elect", "eleven", "elite", "email", "embark", "embody", "embrace", "emerge", "emotion", "employ", "empower", "empty", "enable", "enact", "endless", "endorse", "endure", "enemy", "energy", "enforce", "engage", "engine", "enhance", "enjoy", "enlist", "enough", "enrich", "ensign", "ensure", "enter", "entitle", "entity", "entrance", "envelope", "envision", "envy", "equal", "equip", "equity", "eraser", "erode", "erosion", "error", "erupt", "escape", "escort", "essay", "essence", "estate", "esteem", "eternal", "ethics", "evidence", "evoke", "evolve", "exact", "examine", "example", "exceed", "excel", "except", "excess", "exchange", "excite", "exclude", "excuse", "execute", "exempt", "exhaust", "exhibit", "exist", "expand", "expect", "expert", "explain", "explode", "explore", "export", "expose", "express", "extend", "extra", "eyebrow", "fabric", "facade", "factor", "factory", "faculty", "fading", "falcon", "falling", "fallout", "famous", "fantasy", "farmer", "fashion", "father", "fatigue", "fault", "favor", "feature", "federal", "feeling", "fellow", "female", "fence", "ferry", "fever", "fiber", "fiction", "field", "fierce", "fight", "figure", "filter", "final", "find", "finger", "finish", "fire", "firm", "first"]; return { getRandomWord: function getRandomWord() { return words[Math.floor(Math.random() * words.length)]; } }; }; LK.playMusic('background', { loop: true }); // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var LETTER_SIZE = 140; var LETTER_MARGIN = 20; var PLAYING_FIELD_TOP = 400; var PLAYING_FIELD_HEIGHT = 1300; var SLOT_AREA_TOP = PLAYING_FIELD_TOP + PLAYING_FIELD_HEIGHT + 100; /**** * Game Variables ****/ var wordList = new WordList(); var currentWord = ""; var letters = []; var slots = []; var confetti = []; var score = 0; var wordsCompleted = 0; var timeBar = null; var isGameActive = false; var isProMode = false; var menuContainer = null; var gameContainer = null; var draggedLetter = null; var dragStartPos = { x: 0, y: 0 }; /**** * UI Elements ****/ var background = game.attachAsset('background', {}); game.addChildAt(background, 0); var scoreText = new Text2('SCORE: 0', { size: 70, fill: 0xffffff }); scoreText.anchor.set(1, 0); scoreText.x = GAME_WIDTH - 50; scoreText.y = 50; var wordText = new Text2('WORD: 0', { size: 70, fill: 0xffffff }); wordText.anchor.set(1, 0); wordText.x = GAME_WIDTH - 50; wordText.y = 130; var statusText = new Text2('', { size: 70, fill: 0xffffff }); statusText.anchor.set(0.5); statusText.x = GAME_WIDTH / 2; statusText.y = 200; /**** * Main Menu ****/ function createMainMenu() { menuContainer = new Container(); game.addChild(menuContainer); var menuBg = menuContainer.attachAsset('menuBackground', {}); var titleText = new Text2('WORD PUZZLE', { size: 120, fill: 0xffffff }); titleText.anchor.set(0.5); titleText.x = GAME_WIDTH / 2; titleText.y = GAME_HEIGHT * 0.25; menuContainer.addChild(titleText); var casualButton = new Button('CASUAL MODE'); casualButton.x = GAME_WIDTH / 2; casualButton.y = GAME_HEIGHT * 0.45; menuContainer.addChild(casualButton); var proButton = new Button('PRO MODE', 0xff3366); proButton.x = GAME_WIDTH / 2; proButton.y = GAME_HEIGHT * 0.6; menuContainer.addChild(proButton); var instructionsText = new Text2('Arrange the letters to form the correct word', { size: 50, fill: 0xaaaaff }); instructionsText.anchor.set(0.5); instructionsText.x = GAME_WIDTH / 2; instructionsText.y = GAME_HEIGHT * 0.75; menuContainer.addChild(instructionsText); } /**** * Game Functions ****/ function startGame(proMode) { // Remove menu if it exists if (menuContainer) { menuContainer.destroy(); menuContainer = null; } // Create game container gameContainer = new Container(); game.addChild(gameContainer); // Add UI elements gameContainer.addChild(scoreText); gameContainer.addChild(wordText); gameContainer.addChild(statusText); // Set game mode isProMode = proMode; // Add hint button in casual mode if (!isProMode) { var hintButton = new Button('HINT (-5 SCORE)', 0x33cc33); hintButton.x = GAME_WIDTH / 2; hintButton.y = GAME_HEIGHT - 300; hintButton.on('down', function () { //if (score >= 5) { score -= 5; updateScoreDisplay(); // Implement hint logic here provideHint(); }); gameContainer.addChild(hintButton); } // Create time bar for pro mode if (isProMode) { timeBar = new TimeBar(); timeBar.x = GAME_WIDTH / 2 - 900; timeBar.y = 300; gameContainer.addChild(timeBar); } // Reset game state score = 0; wordsCompleted = 0; letters = []; slots = []; confetti = []; draggedLetter = null; dragStartPos = { x: 0, y: 0 }; updateScoreDisplay(); // Add button to go back to main menu var backButton = new Button('BACK TO MENU', 0xff3366); backButton.x = GAME_WIDTH / 2; backButton.y = GAME_HEIGHT - 100; backButton.on('down', function () { if (gameContainer) { gameContainer.destroy(); gameContainer = null; } // Reset game state variables isGameActive = false; letters = []; slots = []; confetti = []; draggedLetter = null; dragStartPos = { x: 0, y: 0 }; createMainMenu(); }); gameContainer.addChild(backButton); // Start the game isGameActive = true; loadNextWord(); } function loadNextWord() { // Clear current word clearCurrentWord(); // Get a new random word currentWord = wordList.getRandomWord(); // Create slots for the word createSlots(currentWord.length); // Create jumbled letters createLetters(currentWord); // Reset time bar for pro mode if (isProMode && timeBar) { timeBar.reset(); } // Update status if (statusText) { statusText.setText('Arrange the letters!'); if (statusText) { statusText.setStyle({ fill: 0xffffff }); } } } function createSlots(count) { slots = []; var totalWidth = count * (LETTER_SIZE + LETTER_MARGIN); var startX = (GAME_WIDTH - totalWidth) / 2 + LETTER_SIZE / 2; for (var i = 0; i < count; i++) { var slot = new Slot(i); slot.x = startX + i * (LETTER_SIZE + LETTER_MARGIN); slot.y = SLOT_AREA_TOP; slots.push(slot); gameContainer.addChild(slot); } } function createLetters(word) { letters = []; // Create array of characters var chars = word.split(''); // Shuffle the characters for (var i = chars.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = chars[i]; chars[i] = chars[j]; chars[j] = temp; } // Calculate grid dimensions var cols = Math.ceil(Math.sqrt(chars.length)); var rows = Math.ceil(chars.length / cols); // Calculate starting position for grid var gridWidth = cols * (LETTER_SIZE + LETTER_MARGIN); var gridHeight = rows * (LETTER_SIZE + LETTER_MARGIN); var startX = (GAME_WIDTH - gridWidth) / 2 + LETTER_SIZE / 2; var startY = PLAYING_FIELD_TOP + (PLAYING_FIELD_HEIGHT - gridHeight) / 2 + LETTER_SIZE / 2; // Create letter objects for (var k = 0; k < chars.length; k++) { var row = Math.floor(k / cols); var col = k % cols; var letter = new Letter(chars[k], k); letter.x = startX + col * (LETTER_SIZE + LETTER_MARGIN); letter.y = startY + row * (LETTER_SIZE + LETTER_MARGIN); letter.startX = letter.x; letter.startY = letter.y; letters.push(letter); gameContainer.addChild(letter); } } function clearCurrentWord() { // Remove all letters and slots for (var i = 0; i < letters.length; i++) { letters[i].destroy(); } letters = []; for (var j = 0; j < slots.length; j++) { slots[j].destroy(); } slots = []; } function checkWord() { // Check if all slots have letters var allSlotsFilled = true; for (var i = 0; i < slots.length; i++) { if (!slots[i].letter) { allSlotsFilled = false; break; } } if (!allSlotsFilled) { return; } // Get the word formed by the letters in slots var formedWord = ""; for (var j = 0; j < slots.length; j++) { formedWord += slots[j].letter["char"]; } // Check if the word is correct if (formedWord === currentWord) { wordCorrect(); } else { wordIncorrect(); } } function wordCorrect() { // Play sound LK.getSound('correct').play(); // Update status statusText.setText('CORRECT!'); statusText.setStyle({ fill: 0x33ff33 }); // Flash screen effect LK.effects.flashScreen(0x33ff33, 0.3, 500); // Highlight letters for (var i = 0; i < letters.length; i++) { letters[i].setHighlight(true); } // Create confetti effect for (var j = 0; j < 100; j++) { var conf = new Confetti(); conf.x = GAME_WIDTH / 2; conf.y = SLOT_AREA_TOP; confetti.push(conf); gameContainer.addChild(conf); } // Calculate score based on word length and time (for pro mode) var wordScore = currentWord.length; if (isProMode && timeBar) { var timeBonus = Math.floor(timeBar.timeLeft / 10); wordScore += timeBonus; } score += wordScore; wordsCompleted++; updateScoreDisplay(); // Load next word after delay LK.setTimeout(function () { if (isGameActive) { loadNextWord(); } }, 1500); } function wordIncorrect() { // Play sound LK.getSound('wrong').play(); // Update status statusText.setText('TRY AGAIN!'); if (statusText) { statusText.setStyle({ fill: 0xff3333 }); } // Flash screen effect LK.effects.flashScreen(0xff3333, 0.3, 500); // Highlight letters for (var i = 0; i < letters.length; i++) { letters[i].setHighlight(false); } // Return letters to their original positions after delay LK.setTimeout(function () { if (isGameActive) { for (var i = 0; i < letters.length; i++) { if (letters[i].slotIndex !== null) { var slot = slots[letters[i].slotIndex]; slot.clearLetter(); } letters[i].returnToField(); letters[i].setHighlight(undefined); } statusText.setText('Arrange the letters!'); if (statusText) { statusText.setStyle({ fill: 0xffffff }); } } }, 1000); } function updateScoreDisplay() { scoreText.setText('SCORE: ' + score); wordText.setText('WORDS: ' + wordsCompleted); // Submit score to leaderboard LK.setScore(score); } function gameOver() { // Play sound LK.getSound('gameOver').play(); // Update status statusText.setText('GAME OVER! The correct word was: ' + currentWord.toUpperCase()); if (statusText) { statusText.setStyle({ fill: 0xff3333 }); } // Disable game isGameActive = false; // Flash screen effect LK.effects.flashScreen(0xff3333, 0.5, 1000); // Show game over screen after delay LK.setTimeout(function () { LK.showGameOver(); }, 2000); } function findNearestSlot(x, y) { var nearestSlot = null; var minDistance = LETTER_SIZE * 1.5; for (var i = 0; i < slots.length; i++) { var slot = slots[i]; var dx = x - slot.x; var dy = y - slot.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < minDistance && !slot.letter) { nearestSlot = slot; minDistance = distance; } } return nearestSlot; } function findLetterAt(x, y) { for (var i = 0; i < letters.length; i++) { var letter = letters[i]; var dx = x - letter.x; var dy = y - letter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < LETTER_SIZE / 2) { return letter; } } return null; } /**** * Event Handlers ****/ game.on('down', function (x, y, obj) { if (!isGameActive) { // Handle menu clicks if (menuContainer) { // Casual mode button if (x > GAME_WIDTH / 2 - 250 && x < GAME_WIDTH / 2 + 250 && y > GAME_HEIGHT * 0.45 - 75 && y < GAME_HEIGHT * 0.45 + 75) { startGame(false); return; } // Pro mode button if (x > GAME_WIDTH / 2 - 250 && x < GAME_WIDTH / 2 + 250 && y > GAME_HEIGHT * 0.6 - 75 && y < GAME_HEIGHT * 0.6 + 75) { startGame(true); return; } } return; } // Handle letter dragging in game var event = obj; var pos = game.toLocal(event.global); var letter = findLetterAt(pos.x, pos.y); if (letter) { draggedLetter = letter; dragStartPos = { x: pos.x, y: pos.y }; // If letter is in a slot, remove it if (letter.slotIndex !== null) { var oldSlot = slots[letter.slotIndex]; oldSlot.clearLetter(); } } }); game.on('up', function (x, y, obj) { if (!isGameActive || !draggedLetter) { return; } var event = obj; var pos = game.toLocal(event.global); // Find nearest slot var nearestSlot = findNearestSlot(pos.x, pos.y); // Place letter in slot or return to field if (nearestSlot) { nearestSlot.setLetter(draggedLetter); draggedLetter.moveTo(nearestSlot.x, nearestSlot.y); LK.getSound('letterPlace').play(); // Check if word is complete LK.setTimeout(checkWord, 200); } else { draggedLetter.returnToField(); } draggedLetter = null; }); game.on('move', function (x, y, obj) { if (!isGameActive || !draggedLetter) { return; } var event = obj; var pos = game.toLocal(event.global); // Move the letter with the cursor/finger draggedLetter.x = pos.x; draggedLetter.y = pos.y; }); /**** * Game Loop ****/ LK.on('tick', function () { // Update letters for (var i = 0; i < letters.length; i++) { letters[i].update(); } // Update confetti for (var j = confetti.length - 1; j >= 0; j--) { if (confetti[j].update()) { confetti.splice(j, 1); } } // Update timer in pro mode if (isGameActive && isProMode && timeBar) { if (timeBar.update()) { gameOver(); } } }); // Start with the main menu createMainMenu(); function provideHint() { // Find all empty slots var emptySlots = []; for (var i = 0; i < slots.length; i++) { if (!slots[i].letter) { emptySlots.push(i); } } // If no empty slots, return if (emptySlots.length === 0) { return; } // Select a random empty slot var randomIndex = Math.floor(Math.random() * emptySlots.length); var slotIndex = emptySlots[randomIndex]; // Find the correct letter for this slot var correctChar = currentWord[slotIndex]; for (var j = 0; j < letters.length; j++) { if (letters[j]["char"] === correctChar && letters[j].slotIndex === null) { // Move the letter to the slot slots[slotIndex].setLetter(letters[j]); letters[j].moveTo(slots[slotIndex].x, slots[slotIndex].y); LK.getSound('letterPlace').play(); // Apply a highlight effect to indicate the hint LK.effects.flashObject(letters[j], 0xffff00, 500); // Check if word is complete LK.setTimeout(checkWord, 200); return; } } }
/****
* Classes
****/
var Button = Container.expand(function (text, color) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5
});
if (color) {
buttonGraphics.tint = color;
}
var buttonText = new Text2(text, {
size: 70,
fill: 0xffffff
});
buttonText.anchor.set(0.5);
self.addChild(buttonText);
return self;
});
var Confetti = Container.expand(function () {
var self = Container.call(this);
var confettiGraphics = self.attachAsset('confetti', {
anchorX: 0.5,
anchorY: 0.5
});
// Random color
confettiGraphics.tint = Math.random() * 0xffffff;
self.vx = (Math.random() - 0.5) * 20;
self.vy = -Math.random() * 15 - 5;
self.gravity = 0.5;
self.rotation = Math.random() * Math.PI * 2;
self.rotSpeed = (Math.random() - 0.5) * 0.2;
self.lifetime = 60 + Math.random() * 60;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.vy += self.gravity;
self.rotation += self.rotSpeed;
self.lifetime--;
self.alpha = Math.min(1, self.lifetime / 30);
if (self.lifetime <= 0) {
self.destroy();
return true;
}
return false;
};
});
var Letter = Container.expand(function (_char, index) {
var self = Container.call(this);
var letterGraphics = self.attachAsset('letter', {
anchorX: 0.5,
anchorY: 0.5
});
var letterText = new Text2(_char.toUpperCase(), {
size: 70,
fill: 0x000000
});
letterText.anchor.set(0.5);
self.addChild(letterText);
self["char"] = _char;
self.slotIndex = null;
self.originalIndex = index;
self.isDragging = false;
self.startX = 0;
self.startY = 0;
self.targetX = 0;
self.targetY = 0;
self.isMoving = false;
self.setHighlight = function (isCorrect) {
if (isCorrect) {
letterGraphics.tint = 0x33ff33;
} else if (isCorrect === false) {
// explicitly check for false to differentiate from undefined
letterGraphics.tint = 0xff3333;
} else {
letterGraphics.tint = 0xffffff;
}
};
self.update = function () {
if (self.isMoving) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 5) {
self.x = self.targetX;
self.y = self.targetY;
self.isMoving = false;
} else {
self.x += dx * 0.2;
self.y += dy * 0.2;
}
}
};
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
self.isMoving = true;
};
self.returnToField = function () {
self.slotIndex = null;
self.moveTo(self.startX, self.startY);
};
});
var Slot = Container.expand(function (index) {
var self = Container.call(this);
var slotGraphics = self.attachAsset('slot', {
anchorX: 0.5,
anchorY: 0.5
});
self.index = index;
self.letter = null;
self.setLetter = function (letter) {
self.letter = letter;
if (letter) {
letter.slotIndex = self.index;
}
};
self.clearLetter = function () {
if (self.letter) {
self.letter.slotIndex = null;
self.letter = null;
}
};
});
var TimeBar = Container.expand(function () {
var self = Container.call(this);
var barBg = self.attachAsset('timeBarBg', {
anchorX: 0,
anchorY: 0.5
});
var barFill = new Container();
var barFillGraphics = barFill.attachAsset('timeBar', {
anchorX: 0,
anchorY: 0.5
});
self.addChild(barFill);
self.maxTime = 30 * 60; // 30 seconds at 60fps
self.timeLeft = self.maxTime;
self.reset = function () {
self.timeLeft = self.maxTime;
barFill.scale.x = 1;
};
self.update = function () {
if (self.timeLeft > 0) {
self.timeLeft--;
barFill.scale.x = self.timeLeft / self.maxTime;
}
return self.timeLeft <= 0;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000055
});
/****
* Game Code
****/
// Play background music in a loop
var WordList = function WordList() {
// A selection of 500 English words (5-9 letters)
var words = ["about", "above", "actor", "adult", "after", "again", "agree", "ahead", "album", "allow", "alone", "along", "already", "always", "amount", "angry", "animal", "answer", "anyone", "anything", "appear", "apple", "argue", "around", "arrive", "artist", "assume", "attack", "attend", "author", "autumn", "awake", "award", "badge", "baggage", "bake", "balance", "balloon", "banana", "banner", "barely", "barrel", "basket", "battle", "beach", "beauty", "because", "become", "before", "begin", "behind", "belief", "belong", "beneath", "beside", "better", "between", "beyond", "bicycle", "black", "blame", "blank", "blanket", "blind", "block", "blood", "board", "boast", "bonus", "border", "borrow", "bottle", "bottom", "bounce", "brain", "branch", "brave", "bread", "break", "breath", "brick", "bridge", "brief", "bright", "broad", "broken", "brother", "brown", "brush", "budget", "build", "bumpy", "bunch", "burden", "butter", "button", "cable", "camel", "camera", "cancel", "candy", "cannon", "canoe", "canvas", "canyon", "capable", "capital", "captain", "carbon", "career", "careful", "carpet", "carrot", "carry", "carton", "castle", "cattle", "caught", "cause", "caution", "cease", "ceiling", "celery", "cellar", "century", "certain", "chain", "chair", "chalk", "channel", "chapter", "charge", "charm", "chart", "chase", "cheap", "check", "cheer", "cheese", "cherry", "chicken", "chief", "child", "chill", "choice", "choose", "church", "circle", "claim", "class", "clean", "clear", "clerk", "clever", "cliff", "climb", "clock", "close", "cloth", "cloud", "clown", "coach", "coast", "coffee", "collar", "colony", "color", "column", "combat", "combine", "comedy", "coming", "common", "compass", "complex", "compute", "conceal", "concept", "concern", "concert", "conduct", "confirm", "connect", "consent", "contain", "content", "contest", "control", "convert", "cookie", "copper", "corner", "correct", "cotton", "couch", "cough", "council", "count", "country", "county", "couple", "course", "cousin", "cover", "crack", "craft", "crash", "crawl", "crazy", "cream", "create", "credit", "creek", "crime", "crisp", "critic", "cross", "crowd", "crown", "cruel", "crush", "crystal", "culture", "cunning", "curious", "current", "curtain", "curve", "cushion", "custom", "cutting", "cycle", "daily", "damage", "dance", "danger", "daring", "darken", "dazzle", "dealer", "debate", "debris", "decade", "decay", "decent", "decide", "declare", "decorate", "decrease", "dedicate", "defeat", "defend", "define", "degree", "delay", "delete", "delight", "deliver", "demand", "demise", "denial", "dense", "dental", "depart", "depend", "depict", "deposit", "depth", "deputy", "derive", "describe", "desert", "design", "desire", "despair", "destroy", "detail", "detect", "develop", "device", "devote", "diagnose", "diamond", "diary", "dictate", "differ", "digest", "digital", "dignity", "dilemma", "diminish", "dinner", "direct", "disable", "disagree", "disclose", "discover", "discuss", "disease", "disgust", "dismiss", "display", "dispose", "distance", "distort", "disturb", "divide", "divine", "dizzy", "doctor", "document", "domain", "domestic", "dominate", "donate", "donor", "double", "doubt", "dozen", "draft", "dragon", "drama", "dream", "dress", "drift", "drink", "drive", "drone", "drown", "drunk", "dryer", "duckling", "dumb", "dusk", "dust", "duty", "dwarf", "dwell", "eager", "eagle", "early", "earth", "easily", "easter", "eastern", "eating", "eclipse", "ecology", "economy", "edition", "editor", "educate", "effect", "effort", "eight", "either", "elbow", "elder", "elect", "eleven", "elite", "email", "embark", "embody", "embrace", "emerge", "emotion", "employ", "empower", "empty", "enable", "enact", "endless", "endorse", "endure", "enemy", "energy", "enforce", "engage", "engine", "enhance", "enjoy", "enlist", "enough", "enrich", "ensign", "ensure", "enter", "entitle", "entity", "entrance", "envelope", "envision", "envy", "equal", "equip", "equity", "eraser", "erode", "erosion", "error", "erupt", "escape", "escort", "essay", "essence", "estate", "esteem", "eternal", "ethics", "evidence", "evoke", "evolve", "exact", "examine", "example", "exceed", "excel", "except", "excess", "exchange", "excite", "exclude", "excuse", "execute", "exempt", "exhaust", "exhibit", "exist", "expand", "expect", "expert", "explain", "explode", "explore", "export", "expose", "express", "extend", "extra", "eyebrow", "fabric", "facade", "factor", "factory", "faculty", "fading", "falcon", "falling", "fallout", "famous", "fantasy", "farmer", "fashion", "father", "fatigue", "fault", "favor", "feature", "federal", "feeling", "fellow", "female", "fence", "ferry", "fever", "fiber", "fiction", "field", "fierce", "fight", "figure", "filter", "final", "find", "finger", "finish", "fire", "firm", "first"];
return {
getRandomWord: function getRandomWord() {
return words[Math.floor(Math.random() * words.length)];
}
};
};
LK.playMusic('background', {
loop: true
});
// Game constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var LETTER_SIZE = 140;
var LETTER_MARGIN = 20;
var PLAYING_FIELD_TOP = 400;
var PLAYING_FIELD_HEIGHT = 1300;
var SLOT_AREA_TOP = PLAYING_FIELD_TOP + PLAYING_FIELD_HEIGHT + 100;
/****
* Game Variables
****/
var wordList = new WordList();
var currentWord = "";
var letters = [];
var slots = [];
var confetti = [];
var score = 0;
var wordsCompleted = 0;
var timeBar = null;
var isGameActive = false;
var isProMode = false;
var menuContainer = null;
var gameContainer = null;
var draggedLetter = null;
var dragStartPos = {
x: 0,
y: 0
};
/****
* UI Elements
****/
var background = game.attachAsset('background', {});
game.addChildAt(background, 0);
var scoreText = new Text2('SCORE: 0', {
size: 70,
fill: 0xffffff
});
scoreText.anchor.set(1, 0);
scoreText.x = GAME_WIDTH - 50;
scoreText.y = 50;
var wordText = new Text2('WORD: 0', {
size: 70,
fill: 0xffffff
});
wordText.anchor.set(1, 0);
wordText.x = GAME_WIDTH - 50;
wordText.y = 130;
var statusText = new Text2('', {
size: 70,
fill: 0xffffff
});
statusText.anchor.set(0.5);
statusText.x = GAME_WIDTH / 2;
statusText.y = 200;
/****
* Main Menu
****/
function createMainMenu() {
menuContainer = new Container();
game.addChild(menuContainer);
var menuBg = menuContainer.attachAsset('menuBackground', {});
var titleText = new Text2('WORD PUZZLE', {
size: 120,
fill: 0xffffff
});
titleText.anchor.set(0.5);
titleText.x = GAME_WIDTH / 2;
titleText.y = GAME_HEIGHT * 0.25;
menuContainer.addChild(titleText);
var casualButton = new Button('CASUAL MODE');
casualButton.x = GAME_WIDTH / 2;
casualButton.y = GAME_HEIGHT * 0.45;
menuContainer.addChild(casualButton);
var proButton = new Button('PRO MODE', 0xff3366);
proButton.x = GAME_WIDTH / 2;
proButton.y = GAME_HEIGHT * 0.6;
menuContainer.addChild(proButton);
var instructionsText = new Text2('Arrange the letters to form the correct word', {
size: 50,
fill: 0xaaaaff
});
instructionsText.anchor.set(0.5);
instructionsText.x = GAME_WIDTH / 2;
instructionsText.y = GAME_HEIGHT * 0.75;
menuContainer.addChild(instructionsText);
}
/****
* Game Functions
****/
function startGame(proMode) {
// Remove menu if it exists
if (menuContainer) {
menuContainer.destroy();
menuContainer = null;
}
// Create game container
gameContainer = new Container();
game.addChild(gameContainer);
// Add UI elements
gameContainer.addChild(scoreText);
gameContainer.addChild(wordText);
gameContainer.addChild(statusText);
// Set game mode
isProMode = proMode;
// Add hint button in casual mode
if (!isProMode) {
var hintButton = new Button('HINT (-5 SCORE)', 0x33cc33);
hintButton.x = GAME_WIDTH / 2;
hintButton.y = GAME_HEIGHT - 300;
hintButton.on('down', function () {
//if (score >= 5) {
score -= 5;
updateScoreDisplay();
// Implement hint logic here
provideHint();
});
gameContainer.addChild(hintButton);
}
// Create time bar for pro mode
if (isProMode) {
timeBar = new TimeBar();
timeBar.x = GAME_WIDTH / 2 - 900;
timeBar.y = 300;
gameContainer.addChild(timeBar);
}
// Reset game state
score = 0;
wordsCompleted = 0;
letters = [];
slots = [];
confetti = [];
draggedLetter = null;
dragStartPos = {
x: 0,
y: 0
};
updateScoreDisplay();
// Add button to go back to main menu
var backButton = new Button('BACK TO MENU', 0xff3366);
backButton.x = GAME_WIDTH / 2;
backButton.y = GAME_HEIGHT - 100;
backButton.on('down', function () {
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Reset game state variables
isGameActive = false;
letters = [];
slots = [];
confetti = [];
draggedLetter = null;
dragStartPos = {
x: 0,
y: 0
};
createMainMenu();
});
gameContainer.addChild(backButton);
// Start the game
isGameActive = true;
loadNextWord();
}
function loadNextWord() {
// Clear current word
clearCurrentWord();
// Get a new random word
currentWord = wordList.getRandomWord();
// Create slots for the word
createSlots(currentWord.length);
// Create jumbled letters
createLetters(currentWord);
// Reset time bar for pro mode
if (isProMode && timeBar) {
timeBar.reset();
}
// Update status
if (statusText) {
statusText.setText('Arrange the letters!');
if (statusText) {
statusText.setStyle({
fill: 0xffffff
});
}
}
}
function createSlots(count) {
slots = [];
var totalWidth = count * (LETTER_SIZE + LETTER_MARGIN);
var startX = (GAME_WIDTH - totalWidth) / 2 + LETTER_SIZE / 2;
for (var i = 0; i < count; i++) {
var slot = new Slot(i);
slot.x = startX + i * (LETTER_SIZE + LETTER_MARGIN);
slot.y = SLOT_AREA_TOP;
slots.push(slot);
gameContainer.addChild(slot);
}
}
function createLetters(word) {
letters = [];
// Create array of characters
var chars = word.split('');
// Shuffle the characters
for (var i = chars.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
// Calculate grid dimensions
var cols = Math.ceil(Math.sqrt(chars.length));
var rows = Math.ceil(chars.length / cols);
// Calculate starting position for grid
var gridWidth = cols * (LETTER_SIZE + LETTER_MARGIN);
var gridHeight = rows * (LETTER_SIZE + LETTER_MARGIN);
var startX = (GAME_WIDTH - gridWidth) / 2 + LETTER_SIZE / 2;
var startY = PLAYING_FIELD_TOP + (PLAYING_FIELD_HEIGHT - gridHeight) / 2 + LETTER_SIZE / 2;
// Create letter objects
for (var k = 0; k < chars.length; k++) {
var row = Math.floor(k / cols);
var col = k % cols;
var letter = new Letter(chars[k], k);
letter.x = startX + col * (LETTER_SIZE + LETTER_MARGIN);
letter.y = startY + row * (LETTER_SIZE + LETTER_MARGIN);
letter.startX = letter.x;
letter.startY = letter.y;
letters.push(letter);
gameContainer.addChild(letter);
}
}
function clearCurrentWord() {
// Remove all letters and slots
for (var i = 0; i < letters.length; i++) {
letters[i].destroy();
}
letters = [];
for (var j = 0; j < slots.length; j++) {
slots[j].destroy();
}
slots = [];
}
function checkWord() {
// Check if all slots have letters
var allSlotsFilled = true;
for (var i = 0; i < slots.length; i++) {
if (!slots[i].letter) {
allSlotsFilled = false;
break;
}
}
if (!allSlotsFilled) {
return;
}
// Get the word formed by the letters in slots
var formedWord = "";
for (var j = 0; j < slots.length; j++) {
formedWord += slots[j].letter["char"];
}
// Check if the word is correct
if (formedWord === currentWord) {
wordCorrect();
} else {
wordIncorrect();
}
}
function wordCorrect() {
// Play sound
LK.getSound('correct').play();
// Update status
statusText.setText('CORRECT!');
statusText.setStyle({
fill: 0x33ff33
});
// Flash screen effect
LK.effects.flashScreen(0x33ff33, 0.3, 500);
// Highlight letters
for (var i = 0; i < letters.length; i++) {
letters[i].setHighlight(true);
}
// Create confetti effect
for (var j = 0; j < 100; j++) {
var conf = new Confetti();
conf.x = GAME_WIDTH / 2;
conf.y = SLOT_AREA_TOP;
confetti.push(conf);
gameContainer.addChild(conf);
}
// Calculate score based on word length and time (for pro mode)
var wordScore = currentWord.length;
if (isProMode && timeBar) {
var timeBonus = Math.floor(timeBar.timeLeft / 10);
wordScore += timeBonus;
}
score += wordScore;
wordsCompleted++;
updateScoreDisplay();
// Load next word after delay
LK.setTimeout(function () {
if (isGameActive) {
loadNextWord();
}
}, 1500);
}
function wordIncorrect() {
// Play sound
LK.getSound('wrong').play();
// Update status
statusText.setText('TRY AGAIN!');
if (statusText) {
statusText.setStyle({
fill: 0xff3333
});
}
// Flash screen effect
LK.effects.flashScreen(0xff3333, 0.3, 500);
// Highlight letters
for (var i = 0; i < letters.length; i++) {
letters[i].setHighlight(false);
}
// Return letters to their original positions after delay
LK.setTimeout(function () {
if (isGameActive) {
for (var i = 0; i < letters.length; i++) {
if (letters[i].slotIndex !== null) {
var slot = slots[letters[i].slotIndex];
slot.clearLetter();
}
letters[i].returnToField();
letters[i].setHighlight(undefined);
}
statusText.setText('Arrange the letters!');
if (statusText) {
statusText.setStyle({
fill: 0xffffff
});
}
}
}, 1000);
}
function updateScoreDisplay() {
scoreText.setText('SCORE: ' + score);
wordText.setText('WORDS: ' + wordsCompleted);
// Submit score to leaderboard
LK.setScore(score);
}
function gameOver() {
// Play sound
LK.getSound('gameOver').play();
// Update status
statusText.setText('GAME OVER! The correct word was: ' + currentWord.toUpperCase());
if (statusText) {
statusText.setStyle({
fill: 0xff3333
});
}
// Disable game
isGameActive = false;
// Flash screen effect
LK.effects.flashScreen(0xff3333, 0.5, 1000);
// Show game over screen after delay
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
function findNearestSlot(x, y) {
var nearestSlot = null;
var minDistance = LETTER_SIZE * 1.5;
for (var i = 0; i < slots.length; i++) {
var slot = slots[i];
var dx = x - slot.x;
var dy = y - slot.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance && !slot.letter) {
nearestSlot = slot;
minDistance = distance;
}
}
return nearestSlot;
}
function findLetterAt(x, y) {
for (var i = 0; i < letters.length; i++) {
var letter = letters[i];
var dx = x - letter.x;
var dy = y - letter.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < LETTER_SIZE / 2) {
return letter;
}
}
return null;
}
/****
* Event Handlers
****/
game.on('down', function (x, y, obj) {
if (!isGameActive) {
// Handle menu clicks
if (menuContainer) {
// Casual mode button
if (x > GAME_WIDTH / 2 - 250 && x < GAME_WIDTH / 2 + 250 && y > GAME_HEIGHT * 0.45 - 75 && y < GAME_HEIGHT * 0.45 + 75) {
startGame(false);
return;
}
// Pro mode button
if (x > GAME_WIDTH / 2 - 250 && x < GAME_WIDTH / 2 + 250 && y > GAME_HEIGHT * 0.6 - 75 && y < GAME_HEIGHT * 0.6 + 75) {
startGame(true);
return;
}
}
return;
}
// Handle letter dragging in game
var event = obj;
var pos = game.toLocal(event.global);
var letter = findLetterAt(pos.x, pos.y);
if (letter) {
draggedLetter = letter;
dragStartPos = {
x: pos.x,
y: pos.y
};
// If letter is in a slot, remove it
if (letter.slotIndex !== null) {
var oldSlot = slots[letter.slotIndex];
oldSlot.clearLetter();
}
}
});
game.on('up', function (x, y, obj) {
if (!isGameActive || !draggedLetter) {
return;
}
var event = obj;
var pos = game.toLocal(event.global);
// Find nearest slot
var nearestSlot = findNearestSlot(pos.x, pos.y);
// Place letter in slot or return to field
if (nearestSlot) {
nearestSlot.setLetter(draggedLetter);
draggedLetter.moveTo(nearestSlot.x, nearestSlot.y);
LK.getSound('letterPlace').play();
// Check if word is complete
LK.setTimeout(checkWord, 200);
} else {
draggedLetter.returnToField();
}
draggedLetter = null;
});
game.on('move', function (x, y, obj) {
if (!isGameActive || !draggedLetter) {
return;
}
var event = obj;
var pos = game.toLocal(event.global);
// Move the letter with the cursor/finger
draggedLetter.x = pos.x;
draggedLetter.y = pos.y;
});
/****
* Game Loop
****/
LK.on('tick', function () {
// Update letters
for (var i = 0; i < letters.length; i++) {
letters[i].update();
}
// Update confetti
for (var j = confetti.length - 1; j >= 0; j--) {
if (confetti[j].update()) {
confetti.splice(j, 1);
}
}
// Update timer in pro mode
if (isGameActive && isProMode && timeBar) {
if (timeBar.update()) {
gameOver();
}
}
});
// Start with the main menu
createMainMenu();
function provideHint() {
// Find all empty slots
var emptySlots = [];
for (var i = 0; i < slots.length; i++) {
if (!slots[i].letter) {
emptySlots.push(i);
}
}
// If no empty slots, return
if (emptySlots.length === 0) {
return;
}
// Select a random empty slot
var randomIndex = Math.floor(Math.random() * emptySlots.length);
var slotIndex = emptySlots[randomIndex];
// Find the correct letter for this slot
var correctChar = currentWord[slotIndex];
for (var j = 0; j < letters.length; j++) {
if (letters[j]["char"] === correctChar && letters[j].slotIndex === null) {
// Move the letter to the slot
slots[slotIndex].setLetter(letters[j]);
letters[j].moveTo(slots[slotIndex].x, slots[slotIndex].y);
LK.getSound('letterPlace').play();
// Apply a highlight effect to indicate the hint
LK.effects.flashObject(letters[j], 0xffff00, 500);
// Check if word is complete
LK.setTimeout(checkWord, 200);
return;
}
}
}