User prompt
pickaxe asseti sol mouse ile tetiklendiğinde light_beam asseti görsel olarak gelsin. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add down event handler to pickaxe for red barcode scanning effect like red beam form left side ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pickaxe asseti sol mouse ile tetiklendiğinde kırmızı barkod okuma efekti oluşsun. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
**Divide screen into 3 vertical sections:** - Top section: Y 0 to 911 pixels (1/3) - Middle section: Y 911 to 1821 pixels (1/3) - Bottom section: Y 1821 to 2732 pixels (1/3) **New spawn area would be:** - X: Keep current (100 to 1948 pixels) - Y: 911 to 2632 pixels (middle + bottom sections, with bottom margin)
User prompt
"pickaxe" asseti sol mouse ile basıldığında, resmin sol üst tarafından kırmızı, geniş "v" şeklinde ışık çıkma efekti istiyorum. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
"pickaxe" asseti sol mouse ile basıldığında, resmin sol ucundan beyaz ışık püskürmesini istiyorum. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pickaxe asseti sol mouse ile tetiklenip ateş ettiğinde, pickaxe assetden okuma yapıldığını gösterecek kırmızı ışık hüzmesi çıksın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pickaxe asseti sol mouse ile tetiklennip ateş ettiğinde, pickaxe assetinin sol üst köşesinden lazer hüzmesi çıksın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add laser beam asset initialization ✅ Create LaserBeam class for horizontal red laser effects ✅ Add laser beam from pickaxe left corner ✅ Add laser firing on left mouse press in game down handler ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
sol mouse ile basıldığında pickaxe sol üst köşeden yatay kırmızı lazer hüzmesi çıksın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pickaxe tetiklendiğinde sol üst köşeden kırmızı ışın haresi çıksın. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Move button Y position from 1366 to 1158 to center buttons vertically on screen ✅ Update instruction text Y position to maintain spacing below centered buttons
User prompt
ana açılış ekranında bulunan çekik görselini butonların altına konumla.
User prompt
pickaxe assetini de butonların altına gelecek şekilde konumla.
User prompt
1. **Adjust the vertical positioning**: Move the `buttonY` variable from 1000 to around 1366 (which is the vertical center of the 2732px tall screen) 2. **Keep the horizontal spacing**: The current horizontal positioning is already centered around x=1024, so the button spacing of 450 pixels works well 3. **Update the instruction text position**: The instruction text below the buttons would also need to move down accordingly to maintain proper spacing The specific changes would be: - Change `buttonY` from 1000 to approximately 1366 (screen center) - Adjust the instruction text Y position from `buttonY + 200` to maintain the same relative spacing
Remix started
Copy Crystal Rush Miner
/**** * 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
}
}
};