User prompt
turret otomatik ateş etsin biz döndürelim
User prompt
turret bir dikeyi hedef almasın. tıkladığım yöne ateş etsin
User prompt
turret olmasın tıklayarak yok edelim
User prompt
turret döndürülebilsin
User prompt
Compilation error[L14]: Plugins failed to load.
Code edit (1 edits merged)
Please save this source code
User prompt
Meteor Defender: Save the Earth
Initial prompt
Dünyayı Meteorlardan kurtardığımız bir oyun yap. (İngilizce)
/**** * Classes ****/ // Alien class: 30% chance to spawn, acts as a meteor var Alien = Container.expand(function () { var self = Container.call(this); // Use the 'Alien' asset for alien var alienAsset = self.attachAsset('Alien', { anchorX: 0.5, anchorY: 0.5 }); // Hitbox (ellipse, more accurate for Alien shape) self.hitbox = { x: 0, y: 0, // Use a slightly smaller ellipse hitbox for fairness radiusX: alienAsset.width * 0.28, radiusY: alienAsset.height * 0.32 }; // Movement: falls straight down, similar to meteor self.speed = 12 + Math.random() * 8; self.rotationSpeed = (Math.random() - 0.5) * 0.08; self.lastIntersecting = false; self.update = function () { self.y += self.speed * 0.4; self.rotation += self.rotationSpeed; self.hitbox.x = self.x; self.hitbox.y = self.y; // No change needed here, just keep hitbox position updated }; return self; }); // Developer class: Rare, shootable, grants fire rate boost var Developer = Container.expand(function () { var self = Container.call(this); // Use the 'x2' asset for developer (powerup) var dev = self.attachAsset('x2', { anchorX: 0.5, anchorY: 0.5 }); // Hitbox (circle) self.hitbox = { x: 0, y: 0, radius: dev.width * 0.45 }; // Movement: falls straight down, similar to meteor self.speed = 32 + Math.random() * 8; self.rotationSpeed = (Math.random() - 0.5) * 0.08; self.lastIntersecting = false; self.update = function () { self.y += self.speed * 0.4; self.rotation += self.rotationSpeed; self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); // HardMeteor class: Tough meteor with unique asset and behavior var HardMeteor = Container.expand(function () { var self = Container.call(this); // Use the 'Hardmeteor' asset for hard meteor (with capital H) var hardMeteor = self.attachAsset('HardMeteor', { anchorX: 0.5, anchorY: 0.5 }); // Hitbox (circle) self.hitbox = { x: 0, y: 0, radius: hardMeteor.width * 0.38 }; // Movement: falls straight down, very slow self.speed = 4 + Math.random() * 2; // MUCH slower than other meteors self.rotationSpeed = (Math.random() - 0.5) * 0.08; self.lastIntersecting = false; // Track hits required to destroy self.hitsLeft = 7; self.update = function () { self.y += self.speed * 0.4; self.rotation += self.rotationSpeed; self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); // Meteor class: Falling enemy var Meteor = Container.expand(function () { var self = Container.call(this); var meteor = self.attachAsset('meteor', { anchorX: 0.5, anchorY: 0.5 }); // Add a hitbox property (circle for simplicity) self.hitbox = { x: 0, y: 0, radius: meteor.width * 0.38 // slightly smaller than graphic for fairness }; // Randomize speed and rotation self.speed = 12 + Math.random() * meteorSpeedBoost; self.rotationSpeed = (Math.random() - 0.5) * 0.08; // For intersection tracking self.lastIntersecting = false; self.update = function () { self.y += self.speed * 0.4; // slowed down to 40% of original speed self.rotation += self.rotationSpeed; // Update hitbox position self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); // Projectile class: Fired by satellite var Projectile = Container.expand(function () { var self = Container.call(this); var proj = self.attachAsset('projectile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -38; // Fast upward self.lastY = undefined; self.update = function () { if (self.lastY === undefined) self.lastY = self.y; self.y += self.speed; }; return self; }); // Satellite class: Orbits above earth, destroys meteors on tap var Satellite = Container.expand(function () { var self = Container.call(this); // Use the 'satellite' asset for the satellite var sat = self.attachAsset('satellite', { anchorX: 0.5, anchorY: 0.5 }); // Satellite hitbox (circle) self.hitbox = { x: 0, y: 0, radius: sat.width * 0.35 }; // Orbit parameters self.orbitRadius = 600; self.orbitCenterX = 2048 / 2; self.orbitCenterY = 2732 - 200; self.orbitAngle = Math.random() * Math.PI * 2; self.orbitSpeed = 0.012 + Math.random() * 0.01; self.update = function () { self.x = self.orbitCenterX; self.y = self.orbitCenterY; self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); // SpaceDebris class: Space junk that acts as a meteor var SpaceDebris = Container.expand(function () { var self = Container.call(this); // Use the 'lives' asset for space debris (was 'debris') var debris = self.attachAsset('lives', { anchorX: 0.5, anchorY: 0.5 }); // Hitbox (circle) self.hitbox = { x: 0, y: 0, radius: debris.width * 0.32 }; // Movement: falls straight down, similar to meteor self.speed = 10 + Math.random() * 10; self.rotationSpeed = (Math.random() - 0.5) * 0.1; self.lastIntersecting = false; self.update = function () { self.y += self.speed * 0.4; self.rotation += self.rotationSpeed; self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); // SuperMeteorite class: Rare, fast meteor var SuperMeteorite = Container.expand(function () { var self = Container.call(this); var superMeteor = self.attachAsset('SuperMeteor', { anchorX: 0.5, anchorY: 0.5 }); // Hitbox similar to fast meteor self.hitbox = { x: 0, y: 0, radius: superMeteor.width * 0.38 }; // Same speed as fast meteor self.speed = 48 + Math.random() * 8; self.rotationSpeed = (Math.random() - 0.5) * 0.08; self.lastIntersecting = false; self.update = function () { self.y += self.speed * 0.4; self.rotation += self.rotationSpeed; self.hitbox.x = self.x; self.hitbox.y = self.y; }; return self; }); /**** * Initialize Game ****/ // Turret class: Player's cannon at the bottom var game = new LK.Game({ backgroundColor: 0x0a2233 }); /**** * Game Code ****/ // Sound effects // Explosion effect (for future use) // Earth: Ground at the bottom // Meteor: Falling enemy // Projectile: Player's bullet // Turret: Defense cannon at the bottom // Game variables var meteors = []; var projectiles = []; var satelliteFireTimer = 0; var satelliteFireInterval = 30; // frames between shots var doubleProjectilePowerup = false; // Powerup: double projectile is off by default var earth; var satellite; var scoreTxt; var livesTxt; var lives = 5; var score = 0; var meteorSpawnInterval = 60; // frames var meteorSpeedBoost = 0; // increases as game progresses var meteorTimer = 0; // Track last score milestone for spawn rate increase var lastScoreMilestone = 0; // Developer spawn scheduling var nextDevScoreSegment = 2; // first eligible segment is 100-199 (segment 2) var devSpawnScheduledScore = null; // the score at which to spawn the next developer var devSpawnedThisSegment = false; // Add 25 background tiles (5 vertical x 5 horizontal) to fill the game area and behind all other elements var backgroundTiles = []; var bgTileRows = 5; var bgTileCols = 5; var bgTileWidth = Math.ceil(2048 / bgTileCols); var bgTileHeight = Math.ceil(2732 / bgTileRows); for (var row = 0; row < bgTileRows; row++) { for (var col = 0; col < bgTileCols; col++) { var bgTile = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: col * bgTileWidth, y: row * bgTileHeight, scaleX: bgTileWidth / 100, scaleY: bgTileHeight / 100 }); game.addChild(bgTile); backgroundTiles.push(bgTile); } } earth = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 1, // anchor at bottom center x: 2048 / 2, y: 2732 + 200, // move earth further down scaleX: 7, scaleY: 2.5 }); // Move earth down so more of it is below the screen, only a smaller top part is visible earth.y = 2732 + 700; // move earth even further down, only a thin top slice is visible game.addChild(earth); // Add satellite satellite = new Satellite(); satellite.orbitCenterX = 2048 / 2; satellite.orbitCenterY = 2732 - 350; // moved satellite higher above earth satellite.orbitRadius = 600; game.addChild(satellite); // Score text (top center) scoreTxt = new Text2('Score: 0', { size: 100, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Lives text (top right, avoid top left 100x100) livesTxt = new Text2('Lives: 5', { size: 80, fill: 0xFFB300 }); livesTxt.anchor.set(1, 0); LK.gui.topRight.addChild(livesTxt); // Start playing background music LK.playMusic('gamemusic'); // Dragging logic for satellite var draggingSatellite = false; var dragOffsetX = 0; game.move = function (x, y, obj) { // If currently dragging satellite, update its X position only if (draggingSatellite) { // Clamp satellite X to stay within game bounds (avoid going off screen) var minX = 120; var maxX = 2048 - 120; var newX = x - dragOffsetX; if (newX < minX) newX = minX; if (newX > maxX) newX = maxX; satellite.x = newX; satellite.orbitCenterX = newX; // keep its logical center in sync return; } // First, check if satellite is tapped to start dragging var dxSat = x - satellite.x; var dySat = y - satellite.y; var distSat = Math.sqrt(dxSat * dxSat + dySat * dySat); if (distSat <= satellite.hitbox.radius) { // Start dragging draggingSatellite = true; dragOffsetX = x - satellite.x; return; } // Check if a meteor is tapped for (var i = meteors.length - 1; i >= 0; i--) { var mtr = meteors[i]; // Calculate distance from tap to meteor center var dx = x - mtr.x; var dy = y - mtr.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= mtr.hitbox.radius) { // Destroy meteor mtr.destroy(); meteors.splice(i, 1); score += 1; scoreTxt.setText('Score: ' + score); // Optional: add explosion effect here if desired break; // Only destroy one meteor per tap } ; // Update projectiles and remove if off screen for (var p = projectiles.length - 1; p >= 0; p--) { var proj = projectiles[p]; proj.update(); if (proj.y < -100) { proj.destroy(); projectiles.splice(p, 1); } } } ; }; // Release drag on up game.up = function (x, y, obj) { draggingSatellite = false; }; game.up = function (x, y, obj) {}; // Main update loop game.update = function () { // Every 50 score, increase spawn rate by 10% (decrease interval by 10%) if (score >= lastScoreMilestone + 50) { lastScoreMilestone += 50; meteorSpawnInterval = Math.max(8, Math.floor(meteorSpawnInterval * 0.9)); } // Developer spawn scheduling logic // Only after first 100 score, for each 100-score segment, schedule one developer at a random score in that segment if (score >= 100) { // Determine current segment (segment 2: 100-199, segment 3: 200-299, etc.) var currentSegment = Math.floor(score / 100) + 1; // If we have entered a new segment, schedule a new developer spawn if (currentSegment >= nextDevScoreSegment) { // Schedule developer for this segment at a random score in [segmentStart, segmentEnd] var segmentStart = (currentSegment - 1) * 100; var segmentEnd = segmentStart + 99; // Pick a random score in this segment, but not the very first score (to avoid instant spawn) devSpawnScheduledScore = segmentStart + Math.floor(Math.random() * 100); devSpawnedThisSegment = false; nextDevScoreSegment = currentSegment + 1; } } // Spawn meteors meteorTimer++; var spawnRate = meteorSpawnInterval; if (meteorTimer >= spawnRate) { meteorTimer = 0; // Super meteor, fast meteor, and developer spawn logic with new probabilities after score > 100 var superMeteorChance = 0; var fastMeteorChance = 0; // Remove random developerChance, we now use scheduled spawn var developerShouldSpawn = false; if (devSpawnScheduledScore !== null && !devSpawnedThisSegment && score >= devSpawnScheduledScore) { developerShouldSpawn = true; } if (score >= 1250) { // 100% super meteor, 0% fast meteor, 0% alien superMeteorChance = 1.0; // 100% fastMeteorChance = 0.0; alienChance = 0.0; } else if (score >= 1000) { // 95% fast meteor, 5% super meteor, 0% alien superMeteorChance = 0.05; // 5% fastMeteorChance = 0.95; // 95% alienChance = 0.0; // 0% } else if (score >= 700) { // 75% fast meteor, 20% super meteor, 5% alien superMeteorChance = 0.20; // 20% fastMeteorChance = 0.75; // 75% alienChance = 0.05; // 5% } else if (score >= 400) { superMeteorChance = 0.15; // 15% fastMeteorChance = 0.5; // 50% alienChance = 0.3; // 30% (default for Alien below 700) } else if (score > 200) { superMeteorChance = 0.075; // 7.5% fastMeteorChance = 0.15; // 15% alienChance = 0.3; } else if (score > 100) { superMeteorChance = 0.05; // 5% fastMeteorChance = 0.10; // 10% alienChance = 0.3; } else if (score > 50) { superMeteorChance = 0.03; // 3% fastMeteorChance = 0.05; // 5% alienChance = 0.3; } else if (score >= 50) { superMeteorChance = 0.01; // 1% fastMeteorChance = 0.05; // 5% alienChance = 0.3; } else { superMeteorChance = 0; fastMeteorChance = 0; alienChance = 0.3; } // Scheduled Developer spawn (only after 100 score, one per segment) if (developerShouldSpawn) { var dev = new Developer(); dev.x = 120 + Math.random() * (2048 - 240); dev.y = -80; meteors.push(dev); game.addChild(dev); devSpawnedThisSegment = true; } else if (superMeteorChance > 0 && Math.random() < superMeteorChance) { var m = new SuperMeteorite(); // Süper meteorları %25 yavaşlat m.speed = m.speed * 0.75; m.x = 120 + Math.random() * (2048 - 240); m.y = -80; meteors.push(m); game.addChild(m); } else { // Track if debris has already spawned if (typeof debrisHasSpawned === "undefined") { var debrisHasSpawned = false; } // 1% chance to spawn space debris instead of meteor, but only if 100 <= score <= 400 and debris hasn't spawned yet if (!debrisHasSpawned && score >= 100 && score <= 400 && Math.random() < 0.01) { var debris = new SpaceDebris(); debris.x = 120 + Math.random() * (2048 - 240); debris.y = -80; meteors.push(debris); game.addChild(debris); debrisHasSpawned = true; } else if (Math.random() < alienChance) { // Alien spawn chance (5% if score >= 700, else 30%) var alien = new Alien(); alien.x = 120 + Math.random() * (2048 - 240); alien.y = -80; meteors.push(alien); game.addChild(alien); } else { // HardMeteor spawn: Only if score > 100. 100% if score > 1500, 1% if 100 < score <= 1500 if (score > 100 && (score > 1500 || score <= 1500 && Math.random() < 0.01)) { var hard = new HardMeteor(); hard.x = 120 + Math.random() * (2048 - 240); hard.y = -80; meteors.push(hard); game.addChild(hard); } else { var m = new Meteor(); // Fast meteor spawn if (fastMeteorChance > 0 && Math.random() < fastMeteorChance) { m.speed = 48 + Math.random() * 8; // Hızlı meteorları %50 yavaşlat m.speed = m.speed * 0.5; // Hızlı meteorları %5 daha hızlı yap m.speed = m.speed * 1.05; // Replace meteor asset with FastMeteorite if (m.children && m.children.length > 0) { var oldMeteor = m.children[0]; m.removeChild(oldMeteor); } var fastMeteor = m.attachAsset('FastMeteorite', { anchorX: 0.5, anchorY: 0.5 }); // Update hitbox to match new asset size m.hitbox.radius = fastMeteor.width * 0.38; } m.x = 120 + Math.random() * (2048 - 240); m.y = -80; meteors.push(m); game.addChild(m); } } } } // Remove difficulty scaling meteorSpeedBoost = 0; // Speed up all falling objects by 25% at score 500 (only once) if (!game.speedBoosted && score >= 500) { game.speedBoosted = true; // Boost all current meteors for (var i = 0; i < meteors.length; i++) { if (meteors[i].speed !== undefined) { meteors[i].speed *= 1.25; } } // Boost future meteors by increasing meteorSpeedBoost // (affects Meteor class randomization) meteorSpeedBoost = meteorSpeedBoost * 1.25 + 2.5; // ensure new meteors are faster } // Update meteors for (var k = meteors.length - 1; k >= 0; k--) { var mtr = meteors[k]; mtr.update(); // If meteor hits earth if (mtr.y + 60 >= earth.y - earth.height / 2) { // If it's a Developer, take 2 lives and remove it if (mtr instanceof Developer) { LK.getSound('lose').play(); mtr.destroy(); meteors.splice(k, 1); lives -= 2; livesTxt.setText('Lives: ' + lives); LK.effects.flashScreen(0xff0000, 400); if (lives <= 0) { debrisHasSpawned = false; LK.showGameOver(); return; } continue; } // If it's SpaceDebris, just remove it (do not change lives) if (mtr instanceof SpaceDebris) { mtr.destroy(); meteors.splice(k, 1); continue; } LK.getSound('lose').play(); mtr.destroy(); meteors.splice(k, 1); lives -= 1; livesTxt.setText('Lives: ' + lives); // Flash screen LK.effects.flashScreen(0xff0000, 400); if (lives <= 0) { debrisHasSpawned = false; LK.showGameOver(); return; } continue; } // Check collision with projectiles for (var j = projectiles.length - 1; j >= 0; j--) { var proj = projectiles[j]; // Collision: use ellipse hitbox for Alien, circle for others var dx = proj.x - mtr.x; var dy = proj.y - mtr.y; var hit = false; if (mtr instanceof Alien) { // Ellipse hitbox: (dx/rx)^2 + (dy/ry)^2 <= 1 var rx = mtr.hitbox.radiusX + 40; var ry = mtr.hitbox.radiusY + 40; if (dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1) { hit = true; } } else { var dist = Math.sqrt(dx * dx + dy * dy); if (dist <= (mtr.hitbox.radius !== undefined ? mtr.hitbox.radius : 0) + 40) { hit = true; } } if (hit) { // 40 is half projectile height, rough // If hit is on Developer, boost fire rate if (mtr instanceof Developer) { // Fire rate boost: halve the interval, but not less than 6 frames (10 shots/sec) satelliteFireInterval = Math.max(6, Math.floor(satelliteFireInterval / 2)); // Enable double projectile powerup when Developer is shot doubleProjectilePowerup = true; // Destroy Developer (powerup) when hit by projectile mtr.destroy(); meteors.splice(k, 1); } else if (mtr instanceof SpaceDebris) { // If hit is on SpaceDebris, increase projectile size slightly // Only increase if not already too large if (proj.children && proj.children.length > 0) { var projAsset = proj.children[0]; // Limit max scale to avoid infinite growth if (projAsset.scaleX < 2.0 && projAsset.scaleY < 2.0) { projAsset.scaleX += 0.15; projAsset.scaleY += 0.15; } } // Grant +1 life when debris is shot lives += 1; livesTxt.setText('Lives: ' + lives); score += 1; scoreTxt.setText('Score: ' + score); // Destroy SpaceDebris (lives) when hit by a projectile mtr.destroy(); meteors.splice(k, 1); proj.destroy(); projectiles.splice(j, 1); break; // Only one projectile can hit a meteor at a time } else if (mtr.children && mtr.children.length > 0 && mtr.children[0].assetId === 'FastMeteorite') { score += 2; scoreTxt.setText('Score: ' + score); } else if (mtr instanceof SuperMeteorite) { score += 5; scoreTxt.setText('Score: ' + score); mtr.destroy(); meteors.splice(k, 1); proj.destroy(); projectiles.splice(j, 1); break; // Only one projectile can hit a meteor at a time } else if (mtr instanceof HardMeteor) { // Reduce hitsLeft, only destroy if 0 mtr.hitsLeft -= 1; if (mtr.hitsLeft <= 0) { score += 3; scoreTxt.setText('Score: ' + score); mtr.destroy(); meteors.splice(k, 1); } proj.destroy(); projectiles.splice(j, 1); break; // Only one projectile can hit a meteor at a time } else { score += 1; scoreTxt.setText('Score: ' + score); // Destroy both mtr.destroy(); meteors.splice(k, 1); proj.destroy(); projectiles.splice(j, 1); break; // Only one projectile can hit a meteor at a time } } } } // Update satellite if (satellite && satellite.update) { satellite.update(); // Satellite fires projectiles at interval satelliteFireTimer++; if (satelliteFireTimer >= satelliteFireInterval) { satelliteFireTimer = 0; if (doubleProjectilePowerup) { // Fire two projectiles, slightly offset var proj1 = new Projectile(); proj1.x = satellite.x - 40; proj1.y = satellite.y - 60; projectiles.push(proj1); game.addChild(proj1); var proj2 = new Projectile(); proj2.x = satellite.x + 40; proj2.y = satellite.y - 60; projectiles.push(proj2); game.addChild(proj2); } else { var proj = new Projectile(); proj.x = satellite.x; proj.y = satellite.y - 60; // fire from above satellite projectiles.push(proj); game.addChild(proj); } } } };
/****
* Classes
****/
// Alien class: 30% chance to spawn, acts as a meteor
var Alien = Container.expand(function () {
var self = Container.call(this);
// Use the 'Alien' asset for alien
var alienAsset = self.attachAsset('Alien', {
anchorX: 0.5,
anchorY: 0.5
});
// Hitbox (ellipse, more accurate for Alien shape)
self.hitbox = {
x: 0,
y: 0,
// Use a slightly smaller ellipse hitbox for fairness
radiusX: alienAsset.width * 0.28,
radiusY: alienAsset.height * 0.32
};
// Movement: falls straight down, similar to meteor
self.speed = 12 + Math.random() * 8;
self.rotationSpeed = (Math.random() - 0.5) * 0.08;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed * 0.4;
self.rotation += self.rotationSpeed;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
// No change needed here, just keep hitbox position updated
};
return self;
});
// Developer class: Rare, shootable, grants fire rate boost
var Developer = Container.expand(function () {
var self = Container.call(this);
// Use the 'x2' asset for developer (powerup)
var dev = self.attachAsset('x2', {
anchorX: 0.5,
anchorY: 0.5
});
// Hitbox (circle)
self.hitbox = {
x: 0,
y: 0,
radius: dev.width * 0.45
};
// Movement: falls straight down, similar to meteor
self.speed = 32 + Math.random() * 8;
self.rotationSpeed = (Math.random() - 0.5) * 0.08;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed * 0.4;
self.rotation += self.rotationSpeed;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
// HardMeteor class: Tough meteor with unique asset and behavior
var HardMeteor = Container.expand(function () {
var self = Container.call(this);
// Use the 'Hardmeteor' asset for hard meteor (with capital H)
var hardMeteor = self.attachAsset('HardMeteor', {
anchorX: 0.5,
anchorY: 0.5
});
// Hitbox (circle)
self.hitbox = {
x: 0,
y: 0,
radius: hardMeteor.width * 0.38
};
// Movement: falls straight down, very slow
self.speed = 4 + Math.random() * 2; // MUCH slower than other meteors
self.rotationSpeed = (Math.random() - 0.5) * 0.08;
self.lastIntersecting = false;
// Track hits required to destroy
self.hitsLeft = 7;
self.update = function () {
self.y += self.speed * 0.4;
self.rotation += self.rotationSpeed;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
// Meteor class: Falling enemy
var Meteor = Container.expand(function () {
var self = Container.call(this);
var meteor = self.attachAsset('meteor', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a hitbox property (circle for simplicity)
self.hitbox = {
x: 0,
y: 0,
radius: meteor.width * 0.38 // slightly smaller than graphic for fairness
};
// Randomize speed and rotation
self.speed = 12 + Math.random() * meteorSpeedBoost;
self.rotationSpeed = (Math.random() - 0.5) * 0.08;
// For intersection tracking
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed * 0.4; // slowed down to 40% of original speed
self.rotation += self.rotationSpeed;
// Update hitbox position
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
// Projectile class: Fired by satellite
var Projectile = Container.expand(function () {
var self = Container.call(this);
var proj = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -38; // Fast upward
self.lastY = undefined;
self.update = function () {
if (self.lastY === undefined) self.lastY = self.y;
self.y += self.speed;
};
return self;
});
// Satellite class: Orbits above earth, destroys meteors on tap
var Satellite = Container.expand(function () {
var self = Container.call(this);
// Use the 'satellite' asset for the satellite
var sat = self.attachAsset('satellite', {
anchorX: 0.5,
anchorY: 0.5
});
// Satellite hitbox (circle)
self.hitbox = {
x: 0,
y: 0,
radius: sat.width * 0.35
};
// Orbit parameters
self.orbitRadius = 600;
self.orbitCenterX = 2048 / 2;
self.orbitCenterY = 2732 - 200;
self.orbitAngle = Math.random() * Math.PI * 2;
self.orbitSpeed = 0.012 + Math.random() * 0.01;
self.update = function () {
self.x = self.orbitCenterX;
self.y = self.orbitCenterY;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
// SpaceDebris class: Space junk that acts as a meteor
var SpaceDebris = Container.expand(function () {
var self = Container.call(this);
// Use the 'lives' asset for space debris (was 'debris')
var debris = self.attachAsset('lives', {
anchorX: 0.5,
anchorY: 0.5
});
// Hitbox (circle)
self.hitbox = {
x: 0,
y: 0,
radius: debris.width * 0.32
};
// Movement: falls straight down, similar to meteor
self.speed = 10 + Math.random() * 10;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed * 0.4;
self.rotation += self.rotationSpeed;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
// SuperMeteorite class: Rare, fast meteor
var SuperMeteorite = Container.expand(function () {
var self = Container.call(this);
var superMeteor = self.attachAsset('SuperMeteor', {
anchorX: 0.5,
anchorY: 0.5
});
// Hitbox similar to fast meteor
self.hitbox = {
x: 0,
y: 0,
radius: superMeteor.width * 0.38
};
// Same speed as fast meteor
self.speed = 48 + Math.random() * 8;
self.rotationSpeed = (Math.random() - 0.5) * 0.08;
self.lastIntersecting = false;
self.update = function () {
self.y += self.speed * 0.4;
self.rotation += self.rotationSpeed;
self.hitbox.x = self.x;
self.hitbox.y = self.y;
};
return self;
});
/****
* Initialize Game
****/
// Turret class: Player's cannon at the bottom
var game = new LK.Game({
backgroundColor: 0x0a2233
});
/****
* Game Code
****/
// Sound effects
// Explosion effect (for future use)
// Earth: Ground at the bottom
// Meteor: Falling enemy
// Projectile: Player's bullet
// Turret: Defense cannon at the bottom
// Game variables
var meteors = [];
var projectiles = [];
var satelliteFireTimer = 0;
var satelliteFireInterval = 30; // frames between shots
var doubleProjectilePowerup = false; // Powerup: double projectile is off by default
var earth;
var satellite;
var scoreTxt;
var livesTxt;
var lives = 5;
var score = 0;
var meteorSpawnInterval = 60; // frames
var meteorSpeedBoost = 0; // increases as game progresses
var meteorTimer = 0;
// Track last score milestone for spawn rate increase
var lastScoreMilestone = 0;
// Developer spawn scheduling
var nextDevScoreSegment = 2; // first eligible segment is 100-199 (segment 2)
var devSpawnScheduledScore = null; // the score at which to spawn the next developer
var devSpawnedThisSegment = false;
// Add 25 background tiles (5 vertical x 5 horizontal) to fill the game area and behind all other elements
var backgroundTiles = [];
var bgTileRows = 5;
var bgTileCols = 5;
var bgTileWidth = Math.ceil(2048 / bgTileCols);
var bgTileHeight = Math.ceil(2732 / bgTileRows);
for (var row = 0; row < bgTileRows; row++) {
for (var col = 0; col < bgTileCols; col++) {
var bgTile = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: col * bgTileWidth,
y: row * bgTileHeight,
scaleX: bgTileWidth / 100,
scaleY: bgTileHeight / 100
});
game.addChild(bgTile);
backgroundTiles.push(bgTile);
}
}
earth = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 1,
// anchor at bottom center
x: 2048 / 2,
y: 2732 + 200,
// move earth further down
scaleX: 7,
scaleY: 2.5
});
// Move earth down so more of it is below the screen, only a smaller top part is visible
earth.y = 2732 + 700; // move earth even further down, only a thin top slice is visible
game.addChild(earth);
// Add satellite
satellite = new Satellite();
satellite.orbitCenterX = 2048 / 2;
satellite.orbitCenterY = 2732 - 350; // moved satellite higher above earth
satellite.orbitRadius = 600;
game.addChild(satellite);
// Score text (top center)
scoreTxt = new Text2('Score: 0', {
size: 100,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives text (top right, avoid top left 100x100)
livesTxt = new Text2('Lives: 5', {
size: 80,
fill: 0xFFB300
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// Start playing background music
LK.playMusic('gamemusic');
// Dragging logic for satellite
var draggingSatellite = false;
var dragOffsetX = 0;
game.move = function (x, y, obj) {
// If currently dragging satellite, update its X position only
if (draggingSatellite) {
// Clamp satellite X to stay within game bounds (avoid going off screen)
var minX = 120;
var maxX = 2048 - 120;
var newX = x - dragOffsetX;
if (newX < minX) newX = minX;
if (newX > maxX) newX = maxX;
satellite.x = newX;
satellite.orbitCenterX = newX; // keep its logical center in sync
return;
}
// First, check if satellite is tapped to start dragging
var dxSat = x - satellite.x;
var dySat = y - satellite.y;
var distSat = Math.sqrt(dxSat * dxSat + dySat * dySat);
if (distSat <= satellite.hitbox.radius) {
// Start dragging
draggingSatellite = true;
dragOffsetX = x - satellite.x;
return;
}
// Check if a meteor is tapped
for (var i = meteors.length - 1; i >= 0; i--) {
var mtr = meteors[i];
// Calculate distance from tap to meteor center
var dx = x - mtr.x;
var dy = y - mtr.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist <= mtr.hitbox.radius) {
// Destroy meteor
mtr.destroy();
meteors.splice(i, 1);
score += 1;
scoreTxt.setText('Score: ' + score);
// Optional: add explosion effect here if desired
break; // Only destroy one meteor per tap
}
;
// Update projectiles and remove if off screen
for (var p = projectiles.length - 1; p >= 0; p--) {
var proj = projectiles[p];
proj.update();
if (proj.y < -100) {
proj.destroy();
projectiles.splice(p, 1);
}
}
}
;
};
// Release drag on up
game.up = function (x, y, obj) {
draggingSatellite = false;
};
game.up = function (x, y, obj) {};
// Main update loop
game.update = function () {
// Every 50 score, increase spawn rate by 10% (decrease interval by 10%)
if (score >= lastScoreMilestone + 50) {
lastScoreMilestone += 50;
meteorSpawnInterval = Math.max(8, Math.floor(meteorSpawnInterval * 0.9));
}
// Developer spawn scheduling logic
// Only after first 100 score, for each 100-score segment, schedule one developer at a random score in that segment
if (score >= 100) {
// Determine current segment (segment 2: 100-199, segment 3: 200-299, etc.)
var currentSegment = Math.floor(score / 100) + 1;
// If we have entered a new segment, schedule a new developer spawn
if (currentSegment >= nextDevScoreSegment) {
// Schedule developer for this segment at a random score in [segmentStart, segmentEnd]
var segmentStart = (currentSegment - 1) * 100;
var segmentEnd = segmentStart + 99;
// Pick a random score in this segment, but not the very first score (to avoid instant spawn)
devSpawnScheduledScore = segmentStart + Math.floor(Math.random() * 100);
devSpawnedThisSegment = false;
nextDevScoreSegment = currentSegment + 1;
}
}
// Spawn meteors
meteorTimer++;
var spawnRate = meteorSpawnInterval;
if (meteorTimer >= spawnRate) {
meteorTimer = 0;
// Super meteor, fast meteor, and developer spawn logic with new probabilities after score > 100
var superMeteorChance = 0;
var fastMeteorChance = 0;
// Remove random developerChance, we now use scheduled spawn
var developerShouldSpawn = false;
if (devSpawnScheduledScore !== null && !devSpawnedThisSegment && score >= devSpawnScheduledScore) {
developerShouldSpawn = true;
}
if (score >= 1250) {
// 100% super meteor, 0% fast meteor, 0% alien
superMeteorChance = 1.0; // 100%
fastMeteorChance = 0.0;
alienChance = 0.0;
} else if (score >= 1000) {
// 95% fast meteor, 5% super meteor, 0% alien
superMeteorChance = 0.05; // 5%
fastMeteorChance = 0.95; // 95%
alienChance = 0.0; // 0%
} else if (score >= 700) {
// 75% fast meteor, 20% super meteor, 5% alien
superMeteorChance = 0.20; // 20%
fastMeteorChance = 0.75; // 75%
alienChance = 0.05; // 5%
} else if (score >= 400) {
superMeteorChance = 0.15; // 15%
fastMeteorChance = 0.5; // 50%
alienChance = 0.3; // 30% (default for Alien below 700)
} else if (score > 200) {
superMeteorChance = 0.075; // 7.5%
fastMeteorChance = 0.15; // 15%
alienChance = 0.3;
} else if (score > 100) {
superMeteorChance = 0.05; // 5%
fastMeteorChance = 0.10; // 10%
alienChance = 0.3;
} else if (score > 50) {
superMeteorChance = 0.03; // 3%
fastMeteorChance = 0.05; // 5%
alienChance = 0.3;
} else if (score >= 50) {
superMeteorChance = 0.01; // 1%
fastMeteorChance = 0.05; // 5%
alienChance = 0.3;
} else {
superMeteorChance = 0;
fastMeteorChance = 0;
alienChance = 0.3;
}
// Scheduled Developer spawn (only after 100 score, one per segment)
if (developerShouldSpawn) {
var dev = new Developer();
dev.x = 120 + Math.random() * (2048 - 240);
dev.y = -80;
meteors.push(dev);
game.addChild(dev);
devSpawnedThisSegment = true;
} else if (superMeteorChance > 0 && Math.random() < superMeteorChance) {
var m = new SuperMeteorite();
// Süper meteorları %25 yavaşlat
m.speed = m.speed * 0.75;
m.x = 120 + Math.random() * (2048 - 240);
m.y = -80;
meteors.push(m);
game.addChild(m);
} else {
// Track if debris has already spawned
if (typeof debrisHasSpawned === "undefined") {
var debrisHasSpawned = false;
}
// 1% chance to spawn space debris instead of meteor, but only if 100 <= score <= 400 and debris hasn't spawned yet
if (!debrisHasSpawned && score >= 100 && score <= 400 && Math.random() < 0.01) {
var debris = new SpaceDebris();
debris.x = 120 + Math.random() * (2048 - 240);
debris.y = -80;
meteors.push(debris);
game.addChild(debris);
debrisHasSpawned = true;
} else if (Math.random() < alienChance) {
// Alien spawn chance (5% if score >= 700, else 30%)
var alien = new Alien();
alien.x = 120 + Math.random() * (2048 - 240);
alien.y = -80;
meteors.push(alien);
game.addChild(alien);
} else {
// HardMeteor spawn: Only if score > 100. 100% if score > 1500, 1% if 100 < score <= 1500
if (score > 100 && (score > 1500 || score <= 1500 && Math.random() < 0.01)) {
var hard = new HardMeteor();
hard.x = 120 + Math.random() * (2048 - 240);
hard.y = -80;
meteors.push(hard);
game.addChild(hard);
} else {
var m = new Meteor();
// Fast meteor spawn
if (fastMeteorChance > 0 && Math.random() < fastMeteorChance) {
m.speed = 48 + Math.random() * 8;
// Hızlı meteorları %50 yavaşlat
m.speed = m.speed * 0.5;
// Hızlı meteorları %5 daha hızlı yap
m.speed = m.speed * 1.05;
// Replace meteor asset with FastMeteorite
if (m.children && m.children.length > 0) {
var oldMeteor = m.children[0];
m.removeChild(oldMeteor);
}
var fastMeteor = m.attachAsset('FastMeteorite', {
anchorX: 0.5,
anchorY: 0.5
});
// Update hitbox to match new asset size
m.hitbox.radius = fastMeteor.width * 0.38;
}
m.x = 120 + Math.random() * (2048 - 240);
m.y = -80;
meteors.push(m);
game.addChild(m);
}
}
}
}
// Remove difficulty scaling
meteorSpeedBoost = 0;
// Speed up all falling objects by 25% at score 500 (only once)
if (!game.speedBoosted && score >= 500) {
game.speedBoosted = true;
// Boost all current meteors
for (var i = 0; i < meteors.length; i++) {
if (meteors[i].speed !== undefined) {
meteors[i].speed *= 1.25;
}
}
// Boost future meteors by increasing meteorSpeedBoost
// (affects Meteor class randomization)
meteorSpeedBoost = meteorSpeedBoost * 1.25 + 2.5; // ensure new meteors are faster
}
// Update meteors
for (var k = meteors.length - 1; k >= 0; k--) {
var mtr = meteors[k];
mtr.update();
// If meteor hits earth
if (mtr.y + 60 >= earth.y - earth.height / 2) {
// If it's a Developer, take 2 lives and remove it
if (mtr instanceof Developer) {
LK.getSound('lose').play();
mtr.destroy();
meteors.splice(k, 1);
lives -= 2;
livesTxt.setText('Lives: ' + lives);
LK.effects.flashScreen(0xff0000, 400);
if (lives <= 0) {
debrisHasSpawned = false;
LK.showGameOver();
return;
}
continue;
}
// If it's SpaceDebris, just remove it (do not change lives)
if (mtr instanceof SpaceDebris) {
mtr.destroy();
meteors.splice(k, 1);
continue;
}
LK.getSound('lose').play();
mtr.destroy();
meteors.splice(k, 1);
lives -= 1;
livesTxt.setText('Lives: ' + lives);
// Flash screen
LK.effects.flashScreen(0xff0000, 400);
if (lives <= 0) {
debrisHasSpawned = false;
LK.showGameOver();
return;
}
continue;
}
// Check collision with projectiles
for (var j = projectiles.length - 1; j >= 0; j--) {
var proj = projectiles[j];
// Collision: use ellipse hitbox for Alien, circle for others
var dx = proj.x - mtr.x;
var dy = proj.y - mtr.y;
var hit = false;
if (mtr instanceof Alien) {
// Ellipse hitbox: (dx/rx)^2 + (dy/ry)^2 <= 1
var rx = mtr.hitbox.radiusX + 40;
var ry = mtr.hitbox.radiusY + 40;
if (dx * dx / (rx * rx) + dy * dy / (ry * ry) <= 1) {
hit = true;
}
} else {
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist <= (mtr.hitbox.radius !== undefined ? mtr.hitbox.radius : 0) + 40) {
hit = true;
}
}
if (hit) {
// 40 is half projectile height, rough
// If hit is on Developer, boost fire rate
if (mtr instanceof Developer) {
// Fire rate boost: halve the interval, but not less than 6 frames (10 shots/sec)
satelliteFireInterval = Math.max(6, Math.floor(satelliteFireInterval / 2));
// Enable double projectile powerup when Developer is shot
doubleProjectilePowerup = true;
// Destroy Developer (powerup) when hit by projectile
mtr.destroy();
meteors.splice(k, 1);
} else if (mtr instanceof SpaceDebris) {
// If hit is on SpaceDebris, increase projectile size slightly
// Only increase if not already too large
if (proj.children && proj.children.length > 0) {
var projAsset = proj.children[0];
// Limit max scale to avoid infinite growth
if (projAsset.scaleX < 2.0 && projAsset.scaleY < 2.0) {
projAsset.scaleX += 0.15;
projAsset.scaleY += 0.15;
}
}
// Grant +1 life when debris is shot
lives += 1;
livesTxt.setText('Lives: ' + lives);
score += 1;
scoreTxt.setText('Score: ' + score);
// Destroy SpaceDebris (lives) when hit by a projectile
mtr.destroy();
meteors.splice(k, 1);
proj.destroy();
projectiles.splice(j, 1);
break; // Only one projectile can hit a meteor at a time
} else if (mtr.children && mtr.children.length > 0 && mtr.children[0].assetId === 'FastMeteorite') {
score += 2;
scoreTxt.setText('Score: ' + score);
} else if (mtr instanceof SuperMeteorite) {
score += 5;
scoreTxt.setText('Score: ' + score);
mtr.destroy();
meteors.splice(k, 1);
proj.destroy();
projectiles.splice(j, 1);
break; // Only one projectile can hit a meteor at a time
} else if (mtr instanceof HardMeteor) {
// Reduce hitsLeft, only destroy if 0
mtr.hitsLeft -= 1;
if (mtr.hitsLeft <= 0) {
score += 3;
scoreTxt.setText('Score: ' + score);
mtr.destroy();
meteors.splice(k, 1);
}
proj.destroy();
projectiles.splice(j, 1);
break; // Only one projectile can hit a meteor at a time
} else {
score += 1;
scoreTxt.setText('Score: ' + score);
// Destroy both
mtr.destroy();
meteors.splice(k, 1);
proj.destroy();
projectiles.splice(j, 1);
break; // Only one projectile can hit a meteor at a time
}
}
}
}
// Update satellite
if (satellite && satellite.update) {
satellite.update();
// Satellite fires projectiles at interval
satelliteFireTimer++;
if (satelliteFireTimer >= satelliteFireInterval) {
satelliteFireTimer = 0;
if (doubleProjectilePowerup) {
// Fire two projectiles, slightly offset
var proj1 = new Projectile();
proj1.x = satellite.x - 40;
proj1.y = satellite.y - 60;
projectiles.push(proj1);
game.addChild(proj1);
var proj2 = new Projectile();
proj2.x = satellite.x + 40;
proj2.y = satellite.y - 60;
projectiles.push(proj2);
game.addChild(proj2);
} else {
var proj = new Projectile();
proj.x = satellite.x;
proj.y = satellite.y - 60; // fire from above satellite
projectiles.push(proj);
game.addChild(proj);
}
}
}
};
meteor . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
dünya yüzeyi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
blue meteor. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
green meteorite. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
spaceship. In-Game asset. 2d. High contrast. No shadows
spaceship debris. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
laser projectile. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
space with only stars. In-Game asset. real. High contrast. with shadows. high resolution
dünyanın bir bölümünün yüzeyi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
alien. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
golden dolar symbol. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
yellow meteor. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
game heart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
shield. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
red meteor with x2 write. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat