/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Gem = Container.expand(function (type) { var self = Container.call(this); // Define gem types var gemTypes = ['red', 'blue', 'green', 'yellow', 'purple']; self.type = type || gemTypes[Math.floor(Math.random() * gemTypes.length)]; var graphics = self.attachAsset('gem_' + self.type, { anchorX: 0.5, anchorY: 0.5 }); self.velocity = { x: 0, y: 0 }; self.matched = false; self.special = false; self.mass = 1; // Make special gems 25% larger and add a pulse effect self.makeSpecial = function () { if (self.special) { return; } self.special = true; self.mass = 1.5; graphics.scaleX = 1.25; graphics.scaleY = 1.25; // Add a white glow using tint pulses function pulseTint() { tween(graphics, { alpha: 0.7 }, { duration: 700, easing: tween.sinceOut, onFinish: function onFinish() { tween(graphics, { alpha: 1 }, { duration: 700, easing: tween.sinceIn, onFinish: pulseTint }); } }); } pulseTint(); }; // Apply physics movement self.update = function () { // Apply velocity to position self.x += self.velocity.x; self.y += self.velocity.y; // Apply friction self.velocity.x *= 0.98; self.velocity.y *= 0.98; // Rotate gem based on movement graphics.rotation += Math.sqrt(Math.pow(self.velocity.x, 2) + Math.pow(self.velocity.y, 2)) * 0.01; // Bounce off edges if (self.x < graphics.width / 2) { self.x = graphics.width / 2; self.velocity.x *= -0.8; } else if (self.x > 2048 - graphics.width / 2) { self.x = 2048 - graphics.width / 2; self.velocity.x *= -0.8; } if (self.y < graphics.height / 2) { self.y = graphics.height / 2; self.velocity.y *= -0.8; } else if (self.y > 2732 - graphics.height / 2) { self.y = 2732 - graphics.height / 2; self.velocity.y *= -0.8; } }; return self; }); var GravityWell = Container.expand(function () { var self = Container.call(this); var rangeGraphics = self.attachAsset('gravity_range', { anchorX: 0.5, anchorY: 0.5, alpha: 0.1 }); var wellGraphics = self.attachAsset('gravity_well', { anchorX: 0.5, anchorY: 0.5 }); self.strength = 5; self.range = rangeGraphics.width / 2; self.active = true; // Pulse animation for the gravity well function startPulseAnimation() { tween(wellGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(wellGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 1000, easing: tween.easeInOut, onFinish: startPulseAnimation }); } }); } startPulseAnimation(); return self; }); var Particle = Container.expand(function (color) { var self = Container.call(this); var graphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); if (color) { graphics.tint = color; } self.velocity = { x: (Math.random() - 0.5) * 20, y: (Math.random() - 0.5) * 20 }; self.lifetime = 30 + Math.random() * 30; self.age = 0; self.update = function () { self.x += self.velocity.x; self.y += self.velocity.y; self.velocity.x *= 0.92; self.velocity.y *= 0.92; self.age++; // Fade out as the particle ages self.alpha = 1 - self.age / self.lifetime; return self.age < self.lifetime; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111122 }); /**** * Game Code ****/ // Game state variables var gems = []; var gravityWells = []; var particles = []; var maxGems = 25; var maxGravityWells = 3; var score = 0; var level = storage.level || 1; var gemTypesInPlay = ['red', 'blue', 'green']; var gemsToMatch = 3; // UI elements var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var levelTxt = new Text2('Level: ' + level, { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0.5, 0); levelTxt.y = 70; LK.gui.top.addChild(levelTxt); var wellsLeftTxt = new Text2('Gravity Wells: ' + maxGravityWells, { size: 50, fill: 0xFFFFFF }); wellsLeftTxt.anchor.set(0, 0); wellsLeftTxt.x = 120; wellsLeftTxt.y = 20; LK.gui.topLeft.addChild(wellsLeftTxt); // Initialize game function initLevel() { // Clear existing objects for (var i = gems.length - 1; i >= 0; i--) { gems[i].destroy(); } gems = []; for (var i = gravityWells.length - 1; i >= 0; i--) { gravityWells[i].destroy(); } gravityWells = []; for (var i = particles.length - 1; i >= 0; i--) { particles[i].destroy(); } particles = []; // Update level if (level > 1) { // Unlock yellow gems at level 2 if (level >= 2 && gemTypesInPlay.indexOf('yellow') === -1) { gemTypesInPlay.push('yellow'); } // Unlock purple gems at level 4 if (level >= 4 && gemTypesInPlay.indexOf('purple') === -1) { gemTypesInPlay.push('purple'); } // Increase gem count as level increases maxGems = 25 + (level - 1) * 5; if (maxGems > 50) { maxGems = 50; } // Cap at 50 gems // Increase gravity wells with level maxGravityWells = 3 + Math.floor((level - 1) / 2); if (maxGravityWells > 7) { maxGravityWells = 7; } // Cap at 7 wells } // Update UI levelTxt.setText('Level: ' + level); wellsLeftTxt.setText('Gravity Wells: ' + maxGravityWells); scoreTxt.setText('Score: ' + score); // Create initial gems for (var i = 0; i < Math.min(10, maxGems); i++) { createGem(); } // Play background music LK.playMusic('bgmusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); } // Create a new gem at a random position function createGem() { if (gems.length >= maxGems) { return; } var gem = new Gem(gemTypesInPlay[Math.floor(Math.random() * gemTypesInPlay.length)]); // Position randomly but not too close to the edges gem.x = 200 + Math.random() * (2048 - 400); gem.y = 200 + Math.random() * (2732 - 400); // Give a small random velocity gem.velocity.x = (Math.random() - 0.5) * 3; gem.velocity.y = (Math.random() - 0.5) * 3; // Make some gems special (about 10% chance) if (Math.random() < 0.1) { gem.makeSpecial(); } game.addChild(gem); gems.push(gem); return gem; } // Create particles at the specified position function createParticleExplosion(x, y, color, count) { for (var i = 0; i < count; i++) { var particle = new Particle(color); particle.x = x; particle.y = y; game.addChild(particle); particles.push(particle); } } // Check for gem matches function checkMatches() { // Group gems by type var gemGroups = {}; for (var i = 0; i < gems.length; i++) { var gem = gems[i]; if (gem.matched) { continue; } var type = gem.type; if (!gemGroups[type]) { gemGroups[type] = []; } gemGroups[type].push(gem); } // Check each group for matches var matchFound = false; for (var type in gemGroups) { var group = gemGroups[type]; for (var i = 0; i < group.length; i++) { var gem1 = group[i]; var matchingGems = [gem1]; for (var j = i + 1; j < group.length; j++) { var gem2 = group[j]; // Check distance between gems var dx = gem1.x - gem2.x; var dy = gem1.y - gem2.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { matchingGems.push(gem2); } } // If we have enough matching gems if (matchingGems.length >= gemsToMatch) { matchFound = true; // Calculate center point of the match var centerX = 0; var centerY = 0; var specialGemFound = false; for (var k = 0; k < matchingGems.length; k++) { var gem = matchingGems[k]; centerX += gem.x; centerY += gem.y; gem.matched = true; if (gem.special) { specialGemFound = true; } } centerX /= matchingGems.length; centerY /= matchingGems.length; // Create particle explosion var color; switch (type) { case 'red': color = 0xff3333; break; case 'blue': color = 0x3333ff; break; case 'green': color = 0x33ff33; break; case 'yellow': color = 0xffff33; break; case 'purple': color = 0x9933ff; break; default: color = 0xffffff; } var particleCount = 20 + matchingGems.length * 5; if (specialGemFound) { particleCount *= 2; LK.getSound('special_gem').play(); } else { LK.getSound('match').play(); } createParticleExplosion(centerX, centerY, color, particleCount); // Award points var matchPoints = matchingGems.length * 10; if (specialGemFound) { matchPoints *= 3; } score += matchPoints; scoreTxt.setText('Score: ' + score); // Flash score text tween(scoreTxt, { alpha: 0.5 }, { duration: 100, easing: tween.linear, onFinish: function onFinish() { tween(scoreTxt, { alpha: 1 }, { duration: 100, easing: tween.linear }); } }); // Check level progression if (score >= level * 1000) { level++; storage.level = level; initLevel(); return; } // Create a new special gem if the match is large enough if (matchingGems.length >= 5 && !specialGemFound) { var specialGem = new Gem(type); specialGem.x = centerX; specialGem.y = centerY; specialGem.makeSpecial(); game.addChild(specialGem); gems.push(specialGem); } } } } // Remove matched gems for (var i = gems.length - 1; i >= 0; i--) { if (gems[i].matched) { gems[i].destroy(); gems.splice(i, 1); } } // Create new gems if needed and we had a match if (matchFound) { var neededGems = Math.min(maxGems - gems.length, 3); for (var i = 0; i < neededGems; i++) { // Delay the creation of new gems LK.setTimeout(createGem, 300 + i * 200); } } return matchFound; } // Calculate gravity influence on a gem function applyGravity() { for (var i = 0; i < gems.length; i++) { var gem = gems[i]; for (var j = 0; j < gravityWells.length; j++) { var well = gravityWells[j]; if (!well.active) { continue; } var dx = well.x - gem.x; var dy = well.y - gem.y; var distance = Math.sqrt(dx * dx + dy * dy); // Only apply gravity within the well's range if (distance < well.range) { // Calculate force based on distance (inverse square law) var force = well.strength / Math.max(50, distance); force = Math.min(force, 1); // Cap the maximum force // Apply force to gem's velocity gem.velocity.x += dx / distance * force * gem.mass; gem.velocity.y += dy / distance * force * gem.mass; } } } } // Handle player input var placingWell = false; var tempWell = null; function handleDown(x, y) { if (gravityWells.length < maxGravityWells && !placingWell) { placingWell = true; tempWell = new GravityWell(); tempWell.x = x; tempWell.y = y; tempWell.alpha = 0.5; // Semi-transparent until placed game.addChild(tempWell); } } function handleMove(x, y) { if (placingWell && tempWell) { tempWell.x = x; tempWell.y = y; } } function handleUp(x, y) { if (placingWell && tempWell) { // Finalize well placement tempWell.alpha = 1; gravityWells.push(tempWell); // Update UI wellsLeftTxt.setText('Gravity Wells: ' + (maxGravityWells - gravityWells.length)); // Play sound LK.getSound('place_well').play(); // Reset placement state placingWell = false; tempWell = null; } } // Game event handlers game.down = function (x, y) { handleDown(x, y); }; game.move = function (x, y) { handleMove(x, y); }; game.up = function (x, y) { handleUp(x, y); }; // Main game update loop game.update = function () { // Process particles for (var i = particles.length - 1; i >= 0; i--) { var alive = particles[i].update(); if (!alive) { particles[i].destroy(); particles.splice(i, 1); } } // Apply gravity to gems applyGravity(); // Update gems for (var i = 0; i < gems.length; i++) { gems[i].update(); } // Check for gem collisions and matches var matchFound = checkMatches(); // Create new gems occasionally if we have space and didn't just match if (!matchFound && gems.length < maxGems && LK.ticks % 60 === 0) { createGem(); } // If no gravity wells left and no gems in motion, game over if (gravityWells.length === maxGravityWells) { var gemsInMotion = false; for (var i = 0; i < gems.length; i++) { var gem = gems[i]; if (Math.abs(gem.velocity.x) > 0.1 || Math.abs(gem.velocity.y) > 0.1) { gemsInMotion = true; break; } } if (!gemsInMotion && !checkMatches()) { // Check if we have any available matches var possible = false; // Simplified check - just see if any gems are close enough to match for (var type in gemTypesInPlay) { var gemsByType = gems.filter(function (gem) { return gem.type === gemTypesInPlay[type]; }); if (gemsByType.length >= gemsToMatch) { possible = true; break; } } if (!possible) { // Game over, no possible moves LK.showGameOver(); } } } }; // Initialize the game initLevel();
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,530 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Gem = Container.expand(function (type) {
+ var self = Container.call(this);
+ // Define gem types
+ var gemTypes = ['red', 'blue', 'green', 'yellow', 'purple'];
+ self.type = type || gemTypes[Math.floor(Math.random() * gemTypes.length)];
+ var graphics = self.attachAsset('gem_' + self.type, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.velocity = {
+ x: 0,
+ y: 0
+ };
+ self.matched = false;
+ self.special = false;
+ self.mass = 1;
+ // Make special gems 25% larger and add a pulse effect
+ self.makeSpecial = function () {
+ if (self.special) {
+ return;
+ }
+ self.special = true;
+ self.mass = 1.5;
+ graphics.scaleX = 1.25;
+ graphics.scaleY = 1.25;
+ // Add a white glow using tint pulses
+ function pulseTint() {
+ tween(graphics, {
+ alpha: 0.7
+ }, {
+ duration: 700,
+ easing: tween.sinceOut,
+ onFinish: function onFinish() {
+ tween(graphics, {
+ alpha: 1
+ }, {
+ duration: 700,
+ easing: tween.sinceIn,
+ onFinish: pulseTint
+ });
+ }
+ });
+ }
+ pulseTint();
+ };
+ // Apply physics movement
+ self.update = function () {
+ // Apply velocity to position
+ self.x += self.velocity.x;
+ self.y += self.velocity.y;
+ // Apply friction
+ self.velocity.x *= 0.98;
+ self.velocity.y *= 0.98;
+ // Rotate gem based on movement
+ graphics.rotation += Math.sqrt(Math.pow(self.velocity.x, 2) + Math.pow(self.velocity.y, 2)) * 0.01;
+ // Bounce off edges
+ if (self.x < graphics.width / 2) {
+ self.x = graphics.width / 2;
+ self.velocity.x *= -0.8;
+ } else if (self.x > 2048 - graphics.width / 2) {
+ self.x = 2048 - graphics.width / 2;
+ self.velocity.x *= -0.8;
+ }
+ if (self.y < graphics.height / 2) {
+ self.y = graphics.height / 2;
+ self.velocity.y *= -0.8;
+ } else if (self.y > 2732 - graphics.height / 2) {
+ self.y = 2732 - graphics.height / 2;
+ self.velocity.y *= -0.8;
+ }
+ };
+ return self;
+});
+var GravityWell = Container.expand(function () {
+ var self = Container.call(this);
+ var rangeGraphics = self.attachAsset('gravity_range', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.1
+ });
+ var wellGraphics = self.attachAsset('gravity_well', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.strength = 5;
+ self.range = rangeGraphics.width / 2;
+ self.active = true;
+ // Pulse animation for the gravity well
+ function startPulseAnimation() {
+ tween(wellGraphics, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 1000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(wellGraphics, {
+ scaleX: 1.0,
+ scaleY: 1.0
+ }, {
+ duration: 1000,
+ easing: tween.easeInOut,
+ onFinish: startPulseAnimation
+ });
+ }
+ });
+ }
+ startPulseAnimation();
+ return self;
+});
+var Particle = Container.expand(function (color) {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('particle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ if (color) {
+ graphics.tint = color;
+ }
+ self.velocity = {
+ x: (Math.random() - 0.5) * 20,
+ y: (Math.random() - 0.5) * 20
+ };
+ self.lifetime = 30 + Math.random() * 30;
+ self.age = 0;
+ self.update = function () {
+ self.x += self.velocity.x;
+ self.y += self.velocity.y;
+ self.velocity.x *= 0.92;
+ self.velocity.y *= 0.92;
+ self.age++;
+ // Fade out as the particle ages
+ self.alpha = 1 - self.age / self.lifetime;
+ return self.age < self.lifetime;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x111122
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+var gems = [];
+var gravityWells = [];
+var particles = [];
+var maxGems = 25;
+var maxGravityWells = 3;
+var score = 0;
+var level = storage.level || 1;
+var gemTypesInPlay = ['red', 'blue', 'green'];
+var gemsToMatch = 3;
+// UI elements
+var scoreTxt = new Text2('Score: 0', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+var levelTxt = new Text2('Level: ' + level, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+levelTxt.anchor.set(0.5, 0);
+levelTxt.y = 70;
+LK.gui.top.addChild(levelTxt);
+var wellsLeftTxt = new Text2('Gravity Wells: ' + maxGravityWells, {
+ size: 50,
+ fill: 0xFFFFFF
+});
+wellsLeftTxt.anchor.set(0, 0);
+wellsLeftTxt.x = 120;
+wellsLeftTxt.y = 20;
+LK.gui.topLeft.addChild(wellsLeftTxt);
+// Initialize game
+function initLevel() {
+ // Clear existing objects
+ for (var i = gems.length - 1; i >= 0; i--) {
+ gems[i].destroy();
+ }
+ gems = [];
+ for (var i = gravityWells.length - 1; i >= 0; i--) {
+ gravityWells[i].destroy();
+ }
+ gravityWells = [];
+ for (var i = particles.length - 1; i >= 0; i--) {
+ particles[i].destroy();
+ }
+ particles = [];
+ // Update level
+ if (level > 1) {
+ // Unlock yellow gems at level 2
+ if (level >= 2 && gemTypesInPlay.indexOf('yellow') === -1) {
+ gemTypesInPlay.push('yellow');
+ }
+ // Unlock purple gems at level 4
+ if (level >= 4 && gemTypesInPlay.indexOf('purple') === -1) {
+ gemTypesInPlay.push('purple');
+ }
+ // Increase gem count as level increases
+ maxGems = 25 + (level - 1) * 5;
+ if (maxGems > 50) {
+ maxGems = 50;
+ } // Cap at 50 gems
+ // Increase gravity wells with level
+ maxGravityWells = 3 + Math.floor((level - 1) / 2);
+ if (maxGravityWells > 7) {
+ maxGravityWells = 7;
+ } // Cap at 7 wells
+ }
+ // Update UI
+ levelTxt.setText('Level: ' + level);
+ wellsLeftTxt.setText('Gravity Wells: ' + maxGravityWells);
+ scoreTxt.setText('Score: ' + score);
+ // Create initial gems
+ for (var i = 0; i < Math.min(10, maxGems); i++) {
+ createGem();
+ }
+ // Play background music
+ LK.playMusic('bgmusic', {
+ fade: {
+ start: 0,
+ end: 0.4,
+ duration: 1000
+ }
+ });
+}
+// Create a new gem at a random position
+function createGem() {
+ if (gems.length >= maxGems) {
+ return;
+ }
+ var gem = new Gem(gemTypesInPlay[Math.floor(Math.random() * gemTypesInPlay.length)]);
+ // Position randomly but not too close to the edges
+ gem.x = 200 + Math.random() * (2048 - 400);
+ gem.y = 200 + Math.random() * (2732 - 400);
+ // Give a small random velocity
+ gem.velocity.x = (Math.random() - 0.5) * 3;
+ gem.velocity.y = (Math.random() - 0.5) * 3;
+ // Make some gems special (about 10% chance)
+ if (Math.random() < 0.1) {
+ gem.makeSpecial();
+ }
+ game.addChild(gem);
+ gems.push(gem);
+ return gem;
+}
+// Create particles at the specified position
+function createParticleExplosion(x, y, color, count) {
+ for (var i = 0; i < count; i++) {
+ var particle = new Particle(color);
+ particle.x = x;
+ particle.y = y;
+ game.addChild(particle);
+ particles.push(particle);
+ }
+}
+// Check for gem matches
+function checkMatches() {
+ // Group gems by type
+ var gemGroups = {};
+ for (var i = 0; i < gems.length; i++) {
+ var gem = gems[i];
+ if (gem.matched) {
+ continue;
+ }
+ var type = gem.type;
+ if (!gemGroups[type]) {
+ gemGroups[type] = [];
+ }
+ gemGroups[type].push(gem);
+ }
+ // Check each group for matches
+ var matchFound = false;
+ for (var type in gemGroups) {
+ var group = gemGroups[type];
+ for (var i = 0; i < group.length; i++) {
+ var gem1 = group[i];
+ var matchingGems = [gem1];
+ for (var j = i + 1; j < group.length; j++) {
+ var gem2 = group[j];
+ // Check distance between gems
+ var dx = gem1.x - gem2.x;
+ var dy = gem1.y - gem2.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 100) {
+ matchingGems.push(gem2);
+ }
+ }
+ // If we have enough matching gems
+ if (matchingGems.length >= gemsToMatch) {
+ matchFound = true;
+ // Calculate center point of the match
+ var centerX = 0;
+ var centerY = 0;
+ var specialGemFound = false;
+ for (var k = 0; k < matchingGems.length; k++) {
+ var gem = matchingGems[k];
+ centerX += gem.x;
+ centerY += gem.y;
+ gem.matched = true;
+ if (gem.special) {
+ specialGemFound = true;
+ }
+ }
+ centerX /= matchingGems.length;
+ centerY /= matchingGems.length;
+ // Create particle explosion
+ var color;
+ switch (type) {
+ case 'red':
+ color = 0xff3333;
+ break;
+ case 'blue':
+ color = 0x3333ff;
+ break;
+ case 'green':
+ color = 0x33ff33;
+ break;
+ case 'yellow':
+ color = 0xffff33;
+ break;
+ case 'purple':
+ color = 0x9933ff;
+ break;
+ default:
+ color = 0xffffff;
+ }
+ var particleCount = 20 + matchingGems.length * 5;
+ if (specialGemFound) {
+ particleCount *= 2;
+ LK.getSound('special_gem').play();
+ } else {
+ LK.getSound('match').play();
+ }
+ createParticleExplosion(centerX, centerY, color, particleCount);
+ // Award points
+ var matchPoints = matchingGems.length * 10;
+ if (specialGemFound) {
+ matchPoints *= 3;
+ }
+ score += matchPoints;
+ scoreTxt.setText('Score: ' + score);
+ // Flash score text
+ tween(scoreTxt, {
+ alpha: 0.5
+ }, {
+ duration: 100,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ tween(scoreTxt, {
+ alpha: 1
+ }, {
+ duration: 100,
+ easing: tween.linear
+ });
+ }
+ });
+ // Check level progression
+ if (score >= level * 1000) {
+ level++;
+ storage.level = level;
+ initLevel();
+ return;
+ }
+ // Create a new special gem if the match is large enough
+ if (matchingGems.length >= 5 && !specialGemFound) {
+ var specialGem = new Gem(type);
+ specialGem.x = centerX;
+ specialGem.y = centerY;
+ specialGem.makeSpecial();
+ game.addChild(specialGem);
+ gems.push(specialGem);
+ }
+ }
+ }
+ }
+ // Remove matched gems
+ for (var i = gems.length - 1; i >= 0; i--) {
+ if (gems[i].matched) {
+ gems[i].destroy();
+ gems.splice(i, 1);
+ }
+ }
+ // Create new gems if needed and we had a match
+ if (matchFound) {
+ var neededGems = Math.min(maxGems - gems.length, 3);
+ for (var i = 0; i < neededGems; i++) {
+ // Delay the creation of new gems
+ LK.setTimeout(createGem, 300 + i * 200);
+ }
+ }
+ return matchFound;
+}
+// Calculate gravity influence on a gem
+function applyGravity() {
+ for (var i = 0; i < gems.length; i++) {
+ var gem = gems[i];
+ for (var j = 0; j < gravityWells.length; j++) {
+ var well = gravityWells[j];
+ if (!well.active) {
+ continue;
+ }
+ var dx = well.x - gem.x;
+ var dy = well.y - gem.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // Only apply gravity within the well's range
+ if (distance < well.range) {
+ // Calculate force based on distance (inverse square law)
+ var force = well.strength / Math.max(50, distance);
+ force = Math.min(force, 1); // Cap the maximum force
+ // Apply force to gem's velocity
+ gem.velocity.x += dx / distance * force * gem.mass;
+ gem.velocity.y += dy / distance * force * gem.mass;
+ }
+ }
+ }
+}
+// Handle player input
+var placingWell = false;
+var tempWell = null;
+function handleDown(x, y) {
+ if (gravityWells.length < maxGravityWells && !placingWell) {
+ placingWell = true;
+ tempWell = new GravityWell();
+ tempWell.x = x;
+ tempWell.y = y;
+ tempWell.alpha = 0.5; // Semi-transparent until placed
+ game.addChild(tempWell);
+ }
+}
+function handleMove(x, y) {
+ if (placingWell && tempWell) {
+ tempWell.x = x;
+ tempWell.y = y;
+ }
+}
+function handleUp(x, y) {
+ if (placingWell && tempWell) {
+ // Finalize well placement
+ tempWell.alpha = 1;
+ gravityWells.push(tempWell);
+ // Update UI
+ wellsLeftTxt.setText('Gravity Wells: ' + (maxGravityWells - gravityWells.length));
+ // Play sound
+ LK.getSound('place_well').play();
+ // Reset placement state
+ placingWell = false;
+ tempWell = null;
+ }
+}
+// Game event handlers
+game.down = function (x, y) {
+ handleDown(x, y);
+};
+game.move = function (x, y) {
+ handleMove(x, y);
+};
+game.up = function (x, y) {
+ handleUp(x, y);
+};
+// Main game update loop
+game.update = function () {
+ // Process particles
+ for (var i = particles.length - 1; i >= 0; i--) {
+ var alive = particles[i].update();
+ if (!alive) {
+ particles[i].destroy();
+ particles.splice(i, 1);
+ }
+ }
+ // Apply gravity to gems
+ applyGravity();
+ // Update gems
+ for (var i = 0; i < gems.length; i++) {
+ gems[i].update();
+ }
+ // Check for gem collisions and matches
+ var matchFound = checkMatches();
+ // Create new gems occasionally if we have space and didn't just match
+ if (!matchFound && gems.length < maxGems && LK.ticks % 60 === 0) {
+ createGem();
+ }
+ // If no gravity wells left and no gems in motion, game over
+ if (gravityWells.length === maxGravityWells) {
+ var gemsInMotion = false;
+ for (var i = 0; i < gems.length; i++) {
+ var gem = gems[i];
+ if (Math.abs(gem.velocity.x) > 0.1 || Math.abs(gem.velocity.y) > 0.1) {
+ gemsInMotion = true;
+ break;
+ }
+ }
+ if (!gemsInMotion && !checkMatches()) {
+ // Check if we have any available matches
+ var possible = false;
+ // Simplified check - just see if any gems are close enough to match
+ for (var type in gemTypesInPlay) {
+ var gemsByType = gems.filter(function (gem) {
+ return gem.type === gemTypesInPlay[type];
+ });
+ if (gemsByType.length >= gemsToMatch) {
+ possible = true;
+ break;
+ }
+ }
+ if (!possible) {
+ // Game over, no possible moves
+ LK.showGameOver();
+ }
+ }
+ }
+};
+// Initialize the game
+initLevel();
\ No newline at end of file