User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of null (setting 'x')' in or related to this line: 'player.x = px;' Line Number: 348
User prompt
Add a starting screen ( with the title and a play button )
User prompt
Make the boss to take 6 hits to defeat it
User prompt
Make the boss to shoot the rockets less frequently, and less spread themed rather faster bullets in single direction and ricochet.
User prompt
Make the enemy ships to stay in one place too ( randomly ) also decrease the frequency of the rockets from enemies to spawn
User prompt
make the enemy space ship to take 3 hits to defeat it ( instead of 1 ), also at 0 point spawn in 2 enemies, 1 point add an enemy ship with the previous ones, continue the same until point 6, cap the number of ships to be 6
User prompt
For each point gained upto 5, add one more enemy ship in the screen
User prompt
Revert the logic, make random ships to spawn
User prompt
Fix after defeating the first 2 enemy ships, no ship is spawning in
User prompt
If there is no enemy ship spawn in +1 ship
User prompt
Start by spawning in 2 enemy ship and for each rocket defeated spawn in +1 enemy ship
User prompt
Get the hearts little bit to the left
User prompt
Slow down the enemy speed and bullet speed. And the bullet should only go vertically down ( don't target the player )
Code edit (1 edits merged)
Please save this source code
User prompt
Space Shooter: Alien Onslaught
Initial prompt
Hi Ava, Now I want to create a game based on space shooter. Game Mechanic: -> We control a space ship beginning from the bottom of the screen, which shoots out rockets. -> Enemies are alien space ship that follows from above the screen. -> Enemies shoot rockets at us too, and we have to dodge it. -> Certain enemies are different ( very rare to spawn ) which can give power ups. Gameplay: -> Make the ship to follow the clicked mouse, ( the ship should be constantly shooting the rockets ) -> The ship has 3 lives, when hit by enemy rockets, we loose health -> power ups from aliens: Fast shooting guns, extra life ( grants extra life ), destroy all ball ( grab to destroy everything ), shield ( to protect from enemy attacks for a brief time ) Gameplay mech: -> Clearing enemies grants points, enemies should go to random locations on top, should not come down, they shoot randomly. each alien ship defeated grants 1 point, when reaching 20 points, a single boss spaceship appears, when defeated we win ( the boss shoot rockets frequently, and in different directions that richochet the screens )
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bomb (for screen clear effect) var Bomb = Container.expand(function () { var self = Container.call(this); var bomb = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); return self; }); // Boss var Boss = Container.expand(function () { var self = Container.call(this); var boss = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.hp = 6; self.targetX = 1024; self.moveSpeed = 18; self.shootCooldown = 30; self.update = function () { // Move horizontally only var dx = self.targetX - self.x; if (Math.abs(dx) > self.moveSpeed) { self.x += dx > 0 ? self.moveSpeed : -self.moveSpeed; } else { self.x = self.targetX; // Pick new target self.targetX = 300 + Math.random() * (2048 - 600); } // Shooting self.shootCooldown--; if (self.shootCooldown <= 0) { // Less frequent: shoot every 60 ticks (was 18) self.shootCooldown = 60; spawnBossRockets(self); } }; return self; }); // Boss Rocket var BossRocket = Container.expand(function () { var self = Container.call(this); var rocket = self.attachAsset('bossRocket', { anchorX: 0.5, anchorY: 0.5 }); self.dx = 0; self.dy = 28; self.ricochet = true; self.update = function () { self.x += self.dx; self.y += self.dy; // Ricochet off walls if (self.ricochet) { if (self.x < 0 && self.dx < 0) self.dx *= -1; if (self.x > 2048 && self.dx > 0) self.dx *= -1; } }; return self; }); // Enemy Rocket var EnemyRocket = Container.expand(function () { var self = Container.call(this); var rocket = self.attachAsset('enemyRocket', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; // slowed down enemy rocket speed self.dx = 0; // always vertical, no horizontal movement self.dy = self.speed; self.ricochet = false; self.update = function () { self.x += self.dx; self.y += self.dy; // Ricochet off walls if enabled if (self.ricochet) { if (self.x < 0 && self.dx < 0) self.dx *= -1; if (self.x > 2048 && self.dx > 0) self.dx *= -1; } }; 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.targetX = 0; self.targetY = 0; self.moveSpeed = 5 + Math.random() * 3; // slowed down enemy movement self.shootCooldown = 60 + Math.floor(Math.random() * 60); self.isRare = false; // rare enemies drop powerups self.hp = 3; // takes 3 hits to defeat self.update = function () { // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > self.moveSpeed) { self.x += dx / dist * self.moveSpeed; self.y += dy / dist * self.moveSpeed; } else { self.x = self.targetX; self.y = self.targetY; // Randomly decide to stay in place for a while if (Math.random() < 0.4) { // Stay in place: do not pick a new target, just wait // Optionally, could add a "waitTicks" property for more control } else { // Pick new target self.targetX = 200 + Math.random() * (2048 - 400); self.targetY = 200 + Math.random() * 800; } } // Shooting self.shootCooldown--; if (self.shootCooldown <= 0) { // Decrease frequency: increase cooldown (was 60-120, now 120-200) self.shootCooldown = 120 + Math.floor(Math.random() * 80); spawnEnemyRocket(self); } }; return self; }); // Player Rocket var PlayerRocket = Container.expand(function () { var self = Container.call(this); var rocket = self.attachAsset('playerRocket', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -32; 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.lives = 3; self.shielded = false; self.fastShoot = false; self.shootTimer = 0; self.shieldNode = null; self.update = function () { // nothing here, movement is handled by drag }; self.setShield = function (active) { if (active && !self.shielded) { self.shielded = true; self.shieldNode = new Shield(); self.shieldNode.x = 0; self.shieldNode.y = 0; self.addChild(self.shieldNode); } else if (!active && self.shielded) { if (self.shieldNode) { self.shieldNode.destroy(); self.shieldNode = null; } self.shielded = false; } }; return self; }); // PowerUp var PowerUp = Container.expand(function () { var self = Container.call(this); var powerup = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'fast'; // 'fast', 'life', 'shield', 'bomb' self.speed = 12; self.update = function () { self.y += self.speed; }; return self; }); // Shield var Shield = Container.expand(function () { var self = Container.call(this); var shield = self.attachAsset('shield', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Play music // Player ship: blue box // Player rocket: yellow box // Enemy ship: red ellipse // Enemy rocket: orange box // Power-up: green ellipse // Shield: cyan ellipse // Boss: purple box // Boss rocket: magenta box // Bomb: white ellipse // Sounds // Music // Game state var gameStarted = false; var startScreen = null; var titleText = null; var playButton = null; // Score, lives, state var score = 0; var lives = 3; var player = null; var playerShieldTimeout = 0; var playerFastShootTimeout = 0; var playerBombActive = false; var playerInvulnTimeout = 0; var boss = null; var bossActive = false; var bossDefeated = false; var bossHpTxt = null; // Arrays for game objects var playerRockets = []; var enemyRockets = []; var bossRockets = []; var enemies = []; var powerups = []; var bombs = []; // GUI var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var livesTxt = new Text2('♥♥♥', { size: 90, fill: 0xFF6666 }); livesTxt.anchor.set(1, 0); livesTxt.x = -60; LK.gui.topRight.addChild(livesTxt); // Helper: update GUI function updateScore() { scoreTxt.setText(score); } function updateLives() { var s = ''; for (var i = 0; i < lives; ++i) s += '♥'; livesTxt.setText(s); } function showBossHp(hp) { if (!bossHpTxt) { bossHpTxt = new Text2('Boss: ' + hp, { size: 90, fill: 0xFFCCFF }); bossHpTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(bossHpTxt); } else { bossHpTxt.setText('Boss: ' + hp); } } function hideBossHp() { if (bossHpTxt) { bossHpTxt.destroy(); bossHpTxt = null; } } // Dragging var dragNode = null; game.down = function (x, y, obj) { // If game hasn't started, start it on any tap if (!gameStarted) { startGame(); return; } // Only allow drag if touch is on player if (player && Math.abs(x - player.x) < 120 && Math.abs(y - player.y) < 80) { dragNode = player; } }; game.up = function (x, y, obj) { dragNode = null; }; function handleMove(x, y, obj) { if (dragNode === player && player) { // Clamp to screen var px = Math.max(80, Math.min(2048 - 80, x)); var py = Math.max(2732 - 300, Math.min(2732 - 80, y)); player.x = px; player.y = py; } } game.move = handleMove; // Spawn enemy function spawnEnemy() { var e = new EnemyShip(); e.x = 200 + Math.random() * (2048 - 400); e.y = 100 + Math.random() * 200; e.targetX = 200 + Math.random() * (2048 - 400); e.targetY = 200 + Math.random() * 800; // 1 in 7 is rare if (Math.random() < 0.14) { e.isRare = true; // Tint rare enemies e.children[0].tint = 0x00ff99; } enemies.push(e); game.addChild(e); } // Spawn powerup function spawnPowerUp(x, y) { var p = new PowerUp(); p.x = x; p.y = y; // Random type var r = Math.random(); if (r < 0.25) p.type = 'fast';else if (r < 0.5) p.type = 'life';else if (r < 0.75) p.type = 'shield';else p.type = 'bomb'; // Color by type if (p.type === 'fast') p.children[0].tint = 0x44ff44; if (p.type === 'life') p.children[0].tint = 0xff66cc; if (p.type === 'shield') p.children[0].tint = 0x00ffff; if (p.type === 'bomb') p.children[0].tint = 0xffffff; powerups.push(p); game.addChild(p); } // Spawn player rocket function spawnPlayerRocket() { var r = new PlayerRocket(); r.x = player.x; r.y = player.y - 80; playerRockets.push(r); game.addChild(r); LK.getSound('shoot').play(); } // Spawn enemy rocket function spawnEnemyRocket(enemy) { var r = new EnemyRocket(); r.x = enemy.x; r.y = enemy.y + 60; // Only shoot vertically down, no targeting r.dx = 0; r.dy = r.speed; r.ricochet = false; enemyRockets.push(r); game.addChild(r); LK.getSound('enemyShoot').play(); } // Spawn boss function spawnBoss() { boss = new Boss(); boss.x = 1024; boss.y = 400; boss.hp = 6; bossActive = true; game.addChild(boss); showBossHp(boss.hp); } // Spawn boss rockets (single fast ricochet, less frequent, less spread) function spawnBossRockets(bossObj) { // Only shoot a single rocket, straight down, fast, ricochet enabled var r = new BossRocket(); r.x = bossObj.x; r.y = bossObj.y + 100; // Angle straight down var angle = Math.PI / 2; r.dx = 0; r.dy = 38; // much faster r.ricochet = true; bossRockets.push(r); game.addChild(r); LK.getSound('bossShoot').play(); } // Bomb effect: clear all enemy/boss rockets and damage all enemies function activateBomb() { if (playerBombActive) return; playerBombActive = true; var bomb = new Bomb(); bomb.x = player.x; bomb.y = player.y - 100; bombs.push(bomb); game.addChild(bomb); LK.getSound('bomb').play(); // Flash LK.effects.flashScreen(0xffffff, 400); // Destroy all enemy/boss rockets for (var i = enemyRockets.length - 1; i >= 0; --i) { enemyRockets[i].destroy(); enemyRockets.splice(i, 1); } for (var i = bossRockets.length - 1; i >= 0; --i) { bossRockets[i].destroy(); bossRockets.splice(i, 1); } // Damage all enemies for (var i = enemies.length - 1; i >= 0; --i) { enemies[i].destroy(); enemies.splice(i, 1); score += 1; updateScore(); } // Damage boss if present if (bossActive && boss) { boss.hp -= 5; if (boss.hp < 0) boss.hp = 0; showBossHp(boss.hp); LK.effects.flashObject(boss, 0xffffff, 400); } // Remove bomb after effect LK.setTimeout(function () { if (bomb) bomb.destroy(); playerBombActive = false; }, 600); } // Main update game.update = function () { // Don't update game logic if game hasn't started if (!gameStarted) return; // Player shooting if (player) { player.shootTimer--; var shootInterval = player.fastShoot ? 7 : 18; if (player.shootTimer <= 0) { player.shootTimer = shootInterval; spawnPlayerRocket(); } } // Player powerup timers if (playerFastShootTimeout > 0) { playerFastShootTimeout--; if (playerFastShootTimeout === 0) { player.fastShoot = false; } } if (playerShieldTimeout > 0) { playerShieldTimeout--; if (playerShieldTimeout === 0) { player.setShield(false); } } if (playerInvulnTimeout > 0) { playerInvulnTimeout--; } // Update player rockets for (var i = playerRockets.length - 1; i >= 0; --i) { var r = playerRockets[i]; r.update(); // Off screen if (r.y < -80) { r.destroy(); playerRockets.splice(i, 1); continue; } // Hit enemy for (var j = enemies.length - 1; j >= 0; --j) { var e = enemies[j]; if (r.intersects(e)) { LK.getSound('explosion').play(); r.destroy(); playerRockets.splice(i, 1); e.hp -= 1; LK.effects.flashObject(e, 0xffffff, 120); // Powerup drop if destroyed if (e.hp <= 0) { if (e.isRare) { spawnPowerUp(e.x, e.y); } e.destroy(); enemies.splice(j, 1); score += 1; updateScore(); } break; } } // Hit boss if (bossActive && boss && r.intersects(boss)) { LK.getSound('hit').play(); r.destroy(); playerRockets.splice(i, 1); boss.hp -= 1; showBossHp(boss.hp); LK.effects.flashObject(boss, 0xff33cc, 200); if (boss.hp <= 0) { // Boss defeated bossDefeated = true; boss.destroy(); boss = null; bossActive = false; hideBossHp(); LK.effects.flashScreen(0x00ffcc, 1200); LK.setScore(score); LK.showYouWin(); return; } } } // Update enemy rockets for (var i = enemyRockets.length - 1; i >= 0; --i) { var r = enemyRockets[i]; r.update(); // Off screen if (r.y > 2732 + 80 || r.x < -80 || r.x > 2048 + 80) { r.destroy(); enemyRockets.splice(i, 1); continue; } // Hit player if (player && r.intersects(player)) { r.destroy(); enemyRockets.splice(i, 1); if (player.shielded) { LK.getSound('shield').play(); player.setShield(false); } else if (playerInvulnTimeout === 0) { lives -= 1; updateLives(); LK.getSound('hit').play(); LK.effects.flashObject(player, 0xff0000, 600); playerInvulnTimeout = 60; if (lives <= 0) { LK.effects.flashScreen(0xff0000, 1200); LK.setScore(score); LK.showGameOver(); return; } } } } // Update boss rockets for (var i = bossRockets.length - 1; i >= 0; --i) { var r = bossRockets[i]; r.update(); // Off screen if (r.y > 2732 + 80 || r.x < -80 || r.x > 2048 + 80) { r.destroy(); bossRockets.splice(i, 1); continue; } // Hit player if (player && r.intersects(player)) { r.destroy(); bossRockets.splice(i, 1); if (player.shielded) { LK.getSound('shield').play(); player.setShield(false); } else if (playerInvulnTimeout === 0) { lives -= 1; updateLives(); LK.getSound('hit').play(); LK.effects.flashObject(player, 0xff0000, 600); playerInvulnTimeout = 60; if (lives <= 0) { LK.effects.flashScreen(0xff0000, 1200); LK.setScore(score); LK.showGameOver(); return; } } } } // Update enemies for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // Off screen (shouldn't happen) if (e.y > 2732 + 100) { e.destroy(); enemies.splice(i, 1); continue; } // Collide with player if (player && e.intersects(player)) { LK.getSound('hit').play(); e.destroy(); enemies.splice(i, 1); if (player.shielded) { player.setShield(false); } else if (playerInvulnTimeout === 0) { lives -= 1; updateLives(); LK.effects.flashObject(player, 0xff0000, 600); playerInvulnTimeout = 60; if (lives <= 0) { LK.effects.flashScreen(0xff0000, 1200); LK.setScore(score); LK.showGameOver(); return; } } } } // Update powerups for (var i = powerups.length - 1; i >= 0; --i) { var p = powerups[i]; p.update(); // Off screen if (p.y > 2732 + 80) { p.destroy(); powerups.splice(i, 1); continue; } // Collect if (player && p.intersects(player)) { LK.getSound('powerup').play(); if (p.type === 'fast') { player.fastShoot = true; playerFastShootTimeout = 360; } else if (p.type === 'life') { lives += 1; updateLives(); LK.getSound('lifeup').play(); } else if (p.type === 'shield') { player.setShield(true); playerShieldTimeout = 360; LK.getSound('shield').play(); } else if (p.type === 'bomb') { activateBomb(); } p.destroy(); powerups.splice(i, 1); } } // Update bombs for (var i = bombs.length - 1; i >= 0; --i) { // Bombs are visual only, auto destroy after effect } // Boss if (bossActive && boss) { boss.update(); } // Spawn enemies: 2 at 0 points, +1 per point up to 6, always keep at least (score+2, max 6) enemies on screen if (!bossActive) { var desiredEnemies = Math.min(score + 2, 6); var toSpawn = desiredEnemies - enemies.length; for (var i = 0; i < toSpawn; ++i) { spawnEnemy(); } } // Boss appears at 20 points if (!bossActive && !bossDefeated && score >= 20) { // Remove all enemies for (var i = enemies.length - 1; i >= 0; --i) { enemies[i].destroy(); enemies.splice(i, 1); } spawnBoss(); } }; // Create start screen function createStartScreen() { startScreen = new Container(); game.addChild(startScreen); // Title text titleText = new Text2('SPACE SHOOTER', { size: 180, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 1000; startScreen.addChild(titleText); // Play button playButton = new Text2('TAP TO PLAY', { size: 120, fill: 0x00FF00 }); playButton.anchor.set(0.5, 0.5); playButton.x = 1024; playButton.y = 1400; startScreen.addChild(playButton); } // Start the actual game function startGame() { if (gameStarted) return; gameStarted = true; // Remove start screen if (startScreen) { startScreen.destroy(); startScreen = null; } // Start music LK.playMusic('spacebg'); // Spawn player player = new PlayerShip(); player.x = 1024; player.y = 2732 - 180; game.addChild(player); // Set initial GUI updateScore(); updateLives(); } // Initialize start screen createStartScreen();
===================================================================
--- original.js
+++ change.js
@@ -307,9 +307,9 @@
game.up = function (x, y, obj) {
dragNode = null;
};
function handleMove(x, y, obj) {
- if (dragNode === player) {
+ if (dragNode === player && player) {
// Clamp to screen
var px = Math.max(80, Math.min(2048 - 80, x));
var py = Math.max(2732 - 300, Math.min(2732 - 80, y));
player.x = px;
A bomb. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Boss ship top down. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Enemy ship. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Spaceship for players. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
make it greyish
Kinda a spike ball very red. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Diamond, . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat