/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Claw class var Claw = Container.expand(function () { var self = Container.call(this); // Arm var arm = self.attachAsset('clawArm', { anchorX: 0.5, anchorY: 0, x: 0, y: 0 }); // Claw head var head = self.attachAsset('clawHead', { anchorX: 0.5, anchorY: 0, x: 0, y: arm.height }); // State self.swingAngle = 0; // in radians self.swingDir = 1; // 1 or -1 self.swingSpeed = 0.025; // radians per tick self.swingMax = Math.PI / 3; // 60 deg left/right self.state = 'swing'; // 'swing', 'extend', 'retract', 'grabbed' self.length = arm.height; // current arm length self.baseLength = arm.height; self.maxLength = GAME_HEIGHT - 100; // how far the claw can extend (let rope go to bottom) self.speed = 32; // pixels per tick when extending self.retractSpeed = 32; // default retract speed self.grabbedObj = null; // reference to grabbed object // Update arm and head positions based on length and angle self.updateClaw = function () { var dx = Math.sin(self.swingAngle) * self.length; var dy = Math.cos(self.swingAngle) * self.length; arm.rotation = -self.swingAngle; arm.height = self.length; head.x = dx; head.y = dy; head.rotation = -self.swingAngle; if (self.grabbedObj) { self.grabbedObj.x = self.x + dx; self.grabbedObj.y = self.y + dy + head.height / 2; } }; // Called every tick self.update = function () { if (self.state === 'swing') { self.swingAngle += self.swingDir * self.swingSpeed; if (self.swingAngle > self.swingMax) { self.swingAngle = self.swingMax; self.swingDir = -1; } if (self.swingAngle < -self.swingMax) { self.swingAngle = -self.swingMax; self.swingDir = 1; } } else if (self.state === 'extend') { self.length += self.speed; if (self.length >= self.maxLength) { self.length = self.maxLength; self.state = 'retract'; } } else if (self.state === 'retract') { self.length -= self.retractSpeed; if (self.length <= self.baseLength) { self.length = self.baseLength; self.state = 'swing'; if (self.grabbedObj) { // Drop object at top self.grabbedObj.onCollected(); self.grabbedObj = null; } } } else if (self.state === 'grabbed') { // Wait for retract to finish self.length -= self.retractSpeed; if (self.length <= self.baseLength) { self.length = self.baseLength; self.state = 'swing'; if (self.grabbedObj) { self.grabbedObj.onCollected(); self.grabbedObj = null; } } } self.updateClaw(); }; // Start extending self.startExtend = function () { if (self.state === 'swing') { self.state = 'extend'; // Bag remains on the hook; do not remove it when extending } }; // Called when an object is grabbed self.grabObject = function (obj) { self.grabbedObj = obj; self.state = 'grabbed'; // Set retract speed based on object type self.retractSpeed = obj.retractSpeed; }; // Called when nothing is grabbed (hit ground) self.miss = function () { self.state = 'retract'; self.retractSpeed = 64; //{L} // Faster retract when empty }; return self; }); // Moving Target class var Target = Container.expand(function () { var self = Container.call(this); // Draw as a different asset (targetBox image asset) var boxAsset = self.attachAsset('targetBox', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); // Optionally, you can adjust scaleX/scaleY if you want it smaller/larger self.value = 2; self.speed = 8; // medium speed self.direction = 1; // 1 = right, -1 = left self.y = GROUND_Y - 100; self.x = 400; self.lastX = self.x; self.update = function () { // Move horizontally self.x += self.speed * self.direction; if (self.lastX <= GAME_WIDTH - 200 && self.x > GAME_WIDTH - 200 || self.lastX >= 200 && self.x < 200) { self.direction *= -1; } // Clamp position if (self.x > GAME_WIDTH - 200) self.x = GAME_WIDTH - 200; if (self.x < 200) self.x = 200; self.lastX = self.x; }; // Add a no-op onCollected method to prevent errors if called by Claw self.onCollected = function () { // No-op for moving target }; return self; }); // Base class for all underground objects var UndergroundObject = Container.expand(function () { var self = Container.call(this); self.value = 0; self.retractSpeed = 32; self.grabSound = 'grab'; self.collectedSound = 'collect'; self.collected = false; // Called when collected self.onCollected = function () { if (self.collected) return; self.collected = true; // Play money sound when pulling up captured objects LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); if (typeof score !== 'undefined') { score += self.value; LK.setScore(score); if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score); } self.destroy(); }; return self; }); // Rock var Rock = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var rock = self.attachAsset('rock', { anchorX: 0.5, anchorY: 0.5 }); self.value = 50; self.retractSpeed = 6; // very slow self.grabSound = 'rockhit'; self.collectedSound = 'rockhit'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); self.destroy(); }; return self; }); // Pig var Pig = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var pig = self.attachAsset('pig', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1200; self.retractSpeed = 20; // medium-fast self.grabSound = 'grab'; self.collectedSound = 'collect'; self.onCollected = function () { if (self.collected) return; self.collected = true; // Play explosion sound and flash screen like dynamite LK.getSound('dynamite').play(); LK.effects.flashScreen(0xff0000, 800); // Remove some score as penalty (like dynamite, but you can adjust penalty if desired) score = Math.max(0, score - 400); LK.setScore(score); if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); // Explode nearby pigs if (typeof objects !== "undefined" && Array.isArray(objects)) { for (var i = 0; i < objects.length; i++) { var obj = objects[i]; if (obj === self) continue; if (obj && obj.visible !== false && obj instanceof Pig && !obj.collected) { // Distance between pigs var dx = obj.x - self.x; var dy = obj.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 250) { // 250px radius for explosion obj.onCollected(); } } } } self.destroy(); }; return self; }); // Small gold nugget var GoldSmall = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var gold = self.attachAsset('goldSmall', { anchorX: 0.5, anchorY: 0.5 }); self.value = 250; self.retractSpeed = 24; // medium self.grabSound = 'grab'; self.collectedSound = 'collect'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); self.destroy(); }; return self; }); // Gold nugget var Gold = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var gold = self.attachAsset('gold', { anchorX: 0.5, anchorY: 0.5 }); self.value = 500; self.retractSpeed = 8; // slower self.grabSound = 'grab'; self.collectedSound = 'collect'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); self.destroy(); }; return self; }); // Gem var Gem = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var gem = self.attachAsset('gem', { anchorX: 0.5, anchorY: 0.5 }); self.value = 800; self.retractSpeed = 32; // fast self.grabSound = 'grab'; self.collectedSound = 'collect'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); self.destroy(); }; return self; }); // Dynamite trap var Dynamite = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var dynamite = self.attachAsset('dynamite', { anchorX: 0.5, anchorY: 0.5 }); self.value = 0; self.retractSpeed = 40; // fast retract self.grabSound = 'dynamite'; self.collectedSound = 'dynamite'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound(self.collectedSound).play(); // Flash screen red to indicate explosion LK.effects.flashScreen(0xff0000, 800); // Remove some score as penalty score = Math.max(0, score - 400); LK.setScore(score); if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score); self.visible = false; self.destroy(); }; return self; }); // Bag (Torba) var Bag = UndergroundObject.expand(function () { var self = UndergroundObject.call(this); var bag = self.attachAsset('torba', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1000; self.retractSpeed = 18; // medium-slow self.grabSound = 'grab'; self.collectedSound = 'collect'; self.onCollected = function () { if (self.collected) return; self.collected = true; LK.getSound('money').play(); self.visible = false; if (typeof self.onScore === 'function') self.onScore(); self.destroy(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8B5A2B // brown }); /**** * Game Code ****/ // Game constants // Claw arm (rectangle) // Claw head (ellipse) // Gold nugget (ellipse) // Small gold nugget // Rock (ellipse) // Gem (ellipse) // Sound for grabbing // Sound for collecting // Sound for hitting rock // Music var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var GROUND_Y = 700; // y position where underground objects start var LEVEL_TIME = 60; // seconds var LEVEL_GOAL = 1500; // gold needed to win // Level and difficulty progression var level = 1; var maxLevel = 10; var objects = []; var claw = null; var score = 0; var timer = 0; var timeLeft = LEVEL_TIME; var goal = LEVEL_GOAL; var gameActive = true; // Add multiple moving targets var targets = []; // GUI // Level text (very small, upper right corner) var levelTxt = new Text2('Level ' + level, { size: 40, fill: "#fff" }); levelTxt.anchor.set(1, 0); // right-top levelTxt.x = -8; // 8px from the right edge of gui.topRight levelTxt.y = 0; LK.gui.topRight.addChild(levelTxt); // Goal text (very small, just above the score number) var goalTxt = new Text2('Goal: ' + goal, { size: 32, fill: "#fff" }); goalTxt.anchor.set(1, 0); // right-top goalTxt.x = levelTxt.x - levelTxt.width - 16; // align with score goalTxt.y = 0; // align to top since dollars label is removed LK.gui.topRight.addChild(goalTxt); // Score text (small, right next to level text, to the left) var scoreTxt = new Text2('0', { size: 40, fill: "#fff" }); scoreTxt.anchor.set(1, 0); // right-top scoreTxt.x = levelTxt.x - levelTxt.width - 16; // 16px padding between score and level scoreTxt.y = goalTxt.y + goalTxt.height + 2; // just below goal text LK.gui.topRight.addChild(scoreTxt); // Countdown timer text (small, just below level text) var countdownTxt = new Text2(timeLeft + 's', { size: 32, fill: "#fff" }); countdownTxt.anchor.set(1, 0); // right-top countdownTxt.x = levelTxt.x; countdownTxt.y = levelTxt.height + 4; // 4px below level text LK.gui.topRight.addChild(countdownTxt); // Timer interval to update countdown var countdownInterval = LK.setInterval(function () { if (!gameActive) return; timeLeft--; if (timeLeft < 0) timeLeft = 0; countdownTxt.setText(timeLeft + 's'); if (timeLeft === 0 && gameActive) { gameActive = false; LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } }, 1000); // Place claw at top center claw = new Claw(); claw.x = GAME_WIDTH / 2; claw.y = 0; game.addChild(claw); // (Bag is not attached to the hook) // Underground object spawn positions function spawnObjects() { // Clear previous for (var i = 0; i < objects.length; i++) { objects[i].destroy(); } objects = []; // Difficulty scaling var bigGoldCount = 4 + Math.floor(level / 2); var smallGoldCount = 6 + level; var rockCount = 6 + level * 2; var gemCount = 3 + Math.floor(level / 2); var dynamiteCount = 2 + Math.floor(level / 2); // Create all objects in order: gold, diamonds, dynamite, rocks, bags, pigs, then mix var allObjs = []; // Gold (big) for (var i = 0; i < bigGoldCount; i++) { var g = new Gold(); g.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(g); } // Gold (small) for (var i = 0; i < smallGoldCount; i++) { var gs = new GoldSmall(); gs.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(gs); } // Gems for (var i = 0; i < gemCount; i++) { var gem = new Gem(); gem.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(gem); } // Bags (torba) var bagCount = 2 + Math.floor(level / 2); for (var i = 0; i < bagCount; i++) { var bag = new Bag(); bag.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(bag); } // Pigs var pigCount = 2 + Math.floor(level / 2); for (var i = 0; i < pigCount; i++) { var pig = new Pig(); pig.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(pig); } // Dynamite for (var i = 0; i < dynamiteCount; i++) { var d = new Dynamite(); allObjs.push(d); } // Rocks for (var i = 0; i < rockCount; i++) { var r = new Rock(); r.onScore = function () { score += this.value; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); }; allObjs.push(r); } // Shuffle allObjs array for (var i = allObjs.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = allObjs[i]; allObjs[i] = allObjs[j]; allObjs[j] = temp; } // Place objects in the play area, avoiding overlap var gridCols = 8; var gridRows = Math.ceil(allObjs.length / gridCols); var cellW = Math.floor((GAME_WIDTH - 400) / gridCols); var cellH = Math.floor((GAME_HEIGHT - GROUND_Y - 400) / gridRows); var usedCells = []; for (var i = 0; i < allObjs.length; i++) { var obj = allObjs[i]; // Find a free cell var placed = false; var attempts = 0; while (!placed && attempts < 30) { var col = Math.floor(Math.random() * gridCols); var row = Math.floor(Math.random() * gridRows); var cellIdx = row * gridCols + col; if (usedCells.indexOf(cellIdx) === -1) { usedCells.push(cellIdx); obj.x = 200 + col * cellW + Math.floor(cellW / 2); obj.y = GROUND_Y + 200 + row * cellH + Math.floor(cellH / 2); placed = true; } attempts++; } game.addChild(obj); objects.push(obj); } } spawnObjects(); // Create and add multiple moving targets at specific parts of the screen // Destroy old targets if any if (targets && targets.length) { for (var i = 0; i < targets.length; i++) { if (targets[i]) targets[i].destroy(); } } targets = []; // Place fewer moving targets at the top, and more in the middle section var targetPositions = [ // Only one at the top left { x: 300, y: GROUND_Y + 100 }, // Add more to the middle section { x: 600, y: GROUND_Y + 400 }, { x: GAME_WIDTH - 600, y: GROUND_Y + 400 }, { x: 400, y: GROUND_Y + 700 }, { x: GAME_WIDTH - 400, y: GROUND_Y + 700 }, { x: GAME_WIDTH / 2, y: GROUND_Y + 900 }]; for (var i = 0; i < targetPositions.length; i++) { var t = new Target(); t.x = targetPositions[i].x; t.y = targetPositions[i].y; t.direction = i % 2 === 0 ? 1 : -1; targets.push(t); game.addChild(t); } // Add moving TL objects to the top left of the screen var tlObjects = []; var tlCount = 2; // Number of TL objects to add/move for (var i = 0; i < tlCount; i++) { var tl = new Container(); var tlImg = tl.attachAsset('TL', { anchorX: 0.5, anchorY: 0.5 }); tl.x = 120 + i * 120; // Space out horizontally, keep away from top left 100x100 tl.y = 120; tl.speed = 6 + Math.floor(Math.random() * 4); tl.direction = Math.random() < 0.5 ? 1 : -1; tl.lastX = tl.x; tl.update = function () { if (typeof this.lastX !== "number") this.lastX = this.x; this.x += this.speed * this.direction; // Bounce at left/right margin (keep inside 120 to 400 px) if (this.lastX <= 120 && this.x > 120) this.direction = 1; if (this.lastX >= 400 && this.x < 400) this.direction = -1; if (this.x > 400) this.x = 400; if (this.x < 120) this.x = 120; this.lastX = this.x; }; tlObjects.push(tl); game.addChild(tl); } // Draw a dot at the top center to send the rope down var dropDot = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, x: GAME_WIDTH / 2, y: 80 }); game.addChild(dropDot); // Only trigger on dot press, not anywhere dropDot.down = function (x, y, obj) { if (!gameActive) return; if (claw.state === 'swing') { claw.startExtend(); } }; // Touch/click anywhere else does nothing game.down = function (x, y, obj) { // No-op, handled by dropDot }; // Main update loop game.update = function () { if (!gameActive) return; // Claw update handled in class // If claw is extending, check for collision with objects if (claw.state === 'extend') { // Get claw head position var dx = Math.sin(claw.swingAngle) * claw.length; var dy = Math.cos(claw.swingAngle) * claw.length; var cx = claw.x + dx; var cy = claw.y + dy + 30; // 30: half head height // Check for collision with any object var grabbed = false; for (var i = 0; i < objects.length; i++) { var obj = objects[i]; if (obj.collected) continue; // Simple circle collision var dist = Math.sqrt((obj.x - cx) * (obj.x - cx) + (obj.y - cy) * (obj.y - cy)); var r = 60; // approx radius if (dist < r + 40) { // If it's a pig, trigger explosion immediately and do not attach to claw if (obj instanceof Pig) { obj.onCollected(); grabbed = true; break; } // Grab object claw.grabObject(obj); // Dynamite handles penalty in its onCollected grabbed = true; break; } } // Check for collision with any moving target if not already grabbed something if (!grabbed && targets && targets.length) { for (var ti = 0; ti < targets.length; ti++) { var t = targets[ti]; if (!t.visible) continue; if (typeof t.x !== 'number' || typeof t.y !== 'number') continue; var tdist = Math.sqrt((t.x - cx) * (t.x - cx) + (t.y - cy) * (t.y - cy)); var tr = 100; // slightly larger radius for target if (tdist < tr) { // "Grab" the target: treat as a special object claw.grabbedObj = t; claw.state = 'grabbed'; claw.retractSpeed = 32; // Optionally, you can add a sound or effect here // Remove the target visually and respawn after a delay t.visible = false; (function (targetToRespawn) { LK.setTimeout(function () { if (targetToRespawn) { targetToRespawn.x = 400 + Math.floor(Math.random() * (GAME_WIDTH - 800)); targetToRespawn.y = GROUND_Y - 100 - Math.floor(Math.random() * 120); targetToRespawn.visible = true; } }, 2000); })(t); grabbed = true; break; } } } // If reached max length and nothing grabbed, retract if (claw.length >= claw.maxLength && claw.state === 'extend') { claw.miss(); } } // Win condition if (score >= goal && gameActive) { gameActive = false; LK.effects.flashScreen(0xffff00, 800); // Level up logic if (level < maxLevel) { level += 1; // Play level up sound LK.getSound('level').play(); // Increase goal and decrease time for next level goal = LEVEL_GOAL + level * 800; timeLeft = LEVEL_TIME - Math.min(level * 3, 30); // reduce time, but not below 30s score = 0; LK.setScore(score); if (scoreTxt) scoreTxt.setText(score); // Update level text if (levelTxt) levelTxt.setText('Level ' + level); // Update goal text if (goalTxt) goalTxt.setText('Goal: ' + goal); // Reset countdown timer text and timeLeft timeLeft = LEVEL_TIME - Math.min(level * 3, 30); if (countdownTxt) countdownTxt.setText(timeLeft + 's'); // Respawn objects for new level spawnObjects(); gameActive = true; } else { LK.showYouWin(); } } // Update all moving targets if (targets && targets.length) { for (var ti = 0; ti < targets.length; ti++) { if (targets[ti] && typeof targets[ti].update === 'function') { targets[ti].update(); } } } // Update all TL objects if (typeof tlObjects !== "undefined" && tlObjects.length) { for (var i = 0; i < tlObjects.length; i++) { if (tlObjects[i] && typeof tlObjects[i].update === "function") { tlObjects[i].update(); } } } }; // Play background music LK.playMusic('goldminerbg', { fade: { start: 0, end: 1, duration: 1000 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Claw class
var Claw = Container.expand(function () {
var self = Container.call(this);
// Arm
var arm = self.attachAsset('clawArm', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 0
});
// Claw head
var head = self.attachAsset('clawHead', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: arm.height
});
// State
self.swingAngle = 0; // in radians
self.swingDir = 1; // 1 or -1
self.swingSpeed = 0.025; // radians per tick
self.swingMax = Math.PI / 3; // 60 deg left/right
self.state = 'swing'; // 'swing', 'extend', 'retract', 'grabbed'
self.length = arm.height; // current arm length
self.baseLength = arm.height;
self.maxLength = GAME_HEIGHT - 100; // how far the claw can extend (let rope go to bottom)
self.speed = 32; // pixels per tick when extending
self.retractSpeed = 32; // default retract speed
self.grabbedObj = null; // reference to grabbed object
// Update arm and head positions based on length and angle
self.updateClaw = function () {
var dx = Math.sin(self.swingAngle) * self.length;
var dy = Math.cos(self.swingAngle) * self.length;
arm.rotation = -self.swingAngle;
arm.height = self.length;
head.x = dx;
head.y = dy;
head.rotation = -self.swingAngle;
if (self.grabbedObj) {
self.grabbedObj.x = self.x + dx;
self.grabbedObj.y = self.y + dy + head.height / 2;
}
};
// Called every tick
self.update = function () {
if (self.state === 'swing') {
self.swingAngle += self.swingDir * self.swingSpeed;
if (self.swingAngle > self.swingMax) {
self.swingAngle = self.swingMax;
self.swingDir = -1;
}
if (self.swingAngle < -self.swingMax) {
self.swingAngle = -self.swingMax;
self.swingDir = 1;
}
} else if (self.state === 'extend') {
self.length += self.speed;
if (self.length >= self.maxLength) {
self.length = self.maxLength;
self.state = 'retract';
}
} else if (self.state === 'retract') {
self.length -= self.retractSpeed;
if (self.length <= self.baseLength) {
self.length = self.baseLength;
self.state = 'swing';
if (self.grabbedObj) {
// Drop object at top
self.grabbedObj.onCollected();
self.grabbedObj = null;
}
}
} else if (self.state === 'grabbed') {
// Wait for retract to finish
self.length -= self.retractSpeed;
if (self.length <= self.baseLength) {
self.length = self.baseLength;
self.state = 'swing';
if (self.grabbedObj) {
self.grabbedObj.onCollected();
self.grabbedObj = null;
}
}
}
self.updateClaw();
};
// Start extending
self.startExtend = function () {
if (self.state === 'swing') {
self.state = 'extend';
// Bag remains on the hook; do not remove it when extending
}
};
// Called when an object is grabbed
self.grabObject = function (obj) {
self.grabbedObj = obj;
self.state = 'grabbed';
// Set retract speed based on object type
self.retractSpeed = obj.retractSpeed;
};
// Called when nothing is grabbed (hit ground)
self.miss = function () {
self.state = 'retract';
self.retractSpeed = 64; //{L} // Faster retract when empty
};
return self;
});
// Moving Target class
var Target = Container.expand(function () {
var self = Container.call(this);
// Draw as a different asset (targetBox image asset)
var boxAsset = self.attachAsset('targetBox', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
// Optionally, you can adjust scaleX/scaleY if you want it smaller/larger
self.value = 2;
self.speed = 8; // medium speed
self.direction = 1; // 1 = right, -1 = left
self.y = GROUND_Y - 100;
self.x = 400;
self.lastX = self.x;
self.update = function () {
// Move horizontally
self.x += self.speed * self.direction;
if (self.lastX <= GAME_WIDTH - 200 && self.x > GAME_WIDTH - 200 || self.lastX >= 200 && self.x < 200) {
self.direction *= -1;
}
// Clamp position
if (self.x > GAME_WIDTH - 200) self.x = GAME_WIDTH - 200;
if (self.x < 200) self.x = 200;
self.lastX = self.x;
};
// Add a no-op onCollected method to prevent errors if called by Claw
self.onCollected = function () {
// No-op for moving target
};
return self;
});
// Base class for all underground objects
var UndergroundObject = Container.expand(function () {
var self = Container.call(this);
self.value = 0;
self.retractSpeed = 32;
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.collected = false;
// Called when collected
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
// Play money sound when pulling up captured objects
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
if (typeof score !== 'undefined') {
score += self.value;
LK.setScore(score);
if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score);
}
self.destroy();
};
return self;
});
// Rock
var Rock = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var rock = self.attachAsset('rock', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 50;
self.retractSpeed = 6; // very slow
self.grabSound = 'rockhit';
self.collectedSound = 'rockhit';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
self.destroy();
};
return self;
});
// Pig
var Pig = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var pig = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1200;
self.retractSpeed = 20; // medium-fast
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
// Play explosion sound and flash screen like dynamite
LK.getSound('dynamite').play();
LK.effects.flashScreen(0xff0000, 800);
// Remove some score as penalty (like dynamite, but you can adjust penalty if desired)
score = Math.max(0, score - 400);
LK.setScore(score);
if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score);
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
// Explode nearby pigs
if (typeof objects !== "undefined" && Array.isArray(objects)) {
for (var i = 0; i < objects.length; i++) {
var obj = objects[i];
if (obj === self) continue;
if (obj && obj.visible !== false && obj instanceof Pig && !obj.collected) {
// Distance between pigs
var dx = obj.x - self.x;
var dy = obj.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 250) {
// 250px radius for explosion
obj.onCollected();
}
}
}
}
self.destroy();
};
return self;
});
// Small gold nugget
var GoldSmall = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var gold = self.attachAsset('goldSmall', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 250;
self.retractSpeed = 24; // medium
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
self.destroy();
};
return self;
});
// Gold nugget
var Gold = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var gold = self.attachAsset('gold', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 500;
self.retractSpeed = 8; // slower
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
self.destroy();
};
return self;
});
// Gem
var Gem = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var gem = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 800;
self.retractSpeed = 32; // fast
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
self.destroy();
};
return self;
});
// Dynamite trap
var Dynamite = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var dynamite = self.attachAsset('dynamite', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 0;
self.retractSpeed = 40; // fast retract
self.grabSound = 'dynamite';
self.collectedSound = 'dynamite';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound(self.collectedSound).play();
// Flash screen red to indicate explosion
LK.effects.flashScreen(0xff0000, 800);
// Remove some score as penalty
score = Math.max(0, score - 400);
LK.setScore(score);
if (typeof scoreTxt !== 'undefined') scoreTxt.setText(score);
self.visible = false;
self.destroy();
};
return self;
});
// Bag (Torba)
var Bag = UndergroundObject.expand(function () {
var self = UndergroundObject.call(this);
var bag = self.attachAsset('torba', {
anchorX: 0.5,
anchorY: 0.5
});
self.value = 1000;
self.retractSpeed = 18; // medium-slow
self.grabSound = 'grab';
self.collectedSound = 'collect';
self.onCollected = function () {
if (self.collected) return;
self.collected = true;
LK.getSound('money').play();
self.visible = false;
if (typeof self.onScore === 'function') self.onScore();
self.destroy();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8B5A2B // brown
});
/****
* Game Code
****/
// Game constants
// Claw arm (rectangle)
// Claw head (ellipse)
// Gold nugget (ellipse)
// Small gold nugget
// Rock (ellipse)
// Gem (ellipse)
// Sound for grabbing
// Sound for collecting
// Sound for hitting rock
// Music
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var GROUND_Y = 700; // y position where underground objects start
var LEVEL_TIME = 60; // seconds
var LEVEL_GOAL = 1500; // gold needed to win
// Level and difficulty progression
var level = 1;
var maxLevel = 10;
var objects = [];
var claw = null;
var score = 0;
var timer = 0;
var timeLeft = LEVEL_TIME;
var goal = LEVEL_GOAL;
var gameActive = true;
// Add multiple moving targets
var targets = [];
// GUI
// Level text (very small, upper right corner)
var levelTxt = new Text2('Level ' + level, {
size: 40,
fill: "#fff"
});
levelTxt.anchor.set(1, 0); // right-top
levelTxt.x = -8; // 8px from the right edge of gui.topRight
levelTxt.y = 0;
LK.gui.topRight.addChild(levelTxt);
// Goal text (very small, just above the score number)
var goalTxt = new Text2('Goal: ' + goal, {
size: 32,
fill: "#fff"
});
goalTxt.anchor.set(1, 0); // right-top
goalTxt.x = levelTxt.x - levelTxt.width - 16; // align with score
goalTxt.y = 0; // align to top since dollars label is removed
LK.gui.topRight.addChild(goalTxt);
// Score text (small, right next to level text, to the left)
var scoreTxt = new Text2('0', {
size: 40,
fill: "#fff"
});
scoreTxt.anchor.set(1, 0); // right-top
scoreTxt.x = levelTxt.x - levelTxt.width - 16; // 16px padding between score and level
scoreTxt.y = goalTxt.y + goalTxt.height + 2; // just below goal text
LK.gui.topRight.addChild(scoreTxt);
// Countdown timer text (small, just below level text)
var countdownTxt = new Text2(timeLeft + 's', {
size: 32,
fill: "#fff"
});
countdownTxt.anchor.set(1, 0); // right-top
countdownTxt.x = levelTxt.x;
countdownTxt.y = levelTxt.height + 4; // 4px below level text
LK.gui.topRight.addChild(countdownTxt);
// Timer interval to update countdown
var countdownInterval = LK.setInterval(function () {
if (!gameActive) return;
timeLeft--;
if (timeLeft < 0) timeLeft = 0;
countdownTxt.setText(timeLeft + 's');
if (timeLeft === 0 && gameActive) {
gameActive = false;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}, 1000);
// Place claw at top center
claw = new Claw();
claw.x = GAME_WIDTH / 2;
claw.y = 0;
game.addChild(claw);
// (Bag is not attached to the hook)
// Underground object spawn positions
function spawnObjects() {
// Clear previous
for (var i = 0; i < objects.length; i++) {
objects[i].destroy();
}
objects = [];
// Difficulty scaling
var bigGoldCount = 4 + Math.floor(level / 2);
var smallGoldCount = 6 + level;
var rockCount = 6 + level * 2;
var gemCount = 3 + Math.floor(level / 2);
var dynamiteCount = 2 + Math.floor(level / 2);
// Create all objects in order: gold, diamonds, dynamite, rocks, bags, pigs, then mix
var allObjs = [];
// Gold (big)
for (var i = 0; i < bigGoldCount; i++) {
var g = new Gold();
g.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(g);
}
// Gold (small)
for (var i = 0; i < smallGoldCount; i++) {
var gs = new GoldSmall();
gs.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(gs);
}
// Gems
for (var i = 0; i < gemCount; i++) {
var gem = new Gem();
gem.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(gem);
}
// Bags (torba)
var bagCount = 2 + Math.floor(level / 2);
for (var i = 0; i < bagCount; i++) {
var bag = new Bag();
bag.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(bag);
}
// Pigs
var pigCount = 2 + Math.floor(level / 2);
for (var i = 0; i < pigCount; i++) {
var pig = new Pig();
pig.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(pig);
}
// Dynamite
for (var i = 0; i < dynamiteCount; i++) {
var d = new Dynamite();
allObjs.push(d);
}
// Rocks
for (var i = 0; i < rockCount; i++) {
var r = new Rock();
r.onScore = function () {
score += this.value;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
};
allObjs.push(r);
}
// Shuffle allObjs array
for (var i = allObjs.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = allObjs[i];
allObjs[i] = allObjs[j];
allObjs[j] = temp;
}
// Place objects in the play area, avoiding overlap
var gridCols = 8;
var gridRows = Math.ceil(allObjs.length / gridCols);
var cellW = Math.floor((GAME_WIDTH - 400) / gridCols);
var cellH = Math.floor((GAME_HEIGHT - GROUND_Y - 400) / gridRows);
var usedCells = [];
for (var i = 0; i < allObjs.length; i++) {
var obj = allObjs[i];
// Find a free cell
var placed = false;
var attempts = 0;
while (!placed && attempts < 30) {
var col = Math.floor(Math.random() * gridCols);
var row = Math.floor(Math.random() * gridRows);
var cellIdx = row * gridCols + col;
if (usedCells.indexOf(cellIdx) === -1) {
usedCells.push(cellIdx);
obj.x = 200 + col * cellW + Math.floor(cellW / 2);
obj.y = GROUND_Y + 200 + row * cellH + Math.floor(cellH / 2);
placed = true;
}
attempts++;
}
game.addChild(obj);
objects.push(obj);
}
}
spawnObjects();
// Create and add multiple moving targets at specific parts of the screen
// Destroy old targets if any
if (targets && targets.length) {
for (var i = 0; i < targets.length; i++) {
if (targets[i]) targets[i].destroy();
}
}
targets = [];
// Place fewer moving targets at the top, and more in the middle section
var targetPositions = [
// Only one at the top left
{
x: 300,
y: GROUND_Y + 100
},
// Add more to the middle section
{
x: 600,
y: GROUND_Y + 400
}, {
x: GAME_WIDTH - 600,
y: GROUND_Y + 400
}, {
x: 400,
y: GROUND_Y + 700
}, {
x: GAME_WIDTH - 400,
y: GROUND_Y + 700
}, {
x: GAME_WIDTH / 2,
y: GROUND_Y + 900
}];
for (var i = 0; i < targetPositions.length; i++) {
var t = new Target();
t.x = targetPositions[i].x;
t.y = targetPositions[i].y;
t.direction = i % 2 === 0 ? 1 : -1;
targets.push(t);
game.addChild(t);
}
// Add moving TL objects to the top left of the screen
var tlObjects = [];
var tlCount = 2; // Number of TL objects to add/move
for (var i = 0; i < tlCount; i++) {
var tl = new Container();
var tlImg = tl.attachAsset('TL', {
anchorX: 0.5,
anchorY: 0.5
});
tl.x = 120 + i * 120; // Space out horizontally, keep away from top left 100x100
tl.y = 120;
tl.speed = 6 + Math.floor(Math.random() * 4);
tl.direction = Math.random() < 0.5 ? 1 : -1;
tl.lastX = tl.x;
tl.update = function () {
if (typeof this.lastX !== "number") this.lastX = this.x;
this.x += this.speed * this.direction;
// Bounce at left/right margin (keep inside 120 to 400 px)
if (this.lastX <= 120 && this.x > 120) this.direction = 1;
if (this.lastX >= 400 && this.x < 400) this.direction = -1;
if (this.x > 400) this.x = 400;
if (this.x < 120) this.x = 120;
this.lastX = this.x;
};
tlObjects.push(tl);
game.addChild(tl);
}
// Draw a dot at the top center to send the rope down
var dropDot = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: GAME_WIDTH / 2,
y: 80
});
game.addChild(dropDot);
// Only trigger on dot press, not anywhere
dropDot.down = function (x, y, obj) {
if (!gameActive) return;
if (claw.state === 'swing') {
claw.startExtend();
}
};
// Touch/click anywhere else does nothing
game.down = function (x, y, obj) {
// No-op, handled by dropDot
};
// Main update loop
game.update = function () {
if (!gameActive) return;
// Claw update handled in class
// If claw is extending, check for collision with objects
if (claw.state === 'extend') {
// Get claw head position
var dx = Math.sin(claw.swingAngle) * claw.length;
var dy = Math.cos(claw.swingAngle) * claw.length;
var cx = claw.x + dx;
var cy = claw.y + dy + 30; // 30: half head height
// Check for collision with any object
var grabbed = false;
for (var i = 0; i < objects.length; i++) {
var obj = objects[i];
if (obj.collected) continue;
// Simple circle collision
var dist = Math.sqrt((obj.x - cx) * (obj.x - cx) + (obj.y - cy) * (obj.y - cy));
var r = 60; // approx radius
if (dist < r + 40) {
// If it's a pig, trigger explosion immediately and do not attach to claw
if (obj instanceof Pig) {
obj.onCollected();
grabbed = true;
break;
}
// Grab object
claw.grabObject(obj);
// Dynamite handles penalty in its onCollected
grabbed = true;
break;
}
}
// Check for collision with any moving target if not already grabbed something
if (!grabbed && targets && targets.length) {
for (var ti = 0; ti < targets.length; ti++) {
var t = targets[ti];
if (!t.visible) continue;
if (typeof t.x !== 'number' || typeof t.y !== 'number') continue;
var tdist = Math.sqrt((t.x - cx) * (t.x - cx) + (t.y - cy) * (t.y - cy));
var tr = 100; // slightly larger radius for target
if (tdist < tr) {
// "Grab" the target: treat as a special object
claw.grabbedObj = t;
claw.state = 'grabbed';
claw.retractSpeed = 32;
// Optionally, you can add a sound or effect here
// Remove the target visually and respawn after a delay
t.visible = false;
(function (targetToRespawn) {
LK.setTimeout(function () {
if (targetToRespawn) {
targetToRespawn.x = 400 + Math.floor(Math.random() * (GAME_WIDTH - 800));
targetToRespawn.y = GROUND_Y - 100 - Math.floor(Math.random() * 120);
targetToRespawn.visible = true;
}
}, 2000);
})(t);
grabbed = true;
break;
}
}
}
// If reached max length and nothing grabbed, retract
if (claw.length >= claw.maxLength && claw.state === 'extend') {
claw.miss();
}
}
// Win condition
if (score >= goal && gameActive) {
gameActive = false;
LK.effects.flashScreen(0xffff00, 800);
// Level up logic
if (level < maxLevel) {
level += 1;
// Play level up sound
LK.getSound('level').play();
// Increase goal and decrease time for next level
goal = LEVEL_GOAL + level * 800;
timeLeft = LEVEL_TIME - Math.min(level * 3, 30); // reduce time, but not below 30s
score = 0;
LK.setScore(score);
if (scoreTxt) scoreTxt.setText(score);
// Update level text
if (levelTxt) levelTxt.setText('Level ' + level);
// Update goal text
if (goalTxt) goalTxt.setText('Goal: ' + goal);
// Reset countdown timer text and timeLeft
timeLeft = LEVEL_TIME - Math.min(level * 3, 30);
if (countdownTxt) countdownTxt.setText(timeLeft + 's');
// Respawn objects for new level
spawnObjects();
gameActive = true;
} else {
LK.showYouWin();
}
}
// Update all moving targets
if (targets && targets.length) {
for (var ti = 0; ti < targets.length; ti++) {
if (targets[ti] && typeof targets[ti].update === 'function') {
targets[ti].update();
}
}
}
// Update all TL objects
if (typeof tlObjects !== "undefined" && tlObjects.length) {
for (var i = 0; i < tlObjects.length; i++) {
if (tlObjects[i] && typeof tlObjects[i].update === "function") {
tlObjects[i].update();
}
}
}
};
// Play background music
LK.playMusic('goldminerbg', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
gold. In-Game asset. 2d. High contrast. No shadows
diamond. In-Game asset. 2d. High contrast. No shadows
big rock. In-Game asset. 2d. High contrast. No shadows
upright long rope. In-Game asset. 2d. High contrast. No shadows
double pointed hook. In-Game asset. 2d. High contrast. No shadows
big piece of gold. In-Game asset. 2d. High contrast. No shadows
dynamite. In-Game asset. 2d. High contrast. No shadows
pig. In-Game asset. 2d. High contrast. No shadows
soru isฬงareti olan bir torba. In-Game asset. 2d. High contrast. No shadows
Pig with dollar in mouth. In-Game asset. 2d. High contrast. No shadows
tnt yazฤฑlฤฑ varil. In-Game asset. 2d. High contrast. No shadows