/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var MenuButton = Container.expand(function (label, yPos) {
var self = Container.call(this);
// Button background
var buttonBg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
// Button highlight (initially invisible)
var highlight = self.attachAsset('buttonHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Button text
var text = new Text2(label, {
size: 70,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
self.addChild(text);
// Set position
self.y = yPos;
// Event handlers
self.down = function (x, y, obj) {
// Scale down effect
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
// Play sound
LK.getSound('buttonClick').play();
};
self.up = function (x, y, obj) {
// Scale back to normal
tween(buttonBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
// Handle button action
if (label === "Shop") {
showShopView();
} else if (label === "Play") {
showPlayView();
} else if (label === "Settings") {
showSettingsView();
}
};
// Hover effect methods
self.showHighlight = function () {
tween(highlight, {
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
};
self.hideHighlight = function () {
tween(highlight, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
// Function to set the button text
self.setLabel = function (newLabel) {
text.setText(newLabel);
};
return self;
});
var MenuView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Game Menu", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Buttons
var playButton = new MenuButton("Play", -250);
var shopButton = new MenuButton("Shop", 0);
var settingsButton = new MenuButton("Settings", 250);
self.addChild(shopButton);
self.addChild(playButton);
self.addChild(settingsButton);
// Hover tracking
var hoveredButton = null;
// Track mouse movement for hover effects
self.move = function (x, y, obj) {
var localPos = {
x: x,
y: y
};
// Clear previous hover state
if (hoveredButton) {
hoveredButton.hideHighlight();
hoveredButton = null;
}
// Check if hovering over any button
if (playButton.getBounds().contains(localPos.x, localPos.y)) {
playButton.showHighlight();
hoveredButton = playButton;
} else if (shopButton.getBounds().contains(localPos.x, localPos.y)) {
shopButton.showHighlight();
hoveredButton = shopButton;
} else if (settingsButton.getBounds().contains(localPos.x, localPos.y)) {
settingsButton.showHighlight();
hoveredButton = settingsButton;
}
};
// Animation for showing the menu
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
shopButton.alpha = 0;
playButton.alpha = 0;
settingsButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Buttons fade in sequence
LK.setTimeout(function () {
tween(playButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(shopButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(settingsButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
var ShooterGame = Container.expand(function () {
var self = Container.call(this);
// Game elements
var player = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 100,
height: 100,
tint: 0xff0000
});
// Position player at bottom center
player.x = 0;
player.y = 500;
// Score display
var scoreText = new Text2("Score: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = -650;
self.addChild(scoreText);
// Game variables
// Initialize score but keep coins from storage
var score = 0;
var bullets = [];
var enemies = [];
var enemyBullets = []; // Array to track enemy bullets
// Player control - optimized for mobile touch
self.move = function (x, y, obj) {
// Convert global position to local position
// Clamp player position within screen bounds to prevent going off-screen
player.x = Math.max(-900, Math.min(900, x)); // Limit horizontal movement
};
// Shoot function - optimized for mobile
function shoot() {
// Don't create too many bullets on mobile
if (bullets.length > 80) {
// Remove oldest bullets if we have too many (mobile optimization)
var bulletsToRemove = bullets.length - 80;
for (var i = 0; i < bulletsToRemove; i++) {
if (bullets[i]) {
bullets[i].destroy();
}
}
bullets.splice(0, bulletsToRemove);
}
var bullet = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 30,
// Slightly larger for better visibility on mobile
height: 50,
tint: 0xffff00
});
bullet.x = player.x;
bullet.y = player.y - 50;
bullet.speed = -20; // Fast upward speed
self.addChild(bullet);
bullets.push(bullet);
LK.getSound('buttonClick').play();
}
// Player shooting - optimized for mobile touch
self.down = function (x, y, obj) {
// On mobile, we want to ensure the player can still shoot even if they tap slightly away from ship
var touchDistance = Math.sqrt(Math.pow(x - player.x, 2) + Math.pow(y - player.y, 2));
if (touchDistance < 150) {
// Larger touch area for mobile
shoot();
} else {
// If they tap elsewhere, move the player there and shoot
player.x = x;
shoot();
}
};
// Main game loop - optimized for mobile
self.update = function () {
// Auto shooting (adjust fire rate for mobile - slightly slower to prevent lag)
if (LK.ticks % 15 === 0) {
// Fire every 15 ticks instead of 10 for better mobile performance
shoot();
}
// Update bullets - with limit for mobile performance
// Only process a maximum of 50 bullets at once to prevent performance issues
var bulletProcessLimit = Math.min(bullets.length, 50);
for (var i = bulletProcessLimit - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.y += bullet.speed;
// Remove bullets that go off screen
if (bullet.y < -700) {
bullet.destroy();
bullets.splice(i, 1);
}
}
// Create enemies randomly - reduced rate for mobile
if (Math.random() < 0.008) {
// Reduced spawn rate further
// Reduced spawn rate for mobile performance
var enemy = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 80,
tint: 0x00ff00
});
enemy.x = Math.random() * 1000 - 500; // Random position
enemy.y = -700; // Start from top
enemy.speed = 3; // Move downward
enemy.lastShot = LK.ticks; // Track last shot time
self.addChild(enemy);
enemies.push(enemy);
}
// Update enemies - with limit for mobile performance
// Only process a maximum of 30 enemies at once to prevent performance issues
var enemyProcessLimit = Math.min(enemies.length, 30);
for (var j = enemyProcessLimit - 1; j >= 0; j--) {
var enemy = enemies[j];
enemy.y += enemy.speed;
// Enemy shooting logic
if (LK.ticks - enemy.lastShot > 90) {
// Shoot every ~1.5 seconds
// Create enemy bullet
var enemyBullet = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 40,
tint: 0xff0088
});
enemyBullet.x = enemy.x;
enemyBullet.y = enemy.y + 50;
enemyBullet.speed = 8; // Downward speed
self.addChild(enemyBullet);
enemyBullets.push(enemyBullet);
enemy.lastShot = LK.ticks;
}
// Check collision with bullets - optimized for mobile
var hitDetected = false;
for (var k = 0; k < bullets.length && !hitDetected; k++) {
if (enemy.intersects(bullets[k])) {
// Increase score
score += 10;
// Update coins in storage
storage.coins = (storage.coins || 0) + 10;
scoreText.setText("Score: " + score);
// Remove bullet and enemy
bullets[k].destroy();
bullets.splice(k, 1);
enemy.destroy();
enemies.splice(j, 1);
hitDetected = true;
break;
}
}
// Skip rest of processing if enemy was destroyed
if (hitDetected) {
continue;
}
// Remove enemies that go off screen
if (enemy.y > 700) {
enemy.destroy();
enemies.splice(j, 1);
}
}
// Update enemy bullets
for (var m = enemyBullets.length - 1; m >= 0; m--) {
var enemyBullet = enemyBullets[m];
enemyBullet.y += enemyBullet.speed;
// Check collision with player
if (enemyBullet.intersects(player)) {
// Player hit - ensure coins are saved before game over
storage.coins = storage.coins || 0;
// Player hit - game over
LK.showGameOver();
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
// Remove bullets that go off screen
if (enemyBullet.y > 700) {
enemyBullet.destroy();
enemyBullets.splice(m, 1);
}
}
};
return self;
});
var ShopView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Shop", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Buttons
var skinsButton = new MenuButton("Skins", -250);
var upgradesButton = new MenuButton("Upgrades", 0);
var backButton = new MenuButton("Back to Menu", 250);
self.addChild(skinsButton);
self.addChild(upgradesButton);
self.addChild(backButton);
// Button actions
skinsButton.up = function (x, y, obj) {
// Open skins view
showSkinsView();
};
backButton.up = function (x, y, obj) {
// Return to main menu
showMainMenu();
};
// Animation for showing the shop
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
skinsButton.alpha = 0;
upgradesButton.alpha = 0;
backButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Buttons fade in sequence
LK.setTimeout(function () {
tween(skinsButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(upgradesButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(backButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
var SkinsView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Skins", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Skins display (example skins)
var skin1 = new MenuButton("Blue - $10", -250);
var skin2 = new MenuButton("Red - $14", 0);
var greenButton = new MenuButton("Green - $12", 250);
self.addChild(skin1);
self.addChild(skin2);
self.addChild(greenButton);
var backButton = new MenuButton("Back to Shop", 250);
self.addChild(backButton);
// Button actions
backButton.up = function (x, y, obj) {
// Return to shop view
showShopView();
};
// Animation for showing the skins
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
skin1.alpha = 0;
skin2.alpha = 0;
backButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Skins fade in sequence
LK.setTimeout(function () {
tween(skin1, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(skin2, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(backButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
function showSkinsView() {
if (currentView === "skins") {
return;
}
// Destroy current view and create skins view
if (currentView === "shop") {
shopView.destroy();
}
skinsView = new SkinsView();
skinsView.x = 2048 / 2;
skinsView.y = 2732 / 2;
game.addChild(skinsView);
skinsView.animateIn();
currentView = "skins";
}
function showMainMenu() {
if (currentView === "main") {
return;
}
// Destroy current view and create main menu
if (currentView === "shop") {
shopView.destroy();
}
createMainMenu();
currentView = "main";
}
// Main elements
var mainMenu;
var currentView = "main"; // Track which view is currently shown
// Create the main menu
function createMainMenu() {
// Initialize storage.coins if it doesn't exist yet
storage.coins = storage.coins || 0;
mainMenu = new MenuView();
mainMenu.x = 2048 / 2;
mainMenu.y = 2732 / 2;
game.addChild(mainMenu);
mainMenu.animateIn();
}
// Show functions for different views
function showShopView() {
if (currentView === "shop") {
return;
}
// Destroy current view and create shop view
if (currentView === "main") {
mainMenu.destroy();
}
shopView = new ShopView();
shopView.x = 2048 / 2;
shopView.y = 2732 / 2;
game.addChild(shopView);
shopView.animateIn();
// Add coins display to shop view from persistent storage
var scoreDisplay = new Text2("Your Coins: " + (storage.coins || 0), {
size: 60,
fill: 0xFFFFFF
});
scoreDisplay.anchor.set(0.5, 0.5);
scoreDisplay.x = 0;
scoreDisplay.y = -400;
shopView.addChild(scoreDisplay);
currentView = "shop";
}
function showPlayView() {
if (currentView === "play") {
return;
}
// Destroy current view
if (currentView === "main") {
mainMenu.destroy();
} else if (currentView === "shop") {
shopView.destroy();
} else if (currentView === "skins") {
skinsView.destroy();
}
// Create and start the shooter game
function startShooterGame() {
// Initialize the shooter game - with mobile optimizations
var shooterGame = new ShooterGame();
shooterGame.x = 2048 / 2;
shooterGame.y = 2732 / 2;
game.addChild(shooterGame);
// Add mobile-specific instructions
var instructionText = new Text2("Tap to shoot\nDrag to move", {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 0;
instructionText.y = 300;
shooterGame.addChild(instructionText);
// Fade out instructions after 3 seconds
LK.setTimeout(function () {
tween(instructionText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
instructionText.destroy();
}
});
}, 3000);
console.log("Shooter game started!");
}
// Start the shooter game
startShooterGame();
currentView = "play";
}
function showSettingsView() {
if (currentView === "settings") {
return;
}
// Simple feedback for now - in a real game, this would show settings menu
var notification = new Text2("Opening Settings...", {
size: 70,
fill: 0xFFFFFF
});
notification.anchor.set(0.5, 0.5);
notification.x = 2048 / 2;
notification.y = 2732 - 300;
notification.alpha = 0;
game.addChild(notification);
tween(notification, {
alpha: 1
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(notification, {
alpha: 0
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
notification.destroy();
}
});
}, 1500);
}
});
currentView = "settings";
}
// Game events
game.down = function (x, y, obj) {
// Global down event if needed
};
game.up = function (x, y, obj) {
// Global up event if needed
};
game.move = function (x, y, obj) {
// Pass touch/mouse movement to active view based on current state
// For mobile: Add check to ensure we have valid obj
if (!obj || !obj.event) {
return;
}
// Normalize touch events for mobile
if (currentView === "play" && game.getChildAt(0) instanceof ShooterGame) {
// Calculate position relative to game center for consistent mobile experience
var gameX = x - 2048 / 2;
var gameY = y - 2732 / 2;
// Pass the normalized coordinates
game.getChildAt(0).move(gameX, gameY, obj);
}
};
// Initialize game
createMainMenu();
// Play background music
LK.playMusic('menuMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Main game loop
game.update = function () {
// Any continuous updates can go here
// For a menu, we don't need much in the update loop
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var MenuButton = Container.expand(function (label, yPos) {
var self = Container.call(this);
// Button background
var buttonBg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
// Button highlight (initially invisible)
var highlight = self.attachAsset('buttonHighlight', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
// Button text
var text = new Text2(label, {
size: 70,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
self.addChild(text);
// Set position
self.y = yPos;
// Event handlers
self.down = function (x, y, obj) {
// Scale down effect
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut
});
// Play sound
LK.getSound('buttonClick').play();
};
self.up = function (x, y, obj) {
// Scale back to normal
tween(buttonBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
// Handle button action
if (label === "Shop") {
showShopView();
} else if (label === "Play") {
showPlayView();
} else if (label === "Settings") {
showSettingsView();
}
};
// Hover effect methods
self.showHighlight = function () {
tween(highlight, {
alpha: 0.3
}, {
duration: 200,
easing: tween.easeOut
});
};
self.hideHighlight = function () {
tween(highlight, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
// Function to set the button text
self.setLabel = function (newLabel) {
text.setText(newLabel);
};
return self;
});
var MenuView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Game Menu", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Buttons
var playButton = new MenuButton("Play", -250);
var shopButton = new MenuButton("Shop", 0);
var settingsButton = new MenuButton("Settings", 250);
self.addChild(shopButton);
self.addChild(playButton);
self.addChild(settingsButton);
// Hover tracking
var hoveredButton = null;
// Track mouse movement for hover effects
self.move = function (x, y, obj) {
var localPos = {
x: x,
y: y
};
// Clear previous hover state
if (hoveredButton) {
hoveredButton.hideHighlight();
hoveredButton = null;
}
// Check if hovering over any button
if (playButton.getBounds().contains(localPos.x, localPos.y)) {
playButton.showHighlight();
hoveredButton = playButton;
} else if (shopButton.getBounds().contains(localPos.x, localPos.y)) {
shopButton.showHighlight();
hoveredButton = shopButton;
} else if (settingsButton.getBounds().contains(localPos.x, localPos.y)) {
settingsButton.showHighlight();
hoveredButton = settingsButton;
}
};
// Animation for showing the menu
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
shopButton.alpha = 0;
playButton.alpha = 0;
settingsButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Buttons fade in sequence
LK.setTimeout(function () {
tween(playButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(shopButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(settingsButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
var ShooterGame = Container.expand(function () {
var self = Container.call(this);
// Game elements
var player = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 100,
height: 100,
tint: 0xff0000
});
// Position player at bottom center
player.x = 0;
player.y = 500;
// Score display
var scoreText = new Text2("Score: 0", {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 0;
scoreText.y = -650;
self.addChild(scoreText);
// Game variables
// Initialize score but keep coins from storage
var score = 0;
var bullets = [];
var enemies = [];
var enemyBullets = []; // Array to track enemy bullets
// Player control - optimized for mobile touch
self.move = function (x, y, obj) {
// Convert global position to local position
// Clamp player position within screen bounds to prevent going off-screen
player.x = Math.max(-900, Math.min(900, x)); // Limit horizontal movement
};
// Shoot function - optimized for mobile
function shoot() {
// Don't create too many bullets on mobile
if (bullets.length > 80) {
// Remove oldest bullets if we have too many (mobile optimization)
var bulletsToRemove = bullets.length - 80;
for (var i = 0; i < bulletsToRemove; i++) {
if (bullets[i]) {
bullets[i].destroy();
}
}
bullets.splice(0, bulletsToRemove);
}
var bullet = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 30,
// Slightly larger for better visibility on mobile
height: 50,
tint: 0xffff00
});
bullet.x = player.x;
bullet.y = player.y - 50;
bullet.speed = -20; // Fast upward speed
self.addChild(bullet);
bullets.push(bullet);
LK.getSound('buttonClick').play();
}
// Player shooting - optimized for mobile touch
self.down = function (x, y, obj) {
// On mobile, we want to ensure the player can still shoot even if they tap slightly away from ship
var touchDistance = Math.sqrt(Math.pow(x - player.x, 2) + Math.pow(y - player.y, 2));
if (touchDistance < 150) {
// Larger touch area for mobile
shoot();
} else {
// If they tap elsewhere, move the player there and shoot
player.x = x;
shoot();
}
};
// Main game loop - optimized for mobile
self.update = function () {
// Auto shooting (adjust fire rate for mobile - slightly slower to prevent lag)
if (LK.ticks % 15 === 0) {
// Fire every 15 ticks instead of 10 for better mobile performance
shoot();
}
// Update bullets - with limit for mobile performance
// Only process a maximum of 50 bullets at once to prevent performance issues
var bulletProcessLimit = Math.min(bullets.length, 50);
for (var i = bulletProcessLimit - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.y += bullet.speed;
// Remove bullets that go off screen
if (bullet.y < -700) {
bullet.destroy();
bullets.splice(i, 1);
}
}
// Create enemies randomly - reduced rate for mobile
if (Math.random() < 0.008) {
// Reduced spawn rate further
// Reduced spawn rate for mobile performance
var enemy = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 80,
tint: 0x00ff00
});
enemy.x = Math.random() * 1000 - 500; // Random position
enemy.y = -700; // Start from top
enemy.speed = 3; // Move downward
enemy.lastShot = LK.ticks; // Track last shot time
self.addChild(enemy);
enemies.push(enemy);
}
// Update enemies - with limit for mobile performance
// Only process a maximum of 30 enemies at once to prevent performance issues
var enemyProcessLimit = Math.min(enemies.length, 30);
for (var j = enemyProcessLimit - 1; j >= 0; j--) {
var enemy = enemies[j];
enemy.y += enemy.speed;
// Enemy shooting logic
if (LK.ticks - enemy.lastShot > 90) {
// Shoot every ~1.5 seconds
// Create enemy bullet
var enemyBullet = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 40,
tint: 0xff0088
});
enemyBullet.x = enemy.x;
enemyBullet.y = enemy.y + 50;
enemyBullet.speed = 8; // Downward speed
self.addChild(enemyBullet);
enemyBullets.push(enemyBullet);
enemy.lastShot = LK.ticks;
}
// Check collision with bullets - optimized for mobile
var hitDetected = false;
for (var k = 0; k < bullets.length && !hitDetected; k++) {
if (enemy.intersects(bullets[k])) {
// Increase score
score += 10;
// Update coins in storage
storage.coins = (storage.coins || 0) + 10;
scoreText.setText("Score: " + score);
// Remove bullet and enemy
bullets[k].destroy();
bullets.splice(k, 1);
enemy.destroy();
enemies.splice(j, 1);
hitDetected = true;
break;
}
}
// Skip rest of processing if enemy was destroyed
if (hitDetected) {
continue;
}
// Remove enemies that go off screen
if (enemy.y > 700) {
enemy.destroy();
enemies.splice(j, 1);
}
}
// Update enemy bullets
for (var m = enemyBullets.length - 1; m >= 0; m--) {
var enemyBullet = enemyBullets[m];
enemyBullet.y += enemyBullet.speed;
// Check collision with player
if (enemyBullet.intersects(player)) {
// Player hit - ensure coins are saved before game over
storage.coins = storage.coins || 0;
// Player hit - game over
LK.showGameOver();
enemyBullet.destroy();
enemyBullets.splice(m, 1);
continue;
}
// Remove bullets that go off screen
if (enemyBullet.y > 700) {
enemyBullet.destroy();
enemyBullets.splice(m, 1);
}
}
};
return self;
});
var ShopView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Shop", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Buttons
var skinsButton = new MenuButton("Skins", -250);
var upgradesButton = new MenuButton("Upgrades", 0);
var backButton = new MenuButton("Back to Menu", 250);
self.addChild(skinsButton);
self.addChild(upgradesButton);
self.addChild(backButton);
// Button actions
skinsButton.up = function (x, y, obj) {
// Open skins view
showSkinsView();
};
backButton.up = function (x, y, obj) {
// Return to main menu
showMainMenu();
};
// Animation for showing the shop
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
skinsButton.alpha = 0;
upgradesButton.alpha = 0;
backButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Buttons fade in sequence
LK.setTimeout(function () {
tween(skinsButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(upgradesButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(backButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
var SkinsView = Container.expand(function () {
var self = Container.call(this);
// Background panel
var background = self.attachAsset('menuBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Title text
var titleText = new Text2("Skins", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -600;
self.addChild(titleText);
// Skins display (example skins)
var skin1 = new MenuButton("Blue - $10", -250);
var skin2 = new MenuButton("Red - $14", 0);
var greenButton = new MenuButton("Green - $12", 250);
self.addChild(skin1);
self.addChild(skin2);
self.addChild(greenButton);
var backButton = new MenuButton("Back to Shop", 250);
self.addChild(backButton);
// Button actions
backButton.up = function (x, y, obj) {
// Return to shop view
showShopView();
};
// Animation for showing the skins
self.animateIn = function () {
// Initial state
background.alpha = 0;
titleText.alpha = 0;
skin1.alpha = 0;
skin2.alpha = 0;
backButton.alpha = 0;
// Background fade in
tween(background, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Title slide down
titleText.y = -800;
tween(titleText, {
alpha: 1,
y: -600
}, {
duration: 700,
easing: tween.easeOut
});
// Skins fade in sequence
LK.setTimeout(function () {
tween(skin1, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 200);
LK.setTimeout(function () {
tween(skin2, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 350);
LK.setTimeout(function () {
tween(backButton, {
alpha: 1
}, {
duration: 300,
easing: tween.easeOut
});
}, 500);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
function showSkinsView() {
if (currentView === "skins") {
return;
}
// Destroy current view and create skins view
if (currentView === "shop") {
shopView.destroy();
}
skinsView = new SkinsView();
skinsView.x = 2048 / 2;
skinsView.y = 2732 / 2;
game.addChild(skinsView);
skinsView.animateIn();
currentView = "skins";
}
function showMainMenu() {
if (currentView === "main") {
return;
}
// Destroy current view and create main menu
if (currentView === "shop") {
shopView.destroy();
}
createMainMenu();
currentView = "main";
}
// Main elements
var mainMenu;
var currentView = "main"; // Track which view is currently shown
// Create the main menu
function createMainMenu() {
// Initialize storage.coins if it doesn't exist yet
storage.coins = storage.coins || 0;
mainMenu = new MenuView();
mainMenu.x = 2048 / 2;
mainMenu.y = 2732 / 2;
game.addChild(mainMenu);
mainMenu.animateIn();
}
// Show functions for different views
function showShopView() {
if (currentView === "shop") {
return;
}
// Destroy current view and create shop view
if (currentView === "main") {
mainMenu.destroy();
}
shopView = new ShopView();
shopView.x = 2048 / 2;
shopView.y = 2732 / 2;
game.addChild(shopView);
shopView.animateIn();
// Add coins display to shop view from persistent storage
var scoreDisplay = new Text2("Your Coins: " + (storage.coins || 0), {
size: 60,
fill: 0xFFFFFF
});
scoreDisplay.anchor.set(0.5, 0.5);
scoreDisplay.x = 0;
scoreDisplay.y = -400;
shopView.addChild(scoreDisplay);
currentView = "shop";
}
function showPlayView() {
if (currentView === "play") {
return;
}
// Destroy current view
if (currentView === "main") {
mainMenu.destroy();
} else if (currentView === "shop") {
shopView.destroy();
} else if (currentView === "skins") {
skinsView.destroy();
}
// Create and start the shooter game
function startShooterGame() {
// Initialize the shooter game - with mobile optimizations
var shooterGame = new ShooterGame();
shooterGame.x = 2048 / 2;
shooterGame.y = 2732 / 2;
game.addChild(shooterGame);
// Add mobile-specific instructions
var instructionText = new Text2("Tap to shoot\nDrag to move", {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 0;
instructionText.y = 300;
shooterGame.addChild(instructionText);
// Fade out instructions after 3 seconds
LK.setTimeout(function () {
tween(instructionText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
instructionText.destroy();
}
});
}, 3000);
console.log("Shooter game started!");
}
// Start the shooter game
startShooterGame();
currentView = "play";
}
function showSettingsView() {
if (currentView === "settings") {
return;
}
// Simple feedback for now - in a real game, this would show settings menu
var notification = new Text2("Opening Settings...", {
size: 70,
fill: 0xFFFFFF
});
notification.anchor.set(0.5, 0.5);
notification.x = 2048 / 2;
notification.y = 2732 - 300;
notification.alpha = 0;
game.addChild(notification);
tween(notification, {
alpha: 1
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(notification, {
alpha: 0
}, {
duration: 300,
easing: tween.linear,
onFinish: function onFinish() {
notification.destroy();
}
});
}, 1500);
}
});
currentView = "settings";
}
// Game events
game.down = function (x, y, obj) {
// Global down event if needed
};
game.up = function (x, y, obj) {
// Global up event if needed
};
game.move = function (x, y, obj) {
// Pass touch/mouse movement to active view based on current state
// For mobile: Add check to ensure we have valid obj
if (!obj || !obj.event) {
return;
}
// Normalize touch events for mobile
if (currentView === "play" && game.getChildAt(0) instanceof ShooterGame) {
// Calculate position relative to game center for consistent mobile experience
var gameX = x - 2048 / 2;
var gameY = y - 2732 / 2;
// Pass the normalized coordinates
game.getChildAt(0).move(gameX, gameY, obj);
}
};
// Initialize game
createMainMenu();
// Play background music
LK.playMusic('menuMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Main game loop
game.update = function () {
// Any continuous updates can go here
// For a menu, we don't need much in the update loop
};