/****
* 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);
}
};