User prompt
make it less laggy
User prompt
quadriple that
User prompt
triple that
User prompt
make him shoot two bullets instead of one
User prompt
make the player automatically shoot
User prompt
spawn stars in the background
User prompt
make the heart falling more common
User prompt
make the heart fall with the rest of the items
User prompt
add a heart
User prompt
give the player 30 lives
User prompt
add stars to the background
User prompt
make the background space'
User prompt
make the shape of the ship a triangle
User prompt
make it so clicking the ship will make it shoot
User prompt
make the ship follow the mouse
Code edit (1 edits merged)
Please save this source code
User prompt
Galactic Defender
Initial prompt
a space shooter game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Asteroid
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var rock = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = rock.width;
self.height = rock.height;
self.speed = 10 + Math.random() * 6;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
rock.rotation += self.rotationSpeed;
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = 22;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Enemy Ship
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
self.speed = 7 + Math.random() * 4;
self.shootCooldown = 60 + Math.floor(Math.random() * 60);
self.update = function () {
self.y += self.speed;
if (self.shootCooldown > 0) {
self.shootCooldown--;
} else {
self.shoot();
self.shootCooldown = 90 + Math.floor(Math.random() * 60);
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2 + bullet.height / 2;
enemyBullets.push(bullet);
game.addChild(bullet);
};
return self;
});
// HeartDrop (falling heart item)
var HeartDrop = Container.expand(function () {
var self = Container.call(this);
var heart = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = heart.width;
self.height = heart.height;
self.speed = 10;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bullet = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = bullet.width;
self.height = bullet.height;
self.speed = -36;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player Ship
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = ship.width;
self.height = ship.height;
self.shootCooldown = 0;
self.invincible = false;
self.invincibleTicks = 0;
self.update = function () {
if (self.shootCooldown > 0) self.shootCooldown--;
if (self.invincible) {
self.invincibleTicks--;
if (self.invincibleTicks <= 0) {
self.invincible = false;
ship.alpha = 1;
} else {
// Flicker effect
ship.alpha = LK.ticks % 10 < 5 ? 0.4 : 1;
}
}
};
// Shoot method
self.shoot = function () {
if (self.shootCooldown <= 0) {
// Shoot 6 bullets, evenly spread (performance optimized)
var bulletCount = 6;
var spread = 120; // total spread in pixels
for (var i = 0; i < bulletCount; i++) {
var offset = -spread / 2 + spread / (bulletCount - 1) * i;
var bullet = new PlayerBullet();
bullet.x = self.x + offset;
bullet.y = self.y - self.height / 2 - bullet.height / 2;
playerBullets.push(bullet);
game.addChild(bullet);
}
LK.getSound('shoot').play();
self.shootCooldown = 12; // 12 ticks cooldown
}
};
// Invincibility after hit
self.setInvincible = function (ticks) {
self.invincible = true;
self.invincibleTicks = ticks;
};
// Add down handler so clicking the ship makes it shoot
self.down = function (x, y, obj) {
// Only allow shooting if game is not over
if (typeof gameOver !== "undefined" && !gameOver) {
self.shoot();
}
};
return self;
});
// Powerup
var Powerup = Container.expand(function () {
var self = Container.call(this);
var p = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = p.width;
self.height = p.height;
self.speed = 9;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Star (background)
var Star = Container.expand(function () {
var self = Container.call(this);
// Use a white ellipse as a star, random small size
var size = 2 + Math.random() * 4;
var star = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: size,
height: size,
color: 0xffffff
});
self.width = size;
self.height = size;
self.speed = 2 + Math.random() * 4;
self.alpha = 0.3 + Math.random() * 0.5;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Play background music
// Spaceship (player)
// Player bullet
// Enemy ship
// Enemy bullet
// Asteroid
// Power-up
// Explosion effect (for flash)
// Sounds
// Music
LK.playMusic('galacticMusic');
// Game variables
var stars = [];
var starTick = 0;
var player;
var playerBullets = [];
var enemyShips = [];
var enemyBullets = [];
var asteroids = [];
var powerups = [];
var score = 0;
var lives = 30;
var level = 1;
var spawnTick = 0;
var asteroidTick = 0;
var powerupTick = 0;
var heartDropTick = 0;
var heartDrops = [];
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var lastTouchX = 0;
var lastTouchY = 0;
var gameOver = false;
// Score display
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lives display
var livesTxt = new Text2('♥♥♥', {
size: 80,
fill: 0xFF6666
});
livesTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(livesTxt);
// Add a heart image next to the lives text
var heartIcon = LK.getAsset('heart', {
anchorX: 1,
anchorY: 0,
x: -80,
y: 0,
width: 60,
height: 60
});
livesTxt.addChild(heartIcon);
// Center player at bottom center
player = new PlayerShip();
player.x = 2048 / 2;
player.y = 2732 - 300;
game.addChild(player);
// Touch controls
game.down = function (x, y, obj) {
if (gameOver) return;
// Only start drag if touch is on player
var local = player.toLocal(game.toGlobal({
x: x,
y: y
}));
if (local.x > -player.width / 2 && local.x < player.width / 2 && local.y > -player.height / 2 && local.y < player.height / 2) {
dragging = true;
dragOffsetX = player.x - x;
dragOffsetY = player.y - y;
}
lastTouchX = x;
lastTouchY = y;
};
game.move = function (x, y, obj) {
if (gameOver) return;
// Make the player ship follow the mouse/touch position directly, clamped to screen bounds
var halfW = player.width / 2;
var halfH = player.height / 2;
var newX = x;
var newY = y;
if (newX < halfW) newX = halfW;
if (newX > 2048 - halfW) newX = 2048 - halfW;
if (newY < halfH + 200) newY = halfH + 200; // Don't allow too high
if (newY > 2732 - halfH) newY = 2732 - halfH;
player.x = newX;
player.y = newY;
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
dragging = false;
lastTouchX = x;
lastTouchY = y;
};
// Tap to shoot (anywhere)
game.tap = function (x, y, obj) {
if (gameOver) return;
player.shoot();
};
// For compatibility, also allow shooting on down if not dragging
game.down = function (origDown) {
return function (x, y, obj) {
origDown(x, y, obj);
if (!dragging && !gameOver) {
player.shoot();
}
};
}(game.down);
// Main update loop
game.update = function () {
// --- Star background update ---
starTick++;
// Spawn a new star every 6-10 ticks (slower for performance)
if (starTick >= 6 + Math.floor(Math.random() * 5)) {
starTick = 0;
var s = new Star();
s.x = 10 + Math.random() * (2048 - 20);
s.y = -s.height;
s.alpha = 0.3 + Math.random() * 0.5;
stars.push(s);
// Add to back of display list (background)
game.addChildAt(s, 0);
}
// Update and remove off-screen stars
for (var i = stars.length - 1; i >= 0; i--) {
var s = stars[i];
s.update();
if (s.y > 2732 + s.height) {
s.destroy();
stars.splice(i, 1);
}
}
if (gameOver) return;
// Update player
player.update();
// Auto-shoot: player fires every update if not on cooldown and not game over
if (!gameOver) {
player.shoot();
}
// Update player bullets
// Limit max bullets for performance
var maxPlayerBullets = 60;
if (playerBullets.length > maxPlayerBullets) {
// Remove oldest bullets if over limit
for (var rm = 0; rm < playerBullets.length - maxPlayerBullets; rm++) {
var oldB = playerBullets[rm];
oldB.destroy();
}
playerBullets.splice(0, playerBullets.length - maxPlayerBullets);
}
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Remove if off screen
if (b.y < -b.height) {
b.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check collision with enemies
for (var j = enemyShips.length - 1; j >= 0; j--) {
var e = enemyShips[j];
if (b.intersects(e)) {
// Destroy enemy
LK.getSound('enemyExplode').play();
score += 100;
scoreTxt.setText(score);
// Flash enemy
LK.effects.flashObject(e, 0xffffff, 200);
e.destroy();
enemyShips.splice(j, 1);
// Remove bullet
b.destroy();
playerBullets.splice(i, 1);
break;
}
}
// Check collision with asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var a = asteroids[k];
if (b.intersects(a)) {
// Destroy asteroid
LK.getSound('enemyExplode').play();
score += 50;
scoreTxt.setText(score);
LK.effects.flashObject(a, 0xffffff, 150);
a.destroy();
asteroids.splice(k, 1);
// Remove bullet
b.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
// Update enemy ships
for (var i = enemyShips.length - 1; i >= 0; i--) {
var e = enemyShips[i];
e.update();
// Remove if off screen
if (e.y > 2732 + e.height) {
e.destroy();
enemyShips.splice(i, 1);
continue;
}
// Check collision with player
if (!player.invincible && e.intersects(player)) {
handlePlayerHit();
e.destroy();
enemyShips.splice(i, 1);
continue;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var b = enemyBullets[i];
b.update();
if (b.y > 2732 + b.height) {
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (!player.invincible && b.intersects(player)) {
handlePlayerHit();
b.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var a = asteroids[i];
a.update();
if (a.y > 2732 + a.height) {
a.destroy();
asteroids.splice(i, 1);
continue;
}
if (!player.invincible && a.intersects(player)) {
handlePlayerHit();
a.destroy();
asteroids.splice(i, 1);
continue;
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var p = powerups[i];
p.update();
if (p.y > 2732 + p.height) {
p.destroy();
powerups.splice(i, 1);
continue;
}
if (p.intersects(player)) {
LK.getSound('powerup').play();
score += 250;
scoreTxt.setText(score);
// Grant temporary invincibility
player.setInvincible(120);
p.destroy();
powerups.splice(i, 1);
continue;
}
}
// Update heart drops
for (var i = heartDrops.length - 1; i >= 0; i--) {
var h = heartDrops[i];
h.update();
if (h.y > 2732 + h.height) {
h.destroy();
heartDrops.splice(i, 1);
continue;
}
if (h.intersects(player)) {
// Collect heart: +1 life, max 30
if (lives < 30) {
lives++;
updateLivesDisplay();
}
h.destroy();
heartDrops.splice(i, 1);
continue;
}
}
// Spawning logic
spawnTick++;
asteroidTick++;
powerupTick++;
// Enemy spawn
var enemyInterval = Math.max(60, 180 - level * 10);
if (spawnTick >= enemyInterval) {
spawnTick = 0;
var e = new EnemyShip();
e.x = 200 + Math.random() * (2048 - 400);
e.y = -e.height;
enemyShips.push(e);
game.addChild(e);
}
// Asteroid spawn
var asteroidInterval = Math.max(80, 220 - level * 8);
if (asteroidTick >= asteroidInterval) {
asteroidTick = 0;
var a = new Asteroid();
a.x = 100 + Math.random() * (2048 - 200);
a.y = -a.height;
asteroids.push(a);
game.addChild(a);
}
// Powerup spawn
if (powerupTick >= 900) {
powerupTick = 0;
var p = new Powerup();
p.x = 200 + Math.random() * (2048 - 400);
p.y = -p.height;
powerups.push(p);
game.addChild(p);
}
// Heart drop spawn (random, about every 400-700 ticks)
heartDropTick++;
if (heartDropTick >= 400 + Math.floor(Math.random() * 300)) {
heartDropTick = 0;
var h = new HeartDrop();
h.x = 200 + Math.random() * (2048 - 400);
h.y = -h.height;
heartDrops.push(h);
game.addChild(h);
}
// Level up every 1000 points
var newLevel = Math.floor(score / 1000) + 1;
if (newLevel > level) {
level = newLevel;
// Optionally, flash screen or show level up
LK.effects.flashScreen(0x00ffcc, 400);
}
};
// Handle player hit
function handlePlayerHit() {
if (player.invincible) return;
lives--;
updateLivesDisplay();
LK.getSound('playerExplode').play();
LK.effects.flashScreen(0xff0000, 600);
player.setInvincible(90);
if (lives <= 0) {
endGame();
}
}
// Update lives display
function updateLivesDisplay() {
var s = '';
for (var i = 0; i < lives; i++) s += '♥';
livesTxt.setText(s);
}
// End game
function endGame() {
gameOver = true;
LK.showGameOver();
}
// Reset game state on restart
game.on('reset', function () {
// Remove all objects
for (var i = 0; i < stars.length; i++) stars[i].destroy();
for (var i = 0; i < playerBullets.length; i++) playerBullets[i].destroy();
for (var i = 0; i < enemyShips.length; i++) enemyShips[i].destroy();
for (var i = 0; i < enemyBullets.length; i++) enemyBullets[i].destroy();
for (var i = 0; i < asteroids.length; i++) asteroids[i].destroy();
for (var i = 0; i < powerups.length; i++) powerups[i].destroy();
for (var i = 0; i < heartDrops.length; i++) heartDrops[i].destroy();
stars = [];
playerBullets = [];
enemyShips = [];
enemyBullets = [];
asteroids = [];
powerups = [];
heartDrops = [];
score = 0;
level = 1;
lives = 30;
spawnTick = 0;
asteroidTick = 0;
powerupTick = 0;
heartDropTick = 0;
starTick = 0;
dragging = false;
gameOver = false;
scoreTxt.setText('0');
updateLivesDisplay();
player.x = 2048 / 2;
player.y = 2732 - 300;
player.invincible = false;
player.invincibleTicks = 0;
LK.playMusic('galacticMusic');
});
// For touch devices, allow tap to shoot
game.on('tap', function (x, y, obj) {
if (gameOver) return;
player.shoot();
}); ===================================================================
--- original.js
+++ change.js
@@ -124,11 +124,11 @@
};
// Shoot method
self.shoot = function () {
if (self.shootCooldown <= 0) {
- // Shoot 24 bullets, evenly spread (quadruple the previous 6)
- var bulletCount = 24;
- var spread = 180; // total spread in pixels
+ // Shoot 6 bullets, evenly spread (performance optimized)
+ var bulletCount = 6;
+ var spread = 120; // total spread in pixels
for (var i = 0; i < bulletCount; i++) {
var offset = -spread / 2 + spread / (bulletCount - 1) * i;
var bullet = new PlayerBullet();
bullet.x = self.x + offset;
@@ -318,10 +318,10 @@
// Main update loop
game.update = function () {
// --- Star background update ---
starTick++;
- // Spawn a new star every 2-4 ticks (randomize for variety)
- if (starTick >= 2 + Math.floor(Math.random() * 3)) {
+ // Spawn a new star every 6-10 ticks (slower for performance)
+ if (starTick >= 6 + Math.floor(Math.random() * 5)) {
starTick = 0;
var s = new Star();
s.x = 10 + Math.random() * (2048 - 20);
s.y = -s.height;
@@ -346,8 +346,18 @@
if (!gameOver) {
player.shoot();
}
// Update player bullets
+ // Limit max bullets for performance
+ var maxPlayerBullets = 60;
+ if (playerBullets.length > maxPlayerBullets) {
+ // Remove oldest bullets if over limit
+ for (var rm = 0; rm < playerBullets.length - maxPlayerBullets; rm++) {
+ var oldB = playerBullets[rm];
+ oldB.destroy();
+ }
+ playerBullets.splice(0, playerBullets.length - maxPlayerBullets);
+ }
for (var i = playerBullets.length - 1; i >= 0; i--) {
var b = playerBullets[i];
b.update();
// Remove if off screen
a cool ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
an asteroid. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
an evil futuristic looking ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
explosion of metal and fire cloud. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fire bullet. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
green health plus. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
heart. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat