User prompt
Make it so upgrade button works ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: ammoBar' in or related to this line: 'ammoBar.scale.x = player.ammo / player.maxAmmo * 3;' Line Number: 580
User prompt
Make a ammo bar at the top left corner
User prompt
Make a meter that says how much ammo you have
User prompt
Make the enemy bigger
User prompt
Make it so you can click the upgrade button
User prompt
Please fix the bug: 'storage.get is not a function. (In 'storage.get('upgrade_' + upgradeTypes[i])', 'storage.get' is undefined)' in or related to this line: 'var savedLevel = storage.get('upgrade_' + upgradeTypes[i]);' Line Number: 430 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add upgrades
Code edit (1 edits merged)
Please save this source code
User prompt
Shotout Frenzy
User prompt
How about a shotout frenzy
Initial prompt
Hey
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AmmoUI = Container.expand(function () { var self = Container.call(this); var ammoGraphics = self.attachAsset('ammo', { anchorX: 0.5, anchorY: 0.5 }); var ammoText = new Text2('0', { size: 40, fill: 0xFFFFFF }); ammoText.anchor.set(0.5, 0.5); ammoText.y = 60; self.addChild(ammoText); self.update = function (currentAmmo, maxAmmo) { ammoText.setText(currentAmmo + '/' + maxAmmo); }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 1; // Default damage, will be set by player self.update = function () { self.y -= self.speed; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 3; self.scoreValue = 10; self.movePattern = 'direct'; // Can be 'direct', 'zigzag', 'circular' self.moveCounter = 0; self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { return true; // Enemy is destroyed } // Flash white when hit LK.effects.flashObject(self, 0xffffff, 200); return false; }; self.setType = function (type) { if (type === 'basic') { enemyGraphics.tint = 0xe74c3c; // Red self.health = 1; self.speed = 3; self.scoreValue = 10; self.movePattern = 'direct'; } else if (type === 'fast') { enemyGraphics.tint = 0xe67e22; // Orange self.health = 1; self.speed = 6; self.scoreValue = 15; self.movePattern = 'zigzag'; } else if (type === 'tank') { enemyGraphics.tint = 0x7f8c8d; // Gray self.health = 3; self.speed = 2; self.scoreValue = 25; self.movePattern = 'direct'; // Make it bigger enemyGraphics.scale.set(2.0, 2.0); } }; self.update = function () { self.moveCounter++; if (self.movePattern === 'direct') { self.y += self.speed; } else if (self.movePattern === 'zigzag') { self.y += self.speed; self.x += Math.sin(self.moveCounter * 0.1) * 3; } else if (self.movePattern === 'circular') { self.y += self.speed * 0.8; self.x += Math.sin(self.moveCounter * 0.05) * 4; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.ammo = 30; self.maxAmmo = 30; self.fireRate = 10; self.damage = 1; self.lastFired = 0; self.inFrenzyMode = false; self.frenzyTimeLeft = 0; self.frenzyDuration = 300; // Initial frenzy duration (5 seconds at 60fps) self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { self.health = 0; } // Flash red when taking damage LK.effects.flashObject(self, 0xff0000, 300); }; self.shoot = function () { if (LK.ticks - self.lastFired < 60 / self.fireRate) { return null; } if (self.ammo <= 0 && !self.inFrenzyMode) { return null; } if (!self.inFrenzyMode) { self.ammo--; } self.lastFired = LK.ticks; var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y - 40; bullet.damage = self.damage; LK.getSound('shoot').play(); return bullet; }; self.activateFrenzy = function () { self.inFrenzyMode = true; self.frenzyTimeLeft = self.frenzyDuration; playerGraphics.tint = 0xf39c12; // Change color to orange in frenzy mode }; self.reloadAmmo = function (amount) { self.ammo = Math.min(self.maxAmmo, self.ammo + amount); }; self.update = function () { if (self.inFrenzyMode) { self.frenzyTimeLeft--; if (self.frenzyTimeLeft <= 0) { self.inFrenzyMode = false; playerGraphics.tint = 0xffffff; // Reset color } } }; 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 = 'ammo'; // Can be 'ammo', 'frenzy', 'health' self.speed = 2; self.setType = function (newType) { self.type = newType; if (newType === 'ammo') { powerupGraphics.tint = 0x2ecc71; // Green } else if (newType === 'frenzy') { powerupGraphics.tint = 0xf39c12; // Orange } else if (newType === 'health') { powerupGraphics.tint = 0x3498db; // Blue } }; self.update = function () { self.y += self.speed; // Slight wobble effect self.x += Math.sin(LK.ticks * 0.05) * 0.5; }; return self; }); var Upgrade = Container.expand(function () { var self = Container.call(this); var upgradeGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); upgradeGraphics.tint = 0xFFD700; // Gold color for upgrades // Text to display upgrade info var nameText = new Text2('', { size: 30, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0); nameText.y = -50; self.addChild(nameText); var levelText = new Text2('', { size: 24, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.y = -20; self.addChild(levelText); var costText = new Text2('', { size: 24, fill: 0xFFD700 }); costText.anchor.set(0.5, 0); costText.y = 10; self.addChild(costText); self.type = ''; self.level = 1; self.maxLevel = 5; self.cost = 100; self.name = ''; self.description = ''; self.setType = function (type) { self.type = type; if (type === 'fireRate') { self.name = 'Fire Rate'; self.description = 'Increase firing speed'; upgradeGraphics.tint = 0xFF5500; // Orange-red } else if (type === 'damage') { self.name = 'Damage'; self.description = 'Increase bullet damage'; upgradeGraphics.tint = 0xFF0000; // Red } else if (type === 'maxAmmo') { self.name = 'Max Ammo'; self.description = 'Increase ammo capacity'; upgradeGraphics.tint = 0x00FF00; // Green } else if (type === 'frenzyTime') { self.name = 'Frenzy Time'; self.description = 'Extend frenzy duration'; upgradeGraphics.tint = 0xFFFF00; // Yellow } self.updateText(); }; self.updateText = function () { nameText.setText(self.name); levelText.setText('Level: ' + self.level + '/' + self.maxLevel); costText.setText(self.cost + ' pts'); }; self.purchase = function () { if (self.level >= self.maxLevel) { return false; } self.level++; self.cost = Math.floor(self.cost * 1.5); self.updateText(); return true; }; self.down = function (x, y, obj) { // Handle clicking on this upgrade LK.effects.flashObject(self, 0xFFFFFF, 200); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game state variables var player; var bullets = []; var enemies = []; var powerups = []; var score = 0; var wave = 1; var enemiesKilled = 0; var enemiesThisWave = 10; var enemySpawnRate = 120; // Frames between enemy spawns var lastEnemySpawn = 0; var isGameOver = false; var isPaused = false; var showingUpgradeMenu = false; var upgrades = []; // UI elements var scoreText; var waveText; var healthBar; var ammoUI; var frenzyMeter; var upgradeButton; var upgradeMenu; // Game boundaries var gameBounds = { left: 100, right: 2048 - 100, top: 100, bottom: 2732 - 200 }; // Initialize player function initPlayer() { player = new Player(); player.x = 2048 / 2; player.y = 2732 - 300; game.addChild(player); } // Initialize UI function initUI() { // Score display scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); scoreText.x = 120; scoreText.y = 50; LK.gui.addChild(scoreText); // Wave display waveText = new Text2('Wave 1', { size: 60, fill: 0xFFFFFF }); waveText.anchor.set(1, 0); waveText.x = 2048 - 120; waveText.y = 50; LK.gui.addChild(waveText); // Health bar healthBar = game.addChild(LK.getAsset('player', { anchorX: 0, anchorY: 0.5, scaleX: 3, scaleY: 0.3, x: 120, y: 130, tint: 0x3498db })); // Ammo UI ammoUI = new AmmoUI(); ammoUI.x = 200; ammoUI.y = 200; game.addChild(ammoUI); ammoUI.update(player.ammo, player.maxAmmo); // Initialize with current ammo values // Ammo Bar var ammoBarBackground = game.addChild(LK.getAsset('bullet', { anchorX: 0, anchorY: 0.5, scaleX: 3, scaleY: 0.3, x: 120, y: 200, tint: 0x333333 })); ammoBar = game.addChild(LK.getAsset('bullet', { anchorX: 0, anchorY: 0.5, scaleX: 3, scaleY: 0.3, x: 120, y: 200, tint: 0x2ecc71 })); // Frenzy indicator frenzyMeter = game.addChild(LK.getAsset('powerup', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 150, y: 150, alpha: 0.3, tint: 0xf39c12 })); // Upgrade button upgradeButton = new Text2('UPGRADES', { size: 50, fill: 0xFFD700 }); upgradeButton.anchor.set(0.5, 0.5); upgradeButton.x = 2048 - 200; upgradeButton.y = 250; game.addChild(upgradeButton); // Upgrade menu container (initially hidden) upgradeMenu = new Container(); upgradeMenu.visible = false; game.addChild(upgradeMenu); // Semi-transparent background var menuBg = LK.getAsset('bullet', { anchorX: 0, anchorY: 0, scaleX: 20, scaleY: 25, tint: 0x000000, alpha: 0.7 }); upgradeMenu.addChild(menuBg); // Menu title var menuTitle = new Text2('UPGRADES', { size: 80, fill: 0xFFD700 }); menuTitle.anchor.set(0.5, 0); menuTitle.x = 2048 / 2; menuTitle.y = 100; upgradeMenu.addChild(menuTitle); // Close button var closeButton = new Text2('CLOSE', { size: 60, fill: 0xFFFFFF }); closeButton.anchor.set(0.5, 0.5); closeButton.x = 2048 / 2; closeButton.y = 2732 - 200; closeButton.down = function () { toggleUpgradeMenu(); }; upgradeMenu.addChild(closeButton); // Create upgrade options initUpgrades(); } // Initialize upgrades function initUpgrades() { // Clear previous upgrades if any for (var i = 0; i < upgrades.length; i++) { upgrades[i].destroy(); } upgrades = []; // Create new upgrades var upgradeTypes = ['fireRate', 'damage', 'maxAmmo', 'frenzyTime']; var baseX = 2048 / 2; var baseY = 600; var spacing = 300; for (var i = 0; i < upgradeTypes.length; i++) { var upgrade = new Upgrade(); upgrade.setType(upgradeTypes[i]); upgrade.x = baseX; upgrade.y = baseY + i * spacing; // Load saved level if exists var upgradeKey = 'upgrade_' + upgradeTypes[i]; var savedLevel = storage[upgradeKey]; if (savedLevel !== undefined) { upgrade.level = savedLevel; upgrade.cost = Math.floor(100 * Math.pow(1.5, upgrade.level - 1)); upgrade.updateText(); } upgrade.down = function () { if (score >= this.cost && this.level < this.maxLevel) { score -= this.cost; scoreText.setText('Score: ' + score); this.purchase(); // Apply upgrade effect applyUpgrade(this.type, this.level); // Save upgrade level var upgradeKey = 'upgrade_' + this.type; storage[upgradeKey] = this.level; // Flash to indicate purchase LK.effects.flashObject(this, 0x00FF00, 300); } else { // Flash red if can't afford LK.effects.flashObject(this, 0xFF0000, 300); } }; upgradeMenu.addChild(upgrade); upgrades.push(upgrade); } // Apply saved upgrades to player for (var i = 0; i < upgrades.length; i++) { applyUpgrade(upgrades[i].type, upgrades[i].level); } } // Apply upgrade effects to player function applyUpgrade(type, level) { if (!player) { return; } var baseValue, increment; if (type === 'fireRate') { baseValue = 10; increment = 2; player.fireRate = baseValue + (level - 1) * increment; } else if (type === 'damage') { baseValue = 1; increment = 0.5; player.damage = baseValue + (level - 1) * increment; } else if (type === 'maxAmmo') { baseValue = 30; increment = 10; var newMaxAmmo = baseValue + (level - 1) * increment; player.ammo += newMaxAmmo - player.maxAmmo; player.maxAmmo = newMaxAmmo; } else if (type === 'frenzyTime') { baseValue = 300; increment = 60; player.frenzyDuration = baseValue + (level - 1) * increment; } } // Toggle upgrade menu visibility function toggleUpgradeMenu() { showingUpgradeMenu = !showingUpgradeMenu; upgradeMenu.visible = showingUpgradeMenu; } // Spawn enemy function spawnEnemy() { var enemy = new Enemy(); // Randomize initial position (along top of screen) enemy.x = gameBounds.left + Math.random() * (gameBounds.right - gameBounds.left); enemy.y = -50; // Determine enemy type based on wave and randomness var rand = Math.random(); if (wave < 3) { enemy.setType('basic'); } else if (wave < 5) { if (rand < 0.7) { enemy.setType('basic'); } else if (rand < 0.9) { enemy.setType('fast'); } else { enemy.setType('tank'); } } else { if (rand < 0.5) { enemy.setType('basic'); } else if (rand < 0.8) { enemy.setType('fast'); } else { enemy.setType('tank'); } } game.addChild(enemy); enemies.push(enemy); } // Spawn powerup function spawnPowerup(x, y) { // 20% chance to spawn a powerup when enemy dies if (Math.random() > 0.2) { return; } var powerup = new PowerUp(); powerup.x = x; powerup.y = y; // Determine powerup type var rand = Math.random(); if (rand < 0.6) { powerup.setType('ammo'); } else if (rand < 0.9) { powerup.setType('health'); } else { powerup.setType('frenzy'); } game.addChild(powerup); powerups.push(powerup); } // Handle player shooting function handlePlayerShoot() { var bullet = player.shoot(); if (bullet) { game.addChild(bullet); bullets.push(bullet); } } // Update game state function updateGameState() { // Update player player.update(); ammoUI.update(player.ammo, player.maxAmmo); // Update health bar healthBar.scale.x = player.health / 100 * 3; // Update ammo bar ammoBar.scale.x = player.ammo / player.maxAmmo * 3; // Update frenzy meter if (player.inFrenzyMode) { frenzyMeter.alpha = 0.5 + Math.sin(LK.ticks * 0.2) * 0.5; } else { frenzyMeter.alpha = 0.3; } // Spawn enemies if (LK.ticks - lastEnemySpawn >= enemySpawnRate && enemies.length < enemiesThisWave) { spawnEnemy(); lastEnemySpawn = LK.ticks; } // Next wave logic if (enemiesKilled >= enemiesThisWave) { wave++; enemiesKilled = 0; enemiesThisWave = Math.min(50, 10 + wave * 5); enemySpawnRate = Math.max(30, 120 - wave * 10); waveText.setText('Wave ' + wave); // Flash screen green for new wave LK.effects.flashScreen(0x2ecc71, 500); } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; bullet.update(); // Remove bullets that go off screen if (bullet.y < -50) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check for bullet collisions with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { // Enemy takes damage var destroyed = enemy.takeDamage(bullet.damage); if (destroyed) { // Add score score += enemy.scoreValue; scoreText.setText('Score: ' + score); // Increment kill counter enemiesKilled++; // Spawn powerup spawnPowerup(enemy.x, enemy.y); // Remove enemy enemy.destroy(); enemies.splice(j, 1); } // Remove bullet bullet.destroy(); bullets.splice(i, 1); // Play hit sound LK.getSound('enemyHit').play(); // Break since bullet is gone break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Remove enemies that go off bottom of screen if (enemy.y > gameBounds.bottom + 50) { // Player takes damage when enemy passes player.takeDamage(10); // Remove enemy enemy.destroy(); enemies.splice(i, 1); // Play hit sound LK.getSound('playerHit').play(); continue; } // Check collision with player if (enemy.intersects(player)) { // Player takes damage player.takeDamage(20); // Remove enemy enemy.destroy(); enemies.splice(i, 1); // Play hit sound LK.getSound('playerHit').play(); } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; powerup.update(); // Remove powerups that go off bottom of screen if (powerup.y > gameBounds.bottom + 50) { powerup.destroy(); powerups.splice(i, 1); continue; } // Check collision with player if (powerup.intersects(player)) { if (powerup.type === 'ammo') { player.reloadAmmo(15); } else if (powerup.type === 'health') { player.health = Math.min(100, player.health + 20); } else if (powerup.type === 'frenzy') { player.activateFrenzy(); } // Play powerup sound LK.getSound('powerupCollect').play(); // Remove powerup powerup.destroy(); powerups.splice(i, 1); } } // Check for game over if (player.health <= 0 && !isGameOver) { isGameOver = true; LK.showGameOver(); } // Auto-shoot in frenzy mode if (player.inFrenzyMode && LK.ticks % 5 === 0) { handlePlayerShoot(); } } // Initialize game function initGame() { // Reset game state bullets = []; enemies = []; powerups = []; showingUpgradeMenu = false; score = 0; wave = 1; enemiesKilled = 0; enemiesThisWave = 10; enemySpawnRate = 120; lastEnemySpawn = 0; isGameOver = false; // Set score LK.setScore(0); // Init player and UI initPlayer(); initUI(); // Play music LK.playMusic('gameMusic', { fade: { start: 0, end: 1, duration: 1000 } }); } // Initialize the game initGame(); // Touch/mouse handlers for player movement var isDragging = false; game.down = function (x, y, obj) { // Check if upgrade button was clicked if (obj.target === upgradeButton) { toggleUpgradeMenu(); return; } // If upgrade menu is showing, don't process player movement/shooting if (showingUpgradeMenu) { return; } isDragging = true; player.x = x; // Constrain player to game bounds player.x = Math.max(gameBounds.left, Math.min(gameBounds.right, player.x)); // Shoot on tap handlePlayerShoot(); }; game.up = function (x, y, obj) { isDragging = false; }; game.move = function (x, y, obj) { if (isDragging && !showingUpgradeMenu) { player.x = x; // Constrain player to game bounds player.x = Math.max(gameBounds.left, Math.min(gameBounds.right, player.x)); } }; // Main game loop game.update = function () { if (!isGameOver && !showingUpgradeMenu) { updateGameState(); } // Update score LK.setScore(score); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AmmoUI = Container.expand(function () {
var self = Container.call(this);
var ammoGraphics = self.attachAsset('ammo', {
anchorX: 0.5,
anchorY: 0.5
});
var ammoText = new Text2('0', {
size: 40,
fill: 0xFFFFFF
});
ammoText.anchor.set(0.5, 0.5);
ammoText.y = 60;
self.addChild(ammoText);
self.update = function (currentAmmo, maxAmmo) {
ammoText.setText(currentAmmo + '/' + maxAmmo);
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1; // Default damage, will be set by player
self.update = function () {
self.y -= self.speed;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 3;
self.scoreValue = 10;
self.movePattern = 'direct'; // Can be 'direct', 'zigzag', 'circular'
self.moveCounter = 0;
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
return true; // Enemy is destroyed
}
// Flash white when hit
LK.effects.flashObject(self, 0xffffff, 200);
return false;
};
self.setType = function (type) {
if (type === 'basic') {
enemyGraphics.tint = 0xe74c3c; // Red
self.health = 1;
self.speed = 3;
self.scoreValue = 10;
self.movePattern = 'direct';
} else if (type === 'fast') {
enemyGraphics.tint = 0xe67e22; // Orange
self.health = 1;
self.speed = 6;
self.scoreValue = 15;
self.movePattern = 'zigzag';
} else if (type === 'tank') {
enemyGraphics.tint = 0x7f8c8d; // Gray
self.health = 3;
self.speed = 2;
self.scoreValue = 25;
self.movePattern = 'direct';
// Make it bigger
enemyGraphics.scale.set(2.0, 2.0);
}
};
self.update = function () {
self.moveCounter++;
if (self.movePattern === 'direct') {
self.y += self.speed;
} else if (self.movePattern === 'zigzag') {
self.y += self.speed;
self.x += Math.sin(self.moveCounter * 0.1) * 3;
} else if (self.movePattern === 'circular') {
self.y += self.speed * 0.8;
self.x += Math.sin(self.moveCounter * 0.05) * 4;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 100;
self.ammo = 30;
self.maxAmmo = 30;
self.fireRate = 10;
self.damage = 1;
self.lastFired = 0;
self.inFrenzyMode = false;
self.frenzyTimeLeft = 0;
self.frenzyDuration = 300; // Initial frenzy duration (5 seconds at 60fps)
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
}
// Flash red when taking damage
LK.effects.flashObject(self, 0xff0000, 300);
};
self.shoot = function () {
if (LK.ticks - self.lastFired < 60 / self.fireRate) {
return null;
}
if (self.ammo <= 0 && !self.inFrenzyMode) {
return null;
}
if (!self.inFrenzyMode) {
self.ammo--;
}
self.lastFired = LK.ticks;
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y - 40;
bullet.damage = self.damage;
LK.getSound('shoot').play();
return bullet;
};
self.activateFrenzy = function () {
self.inFrenzyMode = true;
self.frenzyTimeLeft = self.frenzyDuration;
playerGraphics.tint = 0xf39c12; // Change color to orange in frenzy mode
};
self.reloadAmmo = function (amount) {
self.ammo = Math.min(self.maxAmmo, self.ammo + amount);
};
self.update = function () {
if (self.inFrenzyMode) {
self.frenzyTimeLeft--;
if (self.frenzyTimeLeft <= 0) {
self.inFrenzyMode = false;
playerGraphics.tint = 0xffffff; // Reset color
}
}
};
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 = 'ammo'; // Can be 'ammo', 'frenzy', 'health'
self.speed = 2;
self.setType = function (newType) {
self.type = newType;
if (newType === 'ammo') {
powerupGraphics.tint = 0x2ecc71; // Green
} else if (newType === 'frenzy') {
powerupGraphics.tint = 0xf39c12; // Orange
} else if (newType === 'health') {
powerupGraphics.tint = 0x3498db; // Blue
}
};
self.update = function () {
self.y += self.speed;
// Slight wobble effect
self.x += Math.sin(LK.ticks * 0.05) * 0.5;
};
return self;
});
var Upgrade = Container.expand(function () {
var self = Container.call(this);
var upgradeGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
upgradeGraphics.tint = 0xFFD700; // Gold color for upgrades
// Text to display upgrade info
var nameText = new Text2('', {
size: 30,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = -50;
self.addChild(nameText);
var levelText = new Text2('', {
size: 24,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.y = -20;
self.addChild(levelText);
var costText = new Text2('', {
size: 24,
fill: 0xFFD700
});
costText.anchor.set(0.5, 0);
costText.y = 10;
self.addChild(costText);
self.type = '';
self.level = 1;
self.maxLevel = 5;
self.cost = 100;
self.name = '';
self.description = '';
self.setType = function (type) {
self.type = type;
if (type === 'fireRate') {
self.name = 'Fire Rate';
self.description = 'Increase firing speed';
upgradeGraphics.tint = 0xFF5500; // Orange-red
} else if (type === 'damage') {
self.name = 'Damage';
self.description = 'Increase bullet damage';
upgradeGraphics.tint = 0xFF0000; // Red
} else if (type === 'maxAmmo') {
self.name = 'Max Ammo';
self.description = 'Increase ammo capacity';
upgradeGraphics.tint = 0x00FF00; // Green
} else if (type === 'frenzyTime') {
self.name = 'Frenzy Time';
self.description = 'Extend frenzy duration';
upgradeGraphics.tint = 0xFFFF00; // Yellow
}
self.updateText();
};
self.updateText = function () {
nameText.setText(self.name);
levelText.setText('Level: ' + self.level + '/' + self.maxLevel);
costText.setText(self.cost + ' pts');
};
self.purchase = function () {
if (self.level >= self.maxLevel) {
return false;
}
self.level++;
self.cost = Math.floor(self.cost * 1.5);
self.updateText();
return true;
};
self.down = function (x, y, obj) {
// Handle clicking on this upgrade
LK.effects.flashObject(self, 0xFFFFFF, 200);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state variables
var player;
var bullets = [];
var enemies = [];
var powerups = [];
var score = 0;
var wave = 1;
var enemiesKilled = 0;
var enemiesThisWave = 10;
var enemySpawnRate = 120; // Frames between enemy spawns
var lastEnemySpawn = 0;
var isGameOver = false;
var isPaused = false;
var showingUpgradeMenu = false;
var upgrades = [];
// UI elements
var scoreText;
var waveText;
var healthBar;
var ammoUI;
var frenzyMeter;
var upgradeButton;
var upgradeMenu;
// Game boundaries
var gameBounds = {
left: 100,
right: 2048 - 100,
top: 100,
bottom: 2732 - 200
};
// Initialize player
function initPlayer() {
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 300;
game.addChild(player);
}
// Initialize UI
function initUI() {
// Score display
scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 120;
scoreText.y = 50;
LK.gui.addChild(scoreText);
// Wave display
waveText = new Text2('Wave 1', {
size: 60,
fill: 0xFFFFFF
});
waveText.anchor.set(1, 0);
waveText.x = 2048 - 120;
waveText.y = 50;
LK.gui.addChild(waveText);
// Health bar
healthBar = game.addChild(LK.getAsset('player', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.3,
x: 120,
y: 130,
tint: 0x3498db
}));
// Ammo UI
ammoUI = new AmmoUI();
ammoUI.x = 200;
ammoUI.y = 200;
game.addChild(ammoUI);
ammoUI.update(player.ammo, player.maxAmmo); // Initialize with current ammo values
// Ammo Bar
var ammoBarBackground = game.addChild(LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.3,
x: 120,
y: 200,
tint: 0x333333
}));
ammoBar = game.addChild(LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0.5,
scaleX: 3,
scaleY: 0.3,
x: 120,
y: 200,
tint: 0x2ecc71
}));
// Frenzy indicator
frenzyMeter = game.addChild(LK.getAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 150,
y: 150,
alpha: 0.3,
tint: 0xf39c12
}));
// Upgrade button
upgradeButton = new Text2('UPGRADES', {
size: 50,
fill: 0xFFD700
});
upgradeButton.anchor.set(0.5, 0.5);
upgradeButton.x = 2048 - 200;
upgradeButton.y = 250;
game.addChild(upgradeButton);
// Upgrade menu container (initially hidden)
upgradeMenu = new Container();
upgradeMenu.visible = false;
game.addChild(upgradeMenu);
// Semi-transparent background
var menuBg = LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
scaleX: 20,
scaleY: 25,
tint: 0x000000,
alpha: 0.7
});
upgradeMenu.addChild(menuBg);
// Menu title
var menuTitle = new Text2('UPGRADES', {
size: 80,
fill: 0xFFD700
});
menuTitle.anchor.set(0.5, 0);
menuTitle.x = 2048 / 2;
menuTitle.y = 100;
upgradeMenu.addChild(menuTitle);
// Close button
var closeButton = new Text2('CLOSE', {
size: 60,
fill: 0xFFFFFF
});
closeButton.anchor.set(0.5, 0.5);
closeButton.x = 2048 / 2;
closeButton.y = 2732 - 200;
closeButton.down = function () {
toggleUpgradeMenu();
};
upgradeMenu.addChild(closeButton);
// Create upgrade options
initUpgrades();
}
// Initialize upgrades
function initUpgrades() {
// Clear previous upgrades if any
for (var i = 0; i < upgrades.length; i++) {
upgrades[i].destroy();
}
upgrades = [];
// Create new upgrades
var upgradeTypes = ['fireRate', 'damage', 'maxAmmo', 'frenzyTime'];
var baseX = 2048 / 2;
var baseY = 600;
var spacing = 300;
for (var i = 0; i < upgradeTypes.length; i++) {
var upgrade = new Upgrade();
upgrade.setType(upgradeTypes[i]);
upgrade.x = baseX;
upgrade.y = baseY + i * spacing;
// Load saved level if exists
var upgradeKey = 'upgrade_' + upgradeTypes[i];
var savedLevel = storage[upgradeKey];
if (savedLevel !== undefined) {
upgrade.level = savedLevel;
upgrade.cost = Math.floor(100 * Math.pow(1.5, upgrade.level - 1));
upgrade.updateText();
}
upgrade.down = function () {
if (score >= this.cost && this.level < this.maxLevel) {
score -= this.cost;
scoreText.setText('Score: ' + score);
this.purchase();
// Apply upgrade effect
applyUpgrade(this.type, this.level);
// Save upgrade level
var upgradeKey = 'upgrade_' + this.type;
storage[upgradeKey] = this.level;
// Flash to indicate purchase
LK.effects.flashObject(this, 0x00FF00, 300);
} else {
// Flash red if can't afford
LK.effects.flashObject(this, 0xFF0000, 300);
}
};
upgradeMenu.addChild(upgrade);
upgrades.push(upgrade);
}
// Apply saved upgrades to player
for (var i = 0; i < upgrades.length; i++) {
applyUpgrade(upgrades[i].type, upgrades[i].level);
}
}
// Apply upgrade effects to player
function applyUpgrade(type, level) {
if (!player) {
return;
}
var baseValue, increment;
if (type === 'fireRate') {
baseValue = 10;
increment = 2;
player.fireRate = baseValue + (level - 1) * increment;
} else if (type === 'damage') {
baseValue = 1;
increment = 0.5;
player.damage = baseValue + (level - 1) * increment;
} else if (type === 'maxAmmo') {
baseValue = 30;
increment = 10;
var newMaxAmmo = baseValue + (level - 1) * increment;
player.ammo += newMaxAmmo - player.maxAmmo;
player.maxAmmo = newMaxAmmo;
} else if (type === 'frenzyTime') {
baseValue = 300;
increment = 60;
player.frenzyDuration = baseValue + (level - 1) * increment;
}
}
// Toggle upgrade menu visibility
function toggleUpgradeMenu() {
showingUpgradeMenu = !showingUpgradeMenu;
upgradeMenu.visible = showingUpgradeMenu;
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
// Randomize initial position (along top of screen)
enemy.x = gameBounds.left + Math.random() * (gameBounds.right - gameBounds.left);
enemy.y = -50;
// Determine enemy type based on wave and randomness
var rand = Math.random();
if (wave < 3) {
enemy.setType('basic');
} else if (wave < 5) {
if (rand < 0.7) {
enemy.setType('basic');
} else if (rand < 0.9) {
enemy.setType('fast');
} else {
enemy.setType('tank');
}
} else {
if (rand < 0.5) {
enemy.setType('basic');
} else if (rand < 0.8) {
enemy.setType('fast');
} else {
enemy.setType('tank');
}
}
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn powerup
function spawnPowerup(x, y) {
// 20% chance to spawn a powerup when enemy dies
if (Math.random() > 0.2) {
return;
}
var powerup = new PowerUp();
powerup.x = x;
powerup.y = y;
// Determine powerup type
var rand = Math.random();
if (rand < 0.6) {
powerup.setType('ammo');
} else if (rand < 0.9) {
powerup.setType('health');
} else {
powerup.setType('frenzy');
}
game.addChild(powerup);
powerups.push(powerup);
}
// Handle player shooting
function handlePlayerShoot() {
var bullet = player.shoot();
if (bullet) {
game.addChild(bullet);
bullets.push(bullet);
}
}
// Update game state
function updateGameState() {
// Update player
player.update();
ammoUI.update(player.ammo, player.maxAmmo);
// Update health bar
healthBar.scale.x = player.health / 100 * 3;
// Update ammo bar
ammoBar.scale.x = player.ammo / player.maxAmmo * 3;
// Update frenzy meter
if (player.inFrenzyMode) {
frenzyMeter.alpha = 0.5 + Math.sin(LK.ticks * 0.2) * 0.5;
} else {
frenzyMeter.alpha = 0.3;
}
// Spawn enemies
if (LK.ticks - lastEnemySpawn >= enemySpawnRate && enemies.length < enemiesThisWave) {
spawnEnemy();
lastEnemySpawn = LK.ticks;
}
// Next wave logic
if (enemiesKilled >= enemiesThisWave) {
wave++;
enemiesKilled = 0;
enemiesThisWave = Math.min(50, 10 + wave * 5);
enemySpawnRate = Math.max(30, 120 - wave * 10);
waveText.setText('Wave ' + wave);
// Flash screen green for new wave
LK.effects.flashScreen(0x2ecc71, 500);
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove bullets that go off screen
if (bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check for bullet collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Enemy takes damage
var destroyed = enemy.takeDamage(bullet.damage);
if (destroyed) {
// Add score
score += enemy.scoreValue;
scoreText.setText('Score: ' + score);
// Increment kill counter
enemiesKilled++;
// Spawn powerup
spawnPowerup(enemy.x, enemy.y);
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
}
// Remove bullet
bullet.destroy();
bullets.splice(i, 1);
// Play hit sound
LK.getSound('enemyHit').play();
// Break since bullet is gone
break;
}
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Remove enemies that go off bottom of screen
if (enemy.y > gameBounds.bottom + 50) {
// Player takes damage when enemy passes
player.takeDamage(10);
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Play hit sound
LK.getSound('playerHit').play();
continue;
}
// Check collision with player
if (enemy.intersects(player)) {
// Player takes damage
player.takeDamage(20);
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Play hit sound
LK.getSound('playerHit').play();
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
// Remove powerups that go off bottom of screen
if (powerup.y > gameBounds.bottom + 50) {
powerup.destroy();
powerups.splice(i, 1);
continue;
}
// Check collision with player
if (powerup.intersects(player)) {
if (powerup.type === 'ammo') {
player.reloadAmmo(15);
} else if (powerup.type === 'health') {
player.health = Math.min(100, player.health + 20);
} else if (powerup.type === 'frenzy') {
player.activateFrenzy();
}
// Play powerup sound
LK.getSound('powerupCollect').play();
// Remove powerup
powerup.destroy();
powerups.splice(i, 1);
}
}
// Check for game over
if (player.health <= 0 && !isGameOver) {
isGameOver = true;
LK.showGameOver();
}
// Auto-shoot in frenzy mode
if (player.inFrenzyMode && LK.ticks % 5 === 0) {
handlePlayerShoot();
}
}
// Initialize game
function initGame() {
// Reset game state
bullets = [];
enemies = [];
powerups = [];
showingUpgradeMenu = false;
score = 0;
wave = 1;
enemiesKilled = 0;
enemiesThisWave = 10;
enemySpawnRate = 120;
lastEnemySpawn = 0;
isGameOver = false;
// Set score
LK.setScore(0);
// Init player and UI
initPlayer();
initUI();
// Play music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 1,
duration: 1000
}
});
}
// Initialize the game
initGame();
// Touch/mouse handlers for player movement
var isDragging = false;
game.down = function (x, y, obj) {
// Check if upgrade button was clicked
if (obj.target === upgradeButton) {
toggleUpgradeMenu();
return;
}
// If upgrade menu is showing, don't process player movement/shooting
if (showingUpgradeMenu) {
return;
}
isDragging = true;
player.x = x;
// Constrain player to game bounds
player.x = Math.max(gameBounds.left, Math.min(gameBounds.right, player.x));
// Shoot on tap
handlePlayerShoot();
};
game.up = function (x, y, obj) {
isDragging = false;
};
game.move = function (x, y, obj) {
if (isDragging && !showingUpgradeMenu) {
player.x = x;
// Constrain player to game bounds
player.x = Math.max(gameBounds.left, Math.min(gameBounds.right, player.x));
}
};
// Main game loop
game.update = function () {
if (!isGameOver && !showingUpgradeMenu) {
updateGameState();
}
// Update score
LK.setScore(score);
};