/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var MenuButton = Container.expand(function (text, difficulty, x, y) { var self = Container.call(this); self.difficulty = difficulty; // Create button background with difficulty-specific asset var buttonAsset = 'button_' + difficulty; var buttonBg = self.attachAsset(buttonAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 1.5 }); // Create button text var buttonText = new Text2(text, { size: 60, fill: 0x000000, stroke: 0x000000, strokeThickness: 2 }); buttonText.anchor.set(0.5, 0.5); self.addChild(buttonText); // Position button self.x = x; self.y = y; // Button press handler self.down = function (x, y, obj) { // Visual feedback tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); } }); // Start game with selected difficulty startGameWithDifficulty(self.difficulty); }; return self; }); var Mineral = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.mineralData = mineralTypes[type]; var mineralGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); // Initialize properties self.timeLeft = self.mineralData.duration; self.maxTime = self.mineralData.duration; self.isCollected = false; self.hasLostLife = false; // Add sparkle effect for rare minerals if (self.mineralData.rarity >= 3) { tween(mineralGraphics, { alpha: 0.7 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(mineralGraphics, { alpha: 1 }, { duration: 500, easing: tween.easeInOut }); } }); } self.update = function () { if (self.isCollected) return; self.timeLeft -= 16.67; // Roughly 60 FPS // Flash when time is running out if (self.timeLeft < 1000) { var flashAlpha = Math.sin(LK.ticks * 0.5) * 0.3 + 0.7; mineralGraphics.alpha = flashAlpha; } // Remove when time expires if (self.timeLeft <= 0) { self.expire(); } }; self.collect = function () { if (self.isCollected) return; self.isCollected = true; // Add score var points = self.mineralData.points * scoreMultiplier; LK.setScore(LK.getScore() + points); // Increase multiplier scoreMultiplier = Math.min(scoreMultiplier + 0.1, 5); consecutiveCollections++; // Play sound LK.getSound('mine').play(); // Animation tween(mineralGraphics, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); // Remove from minerals array for (var i = minerals.length - 1; i >= 0; i--) { if (minerals[i] === self) { minerals.splice(i, 1); break; } } // Update UI updateScoreDisplay(); }; self.expire = function () { // Only lose life if we haven't already lost one for this mineral if (!self.hasLostLife) { // Reset multiplier on missed mineral scoreMultiplier = 1; consecutiveCollections = 0; // Lose a life currentLives--; self.hasLostLife = true; updateScoreDisplay(); // Check game over if (currentLives <= 0) { LK.showGameOver(); return; } } // Fade out animation tween(mineralGraphics, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); // Remove from minerals array for (var i = minerals.length - 1; i >= 0; i--) { if (minerals[i] === self) { minerals.splice(i, 1); break; } } }; self.down = function (x, y, obj) { self.collect(); }; return self; }); var Pickaxe = Container.expand(function () { var self = Container.call(this); var pickaxeGraphics = self.attachAsset('pickaxe', { anchorX: 0.5, anchorY: 0.5 }); // Initialize position self.targetX = 1024; self.targetY = 1366; self.x = self.targetX; self.y = self.targetY; // Smooth following properties self.followSpeed = 0.15; self.update = function () { // Smooth movement towards target position var dx = self.targetX - self.x; var dy = self.targetY - self.y; self.x += dx * self.followSpeed; self.y += dy * self.followSpeed; // Add subtle swaying animation var sway = Math.sin(LK.ticks * 0.05) * 2; pickaxeGraphics.rotation = sway * 0.1; }; self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; // Add a little shake effect when moving to new position tween(pickaxeGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(pickaxeGraphics, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.easeOut }); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Add mining background var backgroundImage = game.attachAsset('mining_background', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); // Game state var gameState = 'menu'; // 'menu' or 'playing' var currentDifficulty = 'normal'; // Game variables var minerals = []; var scoreMultiplier = 1; var consecutiveCollections = 0; var gameTime = 0; var targetScore = 10000; var currentLives = 3; var maxLives = 3; var lifeRegenTimer = 0; var lifeRegenInterval = 30000; // 30 seconds var spawnRateIncrease = 1; // Track spawn rate multiplier for endless mode // Pickaxe var pickaxe = new Pickaxe(); game.addChild(pickaxe); // Menu elements var menuContainer; var titleText; var menuButtons = []; // Difficulty configurations var difficultySettings = { easy: { name: 'Easy', targetScore: 8000, pointMultiplier: 1, spawnRateMultiplier: 1.5, durationMultiplier: 1.5, lives: 5 }, normal: { name: 'Normal', targetScore: 15000, pointMultiplier: 1, spawnRateMultiplier: 1, durationMultiplier: 1, lives: 3 }, hard: { name: 'Hard', targetScore: 30000, pointMultiplier: 1, spawnRateMultiplier: 0.7, durationMultiplier: 0.8, lives: 2 }, endless: { name: 'Endless', targetScore: -1, // No target score for endless pointMultiplier: 1, spawnRateMultiplier: 0.85, durationMultiplier: 0.9, lives: 5 } }; // Base mineral type definitions (will be modified by difficulty) var baseMineralTypes = { coal: { points: 10, duration: 5000, spawnRate: 2500, rarity: 1 }, copper: { points: 20, duration: 5000, spawnRate: 3000, rarity: 1 }, iron: { points: 50, duration: 4000, spawnRate: 6000, rarity: 2 }, silver: { points: 80, duration: 4000, spawnRate: 7000, rarity: 2 }, gold: { points: 200, duration: 3000, spawnRate: 12000, rarity: 3 }, emerald: { points: 300, duration: 3000, spawnRate: 15000, rarity: 3 }, diamond: { points: 800, duration: 2000, spawnRate: 25000, rarity: 4 }, ruby: { points: 1000, duration: 2000, spawnRate: 30000, rarity: 4 } }; // Current mineral types (adjusted for difficulty) var mineralTypes = {}; var mineralTypeArray = Object.keys(mineralTypes); // Spawn timers for each mineral type var spawnTimers = {}; for (var i = 0; i < mineralTypeArray.length; i++) { var type = mineralTypeArray[i]; spawnTimers[type] = 0; } // UI Elements var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var multiplierTxt = new Text2('x1.0', { size: 60, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 2 }); multiplierTxt.anchor.set(1, 0); multiplierTxt.x = -20; multiplierTxt.y = 20; LK.gui.topRight.addChild(multiplierTxt); var targetTxt = new Text2('Target: ' + targetScore, { size: 50, fill: 0x00FF00, stroke: 0x000000, strokeThickness: 2 }); targetTxt.anchor.set(0, 0); targetTxt.x = 120; targetTxt.y = 20; LK.gui.topLeft.addChild(targetTxt); var livesTxt = new Text2('Lives: ' + currentLives, { size: 50, fill: 0xFF0000, stroke: 0x000000, strokeThickness: 2 }); livesTxt.anchor.set(0, 0); livesTxt.x = 120; livesTxt.y = 80; LK.gui.topLeft.addChild(livesTxt); function spawnMineral(type) { var mineral = new Mineral(type); // Random position with margin from edges var margin = 100; mineral.x = margin + Math.random() * (2048 - 2 * margin); mineral.y = margin + Math.random() * (2732 - 2 * margin); // Ensure it doesn't overlap with existing minerals too much and avoid UI areas var attempts = 0; while (attempts < 10) { var tooClose = false; var inUIArea = false; // Check if mineral overlaps with UI areas // Top-left pause button area (expanded to 200x200 for safety) if (mineral.x < 200 && mineral.y < 200) { inUIArea = true; } // Top score area (center top) if (mineral.x > 700 && mineral.x < 1348 && mineral.y < 150) { inUIArea = true; } // Top-right multiplier area (expanded) if (mineral.x > 1700 && mineral.y < 150) { inUIArea = true; } // Top-left counters area (target score and lives) if (mineral.x < 500 && mineral.y < 200) { inUIArea = true; } // Check distance from existing minerals for (var i = 0; i < minerals.length; i++) { var existingMineral = minerals[i]; var dx = mineral.x - existingMineral.x; var dy = mineral.y - existingMineral.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 200) { tooClose = true; break; } } if (!tooClose && !inUIArea) break; mineral.x = margin + Math.random() * (2048 - 2 * margin); mineral.y = margin + Math.random() * (2732 - 2 * margin); attempts++; } minerals.push(mineral); game.addChild(mineral); // Spawn animation mineral.scaleX = 0; mineral.scaleY = 0; tween(mineral, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } function createMenu() { menuContainer = new Container(); game.addChild(menuContainer); // Title titleText = new Text2('Crystal Rush Miner', { size: 120, fill: 0x00CCFF, stroke: 0x000000, strokeThickness: 4 }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 600; menuContainer.addChild(titleText); // Subtitle var subtitleText = new Text2('Select Difficulty', { size: 80, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 750; menuContainer.addChild(subtitleText); // Create difficulty buttons var buttonY = 1000; var buttonSpacing = 450; var easyBtn = new MenuButton('Easy\n8,000 pts', 'easy', 1024 - buttonSpacing * 1.5, buttonY); var normalBtn = new MenuButton('Normal\n15,000 pts', 'normal', 1024 - buttonSpacing * 0.5, buttonY); var hardBtn = new MenuButton('Hard\n30,000 pts', 'hard', 1024 + buttonSpacing * 0.5, buttonY); var endlessBtn = new MenuButton('Endless\nNo Limit', 'endless', 1024 + buttonSpacing * 1.5, buttonY); menuButtons.push(easyBtn, normalBtn, hardBtn, endlessBtn); menuContainer.addChild(easyBtn); menuContainer.addChild(normalBtn); menuContainer.addChild(hardBtn); menuContainer.addChild(endlessBtn); // Add instruction text below buttons var instructionText = new Text2('Tap the ores to mine them', { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3 }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 1024; instructionText.y = buttonY + 200; menuContainer.addChild(instructionText); } function startGameWithDifficulty(difficulty) { currentDifficulty = difficulty; gameState = 'playing'; // Hide menu if (menuContainer) { menuContainer.visible = false; } // Apply difficulty settings var settings = difficultySettings[difficulty]; targetScore = settings.targetScore; // Scale mineral types based on difficulty mineralTypes = {}; var baseTypes = Object.keys(baseMineralTypes); for (var i = 0; i < baseTypes.length; i++) { var type = baseTypes[i]; var base = baseMineralTypes[type]; mineralTypes[type] = { points: Math.floor(base.points * settings.pointMultiplier), duration: Math.floor(base.duration * settings.durationMultiplier), spawnRate: Math.floor(base.spawnRate * settings.spawnRateMultiplier), rarity: base.rarity }; } // Reset game variables minerals = []; scoreMultiplier = 1; consecutiveCollections = 0; gameTime = 0; currentLives = settings.lives; maxLives = settings.lives; lifeRegenTimer = 0; spawnRateIncrease = 1; // Reset spawn rate multiplier LK.setScore(0); // Initialize spawn timers mineralTypeArray = Object.keys(mineralTypes); spawnTimers = {}; for (var i = 0; i < mineralTypeArray.length; i++) { var type = mineralTypeArray[i]; spawnTimers[type] = 0; } // Update UI updateScoreDisplay(); // Start background music LK.playMusic('mining_ambient'); } function updateScoreDisplay() { scoreTxt.setText('Score: ' + LK.getScore()); multiplierTxt.setText('x' + scoreMultiplier.toFixed(1)); livesTxt.setText('Lives: ' + currentLives); // Update target display based on difficulty if (currentDifficulty === 'endless') { targetTxt.setText('Mode: Endless'); } else { targetTxt.setText('Target: ' + targetScore); } // Check win condition (only for non-endless modes) if (currentDifficulty !== 'endless' && LK.getScore() >= targetScore) { LK.showYouWin(); } } // Touch/Mouse movement handler game.move = function (x, y, obj) { if (gameState === 'playing' && pickaxe) { pickaxe.setTarget(x, y); } }; // Touch/Mouse down handler game.down = function (x, y, obj) { if (gameState === 'playing' && pickaxe) { pickaxe.setTarget(x, y); } }; // Initialize menu createMenu(); game.update = function () { // Only update game logic when playing if (gameState !== 'playing') return; gameTime += 16.67; // Roughly 60 FPS // Update spawn timers and spawn minerals for (var i = 0; i < mineralTypeArray.length; i++) { var type = mineralTypeArray[i]; var mineralData = mineralTypes[type]; spawnTimers[type] += 16.67; // Apply spawn rate increase for endless mode var effectiveSpawnRate = mineralData.spawnRate; if (currentDifficulty === 'endless') { effectiveSpawnRate = mineralData.spawnRate / spawnRateIncrease; } if (spawnTimers[type] >= effectiveSpawnRate) { spawnTimers[type] = 0; spawnMineral(type); } } // Gradually decrease multiplier if no collections for a while if (consecutiveCollections === 0 && gameTime % 3000 < 16.67) { scoreMultiplier = Math.max(scoreMultiplier - 0.1, 1); updateScoreDisplay(); } // Life regeneration for endless mode if (currentDifficulty === 'endless') { lifeRegenTimer += 16.67; if (lifeRegenTimer >= lifeRegenInterval && currentLives < maxLives) { currentLives++; lifeRegenTimer = 0; updateScoreDisplay(); // Flash the lives text green to indicate regeneration tween(livesTxt, { tint: 0x00FF00 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(livesTxt, { tint: 0xFFFFFF }, { duration: 200, easing: tween.easeInOut }); } }); } // Increase spawn rate over time in endless mode (every 30 seconds) if (gameTime % 30000 < 16.67) { spawnRateIncrease = Math.min(spawnRateIncrease + 0.1, 3); // Cap at 3x spawn rate } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var MenuButton = Container.expand(function (text, difficulty, x, y) {
var self = Container.call(this);
self.difficulty = difficulty;
// Create button background with difficulty-specific asset
var buttonAsset = 'button_' + difficulty;
var buttonBg = self.attachAsset(buttonAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1.5
});
// Create button text
var buttonText = new Text2(text, {
size: 60,
fill: 0x000000,
stroke: 0x000000,
strokeThickness: 2
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
// Position button
self.x = x;
self.y = y;
// Button press handler
self.down = function (x, y, obj) {
// Visual feedback
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Start game with selected difficulty
startGameWithDifficulty(self.difficulty);
};
return self;
});
var Mineral = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.mineralData = mineralTypes[type];
var mineralGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize properties
self.timeLeft = self.mineralData.duration;
self.maxTime = self.mineralData.duration;
self.isCollected = false;
self.hasLostLife = false;
// Add sparkle effect for rare minerals
if (self.mineralData.rarity >= 3) {
tween(mineralGraphics, {
alpha: 0.7
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(mineralGraphics, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
}
self.update = function () {
if (self.isCollected) return;
self.timeLeft -= 16.67; // Roughly 60 FPS
// Flash when time is running out
if (self.timeLeft < 1000) {
var flashAlpha = Math.sin(LK.ticks * 0.5) * 0.3 + 0.7;
mineralGraphics.alpha = flashAlpha;
}
// Remove when time expires
if (self.timeLeft <= 0) {
self.expire();
}
};
self.collect = function () {
if (self.isCollected) return;
self.isCollected = true;
// Add score
var points = self.mineralData.points * scoreMultiplier;
LK.setScore(LK.getScore() + points);
// Increase multiplier
scoreMultiplier = Math.min(scoreMultiplier + 0.1, 5);
consecutiveCollections++;
// Play sound
LK.getSound('mine').play();
// Animation
tween(mineralGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
// Remove from minerals array
for (var i = minerals.length - 1; i >= 0; i--) {
if (minerals[i] === self) {
minerals.splice(i, 1);
break;
}
}
// Update UI
updateScoreDisplay();
};
self.expire = function () {
// Only lose life if we haven't already lost one for this mineral
if (!self.hasLostLife) {
// Reset multiplier on missed mineral
scoreMultiplier = 1;
consecutiveCollections = 0;
// Lose a life
currentLives--;
self.hasLostLife = true;
updateScoreDisplay();
// Check game over
if (currentLives <= 0) {
LK.showGameOver();
return;
}
}
// Fade out animation
tween(mineralGraphics, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 200,
onFinish: function onFinish() {
self.destroy();
}
});
// Remove from minerals array
for (var i = minerals.length - 1; i >= 0; i--) {
if (minerals[i] === self) {
minerals.splice(i, 1);
break;
}
}
};
self.down = function (x, y, obj) {
self.collect();
};
return self;
});
var Pickaxe = Container.expand(function () {
var self = Container.call(this);
var pickaxeGraphics = self.attachAsset('pickaxe', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize position
self.targetX = 1024;
self.targetY = 1366;
self.x = self.targetX;
self.y = self.targetY;
// Smooth following properties
self.followSpeed = 0.15;
self.update = function () {
// Smooth movement towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
self.x += dx * self.followSpeed;
self.y += dy * self.followSpeed;
// Add subtle swaying animation
var sway = Math.sin(LK.ticks * 0.05) * 2;
pickaxeGraphics.rotation = sway * 0.1;
};
self.setTarget = function (x, y) {
self.targetX = x;
self.targetY = y;
// Add a little shake effect when moving to new position
tween(pickaxeGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pickaxeGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Add mining background
var backgroundImage = game.attachAsset('mining_background', {
x: 0,
y: 0,
anchorX: 0,
anchorY: 0
});
// Game state
var gameState = 'menu'; // 'menu' or 'playing'
var currentDifficulty = 'normal';
// Game variables
var minerals = [];
var scoreMultiplier = 1;
var consecutiveCollections = 0;
var gameTime = 0;
var targetScore = 10000;
var currentLives = 3;
var maxLives = 3;
var lifeRegenTimer = 0;
var lifeRegenInterval = 30000; // 30 seconds
var spawnRateIncrease = 1; // Track spawn rate multiplier for endless mode
// Pickaxe
var pickaxe = new Pickaxe();
game.addChild(pickaxe);
// Menu elements
var menuContainer;
var titleText;
var menuButtons = [];
// Difficulty configurations
var difficultySettings = {
easy: {
name: 'Easy',
targetScore: 8000,
pointMultiplier: 1,
spawnRateMultiplier: 1.5,
durationMultiplier: 1.5,
lives: 5
},
normal: {
name: 'Normal',
targetScore: 15000,
pointMultiplier: 1,
spawnRateMultiplier: 1,
durationMultiplier: 1,
lives: 3
},
hard: {
name: 'Hard',
targetScore: 30000,
pointMultiplier: 1,
spawnRateMultiplier: 0.7,
durationMultiplier: 0.8,
lives: 2
},
endless: {
name: 'Endless',
targetScore: -1,
// No target score for endless
pointMultiplier: 1,
spawnRateMultiplier: 0.85,
durationMultiplier: 0.9,
lives: 5
}
};
// Base mineral type definitions (will be modified by difficulty)
var baseMineralTypes = {
coal: {
points: 10,
duration: 5000,
spawnRate: 2500,
rarity: 1
},
copper: {
points: 20,
duration: 5000,
spawnRate: 3000,
rarity: 1
},
iron: {
points: 50,
duration: 4000,
spawnRate: 6000,
rarity: 2
},
silver: {
points: 80,
duration: 4000,
spawnRate: 7000,
rarity: 2
},
gold: {
points: 200,
duration: 3000,
spawnRate: 12000,
rarity: 3
},
emerald: {
points: 300,
duration: 3000,
spawnRate: 15000,
rarity: 3
},
diamond: {
points: 800,
duration: 2000,
spawnRate: 25000,
rarity: 4
},
ruby: {
points: 1000,
duration: 2000,
spawnRate: 30000,
rarity: 4
}
};
// Current mineral types (adjusted for difficulty)
var mineralTypes = {};
var mineralTypeArray = Object.keys(mineralTypes);
// Spawn timers for each mineral type
var spawnTimers = {};
for (var i = 0; i < mineralTypeArray.length; i++) {
var type = mineralTypeArray[i];
spawnTimers[type] = 0;
}
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var multiplierTxt = new Text2('x1.0', {
size: 60,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 2
});
multiplierTxt.anchor.set(1, 0);
multiplierTxt.x = -20;
multiplierTxt.y = 20;
LK.gui.topRight.addChild(multiplierTxt);
var targetTxt = new Text2('Target: ' + targetScore, {
size: 50,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 2
});
targetTxt.anchor.set(0, 0);
targetTxt.x = 120;
targetTxt.y = 20;
LK.gui.topLeft.addChild(targetTxt);
var livesTxt = new Text2('Lives: ' + currentLives, {
size: 50,
fill: 0xFF0000,
stroke: 0x000000,
strokeThickness: 2
});
livesTxt.anchor.set(0, 0);
livesTxt.x = 120;
livesTxt.y = 80;
LK.gui.topLeft.addChild(livesTxt);
function spawnMineral(type) {
var mineral = new Mineral(type);
// Random position with margin from edges
var margin = 100;
mineral.x = margin + Math.random() * (2048 - 2 * margin);
mineral.y = margin + Math.random() * (2732 - 2 * margin);
// Ensure it doesn't overlap with existing minerals too much and avoid UI areas
var attempts = 0;
while (attempts < 10) {
var tooClose = false;
var inUIArea = false;
// Check if mineral overlaps with UI areas
// Top-left pause button area (expanded to 200x200 for safety)
if (mineral.x < 200 && mineral.y < 200) {
inUIArea = true;
}
// Top score area (center top)
if (mineral.x > 700 && mineral.x < 1348 && mineral.y < 150) {
inUIArea = true;
}
// Top-right multiplier area (expanded)
if (mineral.x > 1700 && mineral.y < 150) {
inUIArea = true;
}
// Top-left counters area (target score and lives)
if (mineral.x < 500 && mineral.y < 200) {
inUIArea = true;
}
// Check distance from existing minerals
for (var i = 0; i < minerals.length; i++) {
var existingMineral = minerals[i];
var dx = mineral.x - existingMineral.x;
var dy = mineral.y - existingMineral.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
tooClose = true;
break;
}
}
if (!tooClose && !inUIArea) break;
mineral.x = margin + Math.random() * (2048 - 2 * margin);
mineral.y = margin + Math.random() * (2732 - 2 * margin);
attempts++;
}
minerals.push(mineral);
game.addChild(mineral);
// Spawn animation
mineral.scaleX = 0;
mineral.scaleY = 0;
tween(mineral, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
function createMenu() {
menuContainer = new Container();
game.addChild(menuContainer);
// Title
titleText = new Text2('Crystal Rush Miner', {
size: 120,
fill: 0x00CCFF,
stroke: 0x000000,
strokeThickness: 4
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 600;
menuContainer.addChild(titleText);
// Subtitle
var subtitleText = new Text2('Select Difficulty', {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 750;
menuContainer.addChild(subtitleText);
// Create difficulty buttons
var buttonY = 1000;
var buttonSpacing = 450;
var easyBtn = new MenuButton('Easy\n8,000 pts', 'easy', 1024 - buttonSpacing * 1.5, buttonY);
var normalBtn = new MenuButton('Normal\n15,000 pts', 'normal', 1024 - buttonSpacing * 0.5, buttonY);
var hardBtn = new MenuButton('Hard\n30,000 pts', 'hard', 1024 + buttonSpacing * 0.5, buttonY);
var endlessBtn = new MenuButton('Endless\nNo Limit', 'endless', 1024 + buttonSpacing * 1.5, buttonY);
menuButtons.push(easyBtn, normalBtn, hardBtn, endlessBtn);
menuContainer.addChild(easyBtn);
menuContainer.addChild(normalBtn);
menuContainer.addChild(hardBtn);
menuContainer.addChild(endlessBtn);
// Add instruction text below buttons
var instructionText = new Text2('Tap the ores to mine them', {
size: 60,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 1024;
instructionText.y = buttonY + 200;
menuContainer.addChild(instructionText);
}
function startGameWithDifficulty(difficulty) {
currentDifficulty = difficulty;
gameState = 'playing';
// Hide menu
if (menuContainer) {
menuContainer.visible = false;
}
// Apply difficulty settings
var settings = difficultySettings[difficulty];
targetScore = settings.targetScore;
// Scale mineral types based on difficulty
mineralTypes = {};
var baseTypes = Object.keys(baseMineralTypes);
for (var i = 0; i < baseTypes.length; i++) {
var type = baseTypes[i];
var base = baseMineralTypes[type];
mineralTypes[type] = {
points: Math.floor(base.points * settings.pointMultiplier),
duration: Math.floor(base.duration * settings.durationMultiplier),
spawnRate: Math.floor(base.spawnRate * settings.spawnRateMultiplier),
rarity: base.rarity
};
}
// Reset game variables
minerals = [];
scoreMultiplier = 1;
consecutiveCollections = 0;
gameTime = 0;
currentLives = settings.lives;
maxLives = settings.lives;
lifeRegenTimer = 0;
spawnRateIncrease = 1; // Reset spawn rate multiplier
LK.setScore(0);
// Initialize spawn timers
mineralTypeArray = Object.keys(mineralTypes);
spawnTimers = {};
for (var i = 0; i < mineralTypeArray.length; i++) {
var type = mineralTypeArray[i];
spawnTimers[type] = 0;
}
// Update UI
updateScoreDisplay();
// Start background music
LK.playMusic('mining_ambient');
}
function updateScoreDisplay() {
scoreTxt.setText('Score: ' + LK.getScore());
multiplierTxt.setText('x' + scoreMultiplier.toFixed(1));
livesTxt.setText('Lives: ' + currentLives);
// Update target display based on difficulty
if (currentDifficulty === 'endless') {
targetTxt.setText('Mode: Endless');
} else {
targetTxt.setText('Target: ' + targetScore);
}
// Check win condition (only for non-endless modes)
if (currentDifficulty !== 'endless' && LK.getScore() >= targetScore) {
LK.showYouWin();
}
}
// Touch/Mouse movement handler
game.move = function (x, y, obj) {
if (gameState === 'playing' && pickaxe) {
pickaxe.setTarget(x, y);
}
};
// Touch/Mouse down handler
game.down = function (x, y, obj) {
if (gameState === 'playing' && pickaxe) {
pickaxe.setTarget(x, y);
}
};
// Initialize menu
createMenu();
game.update = function () {
// Only update game logic when playing
if (gameState !== 'playing') return;
gameTime += 16.67; // Roughly 60 FPS
// Update spawn timers and spawn minerals
for (var i = 0; i < mineralTypeArray.length; i++) {
var type = mineralTypeArray[i];
var mineralData = mineralTypes[type];
spawnTimers[type] += 16.67;
// Apply spawn rate increase for endless mode
var effectiveSpawnRate = mineralData.spawnRate;
if (currentDifficulty === 'endless') {
effectiveSpawnRate = mineralData.spawnRate / spawnRateIncrease;
}
if (spawnTimers[type] >= effectiveSpawnRate) {
spawnTimers[type] = 0;
spawnMineral(type);
}
}
// Gradually decrease multiplier if no collections for a while
if (consecutiveCollections === 0 && gameTime % 3000 < 16.67) {
scoreMultiplier = Math.max(scoreMultiplier - 0.1, 1);
updateScoreDisplay();
}
// Life regeneration for endless mode
if (currentDifficulty === 'endless') {
lifeRegenTimer += 16.67;
if (lifeRegenTimer >= lifeRegenInterval && currentLives < maxLives) {
currentLives++;
lifeRegenTimer = 0;
updateScoreDisplay();
// Flash the lives text green to indicate regeneration
tween(livesTxt, {
tint: 0x00FF00
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(livesTxt, {
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeInOut
});
}
});
}
// Increase spawn rate over time in endless mode (every 30 seconds)
if (gameTime % 30000 < 16.67) {
spawnRateIncrease = Math.min(spawnRateIncrease + 0.1, 3); // Cap at 3x spawn rate
}
}
};