/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); var Obstacle = Container.expand(function (type) { var self = Container.call(this); var assetName = 'obstacle' + (type || 1); var obstacleGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1.0 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); self.lane = 1; // 0=left, 1=center, 2=right self.targetX = 0; self.update = function () { // Smooth movement to target lane var diff = self.targetX - self.x; if (Math.abs(diff) > 5) { self.x += diff * 0.15; } else { self.x = self.targetX; } }; return self; }); var QuestionPanel = Container.expand(function () { var self = Container.call(this); var background = self.attachAsset('questionBg', { anchorX: 0.5, anchorY: 0.5 }); self.questionText = new Text2('', { size: 110, // Increased by 20% from 92 fill: 0x000000, font: "'Arial Black'" }); self.questionText.anchor.set(0.5, 0.5); self.questionText.y = -150; self.addChild(self.questionText); self.timerText = new Text2('9', { size: 90, fill: 0xFF0000, font: "'Arial Black'" }); self.timerText.anchor.set(0.5, 0.5); self.timerText.y = -250; self.addChild(self.timerText); self.answerButtons = []; for (var i = 0; i < 3; i++) { var button = self.addChild(LK.getAsset('answerButton', { anchorX: 0.5, anchorY: 0.5 })); button.x = (i - 1) * 450; button.y = 50; var buttonText = new Text2('', { size: 86, // Increased by 20% from 72 fill: 0x000000, font: "'Arial Black'" }); buttonText.anchor.set(0.5, 0.5); button.addChild(buttonText); button.text = buttonText; button.answerValue = 0; self.answerButtons.push(button); } self.setupQuestion = function () { var num1 = Math.floor(Math.random() * 9) + 2; var num2 = Math.floor(Math.random() * 9) + 2; var correctAnswer = num1 * num2; self.questionText.setText(num1 + ' × ' + num2 + ' = ?'); self.correctAnswer = correctAnswer; // Generate wrong answers var wrongAnswers = []; while (wrongAnswers.length < 2) { var wrong = correctAnswer + Math.floor(Math.random() * 20) - 10; if (wrong !== correctAnswer && wrong > 0 && wrongAnswers.indexOf(wrong) === -1) { wrongAnswers.push(wrong); } } // Randomize button positions var answers = [correctAnswer, wrongAnswers[0], wrongAnswers[1]]; for (var i = 0; i < 3; i++) { var randomIndex = Math.floor(Math.random() * answers.length); var answer = answers.splice(randomIndex, 1)[0]; self.answerButtons[i].answerValue = answer; self.answerButtons[i].text.setText(answer.toString()); } questionTimer = 9; self.timerText.setText(questionTimer.toString()); }; return self; }); var SpecialCoin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('specialCoin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.pointValue = 500; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // fence // desk // backpack // Game variables var gameStarted = false; var startScreen = null; var gameSpeed = 8; var initialGameSpeed = 8; var speedIncrement = 0.005; var maxSpeed = 20; var lanePositions = [2048 / 2 - 300, 2048 / 2, 2048 / 2 + 300]; var groundY = 2732 - 100; var obstacles = []; var coins = []; var specialCoins = []; var obstacleSpawnTimer = 0; var coinSpawnTimer = 0; var specialCoinSpawnTimer = 0; var scoreMultiplier = 1.0; var questionActive = false; var questionTimer = 0; var questionPanel = null; var firstCoinCollected = false; var lastBonus5xTriggered = false; var forcedQuestionTimer = 0; var forcedQuestionInterval = 1800; // 30 seconds at 60fps var obstaclesPassed = 0; var maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // Random between 10-20 var player = game.addChild(new Player()); player.x = lanePositions[1]; player.y = groundY; player.targetX = lanePositions[1]; // Ground var ground = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0 })); ground.x = 0; ground.y = groundY; // UI Elements var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF, font: "'Arial Black'" }); scoreText.anchor.set(1, 0); scoreText.x = -20; scoreText.y = 20; scoreText.visible = false; // Hide initially LK.gui.topRight.addChild(scoreText); var multiplierText = new Text2('BONUS: 1.0x', { size: 50, fill: 0xFFFF00, font: "'Arial Black'" }); multiplierText.anchor.set(1, 0); multiplierText.x = -20; multiplierText.y = 80; multiplierText.visible = false; // Hide initially LK.gui.topRight.addChild(multiplierText); // Create start screen startScreen = game.addChild(LK.getAsset('startImage', { anchorX: 0.5, anchorY: 0.5, scaleX: 2048 / 1400, // Scale to full width scaleY: 2732 / 2100 // Scale to full height })); startScreen.x = 2048 / 2; startScreen.y = 2732 / 2; // Hide game elements until game starts player.visible = false; ground.visible = false; function updateUI() { scoreText.setText('Score: ' + LK.getScore()); multiplierText.setText('BONUS: ' + scoreMultiplier.toFixed(1) + 'x'); // Add flaming animation when bonus is 5x or higher if (scoreMultiplier >= 5.0) { // Play special sound when reaching 5x bonus for the first time if (!lastBonus5xTriggered) { LK.getSound('bonus5x').play(); lastBonus5xTriggered = true; } // Stop any existing tweens tween.stop(multiplierText); // Create more intense flame-like movement var flameIntensity = Math.min(scoreMultiplier / 5, 3); // Scale with multiplier, max 3x tween(multiplierText, { x: multiplierText.x + (Math.random() * 12 - 6) * flameIntensity, y: multiplierText.y + (Math.random() * 8 - 4) * flameIntensity, scaleX: 1 + (Math.random() * 0.3 - 0.15) * flameIntensity, scaleY: 1 + (Math.random() * 0.3 - 0.15) * flameIntensity }, { duration: 80, easing: tween.easeInOut, onFinish: function onFinish() { tween(multiplierText, { x: -20, y: 80, scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.easeOut }); } }); // More dramatic color transitions with multiple flame colors var flameColors = [0xFF0000, 0xFF4500, 0xFF6600, 0xFF8800, 0xFFAA00, 0xFFCC00, 0xFFFF00]; var randomColor1 = flameColors[Math.floor(Math.random() * flameColors.length)]; var randomColor2 = flameColors[Math.floor(Math.random() * flameColors.length)]; tween(multiplierText, { tint: randomColor1 }, { duration: 120, easing: tween.easeInOut, onFinish: function onFinish() { tween(multiplierText, { tint: randomColor2 }, { duration: 120, easing: tween.easeInOut, onFinish: function onFinish() { tween(multiplierText, { tint: 0xFFFF00 }, { duration: 120, easing: tween.easeOut }); } }); } }); // Add subtle rotation for more flame effect tween(multiplierText, { rotation: (Math.random() * 0.2 - 0.1) * flameIntensity }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(multiplierText, { rotation: 0 }, { duration: 150, easing: tween.easeOut }); } }); } else { // Reset to normal appearance tween.stop(multiplierText); multiplierText.tint = 0xFFFF00; multiplierText.x = -20; multiplierText.y = 80; multiplierText.scaleX = 1; multiplierText.scaleY = 1; multiplierText.rotation = 0; // Reset 5x bonus sound trigger when below 5x lastBonus5xTriggered = false; } } function switchLane(direction) { if (questionActive) return; player.lane += direction; if (player.lane < 0) player.lane = 0; if (player.lane > 2) player.lane = 2; player.targetX = lanePositions[player.lane]; } function spawnObstacle() { var lane = Math.floor(Math.random() * 3); var type = Math.floor(Math.random() * 3) + 1; var spawnY = -100; var minDistance = 560; // 2 character widths (280 * 2) var canSpawn = true; // Check distance from other obstacles for (var i = 0; i < obstacles.length; i++) { var existingObstacle = obstacles[i]; if (existingObstacle.lane === lane && Math.abs(existingObstacle.y - spawnY) < minDistance) { canSpawn = false; break; } } // Check distance from coins if (canSpawn) { for (var i = 0; i < coins.length; i++) { var coin = coins[i]; if (coin.lane === lane && Math.abs(coin.y - spawnY) < minDistance) { canSpawn = false; break; } } } // Check distance from special coins if (canSpawn) { for (var i = 0; i < specialCoins.length; i++) { var specialCoin = specialCoins[i]; if (specialCoin.lane === lane && Math.abs(specialCoin.y - spawnY) < minDistance) { canSpawn = false; break; } } } if (canSpawn) { var obstacle = game.addChild(new Obstacle(type)); obstacle.x = lanePositions[lane]; obstacle.y = spawnY; obstacle.lane = lane; obstacles.push(obstacle); } } function spawnCoin() { var lane = Math.floor(Math.random() * 3); var spawnY = -50; var minDistance = 560; // 2 character widths (280 * 2) var canSpawn = true; // Check distance from obstacles for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (obstacle.lane === lane && Math.abs(obstacle.y - spawnY) < minDistance) { canSpawn = false; break; } } // Check distance from other coins if (canSpawn) { for (var i = 0; i < coins.length; i++) { var existingCoin = coins[i]; if (existingCoin.lane === lane && Math.abs(existingCoin.y - spawnY) < minDistance) { canSpawn = false; break; } } } // Check distance from special coins if (canSpawn) { for (var i = 0; i < specialCoins.length; i++) { var specialCoin = specialCoins[i]; if (specialCoin.lane === lane && Math.abs(specialCoin.y - spawnY) < minDistance) { canSpawn = false; break; } } } if (canSpawn) { var coin = game.addChild(new Coin()); coin.x = lanePositions[lane]; coin.y = spawnY; coin.lane = lane; coins.push(coin); } } function spawnSpecialCoin() { var lane = Math.floor(Math.random() * 3); var spawnY = -50; var minDistance = 560; // 2 character widths (280 * 2) var canSpawn = true; // Check distance from obstacles for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (obstacle.lane === lane && Math.abs(obstacle.y - spawnY) < minDistance) { canSpawn = false; break; } } // Check distance from coins if (canSpawn) { for (var i = 0; i < coins.length; i++) { var coin = coins[i]; if (coin.lane === lane && Math.abs(coin.y - spawnY) < minDistance) { canSpawn = false; break; } } } // Check distance from other special coins if (canSpawn) { for (var i = 0; i < specialCoins.length; i++) { var existingSpecialCoin = specialCoins[i]; if (existingSpecialCoin.lane === lane && Math.abs(existingSpecialCoin.y - spawnY) < minDistance) { canSpawn = false; break; } } } if (canSpawn) { var specialCoin = game.addChild(new SpecialCoin()); specialCoin.x = lanePositions[lane]; specialCoin.y = spawnY; specialCoin.lane = lane; specialCoins.push(specialCoin); } } function spawnForcedQuestionObstacles() { // Clear existing obstacles to prevent conflicts for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Clear existing coins and special coins for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } for (var i = specialCoins.length - 1; i >= 0; i--) { specialCoins[i].destroy(); specialCoins.splice(i, 1); } // Spawn obstacles in all 3 lanes at the same Y position var spawnY = -100; for (var lane = 0; lane < 3; lane++) { var type = Math.floor(Math.random() * 3) + 1; var obstacle = game.addChild(new Obstacle(type)); obstacle.x = lanePositions[lane]; obstacle.y = spawnY; obstacle.lane = lane; obstacles.push(obstacle); } } function showQuestion() { questionActive = true; // Clear all obstacles for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Clear all coins for (var i = coins.length - 1; i >= 0; i--) { coins[i].destroy(); coins.splice(i, 1); } // Clear all special coins for (var i = specialCoins.length - 1; i >= 0; i--) { specialCoins[i].destroy(); specialCoins.splice(i, 1); } questionPanel = game.addChild(new QuestionPanel()); questionPanel.x = 2048 / 2; questionPanel.y = 2732 / 2; questionPanel.setupQuestion(); } function hideQuestion() { if (questionPanel) { questionPanel.destroy(); questionPanel = null; } questionActive = false; } function answerQuestion(selectedAnswer) { if (!questionActive) return; var correct = selectedAnswer === questionPanel.correctAnswer; if (correct) { scoreMultiplier += 0.5; // Cap bonus multiplier at 5x if (scoreMultiplier > 5.0) { scoreMultiplier = 5.0; } gameSpeed *= 1.01; // Increase speed by 1% for correct answers LK.getSound('correct').play(); } else { scoreMultiplier = 1.0; var speedLimit = initialGameSpeed * 1.6; // 60% more than initial speed if (gameSpeed < speedLimit) { gameSpeed *= 1.03; // Increase speed by 3% } else { // At speed limit, give 6x score bonus instead var bonusPoints = Math.round(60 * scoreMultiplier); // 6x the base 10 points LK.setScore(LK.getScore() + bonusPoints); } LK.getSound('wrong').play(); } hideQuestion(); updateUI(); } // Touch controls game.down = function (x, y, obj) { if (!gameStarted) { // Start the game when clicking on start screen gameStarted = true; if (startScreen) { startScreen.destroy(); startScreen = null; } player.visible = true; ground.visible = true; scoreText.visible = true; // Show score when game starts multiplierText.visible = true; // Show bonus when game starts return; } if (questionActive && questionPanel) { // Check if clicking on answer buttons for (var i = 0; i < questionPanel.answerButtons.length; i++) { var button = questionPanel.answerButtons[i]; var buttonPos = game.toLocal(button.parent.toGlobal(button.position)); if (Math.abs(x - buttonPos.x) < 200 && Math.abs(y - buttonPos.y) < 50) { answerQuestion(button.answerValue); return; } } } else { // Lane switching if (x < 2048 / 2) { switchLane(-1); // Move left } else { switchLane(1); // Move right } } }; game.update = function () { if (!gameStarted) { return; // Don't update game until started } if (questionActive) { // Handle question timer if (LK.ticks % 60 === 0) { // Every second questionTimer--; if (questionPanel) { questionPanel.timerText.setText(questionTimer.toString()); } if (questionTimer <= 0) { // Time's up - wrong answer scoreMultiplier = 1.0; hideQuestion(); updateUI(); } } return; // Don't update game objects during question } // Increase speed gradually if (gameSpeed < maxSpeed) { gameSpeed += speedIncrement; } // Spawn obstacles obstacleSpawnTimer++; if (obstacleSpawnTimer > 120 - gameSpeed * 2) { // Spawn more frequently as speed increases spawnObstacle(); obstacleSpawnTimer = 0; } // Spawn coins coinSpawnTimer++; if (coinSpawnTimer > 180) { spawnCoin(); coinSpawnTimer = 0; } // Spawn special coins (less frequently) specialCoinSpawnTimer++; if (specialCoinSpawnTimer > 600) { spawnSpecialCoin(); specialCoinSpawnTimer = 0; } // Handle forced question timer forcedQuestionTimer++; if (forcedQuestionTimer > forcedQuestionInterval) { spawnForcedQuestionObstacles(); forcedQuestionTimer = 0; obstaclesPassed = 0; // Reset obstacle counter when across-lane spawn occurs maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // New random threshold between 10-20 // Increase interval slightly each time to make it less predictable forcedQuestionInterval = Math.floor(forcedQuestionInterval * 1.1); if (forcedQuestionInterval > 3600) { // Cap at 60 seconds forcedQuestionInterval = 3600; } } // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; if (!obstacle) continue; // Skip if obstacle is undefined obstacle.speed = gameSpeed; // Check collision with player if (obstacle.lane === player.lane && Math.abs(obstacle.y - player.y) < 80 && Math.abs(obstacle.x - player.x) < 60) { LK.getSound('hit').play(); showQuestion(); obstacle.destroy(); obstacles.splice(i, 1); continue; } // Remove off-screen obstacles if (obstacle.y > 2732 + 100) { obstaclesPassed++; obstacle.destroy(); obstacles.splice(i, 1); // Force across-lane obstacles after random number of obstacles passed if (obstaclesPassed >= maxObstaclesBeforeForced) { spawnForcedQuestionObstacles(); obstaclesPassed = 0; // Reset counter maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // New random threshold between 10-20 } } } // Update coins for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; if (!coin) continue; // Skip if coin is undefined coin.speed = gameSpeed; // Check collection if (coin.lane === player.lane && Math.abs(coin.y - player.y) < 60 && Math.abs(coin.x - player.x) < 50) { var coinPoints = Math.round(10 * scoreMultiplier); LK.setScore(LK.getScore() + coinPoints); LK.getSound('collect').play(); // Check if score exceeded 5000 if (LK.getScore() > 5000) { // Stop background music LK.stopMusic(); // Hide UI elements scoreText.visible = false; multiplierText.visible = false; // Show victory visual var completionImage = game.addChild(LK.getAsset('completionImage', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 0.1, scaleY: 0.1 })); // Play completion sound LK.getSound('completionSound').play(); // Add victory animation tween(completionImage, { scaleX: 1.5, scaleY: 1.5, rotation: Math.PI * 2 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { // Wait for completion sound to finish before showing play again button LK.setTimeout(function () { LK.showYouWin(); }, 1000); // 1 second delay to allow sound to complete } }); } // Start background music on first coin collection if (!firstCoinCollected) { firstCoinCollected = true; LK.playMusic('onepiecesoundtrack', { loop: true }); } updateUI(); // Add coin disappearing animation tween(coin, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { coin.destroy(); } }); coins.splice(i, 1); continue; } // Remove off-screen coins if (coin.y > 2732 + 50) { coin.destroy(); coins.splice(i, 1); } } // Update special coins for (var i = specialCoins.length - 1; i >= 0; i--) { var specialCoin = specialCoins[i]; if (!specialCoin) continue; // Skip if specialCoin is undefined specialCoin.speed = gameSpeed; // Check collection if (specialCoin.lane === player.lane && Math.abs(specialCoin.y - player.y) < 60 && Math.abs(specialCoin.x - player.x) < 50) { var specialCoinPoints = Math.round(specialCoin.pointValue * scoreMultiplier); LK.setScore(LK.getScore() + specialCoinPoints); // Check if score exceeded 5000 if (LK.getScore() > 5000) { // Stop background music LK.stopMusic(); // Hide UI elements scoreText.visible = false; multiplierText.visible = false; // Show victory visual var completionImage = game.addChild(LK.getAsset('completionImage', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 0.1, scaleY: 0.1 })); // Play completion sound LK.getSound('completionSound').play(); // Add victory animation tween(completionImage, { scaleX: 1.5, scaleY: 1.5, rotation: Math.PI * 2 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { // Wait for completion sound to finish before showing play again button LK.setTimeout(function () { LK.showYouWin(); }, 1000); // 1 second delay to allow sound to complete } }); } var specialSound = LK.getSound('specialCollect'); specialSound.play(); // Create a temporary object to tween the music volume var musicVolume = { volume: 0.3 }; // Mute background music volume when special collect sound plays tween(musicVolume, { volume: 0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { // Update the actual music volume LK.playMusic('onepiecesoundtrack', { volume: musicVolume.volume }); } }); // Fade back to normal volume when special collect sound finishes LK.setTimeout(function () { tween(musicVolume, { volume: 0.3 }, { duration: 100, easing: tween.easeIn, onFinish: function onFinish() { // Update the actual music volume back to normal LK.playMusic('onepiecesoundtrack', { volume: musicVolume.volume }); } }); }, 630); // Duration of specialCollect sound (0.898 - 0.835) * 1000 = 63ms, but adding buffer // Start background music on first coin collection if (!firstCoinCollected) { firstCoinCollected = true; LK.playMusic('onepiecesoundtrack', { loop: true }); } updateUI(); // Add special coin disappearing animation tween(specialCoin, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { specialCoin.destroy(); } }); specialCoins.splice(i, 1); continue; } // Remove off-screen special coins if (specialCoin.y > 2732 + 50) { specialCoin.destroy(); specialCoins.splice(i, 1); } } }; updateUI();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
var assetName = 'obstacle' + (type || 1);
var obstacleGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.lane = 1; // 0=left, 1=center, 2=right
self.targetX = 0;
self.update = function () {
// Smooth movement to target lane
var diff = self.targetX - self.x;
if (Math.abs(diff) > 5) {
self.x += diff * 0.15;
} else {
self.x = self.targetX;
}
};
return self;
});
var QuestionPanel = Container.expand(function () {
var self = Container.call(this);
var background = self.attachAsset('questionBg', {
anchorX: 0.5,
anchorY: 0.5
});
self.questionText = new Text2('', {
size: 110,
// Increased by 20% from 92
fill: 0x000000,
font: "'Arial Black'"
});
self.questionText.anchor.set(0.5, 0.5);
self.questionText.y = -150;
self.addChild(self.questionText);
self.timerText = new Text2('9', {
size: 90,
fill: 0xFF0000,
font: "'Arial Black'"
});
self.timerText.anchor.set(0.5, 0.5);
self.timerText.y = -250;
self.addChild(self.timerText);
self.answerButtons = [];
for (var i = 0; i < 3; i++) {
var button = self.addChild(LK.getAsset('answerButton', {
anchorX: 0.5,
anchorY: 0.5
}));
button.x = (i - 1) * 450;
button.y = 50;
var buttonText = new Text2('', {
size: 86,
// Increased by 20% from 72
fill: 0x000000,
font: "'Arial Black'"
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonText);
button.text = buttonText;
button.answerValue = 0;
self.answerButtons.push(button);
}
self.setupQuestion = function () {
var num1 = Math.floor(Math.random() * 9) + 2;
var num2 = Math.floor(Math.random() * 9) + 2;
var correctAnswer = num1 * num2;
self.questionText.setText(num1 + ' × ' + num2 + ' = ?');
self.correctAnswer = correctAnswer;
// Generate wrong answers
var wrongAnswers = [];
while (wrongAnswers.length < 2) {
var wrong = correctAnswer + Math.floor(Math.random() * 20) - 10;
if (wrong !== correctAnswer && wrong > 0 && wrongAnswers.indexOf(wrong) === -1) {
wrongAnswers.push(wrong);
}
}
// Randomize button positions
var answers = [correctAnswer, wrongAnswers[0], wrongAnswers[1]];
for (var i = 0; i < 3; i++) {
var randomIndex = Math.floor(Math.random() * answers.length);
var answer = answers.splice(randomIndex, 1)[0];
self.answerButtons[i].answerValue = answer;
self.answerButtons[i].text.setText(answer.toString());
}
questionTimer = 9;
self.timerText.setText(questionTimer.toString());
};
return self;
});
var SpecialCoin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('specialCoin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.pointValue = 500;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// fence
// desk
// backpack
// Game variables
var gameStarted = false;
var startScreen = null;
var gameSpeed = 8;
var initialGameSpeed = 8;
var speedIncrement = 0.005;
var maxSpeed = 20;
var lanePositions = [2048 / 2 - 300, 2048 / 2, 2048 / 2 + 300];
var groundY = 2732 - 100;
var obstacles = [];
var coins = [];
var specialCoins = [];
var obstacleSpawnTimer = 0;
var coinSpawnTimer = 0;
var specialCoinSpawnTimer = 0;
var scoreMultiplier = 1.0;
var questionActive = false;
var questionTimer = 0;
var questionPanel = null;
var firstCoinCollected = false;
var lastBonus5xTriggered = false;
var forcedQuestionTimer = 0;
var forcedQuestionInterval = 1800; // 30 seconds at 60fps
var obstaclesPassed = 0;
var maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // Random between 10-20
var player = game.addChild(new Player());
player.x = lanePositions[1];
player.y = groundY;
player.targetX = lanePositions[1];
// Ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = groundY;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF,
font: "'Arial Black'"
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
scoreText.y = 20;
scoreText.visible = false; // Hide initially
LK.gui.topRight.addChild(scoreText);
var multiplierText = new Text2('BONUS: 1.0x', {
size: 50,
fill: 0xFFFF00,
font: "'Arial Black'"
});
multiplierText.anchor.set(1, 0);
multiplierText.x = -20;
multiplierText.y = 80;
multiplierText.visible = false; // Hide initially
LK.gui.topRight.addChild(multiplierText);
// Create start screen
startScreen = game.addChild(LK.getAsset('startImage', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2048 / 1400,
// Scale to full width
scaleY: 2732 / 2100 // Scale to full height
}));
startScreen.x = 2048 / 2;
startScreen.y = 2732 / 2;
// Hide game elements until game starts
player.visible = false;
ground.visible = false;
function updateUI() {
scoreText.setText('Score: ' + LK.getScore());
multiplierText.setText('BONUS: ' + scoreMultiplier.toFixed(1) + 'x');
// Add flaming animation when bonus is 5x or higher
if (scoreMultiplier >= 5.0) {
// Play special sound when reaching 5x bonus for the first time
if (!lastBonus5xTriggered) {
LK.getSound('bonus5x').play();
lastBonus5xTriggered = true;
}
// Stop any existing tweens
tween.stop(multiplierText);
// Create more intense flame-like movement
var flameIntensity = Math.min(scoreMultiplier / 5, 3); // Scale with multiplier, max 3x
tween(multiplierText, {
x: multiplierText.x + (Math.random() * 12 - 6) * flameIntensity,
y: multiplierText.y + (Math.random() * 8 - 4) * flameIntensity,
scaleX: 1 + (Math.random() * 0.3 - 0.15) * flameIntensity,
scaleY: 1 + (Math.random() * 0.3 - 0.15) * flameIntensity
}, {
duration: 80,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(multiplierText, {
x: -20,
y: 80,
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeOut
});
}
});
// More dramatic color transitions with multiple flame colors
var flameColors = [0xFF0000, 0xFF4500, 0xFF6600, 0xFF8800, 0xFFAA00, 0xFFCC00, 0xFFFF00];
var randomColor1 = flameColors[Math.floor(Math.random() * flameColors.length)];
var randomColor2 = flameColors[Math.floor(Math.random() * flameColors.length)];
tween(multiplierText, {
tint: randomColor1
}, {
duration: 120,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(multiplierText, {
tint: randomColor2
}, {
duration: 120,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(multiplierText, {
tint: 0xFFFF00
}, {
duration: 120,
easing: tween.easeOut
});
}
});
}
});
// Add subtle rotation for more flame effect
tween(multiplierText, {
rotation: (Math.random() * 0.2 - 0.1) * flameIntensity
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(multiplierText, {
rotation: 0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
} else {
// Reset to normal appearance
tween.stop(multiplierText);
multiplierText.tint = 0xFFFF00;
multiplierText.x = -20;
multiplierText.y = 80;
multiplierText.scaleX = 1;
multiplierText.scaleY = 1;
multiplierText.rotation = 0;
// Reset 5x bonus sound trigger when below 5x
lastBonus5xTriggered = false;
}
}
function switchLane(direction) {
if (questionActive) return;
player.lane += direction;
if (player.lane < 0) player.lane = 0;
if (player.lane > 2) player.lane = 2;
player.targetX = lanePositions[player.lane];
}
function spawnObstacle() {
var lane = Math.floor(Math.random() * 3);
var type = Math.floor(Math.random() * 3) + 1;
var spawnY = -100;
var minDistance = 560; // 2 character widths (280 * 2)
var canSpawn = true;
// Check distance from other obstacles
for (var i = 0; i < obstacles.length; i++) {
var existingObstacle = obstacles[i];
if (existingObstacle.lane === lane && Math.abs(existingObstacle.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
// Check distance from coins
if (canSpawn) {
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
if (coin.lane === lane && Math.abs(coin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
// Check distance from special coins
if (canSpawn) {
for (var i = 0; i < specialCoins.length; i++) {
var specialCoin = specialCoins[i];
if (specialCoin.lane === lane && Math.abs(specialCoin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
if (canSpawn) {
var obstacle = game.addChild(new Obstacle(type));
obstacle.x = lanePositions[lane];
obstacle.y = spawnY;
obstacle.lane = lane;
obstacles.push(obstacle);
}
}
function spawnCoin() {
var lane = Math.floor(Math.random() * 3);
var spawnY = -50;
var minDistance = 560; // 2 character widths (280 * 2)
var canSpawn = true;
// Check distance from obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.lane === lane && Math.abs(obstacle.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
// Check distance from other coins
if (canSpawn) {
for (var i = 0; i < coins.length; i++) {
var existingCoin = coins[i];
if (existingCoin.lane === lane && Math.abs(existingCoin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
// Check distance from special coins
if (canSpawn) {
for (var i = 0; i < specialCoins.length; i++) {
var specialCoin = specialCoins[i];
if (specialCoin.lane === lane && Math.abs(specialCoin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
if (canSpawn) {
var coin = game.addChild(new Coin());
coin.x = lanePositions[lane];
coin.y = spawnY;
coin.lane = lane;
coins.push(coin);
}
}
function spawnSpecialCoin() {
var lane = Math.floor(Math.random() * 3);
var spawnY = -50;
var minDistance = 560; // 2 character widths (280 * 2)
var canSpawn = true;
// Check distance from obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.lane === lane && Math.abs(obstacle.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
// Check distance from coins
if (canSpawn) {
for (var i = 0; i < coins.length; i++) {
var coin = coins[i];
if (coin.lane === lane && Math.abs(coin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
// Check distance from other special coins
if (canSpawn) {
for (var i = 0; i < specialCoins.length; i++) {
var existingSpecialCoin = specialCoins[i];
if (existingSpecialCoin.lane === lane && Math.abs(existingSpecialCoin.y - spawnY) < minDistance) {
canSpawn = false;
break;
}
}
}
if (canSpawn) {
var specialCoin = game.addChild(new SpecialCoin());
specialCoin.x = lanePositions[lane];
specialCoin.y = spawnY;
specialCoin.lane = lane;
specialCoins.push(specialCoin);
}
}
function spawnForcedQuestionObstacles() {
// Clear existing obstacles to prevent conflicts
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Clear existing coins and special coins
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
for (var i = specialCoins.length - 1; i >= 0; i--) {
specialCoins[i].destroy();
specialCoins.splice(i, 1);
}
// Spawn obstacles in all 3 lanes at the same Y position
var spawnY = -100;
for (var lane = 0; lane < 3; lane++) {
var type = Math.floor(Math.random() * 3) + 1;
var obstacle = game.addChild(new Obstacle(type));
obstacle.x = lanePositions[lane];
obstacle.y = spawnY;
obstacle.lane = lane;
obstacles.push(obstacle);
}
}
function showQuestion() {
questionActive = true;
// Clear all obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Clear all coins
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
// Clear all special coins
for (var i = specialCoins.length - 1; i >= 0; i--) {
specialCoins[i].destroy();
specialCoins.splice(i, 1);
}
questionPanel = game.addChild(new QuestionPanel());
questionPanel.x = 2048 / 2;
questionPanel.y = 2732 / 2;
questionPanel.setupQuestion();
}
function hideQuestion() {
if (questionPanel) {
questionPanel.destroy();
questionPanel = null;
}
questionActive = false;
}
function answerQuestion(selectedAnswer) {
if (!questionActive) return;
var correct = selectedAnswer === questionPanel.correctAnswer;
if (correct) {
scoreMultiplier += 0.5;
// Cap bonus multiplier at 5x
if (scoreMultiplier > 5.0) {
scoreMultiplier = 5.0;
}
gameSpeed *= 1.01; // Increase speed by 1% for correct answers
LK.getSound('correct').play();
} else {
scoreMultiplier = 1.0;
var speedLimit = initialGameSpeed * 1.6; // 60% more than initial speed
if (gameSpeed < speedLimit) {
gameSpeed *= 1.03; // Increase speed by 3%
} else {
// At speed limit, give 6x score bonus instead
var bonusPoints = Math.round(60 * scoreMultiplier); // 6x the base 10 points
LK.setScore(LK.getScore() + bonusPoints);
}
LK.getSound('wrong').play();
}
hideQuestion();
updateUI();
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
// Start the game when clicking on start screen
gameStarted = true;
if (startScreen) {
startScreen.destroy();
startScreen = null;
}
player.visible = true;
ground.visible = true;
scoreText.visible = true; // Show score when game starts
multiplierText.visible = true; // Show bonus when game starts
return;
}
if (questionActive && questionPanel) {
// Check if clicking on answer buttons
for (var i = 0; i < questionPanel.answerButtons.length; i++) {
var button = questionPanel.answerButtons[i];
var buttonPos = game.toLocal(button.parent.toGlobal(button.position));
if (Math.abs(x - buttonPos.x) < 200 && Math.abs(y - buttonPos.y) < 50) {
answerQuestion(button.answerValue);
return;
}
}
} else {
// Lane switching
if (x < 2048 / 2) {
switchLane(-1); // Move left
} else {
switchLane(1); // Move right
}
}
};
game.update = function () {
if (!gameStarted) {
return; // Don't update game until started
}
if (questionActive) {
// Handle question timer
if (LK.ticks % 60 === 0) {
// Every second
questionTimer--;
if (questionPanel) {
questionPanel.timerText.setText(questionTimer.toString());
}
if (questionTimer <= 0) {
// Time's up - wrong answer
scoreMultiplier = 1.0;
hideQuestion();
updateUI();
}
}
return; // Don't update game objects during question
}
// Increase speed gradually
if (gameSpeed < maxSpeed) {
gameSpeed += speedIncrement;
}
// Spawn obstacles
obstacleSpawnTimer++;
if (obstacleSpawnTimer > 120 - gameSpeed * 2) {
// Spawn more frequently as speed increases
spawnObstacle();
obstacleSpawnTimer = 0;
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer > 180) {
spawnCoin();
coinSpawnTimer = 0;
}
// Spawn special coins (less frequently)
specialCoinSpawnTimer++;
if (specialCoinSpawnTimer > 600) {
spawnSpecialCoin();
specialCoinSpawnTimer = 0;
}
// Handle forced question timer
forcedQuestionTimer++;
if (forcedQuestionTimer > forcedQuestionInterval) {
spawnForcedQuestionObstacles();
forcedQuestionTimer = 0;
obstaclesPassed = 0; // Reset obstacle counter when across-lane spawn occurs
maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // New random threshold between 10-20
// Increase interval slightly each time to make it less predictable
forcedQuestionInterval = Math.floor(forcedQuestionInterval * 1.1);
if (forcedQuestionInterval > 3600) {
// Cap at 60 seconds
forcedQuestionInterval = 3600;
}
}
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (!obstacle) continue; // Skip if obstacle is undefined
obstacle.speed = gameSpeed;
// Check collision with player
if (obstacle.lane === player.lane && Math.abs(obstacle.y - player.y) < 80 && Math.abs(obstacle.x - player.x) < 60) {
LK.getSound('hit').play();
showQuestion();
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Remove off-screen obstacles
if (obstacle.y > 2732 + 100) {
obstaclesPassed++;
obstacle.destroy();
obstacles.splice(i, 1);
// Force across-lane obstacles after random number of obstacles passed
if (obstaclesPassed >= maxObstaclesBeforeForced) {
spawnForcedQuestionObstacles();
obstaclesPassed = 0; // Reset counter
maxObstaclesBeforeForced = Math.floor(Math.random() * 11) + 10; // New random threshold between 10-20
}
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin) continue; // Skip if coin is undefined
coin.speed = gameSpeed;
// Check collection
if (coin.lane === player.lane && Math.abs(coin.y - player.y) < 60 && Math.abs(coin.x - player.x) < 50) {
var coinPoints = Math.round(10 * scoreMultiplier);
LK.setScore(LK.getScore() + coinPoints);
LK.getSound('collect').play();
// Check if score exceeded 5000
if (LK.getScore() > 5000) {
// Stop background music
LK.stopMusic();
// Hide UI elements
scoreText.visible = false;
multiplierText.visible = false;
// Show victory visual
var completionImage = game.addChild(LK.getAsset('completionImage', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0.1,
scaleY: 0.1
}));
// Play completion sound
LK.getSound('completionSound').play();
// Add victory animation
tween(completionImage, {
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Wait for completion sound to finish before showing play again button
LK.setTimeout(function () {
LK.showYouWin();
}, 1000); // 1 second delay to allow sound to complete
}
});
}
// Start background music on first coin collection
if (!firstCoinCollected) {
firstCoinCollected = true;
LK.playMusic('onepiecesoundtrack', {
loop: true
});
}
updateUI();
// Add coin disappearing animation
tween(coin, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(i, 1);
continue;
}
// Remove off-screen coins
if (coin.y > 2732 + 50) {
coin.destroy();
coins.splice(i, 1);
}
}
// Update special coins
for (var i = specialCoins.length - 1; i >= 0; i--) {
var specialCoin = specialCoins[i];
if (!specialCoin) continue; // Skip if specialCoin is undefined
specialCoin.speed = gameSpeed;
// Check collection
if (specialCoin.lane === player.lane && Math.abs(specialCoin.y - player.y) < 60 && Math.abs(specialCoin.x - player.x) < 50) {
var specialCoinPoints = Math.round(specialCoin.pointValue * scoreMultiplier);
LK.setScore(LK.getScore() + specialCoinPoints);
// Check if score exceeded 5000
if (LK.getScore() > 5000) {
// Stop background music
LK.stopMusic();
// Hide UI elements
scoreText.visible = false;
multiplierText.visible = false;
// Show victory visual
var completionImage = game.addChild(LK.getAsset('completionImage', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0.1,
scaleY: 0.1
}));
// Play completion sound
LK.getSound('completionSound').play();
// Add victory animation
tween(completionImage, {
scaleX: 1.5,
scaleY: 1.5,
rotation: Math.PI * 2
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Wait for completion sound to finish before showing play again button
LK.setTimeout(function () {
LK.showYouWin();
}, 1000); // 1 second delay to allow sound to complete
}
});
}
var specialSound = LK.getSound('specialCollect');
specialSound.play();
// Create a temporary object to tween the music volume
var musicVolume = {
volume: 0.3
};
// Mute background music volume when special collect sound plays
tween(musicVolume, {
volume: 0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Update the actual music volume
LK.playMusic('onepiecesoundtrack', {
volume: musicVolume.volume
});
}
});
// Fade back to normal volume when special collect sound finishes
LK.setTimeout(function () {
tween(musicVolume, {
volume: 0.3
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
// Update the actual music volume back to normal
LK.playMusic('onepiecesoundtrack', {
volume: musicVolume.volume
});
}
});
}, 630); // Duration of specialCollect sound (0.898 - 0.835) * 1000 = 63ms, but adding buffer
// Start background music on first coin collection
if (!firstCoinCollected) {
firstCoinCollected = true;
LK.playMusic('onepiecesoundtrack', {
loop: true
});
}
updateUI();
// Add special coin disappearing animation
tween(specialCoin, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
specialCoin.destroy();
}
});
specialCoins.splice(i, 1);
continue;
}
// Remove off-screen special coins
if (specialCoin.y > 2732 + 50) {
specialCoin.destroy();
specialCoins.splice(i, 1);
}
}
};
updateUI();