/**** * 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);
};