/****
* 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();