/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AnswerButton = Container.expand(function (answerText, isCorrect, onAnswerSelected) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('answerButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(answerText, {
size: 60,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.isCorrect = isCorrect;
self.onAnswerSelected = onAnswerSelected;
self.down = function (x, y, obj) {
self.onAnswerSelected(self.isCorrect);
};
self.setCorrectStyle = function () {
buttonGraphics.tint = 0x00ff00;
};
self.setIncorrectStyle = function () {
buttonGraphics.tint = 0xff0000;
};
self.resetStyle = function () {
buttonGraphics.tint = 0xffffff;
};
return self;
});
var Castle = Container.expand(function () {
var self = Container.call(this);
var castleGraphics = self.attachAsset('castle', {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 1.0
});
self.moveToPosition = function (targetX, questionNumber) {
var duration = 1000;
if (questionNumber === 5 || questionNumber === 10 || questionNumber === 15) {
duration = 2500;
}
tween(self, {
x: targetX
}, {
duration: duration,
easing: tween.easeInOut
});
};
return self;
});
var DifficultySelector = Container.expand(function (onDifficultySelected) {
var self = Container.call(this);
// Create semi-transparent overlay
var overlay = self.attachAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
overlay.x = 0;
overlay.y = 0;
// Create title text
var titleText = new Text2("SELECT DIFFICULTY", {
size: 100,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -400;
self.addChild(titleText);
// Create difficulty buttons
var difficulties = [{
name: 'EASY',
level: 1,
color: 0x00ff00
}, {
name: 'MEDIUM',
level: 2,
color: 0xffff00
}, {
name: 'HARD',
level: 3,
color: 0xff0000
}, {
name: 'INFINITY',
level: 4,
color: 0x9900ff
}];
var buttonPositions = [{
x: -500,
y: 100
}, {
x: 0,
y: 100
}, {
x: 500,
y: 100
}, {
x: 0,
y: 300
}];
for (var i = 0; i < difficulties.length; i++) {
var difficulty = difficulties[i];
var buttonContainer = new Container();
buttonContainer.x = buttonPositions[i].x;
buttonContainer.y = buttonPositions[i].y;
var assetId = difficulty.name.toLowerCase() + 'Button';
var buttonGraphics = buttonContainer.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
buttonGraphics.tint = difficulty.color;
var buttonText = new Text2(difficulty.name, {
size: 60,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
buttonContainer.addChild(buttonText);
buttonContainer.difficulty = difficulty;
buttonContainer.down = function (x, y, obj) {
onDifficultySelected(this.difficulty.level);
};
self.addChild(buttonContainer);
}
return self;
});
var PrincessGuard = Container.expand(function (guardNumber) {
var self = Container.call(this);
var guardAsset = guardNumber === 1 ? 'guard1' : 'guard2';
var guardGraphics = self.attachAsset(guardAsset, {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var currentLevel = storage.currentLevel || 1;
var completedLevels = storage.completedLevels || 0;
var currentQuestion = 0;
var totalQuestions = 15;
var correctAnswers = 0;
var gameActive = false;
var questionTimer = null;
var timeLeft = 10;
var timerText = null;
var hearts = 3;
var heartsDisplay = null;
var isInfinityMode = false;
// Math problem generation
var mathProblems = [];
var currentProblem = null;
// Game objects
var character = null;
var castle = null;
var ground = null;
var path = null;
var questionPanel = null;
var questionText = null;
var progressText = null;
var answerButtons = [];
// Positions
var startX = 200;
var endX = 1800;
var characterY = 2400;
var pathY = 2450;
var guard1 = null;
var guard2 = null;
var princess = null;
var guard1X = startX + (endX - startX) * (5 / 15);
var guard2X = startX + (endX - startX) * (10 / 15);
var princessX = endX;
// Initialize game elements
function initializeGame() {
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2470
}));
// Create path
path = game.addChild(LK.getAsset('path', {
anchorX: 0,
anchorY: 0.5,
x: 124,
y: pathY
}));
// Create character
character = game.addChild(new Character());
character.x = startX;
character.y = characterY;
// Create castle
castle = game.addChild(new Castle());
castle.x = endX;
castle.y = characterY;
// Create guard 1
guard1 = game.addChild(new PrincessGuard(1));
guard1.x = guard1X;
guard1.y = characterY;
// Create guard 2
guard2 = game.addChild(new PrincessGuard(2));
guard2.x = guard2X;
guard2.y = characterY;
// Create princess at the end
// Create question panel
questionPanel = game.addChild(LK.getAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1000
}));
questionPanel.alpha = 0.9;
// Create question text
questionText = new Text2('', {
size: 80,
fill: 0x000000
});
questionText.anchor.set(0.5, 0.5);
questionText.x = 1024;
questionText.y = 880;
game.addChild(questionText);
// Create progress text
progressText = new Text2('', {
size: 60,
fill: 0x2b2b2b
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 1024;
progressText.y = 700;
game.addChild(progressText);
// Create timer text
timerText = new Text2('Time: 10', {
size: 70,
fill: 0xff0000
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 1024;
timerText.y = 550;
game.addChild(timerText);
// Create completion counter text
var completionCounterText = new Text2('Princesses Saved: ' + completedLevels, {
size: 50,
fill: 0x000000
});
completionCounterText.anchor.set(0.5, 0.0);
completionCounterText.x = 1024;
completionCounterText.y = 50;
game.addChild(completionCounterText);
// Create hearts display
heartsDisplay = new Text2('❤️ ❤️ ❤️', {
size: 80,
fill: 0xff0000
});
heartsDisplay.anchor.set(0.5, 0.0);
heartsDisplay.x = 1024;
heartsDisplay.y = 120;
if (!isInfinityMode) {
game.addChild(heartsDisplay);
}
// Create answer buttons
var buttonPositions = [{
x: 512,
y: 1100
}, {
x: 1536,
y: 1100
}, {
x: 512,
y: 1300
}, {
x: 1536,
y: 1300
}];
for (var i = 0; i < 4; i++) {
var button = new AnswerButton('', false, onAnswerSelected);
button.x = buttonPositions[i].x;
button.y = buttonPositions[i].y;
answerButtons.push(button);
game.addChild(button);
}
// Create music toggle icon in top right corner
var musicIcon = new Text2('🎵', {
size: 80,
fill: 0x000000
});
musicIcon.anchor.set(1.0, 0.0);
musicIcon.x = 1948; // 100px from right edge (2048 - 100)
musicIcon.y = 100;
LK.gui.addChild(musicIcon);
// Add click handler to stop music
musicIcon.down = function (x, y, obj) {
LK.stopMusic();
};
generateMathProblems();
startNextQuestion();
}
function generateMathProblems() {
mathProblems = [];
for (var i = 0; i < totalQuestions; i++) {
var problem = generateMathProblem(currentLevel);
mathProblems.push(problem);
}
}
function generateMathProblem(level) {
var num1, num2, operation, correctAnswer, question;
if (level === 1) {
// Easy: Addition and subtraction only, up to 15
num1 = Math.floor(Math.random() * 15) + 1;
num2 = Math.floor(Math.random() * 15) + 1;
operation = Math.random() < 0.5 ? '+' : '-';
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
} else if (level === 2) {
// Medium: Addition and subtraction with low numbers up to 50
var ops = ['+', '-'];
operation = ops[Math.floor(Math.random() * ops.length)];
num1 = Math.floor(Math.random() * 50) + 1;
num2 = Math.floor(Math.random() * 50) + 1;
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
} else {
// Hard: All operations with larger numbers
var ops = ['+', '-', '*', '/'];
operation = ops[Math.floor(Math.random() * ops.length)];
if (operation === '/') {
correctAnswer = Math.floor(Math.random() * 20) + 1;
num2 = Math.floor(Math.random() * 12) + 1;
num1 = correctAnswer * num2;
question = num1 + ' ÷ ' + num2 + ' = ?';
} else if (operation === '*') {
num1 = Math.floor(Math.random() * 25) + 1;
num2 = Math.floor(Math.random() * 25) + 1;
correctAnswer = num1 * num2;
question = num1 + ' × ' + num2 + ' = ?';
} else {
num1 = Math.floor(Math.random() * 100) + 1;
num2 = Math.floor(Math.random() * 100) + 1;
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
}
}
// Generate wrong answers
var wrongAnswers = [];
var attempts = 0;
while (wrongAnswers.length < 3 && attempts < 20) {
var wrongAnswer;
var variation = Math.floor(Math.random() * 10) + 1;
if (Math.random() < 0.5) {
wrongAnswer = correctAnswer + variation;
} else {
wrongAnswer = correctAnswer - variation;
}
if (wrongAnswer !== correctAnswer && wrongAnswer > 0 && wrongAnswers.indexOf(wrongAnswer) === -1) {
wrongAnswers.push(wrongAnswer);
}
attempts++;
}
// Ensure we have exactly 3 wrong answers
while (wrongAnswers.length < 3) {
var fallbackWrong = correctAnswer + Math.floor(Math.random() * 20) - 10;
if (fallbackWrong !== correctAnswer && fallbackWrong > 0 && wrongAnswers.indexOf(fallbackWrong) === -1) {
wrongAnswers.push(fallbackWrong);
}
}
return {
question: question,
correctAnswer: correctAnswer,
wrongAnswers: wrongAnswers
};
}
function updateHeartsDisplay() {
var heartString = '';
for (var i = 0; i < hearts; i++) {
heartString += '❤️ ';
}
if (heartString === '') {
heartString = 'NO HEARTS LEFT';
}
heartsDisplay.setText(heartString);
}
function startTimer() {
timeLeft = 13;
timerText.setText('Time: ' + timeLeft);
timerText.tint = 0xff0000;
if (questionTimer) {
LK.clearInterval(questionTimer);
}
questionTimer = LK.setInterval(function () {
timeLeft--;
timerText.setText('Time: ' + timeLeft);
if (timeLeft <= 0) {
LK.clearInterval(questionTimer);
onTimeUp();
}
}, 1000);
}
function onTimeUp() {
if (!gameActive) {
return;
}
gameActive = false;
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 2000);
// Create failure message text
var failureText = new Text2("Time's up! You couldn't save the princess!", {
size: 70,
fill: 0x000000
});
failureText.anchor.set(0.5, 0.5);
failureText.x = 1024;
failureText.y = 1566;
game.addChild(failureText);
// Animate the text to fade in and out
failureText.alpha = 0;
tween(failureText, {
alpha: 1
}, {
duration: 700,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(failureText, {
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
failureText.destroy();
}
});
}, 1500);
}
});
LK.setTimeout(function () {
LK.showGameOver();
}, 3000);
}
function startNextQuestion() {
if (currentQuestion >= totalQuestions) {
if (questionTimer) {
LK.clearInterval(questionTimer);
}
completeLevel();
return;
}
currentProblem = mathProblems[currentQuestion];
// Update question text
questionText.setText(currentProblem.question);
progressText.setText('Question ' + (currentQuestion + 1) + ' of ' + totalQuestions);
// Create answer options
var answers = [currentProblem.correctAnswer].concat(currentProblem.wrongAnswers);
// Shuffle answers
for (var i = answers.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = answers[i];
answers[i] = answers[j];
answers[j] = temp;
}
// Set button texts and correct answer
for (var i = 0; i < 4; i++) {
answerButtons[i].children[1].setText(answers[i].toString());
answerButtons[i].isCorrect = answers[i] === currentProblem.correctAnswer;
answerButtons[i].resetStyle();
}
gameActive = true;
startTimer();
}
function onAnswerSelected(isCorrect) {
if (!gameActive) {
return;
}
gameActive = false;
if (questionTimer) {
LK.clearInterval(questionTimer);
}
// Show feedback on buttons
for (var i = 0; i < answerButtons.length; i++) {
if (answerButtons[i].isCorrect) {
answerButtons[i].setCorrectStyle();
} else {
answerButtons[i].setIncorrectStyle();
}
}
if (isCorrect) {
correctAnswers++;
LK.getSound('correct').play();
} else {
LK.getSound('incorrect').play();
if (!isInfinityMode) {
hearts--;
updateHeartsDisplay();
}
}
// Move character forward for correct answers, or backward in infinity mode for incorrect answers
var progress;
if (isInfinityMode && !isCorrect) {
// Move backward one step in infinity mode on incorrect answer
var backwardQuestion = Math.max(0, currentQuestion - 1);
progress = backwardQuestion / totalQuestions;
var targetX = startX + (endX - startX) * progress;
character.moveToPosition(targetX, backwardQuestion);
} else {
// Move forward normally
progress = (currentQuestion + 1) / totalQuestions;
var targetX = startX + (endX - startX) * progress;
character.moveToPosition(targetX, currentQuestion + 1);
}
// Check milestones
if (currentQuestion + 1 === 5 && guard1) {
LK.effects.flashScreen(0xffaa00, 800);
guard1.destroy(); //{4p_new}
guard1 = null; //{4p_new2}
}
if (currentQuestion + 1 === 10 && guard2) {
LK.effects.flashScreen(0xffaa00, 800);
guard2.destroy(); //{4r_new}
guard2 = null; //{4r_new2}
}
if (currentQuestion + 1 === 15 && princess) {
LK.effects.flashScreen(0xffff00, 800);
}
// Only award points for correct answers
if (isCorrect) {
LK.setScore(LK.getScore() + 10 * currentLevel);
}
// Wait before next question
LK.setTimeout(function () {
if (isInfinityMode) {
// In infinity mode, only increment question on correct answers
if (isCorrect) {
currentQuestion++;
}
// If incorrect, keep same question (currentQuestion stays the same)
} else {
// In other modes, always increment
currentQuestion++;
}
startNextQuestion();
}, 2000);
}
function completeLevel() {
// Check if player reached the finish (reached castle at question 15)
var reachedFinish = character.x >= princessX - 50;
if (reachedFinish) {
LK.getSound('victory').play();
// Change background to light blue for victory
game.setBackgroundColor(0xadd8e6);
// Flash screen with celebration color
LK.effects.flashScreen(0xffd700, 1500);
// Create princess image
var princessImage = game.addChild(LK.getAsset('princess', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200
}));
princessImage.alpha = 0;
// Create victory text
var victoryText = new Text2("YOU SAVED THE PRINCESS!", {
size: 90,
fill: 0x000000
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 1600;
victoryText.alpha = 0;
game.addChild(victoryText);
// Animate princess image and text to fade in
tween(princessImage, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
tween(victoryText, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
// Increment completion counter
completedLevels++;
storage.completedLevels = completedLevels;
// Update counter display
game.children.forEach(function (child) {
if (child.text && child.text.indexOf('Princesses Saved:') === 0) {
child.setText('Princesses Saved: ' + completedLevels);
}
});
// End game after 15th question
LK.setTimeout(function () {
// Fade out victory elements
tween(princessImage, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
princessImage.destroy();
}
});
tween(victoryText, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
victoryText.destroy();
}
});
// Wait a bit more before showing you win
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}, 3000);
} else {
// Player did not save the princess (either wrong answers or did not reach finish), show failure message
LK.effects.flashScreen(0xff0000, 2000);
// Create failure message text
var failureText = new Text2("You couldn't save the princess!", {
size: 80,
fill: 0x000000
});
failureText.anchor.set(0.5, 0.5);
failureText.x = 1024;
failureText.y = 1566;
game.addChild(failureText);
// Animate the text to fade in and out
failureText.alpha = 0;
tween(failureText, {
alpha: 1
}, {
duration: 700,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(failureText, {
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
failureText.destroy();
}
});
}, 1500);
}
});
LK.setTimeout(function () {
currentQuestion = 0;
correctAnswers = 0;
hearts = 3;
updateHeartsDisplay();
character.x = startX;
// Reset guards for retry
if (guard1) {
guard1.destroy();
}
if (guard2) {
guard2.destroy();
}
if (princess) {
princess.destroy();
}
guard1 = game.addChild(new PrincessGuard(1));
guard1.x = guard1X;
guard1.y = characterY;
guard2 = game.addChild(new PrincessGuard(2));
guard2.x = guard2X;
guard2.y = characterY;
princess = game.addChild(LK.getAsset('princess', {
anchorX: 0.5,
anchorY: 1.0,
x: princessX,
y: characterY
}));
generateMathProblems();
startNextQuestion();
}, 3000);
}
}
// Game state
var gameStarted = false;
// Start screen setup
function showStartScreen() {
// Create semi-transparent overlay
var overlay = game.addChild(LK.getAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.2,
scaleY: 1.2
}));
overlay.tint = 0x222222;
overlay.alpha = 0.8;
// Create title text
var titleText = new Text2("SAVE THE PRINCESS", {
size: 100,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
game.addChild(titleText);
// Create subtitle text
var subtitleText = new Text2("Answer math questions correctly to save the princess!", {
size: 60,
fill: 0xffff00
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 1000;
game.addChild(subtitleText);
// Create start button
var startButton = game.addChild(LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1400
}));
// Create button text with play icon
var buttonText = new Text2("", {
size: 120,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
startButton.addChild(buttonText);
// Handle button click
startButton.down = function (x, y, obj) {
// Remove start screen elements
overlay.destroy();
titleText.destroy();
subtitleText.destroy();
startButton.destroy();
// Show difficulty selector
showDifficultyScreen();
};
}
// Show difficulty selection screen
function showDifficultyScreen() {
var difficultySelector = game.addChild(new DifficultySelector(function (selectedLevel) {
currentLevel = selectedLevel;
isInfinityMode = selectedLevel === 4;
// Remove difficulty selector
difficultySelector.destroy();
// Start game
gameStarted = true;
LK.playMusic('game-song1');
initializeGame();
}));
// Position difficulty selector in center
difficultySelector.x = 1024;
difficultySelector.y = 1366;
}
// Show start screen instead of directly initializing
showStartScreen();
game.update = function () {
// Game update logic if needed
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AnswerButton = Container.expand(function (answerText, isCorrect, onAnswerSelected) {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('answerButton', {
anchorX: 0.5,
anchorY: 0.5
});
var buttonText = new Text2(answerText, {
size: 60,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.isCorrect = isCorrect;
self.onAnswerSelected = onAnswerSelected;
self.down = function (x, y, obj) {
self.onAnswerSelected(self.isCorrect);
};
self.setCorrectStyle = function () {
buttonGraphics.tint = 0x00ff00;
};
self.setIncorrectStyle = function () {
buttonGraphics.tint = 0xff0000;
};
self.resetStyle = function () {
buttonGraphics.tint = 0xffffff;
};
return self;
});
var Castle = Container.expand(function () {
var self = Container.call(this);
var castleGraphics = self.attachAsset('castle', {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 1.0
});
self.moveToPosition = function (targetX, questionNumber) {
var duration = 1000;
if (questionNumber === 5 || questionNumber === 10 || questionNumber === 15) {
duration = 2500;
}
tween(self, {
x: targetX
}, {
duration: duration,
easing: tween.easeInOut
});
};
return self;
});
var DifficultySelector = Container.expand(function (onDifficultySelected) {
var self = Container.call(this);
// Create semi-transparent overlay
var overlay = self.attachAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
overlay.x = 0;
overlay.y = 0;
// Create title text
var titleText = new Text2("SELECT DIFFICULTY", {
size: 100,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -400;
self.addChild(titleText);
// Create difficulty buttons
var difficulties = [{
name: 'EASY',
level: 1,
color: 0x00ff00
}, {
name: 'MEDIUM',
level: 2,
color: 0xffff00
}, {
name: 'HARD',
level: 3,
color: 0xff0000
}, {
name: 'INFINITY',
level: 4,
color: 0x9900ff
}];
var buttonPositions = [{
x: -500,
y: 100
}, {
x: 0,
y: 100
}, {
x: 500,
y: 100
}, {
x: 0,
y: 300
}];
for (var i = 0; i < difficulties.length; i++) {
var difficulty = difficulties[i];
var buttonContainer = new Container();
buttonContainer.x = buttonPositions[i].x;
buttonContainer.y = buttonPositions[i].y;
var assetId = difficulty.name.toLowerCase() + 'Button';
var buttonGraphics = buttonContainer.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
buttonGraphics.tint = difficulty.color;
var buttonText = new Text2(difficulty.name, {
size: 60,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
buttonContainer.addChild(buttonText);
buttonContainer.difficulty = difficulty;
buttonContainer.down = function (x, y, obj) {
onDifficultySelected(this.difficulty.level);
};
self.addChild(buttonContainer);
}
return self;
});
var PrincessGuard = Container.expand(function (guardNumber) {
var self = Container.call(this);
var guardAsset = guardNumber === 1 ? 'guard1' : 'guard2';
var guardGraphics = self.attachAsset(guardAsset, {
anchorX: 0.5,
anchorY: 1.0
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var currentLevel = storage.currentLevel || 1;
var completedLevels = storage.completedLevels || 0;
var currentQuestion = 0;
var totalQuestions = 15;
var correctAnswers = 0;
var gameActive = false;
var questionTimer = null;
var timeLeft = 10;
var timerText = null;
var hearts = 3;
var heartsDisplay = null;
var isInfinityMode = false;
// Math problem generation
var mathProblems = [];
var currentProblem = null;
// Game objects
var character = null;
var castle = null;
var ground = null;
var path = null;
var questionPanel = null;
var questionText = null;
var progressText = null;
var answerButtons = [];
// Positions
var startX = 200;
var endX = 1800;
var characterY = 2400;
var pathY = 2450;
var guard1 = null;
var guard2 = null;
var princess = null;
var guard1X = startX + (endX - startX) * (5 / 15);
var guard2X = startX + (endX - startX) * (10 / 15);
var princessX = endX;
// Initialize game elements
function initializeGame() {
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2470
}));
// Create path
path = game.addChild(LK.getAsset('path', {
anchorX: 0,
anchorY: 0.5,
x: 124,
y: pathY
}));
// Create character
character = game.addChild(new Character());
character.x = startX;
character.y = characterY;
// Create castle
castle = game.addChild(new Castle());
castle.x = endX;
castle.y = characterY;
// Create guard 1
guard1 = game.addChild(new PrincessGuard(1));
guard1.x = guard1X;
guard1.y = characterY;
// Create guard 2
guard2 = game.addChild(new PrincessGuard(2));
guard2.x = guard2X;
guard2.y = characterY;
// Create princess at the end
// Create question panel
questionPanel = game.addChild(LK.getAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1000
}));
questionPanel.alpha = 0.9;
// Create question text
questionText = new Text2('', {
size: 80,
fill: 0x000000
});
questionText.anchor.set(0.5, 0.5);
questionText.x = 1024;
questionText.y = 880;
game.addChild(questionText);
// Create progress text
progressText = new Text2('', {
size: 60,
fill: 0x2b2b2b
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 1024;
progressText.y = 700;
game.addChild(progressText);
// Create timer text
timerText = new Text2('Time: 10', {
size: 70,
fill: 0xff0000
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 1024;
timerText.y = 550;
game.addChild(timerText);
// Create completion counter text
var completionCounterText = new Text2('Princesses Saved: ' + completedLevels, {
size: 50,
fill: 0x000000
});
completionCounterText.anchor.set(0.5, 0.0);
completionCounterText.x = 1024;
completionCounterText.y = 50;
game.addChild(completionCounterText);
// Create hearts display
heartsDisplay = new Text2('❤️ ❤️ ❤️', {
size: 80,
fill: 0xff0000
});
heartsDisplay.anchor.set(0.5, 0.0);
heartsDisplay.x = 1024;
heartsDisplay.y = 120;
if (!isInfinityMode) {
game.addChild(heartsDisplay);
}
// Create answer buttons
var buttonPositions = [{
x: 512,
y: 1100
}, {
x: 1536,
y: 1100
}, {
x: 512,
y: 1300
}, {
x: 1536,
y: 1300
}];
for (var i = 0; i < 4; i++) {
var button = new AnswerButton('', false, onAnswerSelected);
button.x = buttonPositions[i].x;
button.y = buttonPositions[i].y;
answerButtons.push(button);
game.addChild(button);
}
// Create music toggle icon in top right corner
var musicIcon = new Text2('🎵', {
size: 80,
fill: 0x000000
});
musicIcon.anchor.set(1.0, 0.0);
musicIcon.x = 1948; // 100px from right edge (2048 - 100)
musicIcon.y = 100;
LK.gui.addChild(musicIcon);
// Add click handler to stop music
musicIcon.down = function (x, y, obj) {
LK.stopMusic();
};
generateMathProblems();
startNextQuestion();
}
function generateMathProblems() {
mathProblems = [];
for (var i = 0; i < totalQuestions; i++) {
var problem = generateMathProblem(currentLevel);
mathProblems.push(problem);
}
}
function generateMathProblem(level) {
var num1, num2, operation, correctAnswer, question;
if (level === 1) {
// Easy: Addition and subtraction only, up to 15
num1 = Math.floor(Math.random() * 15) + 1;
num2 = Math.floor(Math.random() * 15) + 1;
operation = Math.random() < 0.5 ? '+' : '-';
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
} else if (level === 2) {
// Medium: Addition and subtraction with low numbers up to 50
var ops = ['+', '-'];
operation = ops[Math.floor(Math.random() * ops.length)];
num1 = Math.floor(Math.random() * 50) + 1;
num2 = Math.floor(Math.random() * 50) + 1;
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
} else {
// Hard: All operations with larger numbers
var ops = ['+', '-', '*', '/'];
operation = ops[Math.floor(Math.random() * ops.length)];
if (operation === '/') {
correctAnswer = Math.floor(Math.random() * 20) + 1;
num2 = Math.floor(Math.random() * 12) + 1;
num1 = correctAnswer * num2;
question = num1 + ' ÷ ' + num2 + ' = ?';
} else if (operation === '*') {
num1 = Math.floor(Math.random() * 25) + 1;
num2 = Math.floor(Math.random() * 25) + 1;
correctAnswer = num1 * num2;
question = num1 + ' × ' + num2 + ' = ?';
} else {
num1 = Math.floor(Math.random() * 100) + 1;
num2 = Math.floor(Math.random() * 100) + 1;
if (operation === '+') {
correctAnswer = num1 + num2;
question = num1 + ' + ' + num2 + ' = ?';
} else {
if (num1 < num2) {
var temp = num1;
num1 = num2;
num2 = temp;
}
correctAnswer = num1 - num2;
question = num1 + ' - ' + num2 + ' = ?';
}
}
}
// Generate wrong answers
var wrongAnswers = [];
var attempts = 0;
while (wrongAnswers.length < 3 && attempts < 20) {
var wrongAnswer;
var variation = Math.floor(Math.random() * 10) + 1;
if (Math.random() < 0.5) {
wrongAnswer = correctAnswer + variation;
} else {
wrongAnswer = correctAnswer - variation;
}
if (wrongAnswer !== correctAnswer && wrongAnswer > 0 && wrongAnswers.indexOf(wrongAnswer) === -1) {
wrongAnswers.push(wrongAnswer);
}
attempts++;
}
// Ensure we have exactly 3 wrong answers
while (wrongAnswers.length < 3) {
var fallbackWrong = correctAnswer + Math.floor(Math.random() * 20) - 10;
if (fallbackWrong !== correctAnswer && fallbackWrong > 0 && wrongAnswers.indexOf(fallbackWrong) === -1) {
wrongAnswers.push(fallbackWrong);
}
}
return {
question: question,
correctAnswer: correctAnswer,
wrongAnswers: wrongAnswers
};
}
function updateHeartsDisplay() {
var heartString = '';
for (var i = 0; i < hearts; i++) {
heartString += '❤️ ';
}
if (heartString === '') {
heartString = 'NO HEARTS LEFT';
}
heartsDisplay.setText(heartString);
}
function startTimer() {
timeLeft = 13;
timerText.setText('Time: ' + timeLeft);
timerText.tint = 0xff0000;
if (questionTimer) {
LK.clearInterval(questionTimer);
}
questionTimer = LK.setInterval(function () {
timeLeft--;
timerText.setText('Time: ' + timeLeft);
if (timeLeft <= 0) {
LK.clearInterval(questionTimer);
onTimeUp();
}
}, 1000);
}
function onTimeUp() {
if (!gameActive) {
return;
}
gameActive = false;
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 2000);
// Create failure message text
var failureText = new Text2("Time's up! You couldn't save the princess!", {
size: 70,
fill: 0x000000
});
failureText.anchor.set(0.5, 0.5);
failureText.x = 1024;
failureText.y = 1566;
game.addChild(failureText);
// Animate the text to fade in and out
failureText.alpha = 0;
tween(failureText, {
alpha: 1
}, {
duration: 700,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(failureText, {
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
failureText.destroy();
}
});
}, 1500);
}
});
LK.setTimeout(function () {
LK.showGameOver();
}, 3000);
}
function startNextQuestion() {
if (currentQuestion >= totalQuestions) {
if (questionTimer) {
LK.clearInterval(questionTimer);
}
completeLevel();
return;
}
currentProblem = mathProblems[currentQuestion];
// Update question text
questionText.setText(currentProblem.question);
progressText.setText('Question ' + (currentQuestion + 1) + ' of ' + totalQuestions);
// Create answer options
var answers = [currentProblem.correctAnswer].concat(currentProblem.wrongAnswers);
// Shuffle answers
for (var i = answers.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = answers[i];
answers[i] = answers[j];
answers[j] = temp;
}
// Set button texts and correct answer
for (var i = 0; i < 4; i++) {
answerButtons[i].children[1].setText(answers[i].toString());
answerButtons[i].isCorrect = answers[i] === currentProblem.correctAnswer;
answerButtons[i].resetStyle();
}
gameActive = true;
startTimer();
}
function onAnswerSelected(isCorrect) {
if (!gameActive) {
return;
}
gameActive = false;
if (questionTimer) {
LK.clearInterval(questionTimer);
}
// Show feedback on buttons
for (var i = 0; i < answerButtons.length; i++) {
if (answerButtons[i].isCorrect) {
answerButtons[i].setCorrectStyle();
} else {
answerButtons[i].setIncorrectStyle();
}
}
if (isCorrect) {
correctAnswers++;
LK.getSound('correct').play();
} else {
LK.getSound('incorrect').play();
if (!isInfinityMode) {
hearts--;
updateHeartsDisplay();
}
}
// Move character forward for correct answers, or backward in infinity mode for incorrect answers
var progress;
if (isInfinityMode && !isCorrect) {
// Move backward one step in infinity mode on incorrect answer
var backwardQuestion = Math.max(0, currentQuestion - 1);
progress = backwardQuestion / totalQuestions;
var targetX = startX + (endX - startX) * progress;
character.moveToPosition(targetX, backwardQuestion);
} else {
// Move forward normally
progress = (currentQuestion + 1) / totalQuestions;
var targetX = startX + (endX - startX) * progress;
character.moveToPosition(targetX, currentQuestion + 1);
}
// Check milestones
if (currentQuestion + 1 === 5 && guard1) {
LK.effects.flashScreen(0xffaa00, 800);
guard1.destroy(); //{4p_new}
guard1 = null; //{4p_new2}
}
if (currentQuestion + 1 === 10 && guard2) {
LK.effects.flashScreen(0xffaa00, 800);
guard2.destroy(); //{4r_new}
guard2 = null; //{4r_new2}
}
if (currentQuestion + 1 === 15 && princess) {
LK.effects.flashScreen(0xffff00, 800);
}
// Only award points for correct answers
if (isCorrect) {
LK.setScore(LK.getScore() + 10 * currentLevel);
}
// Wait before next question
LK.setTimeout(function () {
if (isInfinityMode) {
// In infinity mode, only increment question on correct answers
if (isCorrect) {
currentQuestion++;
}
// If incorrect, keep same question (currentQuestion stays the same)
} else {
// In other modes, always increment
currentQuestion++;
}
startNextQuestion();
}, 2000);
}
function completeLevel() {
// Check if player reached the finish (reached castle at question 15)
var reachedFinish = character.x >= princessX - 50;
if (reachedFinish) {
LK.getSound('victory').play();
// Change background to light blue for victory
game.setBackgroundColor(0xadd8e6);
// Flash screen with celebration color
LK.effects.flashScreen(0xffd700, 1500);
// Create princess image
var princessImage = game.addChild(LK.getAsset('princess', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200
}));
princessImage.alpha = 0;
// Create victory text
var victoryText = new Text2("YOU SAVED THE PRINCESS!", {
size: 90,
fill: 0x000000
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 1024;
victoryText.y = 1600;
victoryText.alpha = 0;
game.addChild(victoryText);
// Animate princess image and text to fade in
tween(princessImage, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
tween(victoryText, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn
});
// Increment completion counter
completedLevels++;
storage.completedLevels = completedLevels;
// Update counter display
game.children.forEach(function (child) {
if (child.text && child.text.indexOf('Princesses Saved:') === 0) {
child.setText('Princesses Saved: ' + completedLevels);
}
});
// End game after 15th question
LK.setTimeout(function () {
// Fade out victory elements
tween(princessImage, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
princessImage.destroy();
}
});
tween(victoryText, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
victoryText.destroy();
}
});
// Wait a bit more before showing you win
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}, 3000);
} else {
// Player did not save the princess (either wrong answers or did not reach finish), show failure message
LK.effects.flashScreen(0xff0000, 2000);
// Create failure message text
var failureText = new Text2("You couldn't save the princess!", {
size: 80,
fill: 0x000000
});
failureText.anchor.set(0.5, 0.5);
failureText.x = 1024;
failureText.y = 1566;
game.addChild(failureText);
// Animate the text to fade in and out
failureText.alpha = 0;
tween(failureText, {
alpha: 1
}, {
duration: 700,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(failureText, {
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
failureText.destroy();
}
});
}, 1500);
}
});
LK.setTimeout(function () {
currentQuestion = 0;
correctAnswers = 0;
hearts = 3;
updateHeartsDisplay();
character.x = startX;
// Reset guards for retry
if (guard1) {
guard1.destroy();
}
if (guard2) {
guard2.destroy();
}
if (princess) {
princess.destroy();
}
guard1 = game.addChild(new PrincessGuard(1));
guard1.x = guard1X;
guard1.y = characterY;
guard2 = game.addChild(new PrincessGuard(2));
guard2.x = guard2X;
guard2.y = characterY;
princess = game.addChild(LK.getAsset('princess', {
anchorX: 0.5,
anchorY: 1.0,
x: princessX,
y: characterY
}));
generateMathProblems();
startNextQuestion();
}, 3000);
}
}
// Game state
var gameStarted = false;
// Start screen setup
function showStartScreen() {
// Create semi-transparent overlay
var overlay = game.addChild(LK.getAsset('questionPanel', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
scaleX: 1.2,
scaleY: 1.2
}));
overlay.tint = 0x222222;
overlay.alpha = 0.8;
// Create title text
var titleText = new Text2("SAVE THE PRINCESS", {
size: 100,
fill: 0xffffff
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
game.addChild(titleText);
// Create subtitle text
var subtitleText = new Text2("Answer math questions correctly to save the princess!", {
size: 60,
fill: 0xffff00
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 1000;
game.addChild(subtitleText);
// Create start button
var startButton = game.addChild(LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1400
}));
// Create button text with play icon
var buttonText = new Text2("", {
size: 120,
fill: 0x000000
});
buttonText.anchor.set(0.5, 0.5);
startButton.addChild(buttonText);
// Handle button click
startButton.down = function (x, y, obj) {
// Remove start screen elements
overlay.destroy();
titleText.destroy();
subtitleText.destroy();
startButton.destroy();
// Show difficulty selector
showDifficultyScreen();
};
}
// Show difficulty selection screen
function showDifficultyScreen() {
var difficultySelector = game.addChild(new DifficultySelector(function (selectedLevel) {
currentLevel = selectedLevel;
isInfinityMode = selectedLevel === 4;
// Remove difficulty selector
difficultySelector.destroy();
// Start game
gameStarted = true;
LK.playMusic('game-song1');
initializeGame();
}));
// Position difficulty selector in center
difficultySelector.x = 1024;
difficultySelector.y = 1366;
}
// Show start screen instead of directly initializing
showStartScreen();
game.update = function () {
// Game update logic if needed
};
knight warrior. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
add a princess at the middle top of the castle
stone road. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Princess . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
start button . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
rectangle red color. In-Game asset. 2d. High contrast. No shadows. rectangle red
rectangle purple color . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
rectangle orange color no background. In-Game asset. 2d. High contrast. No shadows. ractangle