User prompt
Double the player's health.
User prompt
When you kill an enemy it gives you 10 coins ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Delete the attack button. When you move, it makes you attack.
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'if (player.isMoving && x < 2048 / 2) {' Line Number: 1031
User prompt
Show a health bar on the top of your screen and add waves. After you defeat 5 waves, you win the game.
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'shootButton.up();' Line Number: 994
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'player.targetX = x;' Line Number: 958
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'shootButton.down(x, y);' Line Number: 964
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'player.update')' in or related to this line: 'player.update();' Line Number: 1002
User prompt
Make a home screen with a start button and a shop. Each time you kill an enemy, it gives you 2 points. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Use your finger to move the player and delete the joystick.
User prompt
Make the joystick move the player.
Code edit (1 edits merged)
Please save this source code
User prompt
Space Defender
Initial prompt
Add a joystick and a shoot button, player and a gun.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var size = 60 + Math.floor(Math.random() * 60);
var asteroidGraphics = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 60,
scaleY: size / 60
});
self.health = 20 + Math.floor(size / 10);
self.speed = 1 + Math.random() * 3;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
self.points = 50;
self.update = function () {
self.y += self.speed;
asteroidGraphics.rotation += self.rotationSpeed;
// Check if asteroid is off-screen
if (self.y > 2832) {
return true; // Mark for removal
}
return false;
};
self.damage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
if (self.health <= 0) {
LK.getSound('explosion').play();
return true; // Asteroid destroyed
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 10;
self.update = function () {
self.y += self.speed;
// Check if bullet is off-screen
if (self.y > 2832) {
return true; // Mark for removal
}
return false;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 30;
self.type = 'standard';
self.speed = 2 + Math.random() * 2;
self.points = 100;
self.fireRate = 120; // Frames between shots
self.fireCooldown = Math.floor(Math.random() * 60);
self.update = function () {
self.y += self.speed;
// Check if enemy is off-screen
if (self.y > 2832) {
return true; // Mark for removal
}
// Random movement
if (Math.random() < 0.02) {
self.direction = Math.random() > 0.5 ? 1 : -1;
}
if (self.direction) {
self.x += self.direction * (self.speed * 0.8);
// Keep within bounds
if (self.x < 100) {
self.x = 100;
self.direction = 1;
} else if (self.x > 2048 - 100) {
self.x = 2048 - 100;
self.direction = -1;
}
}
// Shooting
if (self.fireCooldown <= 0) {
self.fireCooldown = self.fireRate;
self.shoot();
} else {
self.fireCooldown--;
}
return false;
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('enemyShoot').play();
};
self.damage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xffffff, 100);
if (self.health <= 0) {
LK.getSound('explosion').play();
return true; // Enemy destroyed
}
return false;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.power = 10;
self.update = function () {
self.y -= self.speed;
// Check if bullet is off-screen
if (self.y < -50) {
return true; // Mark for removal
}
return false;
};
return self;
});
var PlayerShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.fireRate = 20; // Frames between shots
self.fireCooldown = 0;
self.bulletSpeed = 15;
self.speed = 8;
self.powerLevel = 1;
self.update = function () {
if (self.fireCooldown > 0) {
self.fireCooldown--;
}
};
self.damage = function (amount) {
self.health -= amount;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
self.health = 0;
return true; // Ship destroyed
}
return false;
};
self.shoot = function () {
if (self.fireCooldown <= 0) {
self.fireCooldown = self.fireRate;
LK.getSound('playerShoot').play();
// Create bullets based on power level
if (self.powerLevel === 1) {
// Single bullet
createBullet(self.x, self.y - 40);
} else if (self.powerLevel === 2) {
// Double bullets
createBullet(self.x - 20, self.y - 30);
createBullet(self.x + 20, self.y - 30);
} else {
// Triple bullets
createBullet(self.x, self.y - 40);
createBullet(self.x - 25, self.y - 30);
createBullet(self.x + 25, self.y - 30);
}
}
};
// Helper function to create a bullet
function createBullet(x, y) {
var bullet = new PlayerBullet();
bullet.x = x;
bullet.y = y;
playerBullets.push(bullet);
game.addChild(bullet);
}
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.random() < 0.7 ? 'weapon' : 'health';
self.speed = 3;
// Change color based on type
if (self.type === 'health') {
powerUpGraphics.tint = 0x33ff33; // Green for health
} else {
powerUpGraphics.tint = 0xffcc33; // Yellow for weapon
}
self.update = function () {
self.y += self.speed;
// Slight bobbing motion
self.x += Math.sin(LK.ticks * 0.05) * 0.5;
// Check if power-up is off-screen
if (self.y > 2832) {
return true; // Mark for removal
}
return false;
};
return self;
});
var ShootButton = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('shootButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.pressed = false;
self.down = function () {
self.pressed = true;
buttonGraphics.alpha = 0.9;
buttonGraphics.scale.set(0.9);
};
self.up = function () {
self.pressed = false;
buttonGraphics.alpha = 0.6;
buttonGraphics.scale.set(1);
};
return self;
});
var VirtualJoystick = Container.expand(function () {
var self = Container.call(this);
var baseGraphics = self.attachAsset('joystick', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
var knobGraphics = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.maxDistance = 80;
self.active = false;
self.dx = 0;
self.dy = 0;
self.down = function (x, y) {
var localPos = self.toLocal({
x: x,
y: y
});
if (Math.sqrt(Math.pow(localPos.x, 2) + Math.pow(localPos.y, 2)) <= baseGraphics.width / 2) {
self.active = true;
self.moveKnob(localPos.x, localPos.y);
}
};
self.moveKnob = function (x, y) {
var dist = Math.sqrt(x * x + y * y);
if (dist > self.maxDistance) {
x = x / dist * self.maxDistance;
y = y / dist * self.maxDistance;
}
knobGraphics.x = x;
knobGraphics.y = y;
// Normalize to -1 to 1 range for movement
self.dx = x / self.maxDistance;
self.dy = y / self.maxDistance;
};
self.move = function (x, y) {
if (self.active) {
var localPos = self.toLocal({
x: x,
y: y
});
self.moveKnob(localPos.x, localPos.y);
}
};
self.up = function () {
self.active = false;
knobGraphics.x = 0;
knobGraphics.y = 0;
self.dx = 0;
self.dy = 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state
var gameState = 'playing';
var wave = 1;
var enemySpawnTimer = 0;
var asteroidSpawnTimer = 0;
var waveEnemyCount = 0;
var waveMaxEnemies = 10;
var powerUpChance = 0.2;
var touchIdentifiers = {};
// Game elements
var player;
var joystick;
var shootButton;
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var asteroids = [];
var powerUps = [];
var stars = [];
// UI elements
var scoreText;
var healthBar;
var waveText;
// Initialize game
function initGame() {
// Reset game state
gameState = 'playing';
wave = 1;
enemySpawnTimer = 0;
asteroidSpawnTimer = 0;
waveEnemyCount = 0;
waveMaxEnemies = 5 + wave * 5;
playerBullets = [];
enemies = [];
enemyBullets = [];
asteroids = [];
powerUps = [];
touchIdentifiers = {};
// Set background
game.setBackgroundColor(0x000022);
// Create starfield background
createStarfield();
// Create player
player = new PlayerShip();
player.x = 2048 / 2;
player.y = 2732 - 300;
game.addChild(player);
// Create controls
joystick = new VirtualJoystick();
joystick.x = 300;
joystick.y = 2732 - 300;
game.addChild(joystick);
shootButton = new ShootButton();
shootButton.x = 2048 - 300;
shootButton.y = 2732 - 300;
game.addChild(shootButton);
// Create UI
createUI();
// Start music
LK.playMusic('gameMusic');
}
// Create starfield background
function createStarfield() {
for (var i = 0; i < 100; i++) {
var star = LK.getAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1 + Math.random() * 0.2,
scaleY: 0.1 + Math.random() * 0.2,
alpha: 0.1 + Math.random() * 0.5,
tint: 0xffffff
});
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.speed = 0.5 + Math.random() * 2;
stars.push(star);
game.addChild(star);
}
}
// Create UI elements
function createUI() {
// Score text
scoreText = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 30;
scoreText.y = 30;
LK.gui.addChild(scoreText);
// Health bar background
var healthBarBg = LK.getAsset('playerBullet', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.5,
tint: 0x444444
});
healthBarBg.x = 30;
healthBarBg.y = 100;
LK.gui.addChild(healthBarBg);
// Health bar
healthBar = LK.getAsset('playerBullet', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.5,
tint: 0x33ff33
});
healthBar.x = 30;
healthBar.y = 100;
LK.gui.addChild(healthBar);
// Wave text
waveText = new Text2('WAVE: 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = 2048 - 30;
waveText.y = 30;
LK.gui.addChild(waveText);
}
// Spawn enemy
function spawnEnemy() {
var enemy = new EnemyShip();
enemy.x = 100 + Math.random() * (2048 - 200);
enemy.y = -100;
enemy.direction = Math.random() > 0.5 ? 1 : -1;
// Adjust enemy stats based on wave
enemy.health = 30 + wave * 5;
enemy.speed = 2 + Math.min(wave * 0.3, 3);
enemy.fireRate = Math.max(120 - wave * 5, 60);
enemy.points = 100 + wave * 10;
enemies.push(enemy);
game.addChild(enemy);
waveEnemyCount++;
}
// Spawn asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
asteroid.x = 100 + Math.random() * (2048 - 200);
asteroid.y = -100;
asteroids.push(asteroid);
game.addChild(asteroid);
}
// Spawn power-up
function spawnPowerUp(x, y) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Check collisions
function checkCollisions() {
// Player bullets vs enemies
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
var hitEnemy = false;
// Check against enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
hitEnemy = true;
if (enemy.damage(player.powerLevel * 10)) {
// Enemy destroyed
LK.setScore(LK.getScore() + enemy.points);
scoreText.setText('SCORE: ' + LK.getScore());
// Chance to spawn power-up
if (Math.random() < powerUpChance) {
spawnPowerUp(enemy.x, enemy.y);
}
enemy.destroy();
enemies.splice(j, 1);
}
break;
}
}
// Check against asteroids if bullet didn't hit an enemy
if (!hitEnemy) {
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (bullet.intersects(asteroid)) {
hitEnemy = true;
if (asteroid.damage(player.powerLevel * 10)) {
// Asteroid destroyed
LK.setScore(LK.getScore() + asteroid.points);
scoreText.setText('SCORE: ' + LK.getScore());
// Small chance to spawn power-up
if (Math.random() < powerUpChance * 0.5) {
spawnPowerUp(asteroid.x, asteroid.y);
}
asteroid.destroy();
asteroids.splice(j, 1);
}
break;
}
}
}
// Remove bullet if it hit something or went off-screen
if (hitEnemy || bullet.update()) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
// Enemy bullets vs player
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
// Check if bullet should be removed
if (bullet.update()) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check against player
if (gameState === 'playing' && bullet.intersects(player)) {
if (player.damage(bullet.damage)) {
// Player destroyed
gameOver();
}
// Update health bar
updateHealthBar();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Enemies vs player
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
// Check if enemy should be removed
if (enemy.update()) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check against player
if (gameState === 'playing' && enemy.intersects(player)) {
if (player.damage(30)) {
// Player destroyed
gameOver();
}
// Update health bar
updateHealthBar();
// Destroy enemy
enemy.destroy();
enemies.splice(i, 1);
}
}
// Asteroids vs player
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
// Check if asteroid should be removed
if (asteroid.update()) {
asteroid.destroy();
asteroids.splice(i, 1);
continue;
}
// Check against player
if (gameState === 'playing' && asteroid.intersects(player)) {
if (player.damage(20)) {
// Player destroyed
gameOver();
}
// Update health bar
updateHealthBar();
// Destroy asteroid
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Power-ups vs player
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
// Check if power-up should be removed
if (powerUp.update()) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check against player
if (gameState === 'playing' && powerUp.intersects(player)) {
// Apply power-up effect
if (powerUp.type === 'health') {
player.health = Math.min(player.health + 30, 100);
updateHealthBar();
} else if (powerUp.type === 'weapon') {
player.powerLevel = Math.min(player.powerLevel + 1, 3);
}
// Play sound
LK.getSound('powerUpCollect').play();
// Remove power-up
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
// Update health bar
function updateHealthBar() {
healthBar.scale.x = 3 * (player.health / 100);
// Change color based on health
if (player.health > 60) {
healthBar.tint = 0x33ff33; // Green
} else if (player.health > 30) {
healthBar.tint = 0xffcc33; // Yellow
} else {
healthBar.tint = 0xff3333; // Red
}
}
// Game over
function gameOver() {
gameState = 'gameover';
LK.effects.flashScreen(0xff0000, 500);
LK.showGameOver();
}
// Handle input
game.down = function (x, y, obj) {
// Store touch identifier to track multiple touches
if (obj.identifier !== undefined) {
touchIdentifiers[obj.identifier] = {
x: x,
y: y
};
}
// Check joystick
if (x < 2048 / 2) {
joystick.down(x, y);
}
// Check shoot button
if (x > 2048 / 2) {
shootButton.down(x, y);
player.shoot();
}
};
game.move = function (x, y, obj) {
// Update stored touch position
if (obj.identifier !== undefined && touchIdentifiers[obj.identifier]) {
touchIdentifiers[obj.identifier] = {
x: x,
y: y
};
}
// Update joystick if it's active
if (joystick.active) {
joystick.move(x, y);
}
};
game.up = function (x, y, obj) {
// Remove touch identifier
if (obj.identifier !== undefined) {
delete touchIdentifiers[obj.identifier];
}
// Release joystick and shoot button
joystick.up();
shootButton.up();
};
// Main game loop
game.update = function () {
// Skip if game hasn't been initialized
if (!player) {
initGame();
return;
}
// Update player
player.update();
// Move player based on joystick input
if (joystick.active) {
player.x += joystick.dx * player.speed;
player.y += joystick.dy * player.speed;
// Keep player in bounds
player.x = Math.max(50, Math.min(player.x, 2048 - 50));
player.y = Math.max(50, Math.min(player.y, 2732 - 50));
}
// Auto-fire if shoot button is pressed
if (shootButton.pressed && LK.ticks % player.fireRate === 0) {
player.shoot();
}
// Spawn enemies
if (gameState === 'playing') {
// Check if wave is complete
if (waveEnemyCount >= waveMaxEnemies && enemies.length === 0) {
// Start new wave
wave++;
waveEnemyCount = 0;
waveMaxEnemies = 5 + wave * 5;
waveText.setText('WAVE: ' + wave);
// Flash wave text
tween(waveText, {
scale: 1.5
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(waveText, {
scale: 1
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
// Spawn enemies
if (waveEnemyCount < waveMaxEnemies) {
enemySpawnTimer++;
if (enemySpawnTimer > Math.max(120 - wave * 5, 30)) {
enemySpawnTimer = 0;
spawnEnemy();
}
}
// Spawn asteroids
asteroidSpawnTimer++;
if (asteroidSpawnTimer > Math.max(180 - wave * 3, 60)) {
asteroidSpawnTimer = 0;
spawnAsteroid();
}
}
// Check collisions
checkCollisions();
// Update starfield
for (var i = 0; i < stars.length; i++) {
var star = stars[i];
star.y += star.speed;
if (star.y > 2732) {
star.y = 0;
star.x = Math.random() * 2048;
}
}
};
// Initialize game at startup
initGame(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,739 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Asteroid = Container.expand(function () {
+ var self = Container.call(this);
+ var size = 60 + Math.floor(Math.random() * 60);
+ var asteroidGraphics = self.attachAsset('asteroid', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: size / 60,
+ scaleY: size / 60
+ });
+ self.health = 20 + Math.floor(size / 10);
+ self.speed = 1 + Math.random() * 3;
+ self.rotationSpeed = (Math.random() - 0.5) * 0.05;
+ self.points = 50;
+ self.update = function () {
+ self.y += self.speed;
+ asteroidGraphics.rotation += self.rotationSpeed;
+ // Check if asteroid is off-screen
+ if (self.y > 2832) {
+ return true; // Mark for removal
+ }
+ return false;
+ };
+ self.damage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xffffff, 100);
+ if (self.health <= 0) {
+ LK.getSound('explosion').play();
+ return true; // Asteroid destroyed
+ }
+ return false;
+ };
+ return self;
+});
+var EnemyBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('enemyBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.damage = 10;
+ self.update = function () {
+ self.y += self.speed;
+ // Check if bullet is off-screen
+ if (self.y > 2832) {
+ return true; // Mark for removal
+ }
+ return false;
+ };
+ return self;
+});
+var EnemyShip = Container.expand(function () {
+ var self = Container.call(this);
+ var shipGraphics = self.attachAsset('enemyShip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 30;
+ self.type = 'standard';
+ self.speed = 2 + Math.random() * 2;
+ self.points = 100;
+ self.fireRate = 120; // Frames between shots
+ self.fireCooldown = Math.floor(Math.random() * 60);
+ self.update = function () {
+ self.y += self.speed;
+ // Check if enemy is off-screen
+ if (self.y > 2832) {
+ return true; // Mark for removal
+ }
+ // Random movement
+ if (Math.random() < 0.02) {
+ self.direction = Math.random() > 0.5 ? 1 : -1;
+ }
+ if (self.direction) {
+ self.x += self.direction * (self.speed * 0.8);
+ // Keep within bounds
+ if (self.x < 100) {
+ self.x = 100;
+ self.direction = 1;
+ } else if (self.x > 2048 - 100) {
+ self.x = 2048 - 100;
+ self.direction = -1;
+ }
+ }
+ // Shooting
+ if (self.fireCooldown <= 0) {
+ self.fireCooldown = self.fireRate;
+ self.shoot();
+ } else {
+ self.fireCooldown--;
+ }
+ return false;
+ };
+ self.shoot = function () {
+ var bullet = new EnemyBullet();
+ bullet.x = self.x;
+ bullet.y = self.y + 40;
+ enemyBullets.push(bullet);
+ game.addChild(bullet);
+ LK.getSound('enemyShoot').play();
+ };
+ self.damage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xffffff, 100);
+ if (self.health <= 0) {
+ LK.getSound('explosion').play();
+ return true; // Enemy destroyed
+ }
+ return false;
+ };
+ return self;
+});
+var PlayerBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var bulletGraphics = self.attachAsset('playerBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 15;
+ self.power = 10;
+ self.update = function () {
+ self.y -= self.speed;
+ // Check if bullet is off-screen
+ if (self.y < -50) {
+ return true; // Mark for removal
+ }
+ return false;
+ };
+ return self;
+});
+var PlayerShip = Container.expand(function () {
+ var self = Container.call(this);
+ var shipGraphics = self.attachAsset('playerShip', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.health = 100;
+ self.fireRate = 20; // Frames between shots
+ self.fireCooldown = 0;
+ self.bulletSpeed = 15;
+ self.speed = 8;
+ self.powerLevel = 1;
+ self.update = function () {
+ if (self.fireCooldown > 0) {
+ self.fireCooldown--;
+ }
+ };
+ self.damage = function (amount) {
+ self.health -= amount;
+ LK.effects.flashObject(self, 0xff0000, 300);
+ if (self.health <= 0) {
+ self.health = 0;
+ return true; // Ship destroyed
+ }
+ return false;
+ };
+ self.shoot = function () {
+ if (self.fireCooldown <= 0) {
+ self.fireCooldown = self.fireRate;
+ LK.getSound('playerShoot').play();
+ // Create bullets based on power level
+ if (self.powerLevel === 1) {
+ // Single bullet
+ createBullet(self.x, self.y - 40);
+ } else if (self.powerLevel === 2) {
+ // Double bullets
+ createBullet(self.x - 20, self.y - 30);
+ createBullet(self.x + 20, self.y - 30);
+ } else {
+ // Triple bullets
+ createBullet(self.x, self.y - 40);
+ createBullet(self.x - 25, self.y - 30);
+ createBullet(self.x + 25, self.y - 30);
+ }
+ }
+ };
+ // Helper function to create a bullet
+ function createBullet(x, y) {
+ var bullet = new PlayerBullet();
+ bullet.x = x;
+ bullet.y = y;
+ playerBullets.push(bullet);
+ game.addChild(bullet);
+ }
+ return self;
+});
+var PowerUp = Container.expand(function () {
+ var self = Container.call(this);
+ var powerUpGraphics = self.attachAsset('powerUp', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.type = Math.random() < 0.7 ? 'weapon' : 'health';
+ self.speed = 3;
+ // Change color based on type
+ if (self.type === 'health') {
+ powerUpGraphics.tint = 0x33ff33; // Green for health
+ } else {
+ powerUpGraphics.tint = 0xffcc33; // Yellow for weapon
+ }
+ self.update = function () {
+ self.y += self.speed;
+ // Slight bobbing motion
+ self.x += Math.sin(LK.ticks * 0.05) * 0.5;
+ // Check if power-up is off-screen
+ if (self.y > 2832) {
+ return true; // Mark for removal
+ }
+ return false;
+ };
+ return self;
+});
+var ShootButton = Container.expand(function () {
+ var self = Container.call(this);
+ var buttonGraphics = self.attachAsset('shootButton', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ });
+ self.pressed = false;
+ self.down = function () {
+ self.pressed = true;
+ buttonGraphics.alpha = 0.9;
+ buttonGraphics.scale.set(0.9);
+ };
+ self.up = function () {
+ self.pressed = false;
+ buttonGraphics.alpha = 0.6;
+ buttonGraphics.scale.set(1);
+ };
+ return self;
+});
+var VirtualJoystick = Container.expand(function () {
+ var self = Container.call(this);
+ var baseGraphics = self.attachAsset('joystick', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ });
+ var knobGraphics = self.attachAsset('joystickKnob', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ });
+ self.maxDistance = 80;
+ self.active = false;
+ self.dx = 0;
+ self.dy = 0;
+ self.down = function (x, y) {
+ var localPos = self.toLocal({
+ x: x,
+ y: y
+ });
+ if (Math.sqrt(Math.pow(localPos.x, 2) + Math.pow(localPos.y, 2)) <= baseGraphics.width / 2) {
+ self.active = true;
+ self.moveKnob(localPos.x, localPos.y);
+ }
+ };
+ self.moveKnob = function (x, y) {
+ var dist = Math.sqrt(x * x + y * y);
+ if (dist > self.maxDistance) {
+ x = x / dist * self.maxDistance;
+ y = y / dist * self.maxDistance;
+ }
+ knobGraphics.x = x;
+ knobGraphics.y = y;
+ // Normalize to -1 to 1 range for movement
+ self.dx = x / self.maxDistance;
+ self.dy = y / self.maxDistance;
+ };
+ self.move = function (x, y) {
+ if (self.active) {
+ var localPos = self.toLocal({
+ x: x,
+ y: y
+ });
+ self.moveKnob(localPos.x, localPos.y);
+ }
+ };
+ self.up = function () {
+ self.active = false;
+ knobGraphics.x = 0;
+ knobGraphics.y = 0;
+ self.dx = 0;
+ self.dy = 0;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
backgroundColor: 0x000000
-});
\ No newline at end of file
+});
+
+/****
+* Game Code
+****/
+// Game state
+var gameState = 'playing';
+var wave = 1;
+var enemySpawnTimer = 0;
+var asteroidSpawnTimer = 0;
+var waveEnemyCount = 0;
+var waveMaxEnemies = 10;
+var powerUpChance = 0.2;
+var touchIdentifiers = {};
+// Game elements
+var player;
+var joystick;
+var shootButton;
+var playerBullets = [];
+var enemies = [];
+var enemyBullets = [];
+var asteroids = [];
+var powerUps = [];
+var stars = [];
+// UI elements
+var scoreText;
+var healthBar;
+var waveText;
+// Initialize game
+function initGame() {
+ // Reset game state
+ gameState = 'playing';
+ wave = 1;
+ enemySpawnTimer = 0;
+ asteroidSpawnTimer = 0;
+ waveEnemyCount = 0;
+ waveMaxEnemies = 5 + wave * 5;
+ playerBullets = [];
+ enemies = [];
+ enemyBullets = [];
+ asteroids = [];
+ powerUps = [];
+ touchIdentifiers = {};
+ // Set background
+ game.setBackgroundColor(0x000022);
+ // Create starfield background
+ createStarfield();
+ // Create player
+ player = new PlayerShip();
+ player.x = 2048 / 2;
+ player.y = 2732 - 300;
+ game.addChild(player);
+ // Create controls
+ joystick = new VirtualJoystick();
+ joystick.x = 300;
+ joystick.y = 2732 - 300;
+ game.addChild(joystick);
+ shootButton = new ShootButton();
+ shootButton.x = 2048 - 300;
+ shootButton.y = 2732 - 300;
+ game.addChild(shootButton);
+ // Create UI
+ createUI();
+ // Start music
+ LK.playMusic('gameMusic');
+}
+// Create starfield background
+function createStarfield() {
+ for (var i = 0; i < 100; i++) {
+ var star = LK.getAsset('joystickKnob', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.1 + Math.random() * 0.2,
+ scaleY: 0.1 + Math.random() * 0.2,
+ alpha: 0.1 + Math.random() * 0.5,
+ tint: 0xffffff
+ });
+ star.x = Math.random() * 2048;
+ star.y = Math.random() * 2732;
+ star.speed = 0.5 + Math.random() * 2;
+ stars.push(star);
+ game.addChild(star);
+ }
+}
+// Create UI elements
+function createUI() {
+ // Score text
+ scoreText = new Text2('SCORE: 0', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ scoreText.anchor.set(0, 0);
+ scoreText.x = 30;
+ scoreText.y = 30;
+ LK.gui.addChild(scoreText);
+ // Health bar background
+ var healthBarBg = LK.getAsset('playerBullet', {
+ anchorX: 0,
+ anchorY: 0.5,
+ scaleX: 3,
+ scaleY: 0.5,
+ tint: 0x444444
+ });
+ healthBarBg.x = 30;
+ healthBarBg.y = 100;
+ LK.gui.addChild(healthBarBg);
+ // Health bar
+ healthBar = LK.getAsset('playerBullet', {
+ anchorX: 0,
+ anchorY: 0.5,
+ scaleX: 3,
+ scaleY: 0.5,
+ tint: 0x33ff33
+ });
+ healthBar.x = 30;
+ healthBar.y = 100;
+ LK.gui.addChild(healthBar);
+ // Wave text
+ waveText = new Text2('WAVE: 1', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ waveText.anchor.set(1, 0);
+ waveText.x = 2048 - 30;
+ waveText.y = 30;
+ LK.gui.addChild(waveText);
+}
+// Spawn enemy
+function spawnEnemy() {
+ var enemy = new EnemyShip();
+ enemy.x = 100 + Math.random() * (2048 - 200);
+ enemy.y = -100;
+ enemy.direction = Math.random() > 0.5 ? 1 : -1;
+ // Adjust enemy stats based on wave
+ enemy.health = 30 + wave * 5;
+ enemy.speed = 2 + Math.min(wave * 0.3, 3);
+ enemy.fireRate = Math.max(120 - wave * 5, 60);
+ enemy.points = 100 + wave * 10;
+ enemies.push(enemy);
+ game.addChild(enemy);
+ waveEnemyCount++;
+}
+// Spawn asteroid
+function spawnAsteroid() {
+ var asteroid = new Asteroid();
+ asteroid.x = 100 + Math.random() * (2048 - 200);
+ asteroid.y = -100;
+ asteroids.push(asteroid);
+ game.addChild(asteroid);
+}
+// Spawn power-up
+function spawnPowerUp(x, y) {
+ var powerUp = new PowerUp();
+ powerUp.x = x;
+ powerUp.y = y;
+ powerUps.push(powerUp);
+ game.addChild(powerUp);
+}
+// Check collisions
+function checkCollisions() {
+ // Player bullets vs enemies
+ for (var i = playerBullets.length - 1; i >= 0; i--) {
+ var bullet = playerBullets[i];
+ var hitEnemy = false;
+ // Check against enemies
+ for (var j = enemies.length - 1; j >= 0; j--) {
+ var enemy = enemies[j];
+ if (bullet.intersects(enemy)) {
+ hitEnemy = true;
+ if (enemy.damage(player.powerLevel * 10)) {
+ // Enemy destroyed
+ LK.setScore(LK.getScore() + enemy.points);
+ scoreText.setText('SCORE: ' + LK.getScore());
+ // Chance to spawn power-up
+ if (Math.random() < powerUpChance) {
+ spawnPowerUp(enemy.x, enemy.y);
+ }
+ enemy.destroy();
+ enemies.splice(j, 1);
+ }
+ break;
+ }
+ }
+ // Check against asteroids if bullet didn't hit an enemy
+ if (!hitEnemy) {
+ for (var j = asteroids.length - 1; j >= 0; j--) {
+ var asteroid = asteroids[j];
+ if (bullet.intersects(asteroid)) {
+ hitEnemy = true;
+ if (asteroid.damage(player.powerLevel * 10)) {
+ // Asteroid destroyed
+ LK.setScore(LK.getScore() + asteroid.points);
+ scoreText.setText('SCORE: ' + LK.getScore());
+ // Small chance to spawn power-up
+ if (Math.random() < powerUpChance * 0.5) {
+ spawnPowerUp(asteroid.x, asteroid.y);
+ }
+ asteroid.destroy();
+ asteroids.splice(j, 1);
+ }
+ break;
+ }
+ }
+ }
+ // Remove bullet if it hit something or went off-screen
+ if (hitEnemy || bullet.update()) {
+ bullet.destroy();
+ playerBullets.splice(i, 1);
+ }
+ }
+ // Enemy bullets vs player
+ for (var i = enemyBullets.length - 1; i >= 0; i--) {
+ var bullet = enemyBullets[i];
+ // Check if bullet should be removed
+ if (bullet.update()) {
+ bullet.destroy();
+ enemyBullets.splice(i, 1);
+ continue;
+ }
+ // Check against player
+ if (gameState === 'playing' && bullet.intersects(player)) {
+ if (player.damage(bullet.damage)) {
+ // Player destroyed
+ gameOver();
+ }
+ // Update health bar
+ updateHealthBar();
+ // Remove bullet
+ bullet.destroy();
+ enemyBullets.splice(i, 1);
+ }
+ }
+ // Enemies vs player
+ for (var i = enemies.length - 1; i >= 0; i--) {
+ var enemy = enemies[i];
+ // Check if enemy should be removed
+ if (enemy.update()) {
+ enemy.destroy();
+ enemies.splice(i, 1);
+ continue;
+ }
+ // Check against player
+ if (gameState === 'playing' && enemy.intersects(player)) {
+ if (player.damage(30)) {
+ // Player destroyed
+ gameOver();
+ }
+ // Update health bar
+ updateHealthBar();
+ // Destroy enemy
+ enemy.destroy();
+ enemies.splice(i, 1);
+ }
+ }
+ // Asteroids vs player
+ for (var i = asteroids.length - 1; i >= 0; i--) {
+ var asteroid = asteroids[i];
+ // Check if asteroid should be removed
+ if (asteroid.update()) {
+ asteroid.destroy();
+ asteroids.splice(i, 1);
+ continue;
+ }
+ // Check against player
+ if (gameState === 'playing' && asteroid.intersects(player)) {
+ if (player.damage(20)) {
+ // Player destroyed
+ gameOver();
+ }
+ // Update health bar
+ updateHealthBar();
+ // Destroy asteroid
+ asteroid.destroy();
+ asteroids.splice(i, 1);
+ }
+ }
+ // Power-ups vs player
+ for (var i = powerUps.length - 1; i >= 0; i--) {
+ var powerUp = powerUps[i];
+ // Check if power-up should be removed
+ if (powerUp.update()) {
+ powerUp.destroy();
+ powerUps.splice(i, 1);
+ continue;
+ }
+ // Check against player
+ if (gameState === 'playing' && powerUp.intersects(player)) {
+ // Apply power-up effect
+ if (powerUp.type === 'health') {
+ player.health = Math.min(player.health + 30, 100);
+ updateHealthBar();
+ } else if (powerUp.type === 'weapon') {
+ player.powerLevel = Math.min(player.powerLevel + 1, 3);
+ }
+ // Play sound
+ LK.getSound('powerUpCollect').play();
+ // Remove power-up
+ powerUp.destroy();
+ powerUps.splice(i, 1);
+ }
+ }
+}
+// Update health bar
+function updateHealthBar() {
+ healthBar.scale.x = 3 * (player.health / 100);
+ // Change color based on health
+ if (player.health > 60) {
+ healthBar.tint = 0x33ff33; // Green
+ } else if (player.health > 30) {
+ healthBar.tint = 0xffcc33; // Yellow
+ } else {
+ healthBar.tint = 0xff3333; // Red
+ }
+}
+// Game over
+function gameOver() {
+ gameState = 'gameover';
+ LK.effects.flashScreen(0xff0000, 500);
+ LK.showGameOver();
+}
+// Handle input
+game.down = function (x, y, obj) {
+ // Store touch identifier to track multiple touches
+ if (obj.identifier !== undefined) {
+ touchIdentifiers[obj.identifier] = {
+ x: x,
+ y: y
+ };
+ }
+ // Check joystick
+ if (x < 2048 / 2) {
+ joystick.down(x, y);
+ }
+ // Check shoot button
+ if (x > 2048 / 2) {
+ shootButton.down(x, y);
+ player.shoot();
+ }
+};
+game.move = function (x, y, obj) {
+ // Update stored touch position
+ if (obj.identifier !== undefined && touchIdentifiers[obj.identifier]) {
+ touchIdentifiers[obj.identifier] = {
+ x: x,
+ y: y
+ };
+ }
+ // Update joystick if it's active
+ if (joystick.active) {
+ joystick.move(x, y);
+ }
+};
+game.up = function (x, y, obj) {
+ // Remove touch identifier
+ if (obj.identifier !== undefined) {
+ delete touchIdentifiers[obj.identifier];
+ }
+ // Release joystick and shoot button
+ joystick.up();
+ shootButton.up();
+};
+// Main game loop
+game.update = function () {
+ // Skip if game hasn't been initialized
+ if (!player) {
+ initGame();
+ return;
+ }
+ // Update player
+ player.update();
+ // Move player based on joystick input
+ if (joystick.active) {
+ player.x += joystick.dx * player.speed;
+ player.y += joystick.dy * player.speed;
+ // Keep player in bounds
+ player.x = Math.max(50, Math.min(player.x, 2048 - 50));
+ player.y = Math.max(50, Math.min(player.y, 2732 - 50));
+ }
+ // Auto-fire if shoot button is pressed
+ if (shootButton.pressed && LK.ticks % player.fireRate === 0) {
+ player.shoot();
+ }
+ // Spawn enemies
+ if (gameState === 'playing') {
+ // Check if wave is complete
+ if (waveEnemyCount >= waveMaxEnemies && enemies.length === 0) {
+ // Start new wave
+ wave++;
+ waveEnemyCount = 0;
+ waveMaxEnemies = 5 + wave * 5;
+ waveText.setText('WAVE: ' + wave);
+ // Flash wave text
+ tween(waveText, {
+ scale: 1.5
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(waveText, {
+ scale: 1
+ }, {
+ duration: 300,
+ easing: tween.easeIn
+ });
+ }
+ });
+ }
+ // Spawn enemies
+ if (waveEnemyCount < waveMaxEnemies) {
+ enemySpawnTimer++;
+ if (enemySpawnTimer > Math.max(120 - wave * 5, 30)) {
+ enemySpawnTimer = 0;
+ spawnEnemy();
+ }
+ }
+ // Spawn asteroids
+ asteroidSpawnTimer++;
+ if (asteroidSpawnTimer > Math.max(180 - wave * 3, 60)) {
+ asteroidSpawnTimer = 0;
+ spawnAsteroid();
+ }
+ }
+ // Check collisions
+ checkCollisions();
+ // Update starfield
+ for (var i = 0; i < stars.length; i++) {
+ var star = stars[i];
+ star.y += star.speed;
+ if (star.y > 2732) {
+ star.y = 0;
+ star.x = Math.random() * 2048;
+ }
+ }
+};
+// Initialize game at startup
+initGame();
\ No newline at end of file