User prompt
Every ten wave have one boss enemy who takes multiple hits to defeat and is bigger and has a special gun.
User prompt
Give the player 100 hp
User prompt
Make the enemies move down into about the middle and then stop moving.
User prompt
Make the enemies stay in place
Code edit (1 edits merged)
Please save this source code
User prompt
Shipwave: Endless Upgrades
Initial prompt
Create a game where you are a ship at the bottom of the screen with basic guns and an infinite amount of waves of enemies come at you and after killing a certain amount of enemies you can get upgrades to give you stronger and faster and better guns.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy
var Enemy = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
self.speedY = 6;
self.hp = 1;
self.maxHp = 1;
self.shootCooldown = 0;
self.shootRate = 90 + Math.floor(Math.random() * 60);
self.value = 1;
self.update = function () {
// Move enemy down until it reaches about the middle of the screen, then stop
if (self.lastY === undefined) self.lastY = self.y;
var stopY = 1366; // Middle of 2732px screen
if (self.y < stopY) {
self.y += self.speedY;
if (self.y > stopY) self.y = stopY;
}
if (self.shootCooldown > 0) self.shootCooldown--;
if (self.shootCooldown === 0 && Math.random() < 0.02) {
self.shoot();
self.shootCooldown = self.shootRate;
}
self.lastY = self.y;
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + self.height / 2 + 10;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
};
self.takeDamage = function (amount) {
self.hp -= amount;
LK.getSound('enemyHit').play();
LK.effects.flashObject(self, 0xffffff, 200);
if (self.hp <= 0) {
self.destroyed = true;
}
};
return self;
});
// Enemy Bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
self.speedY = 18;
self.update = function () {
self.y += self.speedY;
};
return self;
});
// Player Bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
self.speedY = -28;
self.speedX = 0;
self.update = function () {
self.y += self.speedY;
self.x += self.speedX;
};
return self;
});
// Player Ship
var Ship = Container.expand(function () {
var self = Container.call(this);
var shipGfx = self.attachAsset('ship', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = shipGfx.width;
self.height = shipGfx.height;
self.fireCooldown = 0;
self.fireRate = 30; // ticks between shots
self.bulletSpeed = -28;
self.bulletCount = 1;
self.bulletSpread = 0;
self.doubleShot = false;
self.tripleShot = false;
self.laser = false;
self.hp = 3;
self.maxHp = 3;
self.invulnTicks = 0;
self.update = function () {
if (self.fireCooldown > 0) self.fireCooldown--;
if (self.invulnTicks > 0) {
self.invulnTicks--;
shipGfx.alpha = LK.ticks % 8 < 4 ? 0.4 : 1;
} else {
shipGfx.alpha = 1;
}
};
self.shoot = function () {
if (self.fireCooldown > 0) return;
self.fireCooldown = self.fireRate;
var shots = [];
var spread = self.bulletSpread;
var count = self.bulletCount;
if (self.tripleShot) {
count = 3;
spread = 0.25;
} else if (self.doubleShot) {
count = 2;
spread = 0.18;
}
for (var i = 0; i < count; i++) {
var angle = (i - (count - 1) / 2) * spread;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - self.height / 2 - 10;
bullet.speedY = self.bulletSpeed * Math.cos(angle);
bullet.speedX = self.bulletSpeed * Math.sin(angle);
playerBullets.push(bullet);
game.addChild(bullet);
shots.push(bullet);
}
LK.getSound('shoot').play();
return shots;
};
self.takeDamage = function (amount) {
if (self.invulnTicks > 0) return;
self.hp -= amount;
self.invulnTicks = 60;
LK.effects.flashObject(self, 0xff0000, 400);
if (self.hp <= 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
};
return self;
});
// Upgrade Card
var UpgradeCard = Container.expand(function () {
var self = Container.call(this);
var highlight = self.attachAsset('upgradeHighlight', {
anchorX: 0.5,
anchorY: 0.5
});
highlight.visible = false;
var card = self.attachAsset('upgradeCard', {
anchorX: 0.5,
anchorY: 0.5
});
self.text = new Text2('', {
size: 70,
fill: 0xFFFFFF
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
self.setText = function (t) {
self.text.setText(t);
};
self.setHighlighted = function (v) {
highlight.visible = v;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Music
// Sound effects
// Upgrade highlight
// Upgrade card
// Enemy bullet
// Bullet (player)
// Enemy
// Ship (player)
// Game state variables
var ship;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var wave = 1;
var enemiesToSpawn = 0;
var enemiesDefeated = 0;
var enemiesPerWave = 8;
var waveInProgress = false;
var upgradePending = false;
var upgradeOptions = [];
var upgradeCards = [];
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
var score = 0;
var scoreTxt;
var hpTxt;
var waveTxt;
var upgradeGroup;
var lastTouch = {
x: 0,
y: 0
};
// Set up background color
game.setBackgroundColor(0x0a0a18);
// Score display
scoreTxt = new Text2('Score: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// HP display
hpTxt = new Text2('HP: 3', {
size: 70,
fill: "#fff"
});
hpTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(hpTxt);
hpTxt.y = 100;
// Wave display
waveTxt = new Text2('Wave: 1', {
size: 70,
fill: "#fff"
});
waveTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(waveTxt);
waveTxt.y = 200;
// Upgrade group (overlay)
upgradeGroup = new Container();
upgradeGroup.visible = false;
game.addChild(upgradeGroup);
// Initialize player ship
ship = new Ship();
ship.hp = 100;
ship.maxHp = 100;
game.addChild(ship);
ship.x = 2048 / 2;
ship.y = 2732 - 180;
// Start first wave
startWave();
// Handle dragging ship
game.down = function (x, y, obj) {
if (upgradePending) return;
if (pointInShip(x, y)) {
dragging = true;
dragOffsetX = ship.x - x;
dragOffsetY = ship.y - y;
}
lastTouch.x = x;
lastTouch.y = y;
};
game.move = function (x, y, obj) {
if (upgradePending) {
// Handle upgrade card selection
for (var i = 0; i < upgradeCards.length; i++) {
var card = upgradeCards[i];
var bounds = getCardBounds(card);
if (x >= bounds.x && x <= bounds.x + bounds.w && y >= bounds.y && y <= bounds.y + bounds.h) {
for (var j = 0; j < upgradeCards.length; j++) {
upgradeCards[j].setHighlighted(j === i);
}
}
}
lastTouch.x = x;
lastTouch.y = y;
return;
}
if (dragging) {
var nx = x + dragOffsetX;
var ny = y + dragOffsetY;
// Clamp to screen
nx = Math.max(ship.width / 2, Math.min(2048 - ship.width / 2, nx));
ny = Math.max(2732 - 400, Math.min(2732 - ship.height / 2, ny));
ship.x = nx;
ship.y = ny;
}
lastTouch.x = x;
lastTouch.y = y;
};
game.up = function (x, y, obj) {
if (upgradePending) {
// Check if an upgrade card was selected
for (var i = 0; i < upgradeCards.length; i++) {
var card = upgradeCards[i];
var bounds = getCardBounds(card);
if (x >= bounds.x && x <= bounds.x + bounds.w && y >= bounds.y && y <= bounds.y + bounds.h) {
selectUpgrade(i);
break;
}
}
return;
}
dragging = false;
};
// Main game update loop
game.update = function () {
if (upgradePending) return;
// Ship update
ship.update();
// Ship auto-fire
if (ship.fireCooldown === 0) {
ship.shoot();
}
// Player bullets
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 = enemies.length - 1; j >= 0; j--) {
var e = enemies[j];
if (b.intersects(e)) {
e.takeDamage(1);
b.destroy();
playerBullets.splice(i, 1);
if (e.hp <= 0 && !e.destroyed) {
e.destroyed = true;
}
break;
}
}
}
// Enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var e = enemies[i];
e.update();
// Remove if off screen
if (e.y > 2732 + e.height) {
e.destroy();
enemies.splice(i, 1);
continue;
}
// Remove if destroyed
if (e.destroyed) {
score += e.value;
enemiesDefeated++;
scoreTxt.setText('Score: ' + score);
e.destroy();
enemies.splice(i, 1);
LK.getSound('hit').play();
// Check for wave end
if (enemiesDefeated >= enemiesPerWave) {
setTimeout(showUpgrade, 600);
}
continue;
}
// Check collision with ship
if (e.intersects(ship) && ship.invulnTicks === 0) {
ship.takeDamage(1);
e.destroyed = true;
}
}
// Enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var eb = enemyBullets[i];
eb.update();
if (eb.y > 2732 + eb.height) {
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
if (eb.intersects(ship) && ship.invulnTicks === 0) {
ship.takeDamage(1);
eb.destroy();
enemyBullets.splice(i, 1);
continue;
}
}
// Spawn enemies
if (waveInProgress && enemiesToSpawn > 0 && enemies.length < Math.min(5 + wave, 10)) {
spawnEnemy();
}
// Update HP and wave display
hpTxt.setText('HP: ' + ship.hp);
waveTxt.setText('Wave: ' + wave);
};
// Start a new wave
function startWave() {
waveInProgress = true;
enemiesToSpawn = enemiesPerWave;
enemiesDefeated = 0;
waveTxt.setText('Wave: ' + wave);
}
// Spawn a single enemy
function spawnEnemy() {
var e = new Enemy();
e.x = 180 + Math.random() * (2048 - 360);
e.y = -e.height / 2 - 10;
// Increase difficulty per wave
e.hp = 1 + Math.floor(wave / 2);
e.maxHp = e.hp;
e.speedY = 6 + Math.floor(wave / 3);
e.shootRate = Math.max(60, 120 - wave * 4 + Math.floor(Math.random() * 40));
e.value = 1 + Math.floor(wave / 2);
enemies.push(e);
game.addChild(e);
enemiesToSpawn--;
}
// Show upgrade selection
function showUpgrade() {
if (upgradePending) return;
upgradePending = true;
waveInProgress = false;
upgradeGroup.visible = true;
// Generate 3 upgrade options
upgradeOptions = getUpgradeOptions();
// Remove old cards
for (var i = 0; i < upgradeCards.length; i++) {
upgradeCards[i].destroy();
}
upgradeCards = [];
// Layout cards
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var spacing = 700;
for (var i = 0; i < 3; i++) {
var card = new UpgradeCard();
card.x = centerX + (i - 1) * spacing;
card.y = centerY;
card.setText(upgradeOptions[i].label);
card.setHighlighted(false);
upgradeGroup.addChild(card);
upgradeCards.push(card);
}
}
// Select an upgrade
function selectUpgrade(idx) {
if (!upgradePending) return;
var upg = upgradeOptions[idx];
applyUpgrade(upg);
LK.getSound('upgrade').play();
// Hide upgrade UI
for (var i = 0; i < upgradeCards.length; i++) {
upgradeCards[i].destroy();
}
upgradeCards = [];
upgradeGroup.visible = false;
upgradePending = false;
// Next wave
wave++;
enemiesPerWave = Math.min(20, 8 + Math.floor(wave * 1.5));
startWave();
}
// Generate upgrade options
function getUpgradeOptions() {
var pool = [{
label: "+1 Max HP",
apply: function apply() {
ship.maxHp += 1;
ship.hp = ship.maxHp;
}
}, {
label: "+1 Bullet per shot",
apply: function apply() {
ship.bulletCount = Math.min(5, ship.bulletCount + 1);
}
}, {
label: "Faster Fire Rate",
apply: function apply() {
ship.fireRate = Math.max(8, ship.fireRate - 4);
}
}, {
label: "Wider Spread",
apply: function apply() {
ship.bulletSpread = Math.min(0.5, ship.bulletSpread + 0.08);
}
}, {
label: "Double Shot",
apply: function apply() {
ship.doubleShot = true;
}
}, {
label: "Triple Shot",
apply: function apply() {
ship.tripleShot = true;
}
}];
// Remove upgrades already owned
if (ship.doubleShot) pool = pool.filter(function (u) {
return u.label !== "Double Shot";
});
if (ship.tripleShot) pool = pool.filter(function (u) {
return u.label !== "Triple Shot";
});
// Pick 3 random upgrades
var options = [];
var used = {};
for (var i = 0; i < 3; i++) {
var idx = Math.floor(Math.random() * pool.length);
while (used[idx]) idx = (idx + 1) % pool.length;
used[idx] = true;
options.push(pool[idx]);
}
return options;
}
// Apply upgrade
function applyUpgrade(upg) {
upg.apply();
}
// Utility: check if point is in ship
function pointInShip(x, y) {
return x >= ship.x - ship.width / 2 && x <= ship.x + ship.width / 2 && y >= ship.y - ship.height / 2 && y <= ship.y + ship.height / 2;
}
// Utility: get card bounds
function getCardBounds(card) {
return {
x: card.x - 310,
y: card.y - 160,
w: 620,
h: 320
};
}
// Utility: setTimeout using LK
function setTimeout(fn, ms) {
return LK.setTimeout(fn, ms);
}
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 1,
duration: 1200
}
}); ===================================================================
--- original.js
+++ change.js
@@ -190,17 +190,17 @@
/****
* Game Code
****/
-// Game state variables
-// Ship (player)
-// Enemy
-// Bullet (player)
-// Enemy bullet
-// Upgrade card
-// Upgrade highlight
-// Sound effects
// Music
+// Sound effects
+// Upgrade highlight
+// Upgrade card
+// Enemy bullet
+// Bullet (player)
+// Enemy
+// Ship (player)
+// Game state variables
var ship;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];