/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Answer Button Class var AnswerButton = Container.expand(function () { var self = Container.call(this); // Attach default button asset var btn = self.attachAsset('answerBtn', { anchorX: 0.5, anchorY: 0.5 }); // Answer text self.txt = self.addChild(new Text2('', { size: 120, fill: 0xFFFFFF })); self.txt.anchor.set(0.5, 0.5); // Value this button represents self.value = null; // State: 'default', 'correct', 'wrong' self.state = 'default'; // Set answer value and text self.setValue = function (val) { self.value = val; self.txt.setText(val + ''); }; // Set state for visual feedback self.setState = function (state) { self.state = state; if (state === 'default') { btn.assetId = 'answerBtn'; btn.setAsset('answerBtn'); } else if (state === 'correct') { btn.assetId = 'answerBtnCorrect'; btn.setAsset('answerBtnCorrect'); } else if (state === 'wrong') { btn.assetId = 'answerBtnWrong'; btn.setAsset('answerBtnWrong'); } }; // Reset to default state self.reset = function () { self.setState('default'); }; // Touch event handler self.down = function (x, y, obj) { if (typeof self.onSelect === 'function') { self.onSelect(self.value, self); } }; return self; }); // Question Box Class var QuestionBox = Container.expand(function () { var self = Container.call(this); var box = self.attachAsset('questionBox', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 // slightly translucent to show the colorful background }); self.txt = self.addChild(new Text2('', { size: 150, fill: "#fff", font: "Comic Sans MS, 'Chalkboard', 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Chalk-like font })); self.txt.anchor.set(0.5, 0.5); self.setQuestion = function (q) { self.txt.setText(q); }; return self; }); // Timer Bar Class var TimerBar = Container.expand(function () { var self = Container.call(this); // The bar background var bar = self.attachAsset('timerBar', { anchorX: 0.5, anchorY: 0.5 }); // The fill bar (will be scaled) self.fill = self.attachAsset('timerBar', { anchorX: 0.5, anchorY: 0.5 }); self.fill.tint = 0x50E3C2; self.fill.y = 0; self.fill.x = 0; // Set progress (0 to 1) self.setProgress = function (p) { if (p < 0) p = 0; if (p > 1) p = 1; self.fill.scaleX = p; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ // No title, no description // Always backgroundColor is black backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables // Math Dash: Quick Solve uses simple shapes for answer buttons and question area. // Colors are chosen for visual clarity and engagement. var score = 0; var question = null; var correctAnswer = null; var answerChoices = []; var answerButtons = []; var questionBox = null; var timerBar = null; var timer = null; var timePerQuestion = 3500; // ms, will decrease as difficulty increases var timeLeft = 0; var questionStartTime = 0; var scoreTxt = null; var gameActive = true; var difficultyLevel = 1; // Increases as player scores // Layout positions var centerX = 2048 / 2; var questionY = 500; var answersStartY = 1100; var answerSpacing = 300; // Add a lively image background (full screen, behind everything) var livelyBg = LK.getAsset('livelyBgImage', { anchorX: 0.5, anchorY: 0, width: 2048, height: 2732 }); livelyBg.x = centerX; livelyBg.y = 0; game.addChild(livelyBg); // Create and add question box (visually on the board) questionBox = new QuestionBox(); questionBox.x = centerX; questionBox.y = questionY + 40; game.addChild(questionBox); // Create and add timer bar (below the board) timerBar = new TimerBar(); timerBar.x = centerX; timerBar.y = questionY + 180 + 40; game.addChild(timerBar); // Add a numeric countdown timer in the top-right corner (not in top left 100x100) var timerTxt = new Text2('', { size: 90, fill: "#fff" }); timerTxt.anchor.set(1, 0); // right-top // Place at top-right, leaving a margin from the edge and out of the top-left 100x100 area timerTxt.x = 2048 - 60; timerTxt.y = 40; LK.gui.top.addChild(timerTxt); // Create answer buttons (4 choices) for (var i = 0; i < 4; i++) { var btn = new AnswerButton(); btn.x = centerX; btn.y = answersStartY + i * answerSpacing; btn.idx = i; btn.onSelect = handleAnswer; answerButtons.push(btn); game.addChild(btn); } // Score text (top center, not in top left 100x100) scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Generate a new math question function generateQuestion() { // Increase difficulty every 10 questions difficultyLevel = 1 + Math.floor(score / 10); // Make number ranges and distractors harder as difficulty increases var ops, op, min, max; if (score >= 10) { // After 10 questions, make numbers even larger and allow more complex distractors ops = ['+', '-', '×', '÷']; op = ops[randInt(0, ops.length - 1)]; min = 10 + difficultyLevel * 2; max = 40 + difficultyLevel * 12; } else { // Stage 1: simpler questions, only + and -, smaller numbers ops = ['+', '-']; op = ops[randInt(0, ops.length - 1)]; min = 1; max = 10 + difficultyLevel * 4; // smaller range for easier questions } var a, b, q, ans; if (op === '+') { a = randInt(min, max); b = randInt(min, max); ans = a + b; q = a + " + " + b + " = ?"; } else if (op === '-') { a = randInt(min, max); b = randInt(min, a); // ensure non-negative ans = a - b; q = a + " - " + b + " = ?"; } else if (op === '×') { a = randInt(min, max - 5); b = randInt(2, 20 + Math.floor(difficultyLevel)); // allow larger multipliers after 10 questions ans = a * b; q = a + " × " + b + " = ?"; } else if (op === '÷') { b = randInt(2, 20 + Math.floor(difficultyLevel)); ans = randInt(min, max - 5); a = ans * b; q = a + " ÷ " + b + " = ?"; } correctAnswer = ans; question = q; // Generate 3 wrong answers, some close, some far, some with swapped digits for more challenge var wrongs = []; while (wrongs.length < 3) { var delta; var wrong; if (score >= 10) { // After 10 questions, make distractors more challenging if (wrongs.length === 0) { // close distractor, but allow negative and larger deltas delta = randInt(2, 7 + Math.floor(difficultyLevel)); wrong = ans + (Math.random() > 0.5 ? delta : -delta); } else if (wrongs.length === 1) { // far distractor, even further delta = randInt(10 + difficultyLevel, 30 + difficultyLevel * 2); wrong = ans + (Math.random() > 0.5 ? delta : -delta); } else { // digit swap, off-by-two, or reversed number wrong = ans; if (ans > 9 && Math.random() > 0.33) { var s = ans.toString().split(''); if (Math.random() > 0.5 && s.length > 2) { // reverse digits s = s.reverse(); wrong = parseInt(s.join('')); } else { // swap two random digits var i = randInt(0, s.length - 2); var tmp = s[i]; s[i] = s[i + 1]; s[i + 1] = tmp; wrong = parseInt(s.join('')); } } else { wrong = ans + (Math.random() > 0.5 ? 2 : -2); } } } else { if (wrongs.length === 0) { // close distractor delta = randInt(1, 3 + Math.floor(difficultyLevel / 2)); wrong = ans + (Math.random() > 0.5 ? delta : -delta); } else if (wrongs.length === 1) { // far distractor delta = randInt(5 + difficultyLevel, 15 + difficultyLevel * 2); wrong = ans + (Math.random() > 0.5 ? delta : -delta); } else { // digit swap or off-by-one error wrong = ans; if (ans > 9 && Math.random() > 0.5) { var s = ans.toString().split(''); var i = randInt(0, s.length - 2); var tmp = s[i]; s[i] = s[i + 1]; s[i + 1] = tmp; wrong = parseInt(s.join('')); } else { wrong = ans + (Math.random() > 0.5 ? 1 : -1); } } } if (wrong !== ans && wrong >= 0 && wrongs.indexOf(wrong) === -1) { wrongs.push(wrong); } } // Shuffle answers answerChoices = wrongs.concat([ans]); shuffleArray(answerChoices); // Set question and answers questionBox.setQuestion(question); for (var i = 0; i < 4; i++) { answerButtons[i].setValue(answerChoices[i]); answerButtons[i].reset(); } } // Handle answer selection function handleAnswer(val, btn) { if (!gameActive) return; if (val === correctAnswer) { btn.setState('correct'); LK.getSound('correct').play(); score += 1; LK.setScore(score); scoreTxt.setText(score + ''); // Animate button tween(btn, { scaleX: 1.15, scaleY: 1.15 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(btn, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } }); // Check win condition: 10 correct answers if (score >= 10) { gameActive = false; LK.effects.flashScreen(0x7ed321, 800); LK.setTimeout(function () { LK.showYouWin(); }, 600); } else { // Next question after short delay LK.setTimeout(nextQuestion, 350); } } else { btn.setState('wrong'); LK.getSound('wrong').play(); // Decrease score by 1, but not below zero score = Math.max(0, score - 1); LK.setScore(score); scoreTxt.setText(score + ''); // Flash wrong, then game over tween(btn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 120, onFinish: function onFinish() { tween(btn, { scaleX: 1, scaleY: 1 }, { duration: 120 }); } }); endGame(); } } // Start next question function nextQuestion() { if (!gameActive) return; // Increase speed as score increases if (score >= 10) { // After 10 questions, shorten by 1 second (1000ms) timePerQuestion = Math.max(1200, 2500 - (score - 10) * 80); } else { timePerQuestion = Math.max(1200, 3500 - score * 80); } timeLeft = timePerQuestion; questionStartTime = Date.now(); generateQuestion(); } // End game function endGame() { if (!gameActive) return; gameActive = false; // Flash screen red LK.effects.flashScreen(0xD0021B, 800); // Show game over (handled by LK) LK.setTimeout(function () { LK.showGameOver(); }, 600); } // Utility: random integer [min, max] function randInt(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } // Utility: shuffle array in-place function shuffleArray(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = randInt(0, i); var t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } // Game update loop game.update = function () { if (!gameActive) return; // Update timer var now = Date.now(); timeLeft = timePerQuestion - (now - questionStartTime); var progress = timeLeft / timePerQuestion; timerBar.setProgress(progress); // Update numeric timer to show time left (countdown) in seconds, min 0 if (typeof timerTxt !== 'undefined') { var left = Math.max(0, timeLeft); var secs = Math.round(left / 100) / 10; timerTxt.setText(secs.toFixed(1) + 's'); } // If time runs out if (timeLeft <= 0) { // Flash all buttons red for (var i = 0; i < 4; i++) { answerButtons[i].setState('wrong'); } endGame(); } }; // Start first question function startGame() { score = 0; LK.setScore(0); scoreTxt.setText('0'); gameActive = true; difficultyLevel = 1; nextQuestion(); } // On game reset, start again startGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Answer Button Class
var AnswerButton = Container.expand(function () {
var self = Container.call(this);
// Attach default button asset
var btn = self.attachAsset('answerBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Answer text
self.txt = self.addChild(new Text2('', {
size: 120,
fill: 0xFFFFFF
}));
self.txt.anchor.set(0.5, 0.5);
// Value this button represents
self.value = null;
// State: 'default', 'correct', 'wrong'
self.state = 'default';
// Set answer value and text
self.setValue = function (val) {
self.value = val;
self.txt.setText(val + '');
};
// Set state for visual feedback
self.setState = function (state) {
self.state = state;
if (state === 'default') {
btn.assetId = 'answerBtn';
btn.setAsset('answerBtn');
} else if (state === 'correct') {
btn.assetId = 'answerBtnCorrect';
btn.setAsset('answerBtnCorrect');
} else if (state === 'wrong') {
btn.assetId = 'answerBtnWrong';
btn.setAsset('answerBtnWrong');
}
};
// Reset to default state
self.reset = function () {
self.setState('default');
};
// Touch event handler
self.down = function (x, y, obj) {
if (typeof self.onSelect === 'function') {
self.onSelect(self.value, self);
}
};
return self;
});
// Question Box Class
var QuestionBox = Container.expand(function () {
var self = Container.call(this);
var box = self.attachAsset('questionBox', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7 // slightly translucent to show the colorful background
});
self.txt = self.addChild(new Text2('', {
size: 150,
fill: "#fff",
font: "Comic Sans MS, 'Chalkboard', 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Chalk-like font
}));
self.txt.anchor.set(0.5, 0.5);
self.setQuestion = function (q) {
self.txt.setText(q);
};
return self;
});
// Timer Bar Class
var TimerBar = Container.expand(function () {
var self = Container.call(this);
// The bar background
var bar = self.attachAsset('timerBar', {
anchorX: 0.5,
anchorY: 0.5
});
// The fill bar (will be scaled)
self.fill = self.attachAsset('timerBar', {
anchorX: 0.5,
anchorY: 0.5
});
self.fill.tint = 0x50E3C2;
self.fill.y = 0;
self.fill.x = 0;
// Set progress (0 to 1)
self.setProgress = function (p) {
if (p < 0) p = 0;
if (p > 1) p = 1;
self.fill.scaleX = p;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Always backgroundColor is black
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
// Math Dash: Quick Solve uses simple shapes for answer buttons and question area.
// Colors are chosen for visual clarity and engagement.
var score = 0;
var question = null;
var correctAnswer = null;
var answerChoices = [];
var answerButtons = [];
var questionBox = null;
var timerBar = null;
var timer = null;
var timePerQuestion = 3500; // ms, will decrease as difficulty increases
var timeLeft = 0;
var questionStartTime = 0;
var scoreTxt = null;
var gameActive = true;
var difficultyLevel = 1; // Increases as player scores
// Layout positions
var centerX = 2048 / 2;
var questionY = 500;
var answersStartY = 1100;
var answerSpacing = 300;
// Add a lively image background (full screen, behind everything)
var livelyBg = LK.getAsset('livelyBgImage', {
anchorX: 0.5,
anchorY: 0,
width: 2048,
height: 2732
});
livelyBg.x = centerX;
livelyBg.y = 0;
game.addChild(livelyBg);
// Create and add question box (visually on the board)
questionBox = new QuestionBox();
questionBox.x = centerX;
questionBox.y = questionY + 40;
game.addChild(questionBox);
// Create and add timer bar (below the board)
timerBar = new TimerBar();
timerBar.x = centerX;
timerBar.y = questionY + 180 + 40;
game.addChild(timerBar);
// Add a numeric countdown timer in the top-right corner (not in top left 100x100)
var timerTxt = new Text2('', {
size: 90,
fill: "#fff"
});
timerTxt.anchor.set(1, 0); // right-top
// Place at top-right, leaving a margin from the edge and out of the top-left 100x100 area
timerTxt.x = 2048 - 60;
timerTxt.y = 40;
LK.gui.top.addChild(timerTxt);
// Create answer buttons (4 choices)
for (var i = 0; i < 4; i++) {
var btn = new AnswerButton();
btn.x = centerX;
btn.y = answersStartY + i * answerSpacing;
btn.idx = i;
btn.onSelect = handleAnswer;
answerButtons.push(btn);
game.addChild(btn);
}
// Score text (top center, not in top left 100x100)
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Generate a new math question
function generateQuestion() {
// Increase difficulty every 10 questions
difficultyLevel = 1 + Math.floor(score / 10);
// Make number ranges and distractors harder as difficulty increases
var ops, op, min, max;
if (score >= 10) {
// After 10 questions, make numbers even larger and allow more complex distractors
ops = ['+', '-', '×', '÷'];
op = ops[randInt(0, ops.length - 1)];
min = 10 + difficultyLevel * 2;
max = 40 + difficultyLevel * 12;
} else {
// Stage 1: simpler questions, only + and -, smaller numbers
ops = ['+', '-'];
op = ops[randInt(0, ops.length - 1)];
min = 1;
max = 10 + difficultyLevel * 4; // smaller range for easier questions
}
var a, b, q, ans;
if (op === '+') {
a = randInt(min, max);
b = randInt(min, max);
ans = a + b;
q = a + " + " + b + " = ?";
} else if (op === '-') {
a = randInt(min, max);
b = randInt(min, a); // ensure non-negative
ans = a - b;
q = a + " - " + b + " = ?";
} else if (op === '×') {
a = randInt(min, max - 5);
b = randInt(2, 20 + Math.floor(difficultyLevel)); // allow larger multipliers after 10 questions
ans = a * b;
q = a + " × " + b + " = ?";
} else if (op === '÷') {
b = randInt(2, 20 + Math.floor(difficultyLevel));
ans = randInt(min, max - 5);
a = ans * b;
q = a + " ÷ " + b + " = ?";
}
correctAnswer = ans;
question = q;
// Generate 3 wrong answers, some close, some far, some with swapped digits for more challenge
var wrongs = [];
while (wrongs.length < 3) {
var delta;
var wrong;
if (score >= 10) {
// After 10 questions, make distractors more challenging
if (wrongs.length === 0) {
// close distractor, but allow negative and larger deltas
delta = randInt(2, 7 + Math.floor(difficultyLevel));
wrong = ans + (Math.random() > 0.5 ? delta : -delta);
} else if (wrongs.length === 1) {
// far distractor, even further
delta = randInt(10 + difficultyLevel, 30 + difficultyLevel * 2);
wrong = ans + (Math.random() > 0.5 ? delta : -delta);
} else {
// digit swap, off-by-two, or reversed number
wrong = ans;
if (ans > 9 && Math.random() > 0.33) {
var s = ans.toString().split('');
if (Math.random() > 0.5 && s.length > 2) {
// reverse digits
s = s.reverse();
wrong = parseInt(s.join(''));
} else {
// swap two random digits
var i = randInt(0, s.length - 2);
var tmp = s[i];
s[i] = s[i + 1];
s[i + 1] = tmp;
wrong = parseInt(s.join(''));
}
} else {
wrong = ans + (Math.random() > 0.5 ? 2 : -2);
}
}
} else {
if (wrongs.length === 0) {
// close distractor
delta = randInt(1, 3 + Math.floor(difficultyLevel / 2));
wrong = ans + (Math.random() > 0.5 ? delta : -delta);
} else if (wrongs.length === 1) {
// far distractor
delta = randInt(5 + difficultyLevel, 15 + difficultyLevel * 2);
wrong = ans + (Math.random() > 0.5 ? delta : -delta);
} else {
// digit swap or off-by-one error
wrong = ans;
if (ans > 9 && Math.random() > 0.5) {
var s = ans.toString().split('');
var i = randInt(0, s.length - 2);
var tmp = s[i];
s[i] = s[i + 1];
s[i + 1] = tmp;
wrong = parseInt(s.join(''));
} else {
wrong = ans + (Math.random() > 0.5 ? 1 : -1);
}
}
}
if (wrong !== ans && wrong >= 0 && wrongs.indexOf(wrong) === -1) {
wrongs.push(wrong);
}
}
// Shuffle answers
answerChoices = wrongs.concat([ans]);
shuffleArray(answerChoices);
// Set question and answers
questionBox.setQuestion(question);
for (var i = 0; i < 4; i++) {
answerButtons[i].setValue(answerChoices[i]);
answerButtons[i].reset();
}
}
// Handle answer selection
function handleAnswer(val, btn) {
if (!gameActive) return;
if (val === correctAnswer) {
btn.setState('correct');
LK.getSound('correct').play();
score += 1;
LK.setScore(score);
scoreTxt.setText(score + '');
// Animate button
tween(btn, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(btn, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
// Check win condition: 10 correct answers
if (score >= 10) {
gameActive = false;
LK.effects.flashScreen(0x7ed321, 800);
LK.setTimeout(function () {
LK.showYouWin();
}, 600);
} else {
// Next question after short delay
LK.setTimeout(nextQuestion, 350);
}
} else {
btn.setState('wrong');
LK.getSound('wrong').play();
// Decrease score by 1, but not below zero
score = Math.max(0, score - 1);
LK.setScore(score);
scoreTxt.setText(score + '');
// Flash wrong, then game over
tween(btn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 120,
onFinish: function onFinish() {
tween(btn, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
endGame();
}
}
// Start next question
function nextQuestion() {
if (!gameActive) return;
// Increase speed as score increases
if (score >= 10) {
// After 10 questions, shorten by 1 second (1000ms)
timePerQuestion = Math.max(1200, 2500 - (score - 10) * 80);
} else {
timePerQuestion = Math.max(1200, 3500 - score * 80);
}
timeLeft = timePerQuestion;
questionStartTime = Date.now();
generateQuestion();
}
// End game
function endGame() {
if (!gameActive) return;
gameActive = false;
// Flash screen red
LK.effects.flashScreen(0xD0021B, 800);
// Show game over (handled by LK)
LK.setTimeout(function () {
LK.showGameOver();
}, 600);
}
// Utility: random integer [min, max]
function randInt(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// Utility: shuffle array in-place
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = randInt(0, i);
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
// Game update loop
game.update = function () {
if (!gameActive) return;
// Update timer
var now = Date.now();
timeLeft = timePerQuestion - (now - questionStartTime);
var progress = timeLeft / timePerQuestion;
timerBar.setProgress(progress);
// Update numeric timer to show time left (countdown) in seconds, min 0
if (typeof timerTxt !== 'undefined') {
var left = Math.max(0, timeLeft);
var secs = Math.round(left / 100) / 10;
timerTxt.setText(secs.toFixed(1) + 's');
}
// If time runs out
if (timeLeft <= 0) {
// Flash all buttons red
for (var i = 0; i < 4; i++) {
answerButtons[i].setState('wrong');
}
endGame();
}
};
// Start first question
function startGame() {
score = 0;
LK.setScore(0);
scoreTxt.setText('0');
gameActive = true;
difficultyLevel = 1;
nextQuestion();
}
// On game reset, start again
startGame();