/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var CelestialObject = Container.expand(function (type, size, color) { var self = Container.call(this); self.type = type || 'asteroid'; self.size = size || 1; self.color = color || 0xffffff; // Physics properties self.velocity = { x: 0, y: 0 }; self.acceleration = { x: 0, y: 0 }; self.mass = size * 10; self.isAttracted = false; self.isRepelled = false; // Create visual representation var visual = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, scaleX: size, scaleY: size }); self.radius = visual.width * size / 2; // Apply physics forces self.applyForce = function (force) { // F = ma, so a = F/m self.acceleration.x += force.x / self.mass; self.acceleration.y += force.y / self.mass; }; // Update position based on physics self.update = function () { // Apply velocity self.velocity.x += self.acceleration.x; self.velocity.y += self.acceleration.y; // Apply velocity limits var maxSpeed = 15; var speedSq = self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y; if (speedSq > maxSpeed * maxSpeed) { var speed = Math.sqrt(speedSq); self.velocity.x = self.velocity.x / speed * maxSpeed; self.velocity.y = self.velocity.y / speed * maxSpeed; } // Update position self.x += self.velocity.x; self.y += self.velocity.y; // Reset acceleration self.acceleration.x = 0; self.acceleration.y = 0; // Screen wrapping if (self.x < -self.radius) { self.x = 2048 + self.radius; } if (self.x > 2048 + self.radius) { self.x = -self.radius; } if (self.y < -self.radius) { self.y = 2732 + self.radius; } if (self.y > 2732 + self.radius) { self.y = -self.radius; } // Visual effects for attraction/repulsion if (self.isAttracted) { self.rotation += 0.02; self.isAttracted = false; } else if (self.isRepelled) { self.rotation -= 0.02; self.isRepelled = false; } }; return self; }); var CentralOrb = Container.expand(function () { var self = Container.call(this); // Create visual orb var orbVisual = self.attachAsset('centralOrb', { anchorX: 0.5, anchorY: 0.5 }); // Attraction field visualization var attractField = self.attachAsset('attractField', { anchorX: 0.5, anchorY: 0.5 }); attractField.alpha = 0; // Repulsion field visualization var repelField = self.attachAsset('repelField', { anchorX: 0.5, anchorY: 0.5 }); repelField.alpha = 0; // Properties self.radius = orbVisual.width / 2; self.attractionRadius = attractField.width / 2; self.mode = 'attract'; // 'attract' or 'repel' self.power = 1.0; self.energy = 100; self.maxEnergy = 100; // Toggle between attract and repel mode self.toggleMode = function () { if (self.mode === 'attract') { self.mode = 'repel'; tween(attractField, { alpha: 0 }, { duration: 300 }); tween(repelField, { alpha: 0.2 }, { duration: 300 }); LK.getSound('repel').play(); } else { self.mode = 'attract'; tween(attractField, { alpha: 0.2 }, { duration: 300 }); tween(repelField, { alpha: 0 }, { duration: 300 }); LK.getSound('attract').play(); } }; // Activate field effect self.activateField = function () { if (self.energy <= 0) { return; } // Show appropriate field if (self.mode === 'attract') { tween(attractField, { alpha: 0.3 }, { duration: 200 }); } else { tween(repelField, { alpha: 0.3 }, { duration: 200 }); } // Energy consumption self.energy -= 0.5; if (self.energy < 0) { self.energy = 0; } }; // Deactivate field effect self.deactivateField = function () { if (self.mode === 'attract') { tween(attractField, { alpha: 0.1 }, { duration: 300 }); } else { tween(repelField, { alpha: 0.1 }, { duration: 300 }); } }; // Pulse effect self.pulse = function () { tween(orbVisual, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(orbVisual, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); }; // Update central orb state self.update = function () { // Passive energy regeneration if (self.energy < self.maxEnergy) { self.energy += 0.1; if (self.energy > self.maxEnergy) { self.energy = self.maxEnergy; } } // Visual effect (slow rotation) orbVisual.rotation += 0.01; }; return self; }); var EnergyBar = Container.expand(function () { var self = Container.call(this); // Energy bar background var barWidth = 200; var barHeight = 30; var barBg = LK.getAsset('bullet', { anchorX: 0, anchorY: 0, scaleX: barWidth / 100, scaleY: barHeight / 100, tint: 0x333333 }); self.addChild(barBg); // Energy bar fill var barFill = LK.getAsset('bullet', { anchorX: 0, anchorY: 0, scaleX: barWidth / 100, scaleY: barHeight / 100, tint: 0x3498db }); self.addChild(barFill); // Label var label = new Text2('ENERGY', { size: 18, fill: 0xFFFFFF }); label.anchor.set(0, 0.5); label.x = 10; label.y = barHeight / 2; self.addChild(label); // Update energy bar self.updateEnergy = function (percent) { barFill.scale.x = barWidth / 100 * (percent / 100); // Change color based on energy level if (percent < 30) { barFill.tint = 0xe74c3c; // Red when low } else if (percent < 60) { barFill.tint = 0xf39c12; // Orange when medium } else { barFill.tint = 0x3498db; // Blue when high } }; return self; }); var StarField = Container.expand(function (count) { var self = Container.call(this); self.stars = []; // Create star field for (var i = 0; i < count; i++) { var star = self.attachAsset('starParticle', { anchorX: 0.5, anchorY: 0.5, alpha: Math.random() * 0.7 + 0.3, scaleX: Math.random() * 0.8 + 0.2, scaleY: Math.random() * 0.8 + 0.2 }); star.x = Math.random() * 2048; star.y = Math.random() * 2732; star.speed = Math.random() * 0.5 + 0.1; self.stars.push(star); } // Update stars (parallax scrolling effect) self.update = function () { for (var i = 0; i < self.stars.length; i++) { var star = self.stars[i]; star.y += star.speed; if (star.y > 2732) { star.y = 0; star.x = Math.random() * 2048; } // Twinkle effect if (Math.random() < 0.005) { tween(star, { alpha: Math.random() * 0.5 + 0.3 }, { duration: 500 }); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game state variables var gameActive = true; var level = 1; var score = 0; var highScore = storage.highScore || 0; var lastSpawnTime = 0; var difficultyMultiplier = 1; // Game elements var centralOrb; var celestialObjects = []; var starField; var energyBar; var scoreText; var levelText; var isFieldActive = false; // Initialize star field background starField = game.addChild(new StarField(100)); // Create central orb centralOrb = game.addChild(new CentralOrb()); centralOrb.x = 2048 / 2; centralOrb.y = 2732 / 2; // Create energy bar energyBar = new EnergyBar(); energyBar.x = 30; energyBar.y = 30; LK.gui.topRight.addChild(energyBar); // Create score text scoreText = new Text2('SCORE: 0', { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Create level text levelText = new Text2('LEVEL: 1', { size: 30, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.y = 50; LK.gui.top.addChild(levelText); // Set High score LK.setScore(score); // Play background music LK.playMusic('cosmicAmbience'); // Event Handlers game.down = function (x, y) { // Toggle attraction/repulsion mode on tap centralOrb.toggleMode(); // Activate field isFieldActive = true; centralOrb.activateField(); }; game.up = function () { // Deactivate field isFieldActive = false; centralOrb.deactivateField(); }; game.move = function (x, y) { // Move central orb to touch position, but limited to the center area var centerX = 2048 / 2; var centerY = 2732 / 2; var maxDistance = 400; var dx = x - centerX; var dy = y - centerY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > maxDistance) { var ratio = maxDistance / distance; dx *= ratio; dy *= ratio; } centralOrb.x = centerX + dx; centralOrb.y = centerY + dy; }; // Spawn celestial objects function spawnCelestialObject() { var type, size, speed; var rand = Math.random(); // Determine type based on random value and level if (rand < 0.7) { type = 'asteroid'; size = Math.random() * 0.5 + 0.5; speed = Math.random() * 3 + 1; } else { type = 'energyParticle'; size = Math.random() * 0.3 + 0.3; speed = Math.random() * 4 + 2; } // Create object var obj = new CelestialObject(type, size); // Position at edge of screen var side = Math.floor(Math.random() * 4); if (side === 0) { // Top obj.x = Math.random() * 2048; obj.y = -obj.radius; obj.velocity.y = speed; } else if (side === 1) { // Right obj.x = 2048 + obj.radius; obj.y = Math.random() * 2732; obj.velocity.x = -speed; } else if (side === 2) { // Bottom obj.x = Math.random() * 2048; obj.y = 2732 + obj.radius; obj.velocity.y = -speed; } else { // Left obj.x = -obj.radius; obj.y = Math.random() * 2732; obj.velocity.x = speed; } // Add small random component to make movement less predictable obj.velocity.x += (Math.random() - 0.5) * 2; obj.velocity.y += (Math.random() - 0.5) * 2; // Add to game game.addChild(obj); celestialObjects.push(obj); return obj; } // Check for collisions between objects function checkCollisions() { // Check for collisions between celestial objects for (var i = 0; i < celestialObjects.length; i++) { var obj1 = celestialObjects[i]; // Check collision with central orb var dx = obj1.x - centralOrb.x; var dy = obj1.y - centralOrb.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < obj1.radius + centralOrb.radius) { // Handle collision based on object type if (obj1.type === 'energyParticle') { // Collect energy particle centralOrb.energy += 10; if (centralOrb.energy > centralOrb.maxEnergy) { centralOrb.energy = centralOrb.maxEnergy; } score += 10; LK.setScore(score); scoreText.setText('SCORE: ' + score); obj1.destroy(); celestialObjects.splice(i, 1); i--; // Visual effect centralOrb.pulse(); LK.getSound('collect').play(); } else { // Collision with asteroid - game over if (gameActive) { gameActive = false; LK.effects.flashScreen(0xff0000, 500); LK.getSound('collision').play(); // Update high score if (score > highScore) { highScore = score; storage.highScore = highScore; } // Show game over after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 1000); } } } // Check collisions with other objects for (var j = i + 1; j < celestialObjects.length; j++) { var obj2 = celestialObjects[j]; dx = obj1.x - obj2.x; dy = obj1.y - obj2.y; distance = Math.sqrt(dx * dx + dy * dy); if (distance < obj1.radius + obj2.radius) { // Calculate collision response var angle = Math.atan2(dy, dx); var totalMass = obj1.mass + obj2.mass; var obj1Ratio = obj2.mass / totalMass; var obj2Ratio = obj1.mass / totalMass; // Apply new velocities var obj1Speed = Math.sqrt(obj1.velocity.x * obj1.velocity.x + obj1.velocity.y * obj1.velocity.y); var obj2Speed = Math.sqrt(obj2.velocity.x * obj2.velocity.x + obj2.velocity.y * obj2.velocity.y); obj1.velocity.x = (obj1.velocity.x * (obj1.mass - obj2.mass) + 2 * obj2.mass * obj2.velocity.x) / totalMass; obj1.velocity.y = (obj1.velocity.y * (obj1.mass - obj2.mass) + 2 * obj2.mass * obj2.velocity.y) / totalMass; obj2.velocity.x = (obj2.velocity.x * (obj2.mass - obj1.mass) + 2 * obj1.mass * obj1.velocity.x) / totalMass; obj2.velocity.y = (obj2.velocity.y * (obj2.mass - obj1.mass) + 2 * obj1.mass * obj1.velocity.y) / totalMass; // Move objects apart to prevent sticking var overlap = obj1.radius + obj2.radius - distance; obj1.x += Math.cos(angle) * overlap * obj1Ratio; obj1.y += Math.sin(angle) * overlap * obj1Ratio; obj2.x -= Math.cos(angle) * overlap * obj2Ratio; obj2.y -= Math.sin(angle) * overlap * obj2Ratio; // Visual effect if (Math.random() > 0.5) { LK.getSound('collision').play(); } } } } } // Apply gravitational forces to celestial objects function applyGravitationalForces() { if (!isFieldActive || centralOrb.energy <= 0) { return; } for (var i = 0; i < celestialObjects.length; i++) { var obj = celestialObjects[i]; // Calculate direction to central orb var dx = centralOrb.x - obj.x; var dy = centralOrb.y - obj.y; var distSq = dx * dx + dy * dy; var dist = Math.sqrt(distSq); // Check if within field radius if (dist < centralOrb.attractionRadius) { // Normalize direction var nx = dx / dist; var ny = dy / dist; // Calculate force based on distance (inverse square law) var strength = centralOrb.power * 5 / Math.max(distSq, 100); // Apply attraction or repulsion if (centralOrb.mode === 'attract') { obj.applyForce({ x: nx * strength, y: ny * strength }); obj.isAttracted = true; } else { obj.applyForce({ x: -nx * strength, y: -ny * strength }); obj.isRepelled = true; } } } } // Update game level function updateLevel() { var newLevel = Math.floor(score / 100) + 1; if (newLevel > level) { level = newLevel; levelText.setText('LEVEL: ' + level); difficultyMultiplier = 1 + (level - 1) * 0.2; // Increase central orb powers centralOrb.maxEnergy += 10; centralOrb.power += 0.1; // Visual effects LK.effects.flashScreen(0x3498db, 300); } } // Main game update function game.update = function () { if (!gameActive) { return; } // Update game objects starField.update(); centralOrb.update(); // Update energy bar energyBar.updateEnergy(centralOrb.energy / centralOrb.maxEnergy * 100); // Check if we need to spawn new objects if (LK.ticks > lastSpawnTime + Math.max(30, 60 - level * 3)) { spawnCelestialObject(); lastSpawnTime = LK.ticks; } // Apply gravitational forces applyGravitationalForces(); // Update all celestial objects for (var i = celestialObjects.length - 1; i >= 0; i--) { celestialObjects[i].update(); } // Check for collisions checkCollisions(); // Update level based on score updateLevel(); // Score increases over time if (LK.ticks % 60 === 0) { score += 1; LK.setScore(score); scoreText.setText('SCORE: ' + score); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var CelestialObject = Container.expand(function (type, size, color) {
var self = Container.call(this);
self.type = type || 'asteroid';
self.size = size || 1;
self.color = color || 0xffffff;
// Physics properties
self.velocity = {
x: 0,
y: 0
};
self.acceleration = {
x: 0,
y: 0
};
self.mass = size * 10;
self.isAttracted = false;
self.isRepelled = false;
// Create visual representation
var visual = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size,
scaleY: size
});
self.radius = visual.width * size / 2;
// Apply physics forces
self.applyForce = function (force) {
// F = ma, so a = F/m
self.acceleration.x += force.x / self.mass;
self.acceleration.y += force.y / self.mass;
};
// Update position based on physics
self.update = function () {
// Apply velocity
self.velocity.x += self.acceleration.x;
self.velocity.y += self.acceleration.y;
// Apply velocity limits
var maxSpeed = 15;
var speedSq = self.velocity.x * self.velocity.x + self.velocity.y * self.velocity.y;
if (speedSq > maxSpeed * maxSpeed) {
var speed = Math.sqrt(speedSq);
self.velocity.x = self.velocity.x / speed * maxSpeed;
self.velocity.y = self.velocity.y / speed * maxSpeed;
}
// Update position
self.x += self.velocity.x;
self.y += self.velocity.y;
// Reset acceleration
self.acceleration.x = 0;
self.acceleration.y = 0;
// Screen wrapping
if (self.x < -self.radius) {
self.x = 2048 + self.radius;
}
if (self.x > 2048 + self.radius) {
self.x = -self.radius;
}
if (self.y < -self.radius) {
self.y = 2732 + self.radius;
}
if (self.y > 2732 + self.radius) {
self.y = -self.radius;
}
// Visual effects for attraction/repulsion
if (self.isAttracted) {
self.rotation += 0.02;
self.isAttracted = false;
} else if (self.isRepelled) {
self.rotation -= 0.02;
self.isRepelled = false;
}
};
return self;
});
var CentralOrb = Container.expand(function () {
var self = Container.call(this);
// Create visual orb
var orbVisual = self.attachAsset('centralOrb', {
anchorX: 0.5,
anchorY: 0.5
});
// Attraction field visualization
var attractField = self.attachAsset('attractField', {
anchorX: 0.5,
anchorY: 0.5
});
attractField.alpha = 0;
// Repulsion field visualization
var repelField = self.attachAsset('repelField', {
anchorX: 0.5,
anchorY: 0.5
});
repelField.alpha = 0;
// Properties
self.radius = orbVisual.width / 2;
self.attractionRadius = attractField.width / 2;
self.mode = 'attract'; // 'attract' or 'repel'
self.power = 1.0;
self.energy = 100;
self.maxEnergy = 100;
// Toggle between attract and repel mode
self.toggleMode = function () {
if (self.mode === 'attract') {
self.mode = 'repel';
tween(attractField, {
alpha: 0
}, {
duration: 300
});
tween(repelField, {
alpha: 0.2
}, {
duration: 300
});
LK.getSound('repel').play();
} else {
self.mode = 'attract';
tween(attractField, {
alpha: 0.2
}, {
duration: 300
});
tween(repelField, {
alpha: 0
}, {
duration: 300
});
LK.getSound('attract').play();
}
};
// Activate field effect
self.activateField = function () {
if (self.energy <= 0) {
return;
}
// Show appropriate field
if (self.mode === 'attract') {
tween(attractField, {
alpha: 0.3
}, {
duration: 200
});
} else {
tween(repelField, {
alpha: 0.3
}, {
duration: 200
});
}
// Energy consumption
self.energy -= 0.5;
if (self.energy < 0) {
self.energy = 0;
}
};
// Deactivate field effect
self.deactivateField = function () {
if (self.mode === 'attract') {
tween(attractField, {
alpha: 0.1
}, {
duration: 300
});
} else {
tween(repelField, {
alpha: 0.1
}, {
duration: 300
});
}
};
// Pulse effect
self.pulse = function () {
tween(orbVisual, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(orbVisual, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
};
// Update central orb state
self.update = function () {
// Passive energy regeneration
if (self.energy < self.maxEnergy) {
self.energy += 0.1;
if (self.energy > self.maxEnergy) {
self.energy = self.maxEnergy;
}
}
// Visual effect (slow rotation)
orbVisual.rotation += 0.01;
};
return self;
});
var EnergyBar = Container.expand(function () {
var self = Container.call(this);
// Energy bar background
var barWidth = 200;
var barHeight = 30;
var barBg = LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
scaleX: barWidth / 100,
scaleY: barHeight / 100,
tint: 0x333333
});
self.addChild(barBg);
// Energy bar fill
var barFill = LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
scaleX: barWidth / 100,
scaleY: barHeight / 100,
tint: 0x3498db
});
self.addChild(barFill);
// Label
var label = new Text2('ENERGY', {
size: 18,
fill: 0xFFFFFF
});
label.anchor.set(0, 0.5);
label.x = 10;
label.y = barHeight / 2;
self.addChild(label);
// Update energy bar
self.updateEnergy = function (percent) {
barFill.scale.x = barWidth / 100 * (percent / 100);
// Change color based on energy level
if (percent < 30) {
barFill.tint = 0xe74c3c; // Red when low
} else if (percent < 60) {
barFill.tint = 0xf39c12; // Orange when medium
} else {
barFill.tint = 0x3498db; // Blue when high
}
};
return self;
});
var StarField = Container.expand(function (count) {
var self = Container.call(this);
self.stars = [];
// Create star field
for (var i = 0; i < count; i++) {
var star = self.attachAsset('starParticle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: Math.random() * 0.7 + 0.3,
scaleX: Math.random() * 0.8 + 0.2,
scaleY: Math.random() * 0.8 + 0.2
});
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.speed = Math.random() * 0.5 + 0.1;
self.stars.push(star);
}
// Update stars (parallax scrolling effect)
self.update = function () {
for (var i = 0; i < self.stars.length; i++) {
var star = self.stars[i];
star.y += star.speed;
if (star.y > 2732) {
star.y = 0;
star.x = Math.random() * 2048;
}
// Twinkle effect
if (Math.random() < 0.005) {
tween(star, {
alpha: Math.random() * 0.5 + 0.3
}, {
duration: 500
});
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var gameActive = true;
var level = 1;
var score = 0;
var highScore = storage.highScore || 0;
var lastSpawnTime = 0;
var difficultyMultiplier = 1;
// Game elements
var centralOrb;
var celestialObjects = [];
var starField;
var energyBar;
var scoreText;
var levelText;
var isFieldActive = false;
// Initialize star field background
starField = game.addChild(new StarField(100));
// Create central orb
centralOrb = game.addChild(new CentralOrb());
centralOrb.x = 2048 / 2;
centralOrb.y = 2732 / 2;
// Create energy bar
energyBar = new EnergyBar();
energyBar.x = 30;
energyBar.y = 30;
LK.gui.topRight.addChild(energyBar);
// Create score text
scoreText = new Text2('SCORE: 0', {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create level text
levelText = new Text2('LEVEL: 1', {
size: 30,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.y = 50;
LK.gui.top.addChild(levelText);
// Set High score
LK.setScore(score);
// Play background music
LK.playMusic('cosmicAmbience');
// Event Handlers
game.down = function (x, y) {
// Toggle attraction/repulsion mode on tap
centralOrb.toggleMode();
// Activate field
isFieldActive = true;
centralOrb.activateField();
};
game.up = function () {
// Deactivate field
isFieldActive = false;
centralOrb.deactivateField();
};
game.move = function (x, y) {
// Move central orb to touch position, but limited to the center area
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var maxDistance = 400;
var dx = x - centerX;
var dy = y - centerY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > maxDistance) {
var ratio = maxDistance / distance;
dx *= ratio;
dy *= ratio;
}
centralOrb.x = centerX + dx;
centralOrb.y = centerY + dy;
};
// Spawn celestial objects
function spawnCelestialObject() {
var type, size, speed;
var rand = Math.random();
// Determine type based on random value and level
if (rand < 0.7) {
type = 'asteroid';
size = Math.random() * 0.5 + 0.5;
speed = Math.random() * 3 + 1;
} else {
type = 'energyParticle';
size = Math.random() * 0.3 + 0.3;
speed = Math.random() * 4 + 2;
}
// Create object
var obj = new CelestialObject(type, size);
// Position at edge of screen
var side = Math.floor(Math.random() * 4);
if (side === 0) {
// Top
obj.x = Math.random() * 2048;
obj.y = -obj.radius;
obj.velocity.y = speed;
} else if (side === 1) {
// Right
obj.x = 2048 + obj.radius;
obj.y = Math.random() * 2732;
obj.velocity.x = -speed;
} else if (side === 2) {
// Bottom
obj.x = Math.random() * 2048;
obj.y = 2732 + obj.radius;
obj.velocity.y = -speed;
} else {
// Left
obj.x = -obj.radius;
obj.y = Math.random() * 2732;
obj.velocity.x = speed;
}
// Add small random component to make movement less predictable
obj.velocity.x += (Math.random() - 0.5) * 2;
obj.velocity.y += (Math.random() - 0.5) * 2;
// Add to game
game.addChild(obj);
celestialObjects.push(obj);
return obj;
}
// Check for collisions between objects
function checkCollisions() {
// Check for collisions between celestial objects
for (var i = 0; i < celestialObjects.length; i++) {
var obj1 = celestialObjects[i];
// Check collision with central orb
var dx = obj1.x - centralOrb.x;
var dy = obj1.y - centralOrb.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < obj1.radius + centralOrb.radius) {
// Handle collision based on object type
if (obj1.type === 'energyParticle') {
// Collect energy particle
centralOrb.energy += 10;
if (centralOrb.energy > centralOrb.maxEnergy) {
centralOrb.energy = centralOrb.maxEnergy;
}
score += 10;
LK.setScore(score);
scoreText.setText('SCORE: ' + score);
obj1.destroy();
celestialObjects.splice(i, 1);
i--;
// Visual effect
centralOrb.pulse();
LK.getSound('collect').play();
} else {
// Collision with asteroid - game over
if (gameActive) {
gameActive = false;
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('collision').play();
// Update high score
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
}
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
}
// Check collisions with other objects
for (var j = i + 1; j < celestialObjects.length; j++) {
var obj2 = celestialObjects[j];
dx = obj1.x - obj2.x;
dy = obj1.y - obj2.y;
distance = Math.sqrt(dx * dx + dy * dy);
if (distance < obj1.radius + obj2.radius) {
// Calculate collision response
var angle = Math.atan2(dy, dx);
var totalMass = obj1.mass + obj2.mass;
var obj1Ratio = obj2.mass / totalMass;
var obj2Ratio = obj1.mass / totalMass;
// Apply new velocities
var obj1Speed = Math.sqrt(obj1.velocity.x * obj1.velocity.x + obj1.velocity.y * obj1.velocity.y);
var obj2Speed = Math.sqrt(obj2.velocity.x * obj2.velocity.x + obj2.velocity.y * obj2.velocity.y);
obj1.velocity.x = (obj1.velocity.x * (obj1.mass - obj2.mass) + 2 * obj2.mass * obj2.velocity.x) / totalMass;
obj1.velocity.y = (obj1.velocity.y * (obj1.mass - obj2.mass) + 2 * obj2.mass * obj2.velocity.y) / totalMass;
obj2.velocity.x = (obj2.velocity.x * (obj2.mass - obj1.mass) + 2 * obj1.mass * obj1.velocity.x) / totalMass;
obj2.velocity.y = (obj2.velocity.y * (obj2.mass - obj1.mass) + 2 * obj1.mass * obj1.velocity.y) / totalMass;
// Move objects apart to prevent sticking
var overlap = obj1.radius + obj2.radius - distance;
obj1.x += Math.cos(angle) * overlap * obj1Ratio;
obj1.y += Math.sin(angle) * overlap * obj1Ratio;
obj2.x -= Math.cos(angle) * overlap * obj2Ratio;
obj2.y -= Math.sin(angle) * overlap * obj2Ratio;
// Visual effect
if (Math.random() > 0.5) {
LK.getSound('collision').play();
}
}
}
}
}
// Apply gravitational forces to celestial objects
function applyGravitationalForces() {
if (!isFieldActive || centralOrb.energy <= 0) {
return;
}
for (var i = 0; i < celestialObjects.length; i++) {
var obj = celestialObjects[i];
// Calculate direction to central orb
var dx = centralOrb.x - obj.x;
var dy = centralOrb.y - obj.y;
var distSq = dx * dx + dy * dy;
var dist = Math.sqrt(distSq);
// Check if within field radius
if (dist < centralOrb.attractionRadius) {
// Normalize direction
var nx = dx / dist;
var ny = dy / dist;
// Calculate force based on distance (inverse square law)
var strength = centralOrb.power * 5 / Math.max(distSq, 100);
// Apply attraction or repulsion
if (centralOrb.mode === 'attract') {
obj.applyForce({
x: nx * strength,
y: ny * strength
});
obj.isAttracted = true;
} else {
obj.applyForce({
x: -nx * strength,
y: -ny * strength
});
obj.isRepelled = true;
}
}
}
}
// Update game level
function updateLevel() {
var newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) {
level = newLevel;
levelText.setText('LEVEL: ' + level);
difficultyMultiplier = 1 + (level - 1) * 0.2;
// Increase central orb powers
centralOrb.maxEnergy += 10;
centralOrb.power += 0.1;
// Visual effects
LK.effects.flashScreen(0x3498db, 300);
}
}
// Main game update function
game.update = function () {
if (!gameActive) {
return;
}
// Update game objects
starField.update();
centralOrb.update();
// Update energy bar
energyBar.updateEnergy(centralOrb.energy / centralOrb.maxEnergy * 100);
// Check if we need to spawn new objects
if (LK.ticks > lastSpawnTime + Math.max(30, 60 - level * 3)) {
spawnCelestialObject();
lastSpawnTime = LK.ticks;
}
// Apply gravitational forces
applyGravitationalForces();
// Update all celestial objects
for (var i = celestialObjects.length - 1; i >= 0; i--) {
celestialObjects[i].update();
}
// Check for collisions
checkCollisions();
// Update level based on score
updateLevel();
// Score increases over time
if (LK.ticks % 60 === 0) {
score += 1;
LK.setScore(score);
scoreText.setText('SCORE: ' + score);
}
};