User prompt
Don't overlap the play button and the shop button anymore. Keep them clearly separated.
User prompt
Add a shop button to the game.
User prompt
Add the shop button below the play button.
User prompt
Add a shop button positioned above the play button.
User prompt
Remove the shop button.
Code edit (3 edits merged)
Please save this source code
User prompt
The shop button is currently overlapping with the play button, but I want the shop button to be positioned above the play button (not overlapping, just placed on top of it).
User prompt
Move the shop button above the play button.
Code edit (2 edits merged)
Please save this source code
User prompt
Set the 'Shop' button's Y position to 300 pixels from the bottom.
Code edit (8 edits merged)
Please save this source code
User prompt
Move the 'Shop' button higher on the screen.
Code edit (1 edits merged)
Please save this source code
User prompt
Move the 'Play' and 'Shop' buttons slightly higher on the start screen.
User prompt
On the start screen, place a 'Shop' button below the 'Play' button. When the player clicks the 'Shop' button, open the in-game shop panel.
User prompt
Implement a shop menu accessible from the main game where players can browse and unlock new costumes using in-game currency
User prompt
On enemy hit, show a quick fire burst effect without changing the enemy size, then immediately remove the enemy from the scene. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make the explosion more fiery and intense when an enemy is destroyed. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make enemy ships explode with a visual effect when they are destroyed. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
"Prevent the game from starting automatically. Ensure it only begins when the player clicks the 'Play' button."
User prompt
"The game should not start until the 'Play' button is clicked, and the background music should begin only after clicking 'Play'."
User prompt
"Create a stylish start screen theme where 'Space Wars' appears at the top in a large font, and 'Galactic Showdown' is displayed below it in a slightly smaller font." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
"Design a stylish start screen for the game with a bold title 'Space Wars: Galactic Showdown' prominently displayed at the top, and a centered 'Play' button below it to begin the game." ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Start playing 'boss music' during boss figths
User prompt
Play the 'sad sounds' file when firing.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ // Boss ship class var BossShip = Container.expand(function () { var self = Container.call(this); // Attach boss asset (use enemyShip but much larger, and red tint) var boss = self.attachAsset('enemyShip', { width: 480, height: 480, color: 0xff0000, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.radius = 240; self.isAlive = true; self.health = 40; self.maxHealth = 40; self.lastY = undefined; // Boss always at top center, stationary self.x = GAME_WIDTH / 2; self.y = 340; // Boss update self.update = function () { // Boss remains stationary at top center // Unique Skill 1: Radial bullet spread every 120 ticks if (LK.ticks % 120 === 0) { var numBullets = 14; for (var i = 0; i < numBullets; i++) { var angle = 2 * Math.PI / numBullets * i; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 220; // Give bullet a custom direction bullet.customVX = Math.cos(angle) * 13; bullet.customVY = Math.sin(angle) * 13; bullet.update = function () { this.x += this.customVX; this.y += this.customVY; }; enemyBullets.push(bullet); game.addChild(bullet); } } // Unique Skill 2: Laser attack every 300 ticks (fires a fast straight bullet down the center) if (LK.ticks % 300 === 0) { var laser = new EnemyBullet(); laser.x = self.x; laser.y = self.y + 260; laser.speed = 38; laser.radius = 60; // Make it visually larger var asset = laser.children[0]; if (asset) { asset.width = 90; asset.height = 340; } enemyBullets.push(laser); game.addChild(laser); } // Unique Skill 3: Area attack (big slow bullet straight down) every 180 ticks if (LK.ticks % 180 === 0) { var area = new EnemyBullet(); area.x = self.x; area.y = self.y + 240; area.speed = 10; area.radius = 120; var asset = area.children[0]; if (asset) { asset.width = 220; asset.height = 120; } enemyBullets.push(area); game.addChild(area); } }; // Flash on hit self.flash = function () { tween(boss, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(boss, { tint: 0xff0000 }, { duration: 120 }); } }); }; return self; }); // Enemy bullet class var EnemyBullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (red, 24x48) var bullet = self.attachAsset('enemyBullet', { width: 24, height: 48, color: 0xff4444, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); self.speed = 14; self.radius = 12; self.update = function () { self.y += self.speed; }; return self; }); // Enemy ship class var EnemyShip = Container.expand(function () { var self = Container.call(this); // Attach enemy asset (ellipse, magenta, 220x220) var enemy = self.attachAsset('enemyShip', { width: 220, height: 220, color: 0xff33cc, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.radius = 110; self.speed = 4 + Math.random() * 2; // Vary speed self.dirX = (Math.random() - 0.5) * 2; // Slight horizontal drift // For movement patterns self.waveOffset = Math.random() * Math.PI * 2; // For collision self.isAlive = true; // Update per frame self.update = function () { // Move down, with a sine wave pattern self.y += self.speed; self.x += Math.sin(LK.ticks / 30 + self.waveOffset) * 2 + self.dirX; // Prevent enemy from moving outside the horizontal screen area var minX = 60; var maxX = 2048 - 60; if (self.x < minX) { self.x = minX; self.dirX = Math.abs(self.dirX); // bounce right } if (self.x > maxX) { self.x = maxX; self.dirX = -Math.abs(self.dirX); // bounce left } }; // Flash on hit self.flash = function () { tween(enemy, { tint: 0xffffff }, { duration: 80, onFinish: function onFinish() { tween(enemy, { tint: 0xff33cc }, { duration: 120 }); } }); }; return self; }); // Player bullet class var PlayerBullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (yellow, 30x60) var bullet = self.attachAsset('playerBullet', { width: 30, height: 60, color: 0xffe066, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); self.speed = -22; self.radius = 15; self.update = function () { self.y += self.speed; }; return self; }); // Player spaceship class var PlayerShip = Container.expand(function () { var self = Container.call(this); // Attach ship asset (box, blue, 220x220) var ship = self.attachAsset('playerShip', { width: 220, height: 220, color: 0x3399ff, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Ship properties self.radius = 110; // for collision self.isAlive = true; // Ship flash effect on hit self.flash = function () { tween(ship, { tint: 0xff3333 }, { duration: 100, onFinish: function onFinish() { tween(ship, { tint: 0x3399ff }, { duration: 200 }); } }); }; return self; }); // Powerup class var PowerUp = Container.expand(function () { var self = Container.call(this); // Attach powerup asset (green ellipse, 120x120) var pu = self.attachAsset('powerUp', { width: 120, height: 120, color: 0x44ff88, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); self.radius = 60; self.speed = 6; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000010 }); /**** * Game Code ****/ // --- Start Screen Overlay --- var startScreenOverlay = new Container(); // Large main title: "Space Wars" var mainTitle = new Text2('Space Wars', { size: 220, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); mainTitle.anchor.set(0.5, 0); mainTitle.x = GAME_WIDTH / 2; mainTitle.y = 120; // Subtitle: "Galactic Showdown" var subTitle = new Text2('Galactic Showdown', { size: 110, fill: 0x99e6ff, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); subTitle.anchor.set(0.5, 0); subTitle.x = GAME_WIDTH / 2; subTitle.y = mainTitle.y + mainTitle.height + 20; // --- SHOP MENU UI --- // Shop state var shopOpen = false; var shopOverlay = new Container(); shopOverlay.visible = false; var shopTitle = new Text2('Costume Shop', { size: 120, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopTitle.anchor.set(0.5, 0); shopTitle.x = GAME_WIDTH / 2; shopTitle.y = 120; shopOverlay.addChild(shopTitle); // Define costumes (id, name, price, asset) var costumes = [{ id: "default", name: "Classic", price: 0, asset: "playerShip" }, { id: "red", name: "Red Comet", price: 200, asset: "enemyShip" }, { id: "gold", name: "Gold Star", price: 500, asset: "playerBullet" }]; // Persistent unlocks if (!storage.unlockedCostumes) storage.unlockedCostumes = { "default": true }; if (!storage.selectedCostume) storage.selectedCostume = "default"; // Shop navigation state var shopIndex = 0; function updateShopUI() { // Remove old preview if any if (shopOverlay.costumePreview) { shopOverlay.removeChild(shopOverlay.costumePreview); shopOverlay.costumePreview = null; } var c = costumes[shopIndex]; var preview = LK.getAsset(c.asset, { width: 320, height: 320, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: 520 }); shopOverlay.addChild(preview); shopOverlay.costumePreview = preview; // Update name/price shopNameTxt.setText(c.name); if (c.price === 0) { shopPriceTxt.setText("Unlocked"); } else if (storage.unlockedCostumes[c.id]) { shopPriceTxt.setText("Unlocked"); } else { shopPriceTxt.setText("Price: " + c.price + " pts"); } // Show select/unlock button if (storage.unlockedCostumes[c.id]) { shopActionBtnText.setText(storage.selectedCostume === c.id ? "Selected" : "Select"); } else { shopActionBtnText.setText("Unlock"); } // Hide select if already selected shopActionBtn.alpha = storage.selectedCostume === c.id && storage.unlockedCostumes[c.id] ? 0.5 : 1; } // Costume name var shopNameTxt = new Text2('', { size: 80, fill: 0xffffff, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopNameTxt.anchor.set(0.5, 0); shopNameTxt.x = GAME_WIDTH / 2; shopNameTxt.y = 900; shopOverlay.addChild(shopNameTxt); // Costume price var shopPriceTxt = new Text2('', { size: 60, fill: 0xFFD700, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopPriceTxt.anchor.set(0.5, 0); shopPriceTxt.x = GAME_WIDTH / 2; shopPriceTxt.y = 1020; shopOverlay.addChild(shopPriceTxt); // Action button (Unlock/Select) var shopActionBtn = LK.getAsset('playerBullet', { width: 420, height: 110, color: 0x00ccff, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: 1200 }); var shopActionBtnText = new Text2('', { size: 70, fill: 0xffffff, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopActionBtnText.anchor.set(0.5, 0.5); shopActionBtnText.x = shopActionBtn.x; shopActionBtnText.y = shopActionBtn.y; shopOverlay.addChild(shopActionBtn); shopOverlay.addChild(shopActionBtnText); // Left/right nav buttons var shopLeftBtn = LK.getAsset('enemyBullet', { width: 100, height: 100, color: 0xFFD700, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2 - 300, y: 520 }); var shopRightBtn = LK.getAsset('enemyBullet', { width: 100, height: 100, color: 0xFFD700, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2 + 300, y: 520 }); shopOverlay.addChild(shopLeftBtn); shopOverlay.addChild(shopRightBtn); // Close button var shopCloseBtn = LK.getAsset('playerBullet', { width: 180, height: 80, color: 0x888888, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: 1450 }); var shopCloseBtnText = new Text2('Close', { size: 50, fill: 0xffffff, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopCloseBtnText.anchor.set(0.5, 0.5); shopCloseBtnText.x = shopCloseBtn.x; shopCloseBtnText.y = shopCloseBtn.y; shopOverlay.addChild(shopCloseBtn); shopOverlay.addChild(shopCloseBtnText); // Shop button on start screen var shopBtn = LK.getAsset('playerBullet', { width: 320, height: 100, color: 0xFFD700, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 + 320 }); var shopBtnText = new Text2('SHOP', { size: 70, fill: 0x000000, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); shopBtnText.anchor.set(0.5, 0.5); shopBtnText.x = shopBtn.x; shopBtnText.y = shopBtn.y; // Shop button handler shopBtn.down = function (x, y, obj) { if (shopOpen) return; shopOpen = true; shopOverlay.visible = true; LK.gui.center.addChild(shopOverlay); updateShopUI(); // Hide start overlay if (startScreenOverlay.parent) startScreenOverlay.visible = false; }; // Shop close handler shopCloseBtn.down = function (x, y, obj) { shopOpen = false; shopOverlay.visible = false; if (shopOverlay.parent) LK.gui.center.removeChild(shopOverlay); if (startScreenOverlay && !gameStarted) startScreenOverlay.visible = true; }; // Shop left/right nav shopLeftBtn.down = function (x, y, obj) { shopIndex = (shopIndex + costumes.length - 1) % costumes.length; updateShopUI(); }; shopRightBtn.down = function (x, y, obj) { shopIndex = (shopIndex + 1) % costumes.length; updateShopUI(); }; // Shop action (unlock/select) shopActionBtn.down = function (x, y, obj) { var c = costumes[shopIndex]; if (storage.unlockedCostumes[c.id]) { // Select storage.selectedCostume = c.id; updateShopUI(); } else { // Unlock if enough score var score = LK.getScore(); if (score >= c.price) { LK.setScore(score - c.price); scoreTxt.setText(LK.getScore()); storage.unlockedCostumes[c.id] = true; storage.selectedCostume = c.id; updateShopUI(); } else { // Not enough points, flash price red shopPriceTxt.setText("Need " + (c.price - score) + " more!"); tween(shopPriceTxt, { fill: 0xff0000 }, { duration: 200, onFinish: function onFinish() { shopPriceTxt.setText("Price: " + c.price + " pts"); } }); } } }; // Add to overlay startScreenOverlay.addChild(mainTitle); startScreenOverlay.addChild(subTitle); startScreenOverlay.addChild(shopBtn); startScreenOverlay.addChild(shopBtnText); // Play button (large, centered) var playBtn = LK.getAsset('playerBullet', { width: 520, height: 140, color: 0x00ccff, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 + 120 }); var playBtnText = new Text2('PLAY', { size: 100, fill: 0xffffff, font: "'GillSans-Bold',Impact,'Arial Black',Tahoma" }); playBtnText.anchor.set(0.5, 0.5); playBtnText.x = playBtn.x; playBtnText.y = playBtn.y; startScreenOverlay.addChild(playBtn); startScreenOverlay.addChild(playBtnText); // Animate main title in mainTitle.alpha = 0; tween(mainTitle, { alpha: 1 }, { duration: 700, easing: tween.cubicOut }); // Animate subtitle in (slightly delayed) subTitle.alpha = 0; tween(subTitle, { alpha: 1 }, { duration: 700, delay: 200, easing: tween.cubicOut }); // Animate play button in playBtn.alpha = 0; playBtnText.alpha = 0; tween(playBtn, { alpha: 1 }, { duration: 700, easing: tween.cubicOut }); tween(playBtnText, { alpha: 1 }, { duration: 900, easing: tween.cubicOut }); // Add to overlay startScreenOverlay.addChild(mainTitle); startScreenOverlay.addChild(subTitle); startScreenOverlay.addChild(playBtn); startScreenOverlay.addChild(playBtnText); LK.gui.center.addChild(startScreenOverlay); // Block gameplay until Play is pressed var gameStarted = false; function hideStartScreen() { if (startScreenOverlay.parent) { LK.gui.center.removeChild(startScreenOverlay); } gameStarted = true; } // Play button interaction playBtn.down = function (x, y, obj) { if (gameStarted) return; // Animate out tween(startScreenOverlay, { alpha: 0 }, { duration: 400, easing: tween.cubicIn, onFinish: function onFinish() { // Start background music only after Play is clicked LK.playMusic('sapce'); hideStartScreen(); } }); }; playBtn.move = function (x, y, obj) {}; playBtn.up = function (x, y, obj) {}; // Block all gameplay input until started var origGameMove = game.move; var origGameDown = game.down; var origGameUp = game.up; game.move = function (x, y, obj) { if (!gameStarted) return; if (origGameMove) origGameMove(x, y, obj); }; game.down = function (x, y, obj) { if (!gameStarted) return; if (origGameDown) origGameDown(x, y, obj); }; game.up = function (x, y, obj) { if (!gameStarted) return; if (origGameUp) origGameUp(x, y, obj); }; // --- Volume Control UI on Pause --- var volumeSlider = null; var volumeLabel = null; var lastPauseState = false; // Helper to create volume slider UI function showVolumeSlider() { if (!LK.isPaused) return; if (volumeSlider) return; // Already shown // Create label volumeLabel = new Text2('Music Volume', { size: 60, fill: 0xFFFFFF }); volumeLabel.anchor.set(0.5, 0.5); volumeLabel.x = GAME_WIDTH / 2; volumeLabel.y = GAME_HEIGHT / 2 - 120; LK.gui.center.addChild(volumeLabel); // Create slider background var sliderBg = LK.getAsset('playerBullet', { width: 500, height: 32, color: 0x222222, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 }); LK.gui.center.addChild(sliderBg); // Create slider knob volumeSlider = LK.getAsset('enemyBullet', { width: 60, height: 60, color: 0xFFD700, anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 }); LK.gui.center.addChild(volumeSlider); // Set initial knob position based on current music volume var currentVolume = LK.getMusicVolume ? LK.getMusicVolume() : 1; var minX = GAME_WIDTH / 2 - 220; var maxX = GAME_WIDTH / 2 + 220; volumeSlider.x = minX + (maxX - minX) * currentVolume; // Drag logic var dragging = false; volumeSlider.down = function (x, y, obj) { dragging = true; }; volumeSlider.up = function (x, y, obj) { dragging = false; }; // Move handler for slider volumeSlider.move = function (x, y, obj) { if (!dragging) return; var minX = GAME_WIDTH / 2 - 220; var maxX = GAME_WIDTH / 2 + 220; var px = Math.max(minX, Math.min(maxX, x)); volumeSlider.x = px; // Calculate volume (0..1) var vol = (px - minX) / (maxX - minX); if (vol < 0) vol = 0; if (vol > 1) vol = 1; LK.setMusicVolume ? LK.setMusicVolume(vol) : null; }; // Attach move/up to gui.center for mobile, but only if game is paused LK.gui.center.move = function (x, y, obj) { if (LK.isPaused && dragging) { volumeSlider.move(x, y, obj); } }; LK.gui.center.up = function (x, y, obj) { if (LK.isPaused) { dragging = false; } }; } // Helper to remove volume slider UI function hideVolumeSlider() { if (volumeSlider) { LK.gui.center.removeChild(volumeSlider); volumeSlider = null; } if (volumeLabel) { LK.gui.center.removeChild(volumeLabel); volumeLabel = null; } // Remove slider background if present var children = LK.gui.center.children; for (var i = children.length - 1; i >= 0; i--) { var c = children[i]; if (c && c.width === 500 && c.height === 32 && c.color === 0x222222) { LK.gui.center.removeChild(c); } } // Remove move/up handlers LK.gui.center.move = null; LK.gui.center.up = null; } // Listen for pause/resume to show/hide slider LK.on('pause', function () { showVolumeSlider(); }); LK.on('resume', function () { hideVolumeSlider(); }); var backgroundImg = LK.getAsset('background', { width: GAME_WIDTH, height: GAME_HEIGHT, anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChildAt(backgroundImg, 0); // Always at the back layer // Play sapce music at game start // (Music will be started after Play is clicked, see playBtn.down handler) // LK.playMusic('sapce'); // Health bar asset (simple red bar, 600x40) // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PLAYER_START_X = GAME_WIDTH / 2; var PLAYER_START_Y = GAME_HEIGHT - 350; // Level system variables var currentLevel = 1; var enemiesPerLevel = 6; // base number of enemies for level 1 var enemiesToSpawn = enemiesPerLevel; var enemiesKilledThisLevel = 0; var enemyScoreBase = 10; // base score for level 1 var enemyScoreThisLevel = enemyScoreBase; // Game state var player; var enemies = []; var playerBullets = []; var enemyBullets = []; var powerUps = []; var dragNode = null; var lastScore = 0; var scoreTxt; var powerUpActive = false; var powerUpTimer = 0; var enemySpawnTimer = 0; var enemyFireTimer = 0; var powerUpSpawnTimer = 0; var gameOver = false; // Boss state var bossActive = false; var bossShip = null; var bossHealthBar = null; // Score display scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Import storage plugin for persistent high score // High score display (top right, avoid top right 100x100) var highScore = storage.highScore || 0; var highScoreTxt = new Text2('High: ' + highScore, { size: 60, fill: 0xFFD700 }); highScoreTxt.anchor.set(1, 0); highScoreTxt.x = GAME_WIDTH - 120; highScoreTxt.y = 0; LK.gui.top.addChild(highScoreTxt); // Health system var playerHealth = 5; // Heart icon assets (use 5 separate heart images for live updating) var heartIcons = []; var heartAssetNames = ['heart1', 'heart2', 'heart3', 'heart4', 'heart5']; for (var i = 0; i < 5; i++) { var heart = LK.getAsset(heartAssetNames[i], { width: 60, height: 60, anchorX: 0.5, anchorY: 0.5, x: 200 + i * 70, y: 30 }); LK.gui.top.addChild(heart); heartIcons.push(heart); } // Helper to update heart icons based on playerHealth function updateHearts() { for (var i = 0; i < heartIcons.length; i++) { heartIcons[i].alpha = i < playerHealth ? 1 : 0.2; } } updateHearts(); // Level display (top left, avoid top left 100x100) var levelTxt = new Text2('Level 1', { size: 40, fill: 0xFFD700 }); levelTxt.anchor.set(0, 0); levelTxt.x = 180; levelTxt.y = 100; LK.gui.top.addChild(levelTxt); // Enemies left display (top left, avoid top left 100x100) var enemiesLeftTxt = new Text2('Enemies: 0', { size: 40, fill: 0xFF8888 }); enemiesLeftTxt.anchor.set(0, 0); enemiesLeftTxt.x = 180; enemiesLeftTxt.y = 60; LK.gui.top.addChild(enemiesLeftTxt); // Initialize player player = new PlayerShip(); // Apply selected costume if not default if (storage.selectedCostume && storage.selectedCostume !== "default") { var costume = null; for (var i = 0; i < costumes.length; i++) { if (costumes[i].id === storage.selectedCostume) costume = costumes[i]; } if (costume) { // Remove old asset and attach new if (player.children.length > 0) player.removeChild(player.children[0]); var costumeAsset = player.attachAsset(costume.asset, { width: 220, height: 220, anchorX: 0.5, anchorY: 0.5 }); } } player.x = PLAYER_START_X; player.y = PLAYER_START_Y; game.addChild(player); // Touch/move controls function handleMove(x, y, obj) { if (dragNode && player.isAlive) { // Clamp to game area, avoid top 100px (menu) var px = Math.max(60, Math.min(GAME_WIDTH - 60, x)); var py = Math.max(200, Math.min(GAME_HEIGHT - 60, y)); dragNode.x = px; dragNode.y = py; } } game.move = handleMove; game.down = function (x, y, obj) { if (player.isAlive) { dragNode = player; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; // Helper: collision check (circle vs circle) function circlesIntersect(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); return dist < a.radius + b.radius; } // Helper: spawn enemy function spawnEnemy() { var enemy = new EnemyShip(); // Spawn in random horizontal position, avoid edges enemy.x = 120 + Math.random() * (GAME_WIDTH - 240); enemy.y = -100; enemies.push(enemy); game.addChild(enemy); } // Helper: spawn enemy bullet function spawnEnemyBullet(enemy) { var bullet = new EnemyBullet(); bullet.x = enemy.x; bullet.y = enemy.y + 60; enemyBullets.push(bullet); game.addChild(bullet); } // Helper: spawn player bullet function spawnPlayerBullet() { var bullet = new PlayerBullet(); bullet.x = player.x; bullet.y = player.y - 80; playerBullets.push(bullet); game.addChild(bullet); } // Helper: spawn powerup function spawnPowerUp() { var pu = new PowerUp(); pu.x = 120 + Math.random() * (GAME_WIDTH - 240); pu.y = -60; powerUps.push(pu); game.addChild(pu); } // Powerup effect: double shot function activatePowerUp() { powerUpActive = true; powerUpTimer = LK.ticks + 360; // 6 seconds at 60fps // Flash player ship green tween(player, { tint: 0x44ff88 }, { duration: 200, onFinish: function onFinish() { tween(player, { tint: 0x3399ff }, { duration: 200 }); } }); } // Main game update game.update = function () { if (!gameStarted) { return; } if (!player.isAlive) { return; } // --- Player auto-fire --- if (LK.ticks % (powerUpActive ? 7 : 14) === 0) { if (powerUpActive) { // Double shot: two bullets var b1 = new PlayerBullet(); b1.x = player.x - 36; b1.y = player.y - 80; playerBullets.push(b1); game.addChild(b1); var b2 = new PlayerBullet(); b2.x = player.x + 36; b2.y = player.y - 80; playerBullets.push(b2); game.addChild(b2); } else { spawnPlayerBullet(); } } // --- Enemy spawn --- if (!bossActive && enemySpawnTimer <= LK.ticks && enemiesToSpawn > 0) { spawnEnemy(); enemiesToSpawn--; // Escalate spawn rate var minDelay = 24, maxDelay = 60; var delay = Math.max(minDelay, maxDelay - Math.floor(LK.getScore() / 10) * 4); enemySpawnTimer = LK.ticks + delay; // Update enemies left UI enemiesLeftTxt.setText('Enemies: ' + (enemiesToSpawn + enemies.length)); } // --- Enemy fire --- if (!bossActive && enemyFireTimer <= LK.ticks && enemies.length > 0) { // Pick random enemy to fire var idx = Math.floor(Math.random() * enemies.length); if (enemies[idx]) { spawnEnemyBullet(enemies[idx]); } // Reduce fire rate: increase min and max fire delay for better balance var minFire = 36, // was 18 maxFire = 100; // was 50 var fireDelay = Math.max(minFire, maxFire - Math.floor(LK.getScore() / 10) * 3); enemyFireTimer = LK.ticks + fireDelay; } // --- Powerup spawn --- if (powerUpSpawnTimer <= LK.ticks) { if (Math.random() < 0.18) { // ~18% chance spawnPowerUp(); } powerUpSpawnTimer = LK.ticks + 300 + Math.floor(Math.random() * 200); } // --- Powerup timer --- if (powerUpActive && LK.ticks > powerUpTimer) { powerUpActive = false; } // --- Update player bullets --- for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); // Remove if off screen if (b.y < -80) { 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 (e.isAlive && circlesIntersect(b, e)) { e.isAlive = false; b.destroy(); playerBullets.splice(i, 1); // --- Quick fire burst effect for enemy hit --- var fireBurst = LK.getAsset('enemyBullet', { width: 120, height: 120, color: 0xffa200, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, x: e.x, y: e.y }); fireBurst.alpha = 0.85; fireBurst.scaleX = 1.0; fireBurst.scaleY = 1.0; game.addChild(fireBurst); tween(fireBurst, { tint: 0xfff200, scaleX: 2.2, scaleY: 2.2, alpha: 0 }, { duration: 120, easing: tween.cubicOut, onFinish: function onFinish() { fireBurst.destroy(); } }); e.destroy(); enemies.splice(j, 1); // Score (scaled by level) LK.setScore(LK.getScore() + enemyScoreThisLevel); scoreTxt.setText(LK.getScore()); if (LK.getScore() > highScore) { highScore = LK.getScore(); highScoreTxt.setText('High: ' + highScore); storage.highScore = highScore; } // Track kills for level progression enemiesKilledThisLevel++; enemiesLeftTxt.setText('Enemies: ' + (enemiesToSpawn + enemies.length)); // If all enemies for this level are killed, immediately start a new level (endless progression) if (enemiesKilledThisLevel >= enemiesPerLevel) { // Boss fight every 5 levels if ((currentLevel + 1) % 5 === 0) { // Spawn boss bossActive = true; bossShip = new BossShip(); // BossShip class now sets its own x/y to top center and is stationary game.addChild(bossShip); // Add boss health bar if (bossHealthBar) { LK.gui.top.removeChild(bossHealthBar); } bossHealthBar = new Text2('Boss: ' + bossShip.health + '/' + bossShip.maxHealth, { size: 90, fill: 0xFF2222 }); bossHealthBar.anchor.set(0.5, 0); bossHealthBar.x = GAME_WIDTH / 2; bossHealthBar.y = 80; LK.gui.top.addChild(bossHealthBar); // Play boss music LK.playMusic('boss'); // UI levelTxt.setText('Boss Level ' + (currentLevel + 1)); enemiesLeftTxt.setText('Boss Fight!'); LK.effects.flashScreen(0xffcc00, 600); } else { // Next level! Endless progression currentLevel++; enemiesPerLevel = Math.floor(enemiesPerLevel * 1.25) + 1; // escalate number of enemies enemiesToSpawn = enemiesPerLevel; enemiesKilledThisLevel = 0; enemyScoreThisLevel = enemyScoreBase * Math.pow(2, currentLevel - 1); // Update UI levelTxt.setText('Level ' + currentLevel); enemiesLeftTxt.setText('Enemies: ' + (enemiesToSpawn + enemies.length)); // Optionally: flash screen or give feedback LK.effects.flashScreen(0x00ffcc, 400); } } break; } } } // --- Boss fight logic --- if (bossActive && bossShip && bossShip.isAlive) { bossShip.update(); // Boss health bar always at top center and visible only when boss is present if (!bossHealthBar) { bossHealthBar = new Text2('Boss: ' + bossShip.health + '/' + bossShip.maxHealth, { size: 90, fill: 0xFF2222 }); bossHealthBar.anchor.set(0.5, 0); bossHealthBar.x = GAME_WIDTH / 2; bossHealthBar.y = 80; LK.gui.top.addChild(bossHealthBar); } else { bossHealthBar.x = GAME_WIDTH / 2; bossHealthBar.y = 80; bossHealthBar.setText('Boss: ' + bossShip.health + '/' + bossShip.maxHealth); } // Check player bullet collision with boss for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; if (bossShip.isAlive && circlesIntersect(bossShip, b)) { bossShip.health--; bossShip.flash(); b.destroy(); playerBullets.splice(i, 1); if (bossShip.health <= 0) { bossShip.isAlive = false; bossActive = false; // Remove boss health bar if (bossHealthBar) { LK.gui.top.removeChild(bossHealthBar); bossHealthBar = null; } // Resume sapce music after boss fight LK.playMusic('sapce'); // Score for boss LK.setScore(LK.getScore() + 100 * currentLevel); scoreTxt.setText(LK.getScore()); if (LK.getScore() > highScore) { highScore = LK.getScore(); highScoreTxt.setText('High: ' + highScore); storage.highScore = highScore; } // Next level currentLevel++; enemiesPerLevel = Math.floor(enemiesPerLevel * 1.25) + 1; enemiesToSpawn = enemiesPerLevel; enemiesKilledThisLevel = 0; enemyScoreThisLevel = enemyScoreBase * Math.pow(2, currentLevel - 1); levelTxt.setText('Level ' + currentLevel); enemiesLeftTxt.setText('Enemies: ' + enemiesPerLevel); LK.effects.flashScreen(0x00ffcc, 600); // Remove boss bossShip.destroy(); bossShip = null; } break; } } // Boss collision with player if (player.isAlive && bossShip && bossShip.isAlive && circlesIntersect(bossShip, player)) { bossShip.isAlive = false; bossActive = false; if (bossHealthBar) { LK.gui.top.removeChild(bossHealthBar); bossHealthBar = null; } // Resume sapce music after boss fight LK.playMusic('sapce'); player.flash(); playerHealth--; updateHearts(); LK.effects.flashScreen(0xff0000, 400); if (playerHealth <= 0) { player.isAlive = false; tween(player, { alpha: 0.2 }, { duration: 400 }); LK.setTimeout(function () { LK.showGameOver(); }, 900); } bossShip.destroy(); bossShip = null; } } // --- Update enemy bullets --- for (var i = enemyBullets.length - 1; i >= 0; i--) { var eb = enemyBullets[i]; eb.update(); if (eb.y > GAME_HEIGHT + 80) { eb.destroy(); enemyBullets.splice(i, 1); continue; } // Check collision with player if (player.isAlive && circlesIntersect(eb, player)) { eb.destroy(); enemyBullets.splice(i, 1); player.flash(); playerHealth--; updateHearts(); LK.effects.flashScreen(0xff0000, 400); if (playerHealth <= 0) { // Game over player.isAlive = false; tween(player, { alpha: 0.2 }, { duration: 400 }); LK.setTimeout(function () { LK.showGameOver(); }, 900); break; } } } // --- Update enemies --- for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; // Track lastY for crossing detection if (typeof e.lastY === "undefined") { e.lastY = e.y; } e.update(); // If enemy crosses into player's area (y > PLAYER_START_Y - 110, i.e. bottom of player ship) if (e.lastY <= PLAYER_START_Y - 110 && e.y > PLAYER_START_Y - 110) { // Only trigger if enemy is alive if (e.isAlive && player.isAlive) { e.isAlive = false; // --- Fiery, intense explosion effect for enemy ship --- var explosion = LK.getAsset('enemyShip', { width: 260, height: 260, color: 0xfff200, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, x: e.x, y: e.y }); explosion.alpha = 0.95; explosion.scaleX = 1.0; explosion.scaleY = 1.0; game.addChild(explosion); tween(explosion, { tint: 0xff6600, scaleX: 2.7, scaleY: 2.7, alpha: 0.7 }, { duration: 120, easing: tween.cubicOut, onFinish: function onFinish() { tween(explosion, { tint: 0xffffcc, scaleX: 3.5, scaleY: 3.5, alpha: 0 }, { duration: 220, easing: tween.cubicIn, onFinish: function onFinish() { explosion.destroy(); } }); } }); tween(e, {}, { duration: 120, onFinish: function onFinish() { e.destroy(); } }); enemies.splice(i, 1); playerHealth--; updateHearts(); LK.effects.flashScreen(0xff0000, 400); // Level progression if this was the last enemy for the level enemiesLeftTxt.setText('Enemies: ' + (enemiesToSpawn + enemies.length)); if (enemiesKilledThisLevel + 1 >= enemiesPerLevel && enemiesToSpawn === 0 && enemies.length === 0) { // Next level! currentLevel++; enemiesPerLevel = Math.floor(enemiesPerLevel * 1.25) + 1; enemiesToSpawn = enemiesPerLevel; enemiesKilledThisLevel = 0; enemyScoreThisLevel = enemyScoreBase * Math.pow(2, currentLevel - 1); // Update UI levelTxt.setText('Level ' + currentLevel); enemiesLeftTxt.setText('Enemies: ' + (enemiesToSpawn + enemies.length)); LK.effects.flashScreen(0x00ffcc, 400); } else { // Only increment kills if not progressing level enemiesKilledThisLevel++; } if (playerHealth <= 0) { // Game over player.isAlive = false; tween(player, { alpha: 0.2 }, { duration: 400 }); LK.setTimeout(function () { LK.showGameOver(); }, 900); break; } continue; } } if (e.y > GAME_HEIGHT + 100) { e.destroy(); enemies.splice(i, 1); continue; } // Check collision with player if (player.isAlive && e.isAlive && circlesIntersect(e, player)) { e.isAlive = false; e.flash(); player.flash(); // --- Fiery, intense explosion effect for enemy ship --- var explosion = LK.getAsset('enemyShip', { width: 260, height: 260, color: 0xfff200, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5, x: e.x, y: e.y }); explosion.alpha = 0.95; explosion.scaleX = 1.0; explosion.scaleY = 1.0; game.addChild(explosion); tween(explosion, { tint: 0xff6600, scaleX: 2.7, scaleY: 2.7, alpha: 0.7 }, { duration: 120, easing: tween.cubicOut, onFinish: function onFinish() { tween(explosion, { tint: 0xffffcc, scaleX: 3.5, scaleY: 3.5, alpha: 0 }, { duration: 220, easing: tween.cubicIn, onFinish: function onFinish() { explosion.destroy(); } }); } }); tween(e, {}, { duration: 120, onFinish: function onFinish() { e.destroy(); } }); enemies.splice(i, 1); playerHealth--; updateHearts(); LK.effects.flashScreen(0xff0000, 400); if (playerHealth <= 0) { // Game over player.isAlive = false; tween(player, { alpha: 0.2 }, { duration: 400 }); LK.setTimeout(function () { LK.showGameOver(); }, 900); break; } } // Update lastY for next frame e.lastY = e.y; } // --- Update powerups --- for (var i = powerUps.length - 1; i >= 0; i--) { var pu = powerUps[i]; pu.update(); if (pu.y > GAME_HEIGHT + 80) { pu.destroy(); powerUps.splice(i, 1); continue; } // Check collision with player if (player.isAlive && circlesIntersect(pu, player)) { pu.destroy(); powerUps.splice(i, 1); activatePowerUp(); } } }; // Set initial score LK.setScore(0); scoreTxt.setText('0'); if (LK.getScore() > highScore) { highScore = LK.getScore(); } highScoreTxt.setText('High: ' + highScore); // Reset level system currentLevel = 1; enemiesPerLevel = 6; enemiesToSpawn = enemiesPerLevel; enemiesKilledThisLevel = 0; enemyScoreThisLevel = enemyScoreBase; levelTxt.setText('Level 1'); enemiesLeftTxt.setText('Enemies: ' + enemiesPerLevel); playerHealth = 5; updateHearts(); // Reset boss state bossActive = false; if (bossShip) { bossShip.destroy(); bossShip = null; } if (bossHealthBar) { LK.gui.top.removeChild(bossHealthBar); bossHealthBar = null; } // Re-apply selected costume to player if (player && storage.selectedCostume && storage.selectedCostume !== "default") { var costume = null; for (var i = 0; i < costumes.length; i++) { if (costumes[i].id === storage.selectedCostume) costume = costumes[i]; } if (costume) { if (player.children.length > 0) player.removeChild(player.children[0]); var costumeAsset = player.attachAsset(costume.asset, { width: 220, height: 220, anchorX: 0.5, anchorY: 0.5 }); } }
===================================================================
--- original.js
+++ change.js
@@ -252,9 +252,9 @@
/****
* Game Code
****/
-// --- Start Screen Overlay ---
+// --- Start Screen Overlay ---
var startScreenOverlay = new Container();
// Large main title: "Space Wars"
var mainTitle = new Text2('Space Wars', {
size: 220,
@@ -272,8 +272,241 @@
});
subTitle.anchor.set(0.5, 0);
subTitle.x = GAME_WIDTH / 2;
subTitle.y = mainTitle.y + mainTitle.height + 20;
+// --- SHOP MENU UI ---
+// Shop state
+var shopOpen = false;
+var shopOverlay = new Container();
+shopOverlay.visible = false;
+var shopTitle = new Text2('Costume Shop', {
+ size: 120,
+ fill: 0xFFD700,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopTitle.anchor.set(0.5, 0);
+shopTitle.x = GAME_WIDTH / 2;
+shopTitle.y = 120;
+shopOverlay.addChild(shopTitle);
+// Define costumes (id, name, price, asset)
+var costumes = [{
+ id: "default",
+ name: "Classic",
+ price: 0,
+ asset: "playerShip"
+}, {
+ id: "red",
+ name: "Red Comet",
+ price: 200,
+ asset: "enemyShip"
+}, {
+ id: "gold",
+ name: "Gold Star",
+ price: 500,
+ asset: "playerBullet"
+}];
+// Persistent unlocks
+if (!storage.unlockedCostumes) storage.unlockedCostumes = {
+ "default": true
+};
+if (!storage.selectedCostume) storage.selectedCostume = "default";
+// Shop navigation state
+var shopIndex = 0;
+function updateShopUI() {
+ // Remove old preview if any
+ if (shopOverlay.costumePreview) {
+ shopOverlay.removeChild(shopOverlay.costumePreview);
+ shopOverlay.costumePreview = null;
+ }
+ var c = costumes[shopIndex];
+ var preview = LK.getAsset(c.asset, {
+ width: 320,
+ height: 320,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2,
+ y: 520
+ });
+ shopOverlay.addChild(preview);
+ shopOverlay.costumePreview = preview;
+ // Update name/price
+ shopNameTxt.setText(c.name);
+ if (c.price === 0) {
+ shopPriceTxt.setText("Unlocked");
+ } else if (storage.unlockedCostumes[c.id]) {
+ shopPriceTxt.setText("Unlocked");
+ } else {
+ shopPriceTxt.setText("Price: " + c.price + " pts");
+ }
+ // Show select/unlock button
+ if (storage.unlockedCostumes[c.id]) {
+ shopActionBtnText.setText(storage.selectedCostume === c.id ? "Selected" : "Select");
+ } else {
+ shopActionBtnText.setText("Unlock");
+ }
+ // Hide select if already selected
+ shopActionBtn.alpha = storage.selectedCostume === c.id && storage.unlockedCostumes[c.id] ? 0.5 : 1;
+}
+// Costume name
+var shopNameTxt = new Text2('', {
+ size: 80,
+ fill: 0xffffff,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopNameTxt.anchor.set(0.5, 0);
+shopNameTxt.x = GAME_WIDTH / 2;
+shopNameTxt.y = 900;
+shopOverlay.addChild(shopNameTxt);
+// Costume price
+var shopPriceTxt = new Text2('', {
+ size: 60,
+ fill: 0xFFD700,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopPriceTxt.anchor.set(0.5, 0);
+shopPriceTxt.x = GAME_WIDTH / 2;
+shopPriceTxt.y = 1020;
+shopOverlay.addChild(shopPriceTxt);
+// Action button (Unlock/Select)
+var shopActionBtn = LK.getAsset('playerBullet', {
+ width: 420,
+ height: 110,
+ color: 0x00ccff,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2,
+ y: 1200
+});
+var shopActionBtnText = new Text2('', {
+ size: 70,
+ fill: 0xffffff,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopActionBtnText.anchor.set(0.5, 0.5);
+shopActionBtnText.x = shopActionBtn.x;
+shopActionBtnText.y = shopActionBtn.y;
+shopOverlay.addChild(shopActionBtn);
+shopOverlay.addChild(shopActionBtnText);
+// Left/right nav buttons
+var shopLeftBtn = LK.getAsset('enemyBullet', {
+ width: 100,
+ height: 100,
+ color: 0xFFD700,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2 - 300,
+ y: 520
+});
+var shopRightBtn = LK.getAsset('enemyBullet', {
+ width: 100,
+ height: 100,
+ color: 0xFFD700,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2 + 300,
+ y: 520
+});
+shopOverlay.addChild(shopLeftBtn);
+shopOverlay.addChild(shopRightBtn);
+// Close button
+var shopCloseBtn = LK.getAsset('playerBullet', {
+ width: 180,
+ height: 80,
+ color: 0x888888,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2,
+ y: 1450
+});
+var shopCloseBtnText = new Text2('Close', {
+ size: 50,
+ fill: 0xffffff,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopCloseBtnText.anchor.set(0.5, 0.5);
+shopCloseBtnText.x = shopCloseBtn.x;
+shopCloseBtnText.y = shopCloseBtn.y;
+shopOverlay.addChild(shopCloseBtn);
+shopOverlay.addChild(shopCloseBtnText);
+// Shop button on start screen
+var shopBtn = LK.getAsset('playerBullet', {
+ width: 320,
+ height: 100,
+ color: 0xFFD700,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: GAME_WIDTH / 2,
+ y: GAME_HEIGHT / 2 + 320
+});
+var shopBtnText = new Text2('SHOP', {
+ size: 70,
+ fill: 0x000000,
+ font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
+});
+shopBtnText.anchor.set(0.5, 0.5);
+shopBtnText.x = shopBtn.x;
+shopBtnText.y = shopBtn.y;
+// Shop button handler
+shopBtn.down = function (x, y, obj) {
+ if (shopOpen) return;
+ shopOpen = true;
+ shopOverlay.visible = true;
+ LK.gui.center.addChild(shopOverlay);
+ updateShopUI();
+ // Hide start overlay
+ if (startScreenOverlay.parent) startScreenOverlay.visible = false;
+};
+// Shop close handler
+shopCloseBtn.down = function (x, y, obj) {
+ shopOpen = false;
+ shopOverlay.visible = false;
+ if (shopOverlay.parent) LK.gui.center.removeChild(shopOverlay);
+ if (startScreenOverlay && !gameStarted) startScreenOverlay.visible = true;
+};
+// Shop left/right nav
+shopLeftBtn.down = function (x, y, obj) {
+ shopIndex = (shopIndex + costumes.length - 1) % costumes.length;
+ updateShopUI();
+};
+shopRightBtn.down = function (x, y, obj) {
+ shopIndex = (shopIndex + 1) % costumes.length;
+ updateShopUI();
+};
+// Shop action (unlock/select)
+shopActionBtn.down = function (x, y, obj) {
+ var c = costumes[shopIndex];
+ if (storage.unlockedCostumes[c.id]) {
+ // Select
+ storage.selectedCostume = c.id;
+ updateShopUI();
+ } else {
+ // Unlock if enough score
+ var score = LK.getScore();
+ if (score >= c.price) {
+ LK.setScore(score - c.price);
+ scoreTxt.setText(LK.getScore());
+ storage.unlockedCostumes[c.id] = true;
+ storage.selectedCostume = c.id;
+ updateShopUI();
+ } else {
+ // Not enough points, flash price red
+ shopPriceTxt.setText("Need " + (c.price - score) + " more!");
+ tween(shopPriceTxt, {
+ fill: 0xff0000
+ }, {
+ duration: 200,
+ onFinish: function onFinish() {
+ shopPriceTxt.setText("Price: " + c.price + " pts");
+ }
+ });
+ }
+ }
+};
+// Add to overlay
+startScreenOverlay.addChild(mainTitle);
+startScreenOverlay.addChild(subTitle);
+startScreenOverlay.addChild(shopBtn);
+startScreenOverlay.addChild(shopBtnText);
// Play button (large, centered)
var playBtn = LK.getAsset('playerBullet', {
width: 520,
height: 140,
@@ -290,8 +523,10 @@
});
playBtnText.anchor.set(0.5, 0.5);
playBtnText.x = playBtn.x;
playBtnText.y = playBtn.y;
+startScreenOverlay.addChild(playBtn);
+startScreenOverlay.addChild(playBtnText);
// Animate main title in
mainTitle.alpha = 0;
tween(mainTitle, {
alpha: 1
@@ -582,8 +817,25 @@
enemiesLeftTxt.y = 60;
LK.gui.top.addChild(enemiesLeftTxt);
// Initialize player
player = new PlayerShip();
+// Apply selected costume if not default
+if (storage.selectedCostume && storage.selectedCostume !== "default") {
+ var costume = null;
+ for (var i = 0; i < costumes.length; i++) {
+ if (costumes[i].id === storage.selectedCostume) costume = costumes[i];
+ }
+ if (costume) {
+ // Remove old asset and attach new
+ if (player.children.length > 0) player.removeChild(player.children[0]);
+ var costumeAsset = player.attachAsset(costume.asset, {
+ width: 220,
+ height: 220,
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
+}
player.x = PLAYER_START_X;
player.y = PLAYER_START_Y;
game.addChild(player);
// Touch/move controls
@@ -1162,5 +1414,21 @@
}
if (bossHealthBar) {
LK.gui.top.removeChild(bossHealthBar);
bossHealthBar = null;
+}
+// Re-apply selected costume to player
+if (player && storage.selectedCostume && storage.selectedCostume !== "default") {
+ var costume = null;
+ for (var i = 0; i < costumes.length; i++) {
+ if (costumes[i].id === storage.selectedCostume) costume = costumes[i];
+ }
+ if (costume) {
+ if (player.children.length > 0) player.removeChild(player.children[0]);
+ var costumeAsset = player.attachAsset(costume.asset, {
+ width: 220,
+ height: 220,
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ }
}
\ No newline at end of file