/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Gear class: represents a single gear that rotates in a given direction and speed var Gear = Container.expand(function () { var self = Container.call(this); // Randomly select one of 5 gear assets var gearAssetIdx = Math.floor(Math.random() * 5) + 1; var gear = self.attachAsset('gear' + gearAssetIdx, { anchorX: 0.5, anchorY: 0.5 }); // Assign unique sound for this gear type // Ensure gear5 uses the correct unique sound asset if (gearAssetIdx === 5) { self._sound = LK.getSound('gearRotate5'); self._soundName = 'gearRotate5'; } else { self._sound = LK.getSound('gearRotate' + gearAssetIdx); self._soundName = 'gearRotate' + gearAssetIdx; } self._gearAssetIdx = gearAssetIdx; // Set up default size for asset (will be overridden externally) gear.width = 270 * 2; gear.height = 270 * 2; // Rotation speed in radians per frame (set externally) self.rotationSpeed = 0; // Removed all gear sound logic // Update method: rotates the gear self.update = function () { // Track last rotation for step detection if (typeof self._lastRotation === "undefined") { self._lastRotation = self.rotation; } self.rotation += self.rotationSpeed; // Play unique sound for this gear type on each full step (e.g. every 1/12 turn) var step = Math.PI / 6; // 30 degrees per step var lastStep = Math.floor(self._lastRotation / step); var currentStep = Math.floor(self.rotation / step); if (self.rotationSpeed !== 0 && self._sound && lastStep !== currentStep) { // Only play sound if at least one gear of this type is present on screen var found = false; for (var i = 0; i < gears.length; i++) { if (gears[i] && gears[i]._gearAssetIdx === self._gearAssetIdx) { found = true; break; } } if (found) { self._sound.play(); } // Score logic: Only update score when a half rotation is completed if (typeof score !== "undefined" && typeof scoreTxt !== "undefined") { // Track completed half turns if (typeof self._lastHalfTurns === "undefined") { self._lastHalfTurns = Math.floor(self._lastRotation / Math.PI); } var currentHalfTurns = Math.floor(self.rotation / Math.PI); if (currentHalfTurns !== self._lastHalfTurns) { // Only update score when a half rotation is completed if (self.rotationSpeed > 0) { score += 1; } else if (self.rotationSpeed < 0) { score -= 1; } animateScoreTo(score); self._lastHalfTurns = currentHalfTurns; } } } self._lastRotation = self.rotation; }; // Handle down event for single tap: remove gear and stop sound self.down = function (x, y, obj) { // Stop the unique sound for this gear if playing if (self._sound && typeof self._sound.stop === "function") { self._sound.stop(); self._soundPlaying = false; } // Remove from game and gears array if (self.parent) { self.parent.removeChild(self); } for (var i = 0; i < gears.length; i++) { if (gears[i] === self) { gears.splice(i, 1); break; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xffffff // White background for clarity }); /**** * Game Code ****/ // We need tween for smooth rotation animations // Add background image (covers the whole game area) var bg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(bg); // --- Animated gear at game start --- // Add finger asset for swipe animation var introGear = new Gear(); introGear.x = 2048 / 2; introGear.y = 2732 / 2; introGear.rotation = 0; introGear.rotationSpeed = 0; introGear.children[0].width = 900; introGear.children[0].height = 900; introGear.alpha = 0; game.addChild(introGear); var finger = LK.getAsset('finger', { anchorX: 0.5, anchorY: 0.5, width: 320, height: 320, x: introGear.x - 300, y: introGear.y + 350, alpha: 0 }); game.addChild(finger); // Animate: finger and gear intro at the same time (parallel animation), but start after 1 second delay LK.setTimeout(function () { // Determine direction based on targetSign var fingerStartX, fingerEndX; if (targetSign < 0) { // Right to left fingerStartX = introGear.x + 300; fingerEndX = introGear.x - 200; } else { // Left to right (default) fingerStartX = introGear.x - 300; fingerEndX = introGear.x + 200; } finger.x = fingerStartX; tween(finger, { alpha: 1 }, { duration: 200, onFinish: function onFinish() { // Start finger swipe and gear animation in parallel tween(finger, { x: fingerEndX }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(finger, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (finger.parent) finger.parent.removeChild(finger); } }); } }); // Start gear animation at the same time as finger swipe tween(introGear, { alpha: 1, scaleX: 1.2, scaleY: 1.2, rotation: targetSign < 0 ? -Math.PI * 2 : Math.PI * 2 // Animate right-to-left if negative }, { duration: 900, easing: tween.easeOut, onFinish: function onFinish() { // Fade out gear after animation tween(introGear, { alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { if (introGear.parent) introGear.parent.removeChild(introGear); } }); } }); } }); }, 1000); // Play background music for the whole game LK.playMusic('backgroundSong'); // List of all gears in the game var gears = []; // Score variable and score text var score = 0; var displayScore = 0; var scoreTween = null; function formatScore(val) { var s = Math.abs(Math.round(val)).toString().padStart(4, "0"); return (val < 0 ? "-" : "") + s; } // Add random target to top left at game start var targetSign = Math.random() < 0.5 ? -1 : 1; var targetValue = Math.floor(Math.random() * 10000); // 0 to 9999 var targetText = (targetSign < 0 ? "-" : "") + targetValue.toString().padStart(4, "0"); var targetTxt = new Text2(targetText, { size: 150, fill: 0xFFD600 // yellow }); targetTxt.anchor.set(0, 0); // top left LK.gui.topLeft.addChild(targetTxt); // Place with margin to avoid menu icon targetTxt.x = 410; targetTxt.y = 10; var scoreTxt = new Text2(formatScore(displayScore), { size: 170, fill: 0xFFFFFF }); // Anchor to top right scoreTxt.anchor.set(1, 0); // right-top LK.gui.topRight.addChild(scoreTxt); // Place at top right, with a small margin from the edge scoreTxt.x = -40; scoreTxt.y = 10; // Helper: animate score change smoothly, one by one function animateScoreTo(target) { if (scoreTween) { tween.stop(scoreTween); scoreTween = null; } var start = displayScore; var end = target; if (start === end) { displayScore = end; scoreTxt.setText(formatScore(displayScore)); return; } var step = start < end ? 1 : -1; var steps = Math.abs(end - start); var durationPerStep = 30; // ms per step, adjust for speed var current = start; function stepTween() { if (current === end) { scoreTween = null; return; } current += step; displayScore = current; scoreTxt.setText(formatScore(displayScore)); scoreTween = LK.setTimeout(stepTween, durationPerStep); } stepTween(); } // For drag/hold/tap detection var dragStart = null; // {x, y, t} var dragCurrent = null; // {x, y} var dragTimer = null; var dragHold = false; var dragGearPreview = null; var dragPreviewGearType = 1; // type of gear to preview/create this drag var dragDirection = 1; // 1: CW, -1: CCW var dragSize = 240; // default var tapThreshold = 200; // ms var holdThreshold = 220; // ms var minGear = 120, // 2x smaller than before maxGear = 390 * 4; //{G} // Allow up to 2x larger gears // Helper: calculate angle between two points (in radians) function getAngle(x1, y1, x2, y2) { return Math.atan2(y2 - y1, x2 - x1); } // Helper: clamp rotation speed function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // Helper: find gear at (x, y) function findGearAt(x, y) { for (var i = 0; i < gears.length; i++) { var g = gears[i]; var dx = g.x - x; var dy = g.y - y; var r = g.children[0].width / 2; if (dx * dx + dy * dy <= r * r) return g; } return null; } // On press down: start drag/tap/hold detection game.down = function (x, y, obj) { dragStart = { x: x, y: y, t: Date.now() }; dragCurrent = { x: x, y: y }; dragHold = false; dragDirection = 1; // Default size is mid-way between min and max dragSize = (minGear + maxGear) / 2; // If tap on existing gear, mark for possible removal var gear = findGearAt(x, y); if (gear) { dragGearPreview = gear; return; } // Start hold timer for gear creation dragTimer = LK.setTimeout(function () { dragHold = true; // Show preview gear // Pick a random gear type and remember it for this drag dragPreviewGearType = Math.floor(Math.random() * 5) + 1; dragGearPreview = new Gear(); dragGearPreview.x = dragStart.x; dragGearPreview.y = dragStart.y; dragGearPreview.rotationSpeed = 0; dragGearPreview.children[0].width = dragSize; dragGearPreview.children[0].height = dragSize; dragGearPreview.alpha = 0.5; // Replace the gear asset with the selected type if (dragGearPreview.children.length > 0) { dragGearPreview.removeChild(dragGearPreview.children[0]); } var previewAsset = dragGearPreview.attachAsset('gear' + dragPreviewGearType, { anchorX: 0.5, anchorY: 0.5 }); previewAsset.width = dragSize; previewAsset.height = dragSize; game.addChild(dragGearPreview); }, holdThreshold); }; // On move: update drag current position, update preview gear size/direction game.move = function (x, y, obj) { if (!dragStart) return; dragCurrent.x = x; dragCurrent.y = y; if (dragHold && dragGearPreview) { // Calculate drag vector var dx = dragCurrent.x - dragStart.x; var dy = dragCurrent.y - dragStart.y; var dist = Math.sqrt(dx * dx + dy * dy); // Size: proportional to drag distance, clamp to min/max // Map drag distance from 0..(max possible) to minGear..maxGear // Let's use up to 900px drag for full range (since maxGear is now 2x larger) var maxDragDist = 900; var size = clamp(minGear + (maxGear - minGear) * Math.min(dist, maxDragDist) / maxDragDist, minGear, maxGear); dragSize = size; dragGearPreview.children[0].width = size; dragGearPreview.children[0].height = size; // Direction: right is CW, left is CCW dragDirection = dx >= 0 ? 1 : -1; dragGearPreview.scale.x = dragDirection; // No speed text shown during drag preview } }; // On release: decide tap/hold/drag action game.up = function (x, y, obj) { if (dragTimer) { LK.clearTimeout(dragTimer); dragTimer = null; } var now = Date.now(); var dt = now - (dragStart ? dragStart.t : now); // Tap on existing gear: remove it if (dragGearPreview && gears.indexOf(dragGearPreview) !== -1) { // Remove gear if (dragGearPreview.parent) dragGearPreview.parent.removeChild(dragGearPreview); var idx = gears.indexOf(dragGearPreview); if (idx !== -1) gears.splice(idx, 1); dragGearPreview = null; dragStart = null; return; } // Short tap: do nothing (no gear created) if (!dragHold && dt < tapThreshold) { // No speed text to remove dragStart = null; dragGearPreview = null; return; } // Hold/drag: create gear at dragStart, with size/direction if (dragHold && dragGearPreview) { // No speed text to remove // Remove preview if (dragGearPreview.parent) dragGearPreview.parent.removeChild(dragGearPreview); dragGearPreview = null; // Prevent overlapping: check if new gear would overlap any existing gear var overlap = false; for (var i = 0; i < gears.length; i++) { var other = gears[i]; var dxg = dragStart.x - other.x; var dyg = dragStart.y - other.y; var distg = Math.sqrt(dxg * dxg + dyg * dyg); var otherGear = other.children[0].width; if (distg < (dragSize + otherGear) / 2 + 10) { overlap = true; break; } } if (!overlap) { var gear = new Gear(); gear.x = dragStart.x; gear.y = dragStart.y; // Assign random speed between 0.01 and 0.06, use dragDirection for direction var minSpeed = 0.01, maxSpeed = 0.06; var randomSpeed = minSpeed + Math.random() * (maxSpeed - minSpeed); gear.rotationSpeed = randomSpeed * dragDirection; // Replace the gear asset with the previewed type if (gear.children.length > 0) { gear.removeChild(gear.children[0]); } var asset = gear.attachAsset('gear' + dragPreviewGearType, { anchorX: 0.5, anchorY: 0.5 }); asset.width = dragSize; asset.height = dragSize; // Set correct sound for this gear type if (dragPreviewGearType === 5) { gear._sound = LK.getSound('gearRotate5'); gear._soundName = 'gearRotate5'; } else { gear._sound = LK.getSound('gearRotate' + dragPreviewGearType); gear._soundName = 'gearRotate' + dragPreviewGearType; } gear._gearAssetIdx = dragPreviewGearType; game.addChild(gear); gears.push(gear); } } dragStart = null; dragGearPreview = null; }; // Update loop: update all gears game.update = function () { for (var i = 0; i < gears.length; i++) { if (gears[i].update) { gears[i].update(); } } // Check win condition: score is greater than or equal to target (with sign) if (targetSign > 0 && score >= targetValue || targetSign < 0 && score <= -targetValue) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Gear class: represents a single gear that rotates in a given direction and speed
var Gear = Container.expand(function () {
var self = Container.call(this);
// Randomly select one of 5 gear assets
var gearAssetIdx = Math.floor(Math.random() * 5) + 1;
var gear = self.attachAsset('gear' + gearAssetIdx, {
anchorX: 0.5,
anchorY: 0.5
});
// Assign unique sound for this gear type
// Ensure gear5 uses the correct unique sound asset
if (gearAssetIdx === 5) {
self._sound = LK.getSound('gearRotate5');
self._soundName = 'gearRotate5';
} else {
self._sound = LK.getSound('gearRotate' + gearAssetIdx);
self._soundName = 'gearRotate' + gearAssetIdx;
}
self._gearAssetIdx = gearAssetIdx;
// Set up default size for asset (will be overridden externally)
gear.width = 270 * 2;
gear.height = 270 * 2;
// Rotation speed in radians per frame (set externally)
self.rotationSpeed = 0;
// Removed all gear sound logic
// Update method: rotates the gear
self.update = function () {
// Track last rotation for step detection
if (typeof self._lastRotation === "undefined") {
self._lastRotation = self.rotation;
}
self.rotation += self.rotationSpeed;
// Play unique sound for this gear type on each full step (e.g. every 1/12 turn)
var step = Math.PI / 6; // 30 degrees per step
var lastStep = Math.floor(self._lastRotation / step);
var currentStep = Math.floor(self.rotation / step);
if (self.rotationSpeed !== 0 && self._sound && lastStep !== currentStep) {
// Only play sound if at least one gear of this type is present on screen
var found = false;
for (var i = 0; i < gears.length; i++) {
if (gears[i] && gears[i]._gearAssetIdx === self._gearAssetIdx) {
found = true;
break;
}
}
if (found) {
self._sound.play();
}
// Score logic: Only update score when a half rotation is completed
if (typeof score !== "undefined" && typeof scoreTxt !== "undefined") {
// Track completed half turns
if (typeof self._lastHalfTurns === "undefined") {
self._lastHalfTurns = Math.floor(self._lastRotation / Math.PI);
}
var currentHalfTurns = Math.floor(self.rotation / Math.PI);
if (currentHalfTurns !== self._lastHalfTurns) {
// Only update score when a half rotation is completed
if (self.rotationSpeed > 0) {
score += 1;
} else if (self.rotationSpeed < 0) {
score -= 1;
}
animateScoreTo(score);
self._lastHalfTurns = currentHalfTurns;
}
}
}
self._lastRotation = self.rotation;
};
// Handle down event for single tap: remove gear and stop sound
self.down = function (x, y, obj) {
// Stop the unique sound for this gear if playing
if (self._sound && typeof self._sound.stop === "function") {
self._sound.stop();
self._soundPlaying = false;
}
// Remove from game and gears array
if (self.parent) {
self.parent.removeChild(self);
}
for (var i = 0; i < gears.length; i++) {
if (gears[i] === self) {
gears.splice(i, 1);
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff // White background for clarity
});
/****
* Game Code
****/
// We need tween for smooth rotation animations
// Add background image (covers the whole game area)
var bg = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
game.addChild(bg);
// --- Animated gear at game start ---
// Add finger asset for swipe animation
var introGear = new Gear();
introGear.x = 2048 / 2;
introGear.y = 2732 / 2;
introGear.rotation = 0;
introGear.rotationSpeed = 0;
introGear.children[0].width = 900;
introGear.children[0].height = 900;
introGear.alpha = 0;
game.addChild(introGear);
var finger = LK.getAsset('finger', {
anchorX: 0.5,
anchorY: 0.5,
width: 320,
height: 320,
x: introGear.x - 300,
y: introGear.y + 350,
alpha: 0
});
game.addChild(finger);
// Animate: finger and gear intro at the same time (parallel animation), but start after 1 second delay
LK.setTimeout(function () {
// Determine direction based on targetSign
var fingerStartX, fingerEndX;
if (targetSign < 0) {
// Right to left
fingerStartX = introGear.x + 300;
fingerEndX = introGear.x - 200;
} else {
// Left to right (default)
fingerStartX = introGear.x - 300;
fingerEndX = introGear.x + 200;
}
finger.x = fingerStartX;
tween(finger, {
alpha: 1
}, {
duration: 200,
onFinish: function onFinish() {
// Start finger swipe and gear animation in parallel
tween(finger, {
x: fingerEndX
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(finger, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (finger.parent) finger.parent.removeChild(finger);
}
});
}
});
// Start gear animation at the same time as finger swipe
tween(introGear, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2,
rotation: targetSign < 0 ? -Math.PI * 2 : Math.PI * 2 // Animate right-to-left if negative
}, {
duration: 900,
easing: tween.easeOut,
onFinish: function onFinish() {
// Fade out gear after animation
tween(introGear, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (introGear.parent) introGear.parent.removeChild(introGear);
}
});
}
});
}
});
}, 1000);
// Play background music for the whole game
LK.playMusic('backgroundSong');
// List of all gears in the game
var gears = [];
// Score variable and score text
var score = 0;
var displayScore = 0;
var scoreTween = null;
function formatScore(val) {
var s = Math.abs(Math.round(val)).toString().padStart(4, "0");
return (val < 0 ? "-" : "") + s;
}
// Add random target to top left at game start
var targetSign = Math.random() < 0.5 ? -1 : 1;
var targetValue = Math.floor(Math.random() * 10000); // 0 to 9999
var targetText = (targetSign < 0 ? "-" : "") + targetValue.toString().padStart(4, "0");
var targetTxt = new Text2(targetText, {
size: 150,
fill: 0xFFD600 // yellow
});
targetTxt.anchor.set(0, 0); // top left
LK.gui.topLeft.addChild(targetTxt);
// Place with margin to avoid menu icon
targetTxt.x = 410;
targetTxt.y = 10;
var scoreTxt = new Text2(formatScore(displayScore), {
size: 170,
fill: 0xFFFFFF
});
// Anchor to top right
scoreTxt.anchor.set(1, 0); // right-top
LK.gui.topRight.addChild(scoreTxt);
// Place at top right, with a small margin from the edge
scoreTxt.x = -40;
scoreTxt.y = 10;
// Helper: animate score change smoothly, one by one
function animateScoreTo(target) {
if (scoreTween) {
tween.stop(scoreTween);
scoreTween = null;
}
var start = displayScore;
var end = target;
if (start === end) {
displayScore = end;
scoreTxt.setText(formatScore(displayScore));
return;
}
var step = start < end ? 1 : -1;
var steps = Math.abs(end - start);
var durationPerStep = 30; // ms per step, adjust for speed
var current = start;
function stepTween() {
if (current === end) {
scoreTween = null;
return;
}
current += step;
displayScore = current;
scoreTxt.setText(formatScore(displayScore));
scoreTween = LK.setTimeout(stepTween, durationPerStep);
}
stepTween();
}
// For drag/hold/tap detection
var dragStart = null; // {x, y, t}
var dragCurrent = null; // {x, y}
var dragTimer = null;
var dragHold = false;
var dragGearPreview = null;
var dragPreviewGearType = 1; // type of gear to preview/create this drag
var dragDirection = 1; // 1: CW, -1: CCW
var dragSize = 240; // default
var tapThreshold = 200; // ms
var holdThreshold = 220; // ms
var minGear = 120,
// 2x smaller than before
maxGear = 390 * 4; //{G} // Allow up to 2x larger gears
// Helper: calculate angle between two points (in radians)
function getAngle(x1, y1, x2, y2) {
return Math.atan2(y2 - y1, x2 - x1);
}
// Helper: clamp rotation speed
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// Helper: find gear at (x, y)
function findGearAt(x, y) {
for (var i = 0; i < gears.length; i++) {
var g = gears[i];
var dx = g.x - x;
var dy = g.y - y;
var r = g.children[0].width / 2;
if (dx * dx + dy * dy <= r * r) return g;
}
return null;
}
// On press down: start drag/tap/hold detection
game.down = function (x, y, obj) {
dragStart = {
x: x,
y: y,
t: Date.now()
};
dragCurrent = {
x: x,
y: y
};
dragHold = false;
dragDirection = 1;
// Default size is mid-way between min and max
dragSize = (minGear + maxGear) / 2;
// If tap on existing gear, mark for possible removal
var gear = findGearAt(x, y);
if (gear) {
dragGearPreview = gear;
return;
}
// Start hold timer for gear creation
dragTimer = LK.setTimeout(function () {
dragHold = true;
// Show preview gear
// Pick a random gear type and remember it for this drag
dragPreviewGearType = Math.floor(Math.random() * 5) + 1;
dragGearPreview = new Gear();
dragGearPreview.x = dragStart.x;
dragGearPreview.y = dragStart.y;
dragGearPreview.rotationSpeed = 0;
dragGearPreview.children[0].width = dragSize;
dragGearPreview.children[0].height = dragSize;
dragGearPreview.alpha = 0.5;
// Replace the gear asset with the selected type
if (dragGearPreview.children.length > 0) {
dragGearPreview.removeChild(dragGearPreview.children[0]);
}
var previewAsset = dragGearPreview.attachAsset('gear' + dragPreviewGearType, {
anchorX: 0.5,
anchorY: 0.5
});
previewAsset.width = dragSize;
previewAsset.height = dragSize;
game.addChild(dragGearPreview);
}, holdThreshold);
};
// On move: update drag current position, update preview gear size/direction
game.move = function (x, y, obj) {
if (!dragStart) return;
dragCurrent.x = x;
dragCurrent.y = y;
if (dragHold && dragGearPreview) {
// Calculate drag vector
var dx = dragCurrent.x - dragStart.x;
var dy = dragCurrent.y - dragStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Size: proportional to drag distance, clamp to min/max
// Map drag distance from 0..(max possible) to minGear..maxGear
// Let's use up to 900px drag for full range (since maxGear is now 2x larger)
var maxDragDist = 900;
var size = clamp(minGear + (maxGear - minGear) * Math.min(dist, maxDragDist) / maxDragDist, minGear, maxGear);
dragSize = size;
dragGearPreview.children[0].width = size;
dragGearPreview.children[0].height = size;
// Direction: right is CW, left is CCW
dragDirection = dx >= 0 ? 1 : -1;
dragGearPreview.scale.x = dragDirection;
// No speed text shown during drag preview
}
};
// On release: decide tap/hold/drag action
game.up = function (x, y, obj) {
if (dragTimer) {
LK.clearTimeout(dragTimer);
dragTimer = null;
}
var now = Date.now();
var dt = now - (dragStart ? dragStart.t : now);
// Tap on existing gear: remove it
if (dragGearPreview && gears.indexOf(dragGearPreview) !== -1) {
// Remove gear
if (dragGearPreview.parent) dragGearPreview.parent.removeChild(dragGearPreview);
var idx = gears.indexOf(dragGearPreview);
if (idx !== -1) gears.splice(idx, 1);
dragGearPreview = null;
dragStart = null;
return;
}
// Short tap: do nothing (no gear created)
if (!dragHold && dt < tapThreshold) {
// No speed text to remove
dragStart = null;
dragGearPreview = null;
return;
}
// Hold/drag: create gear at dragStart, with size/direction
if (dragHold && dragGearPreview) {
// No speed text to remove
// Remove preview
if (dragGearPreview.parent) dragGearPreview.parent.removeChild(dragGearPreview);
dragGearPreview = null;
// Prevent overlapping: check if new gear would overlap any existing gear
var overlap = false;
for (var i = 0; i < gears.length; i++) {
var other = gears[i];
var dxg = dragStart.x - other.x;
var dyg = dragStart.y - other.y;
var distg = Math.sqrt(dxg * dxg + dyg * dyg);
var otherGear = other.children[0].width;
if (distg < (dragSize + otherGear) / 2 + 10) {
overlap = true;
break;
}
}
if (!overlap) {
var gear = new Gear();
gear.x = dragStart.x;
gear.y = dragStart.y;
// Assign random speed between 0.01 and 0.06, use dragDirection for direction
var minSpeed = 0.01,
maxSpeed = 0.06;
var randomSpeed = minSpeed + Math.random() * (maxSpeed - minSpeed);
gear.rotationSpeed = randomSpeed * dragDirection;
// Replace the gear asset with the previewed type
if (gear.children.length > 0) {
gear.removeChild(gear.children[0]);
}
var asset = gear.attachAsset('gear' + dragPreviewGearType, {
anchorX: 0.5,
anchorY: 0.5
});
asset.width = dragSize;
asset.height = dragSize;
// Set correct sound for this gear type
if (dragPreviewGearType === 5) {
gear._sound = LK.getSound('gearRotate5');
gear._soundName = 'gearRotate5';
} else {
gear._sound = LK.getSound('gearRotate' + dragPreviewGearType);
gear._soundName = 'gearRotate' + dragPreviewGearType;
}
gear._gearAssetIdx = dragPreviewGearType;
game.addChild(gear);
gears.push(gear);
}
}
dragStart = null;
dragGearPreview = null;
};
// Update loop: update all gears
game.update = function () {
for (var i = 0; i < gears.length; i++) {
if (gears[i].update) {
gears[i].update();
}
}
// Check win condition: score is greater than or equal to target (with sign)
if (targetSign > 0 && score >= targetValue || targetSign < 0 && score <= -targetValue) {
LK.showYouWin();
}
};
red gear top view tranparent. In-Game asset. 2d. High contrast. No shadows
yellow gear top view tranparent. In-Game asset. 2d. High contrast. No shadows
Green gear top view tranparent. In-Game asset. 2d. High contrast. No shadows
Mavi renk deniz manzarası. In-Game asset. 2d. High contrast. No shadows
Just a finger top view. In-Game asset. 2d. High contrast. No shadows