/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
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.update = function () {
self.y += self.speed;
};
return self;
});
var FallingObject = Container.expand(function (type) {
var self = Container.call(this);
var objectGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = (Math.random() * 3 + 2) * 2;
self.type = type;
// Set hit points based on object type
if (type === 'bat') {
self.hitPoints = 2;
} else if (type === 'stick') {
self.hitPoints = 1;
} else if (type === 'knife') {
self.hitPoints = 1;
} else if (type === 'sword') {
self.hitPoints = 4;
} else if (type === 'rock') {
self.hitPoints = 25;
}
self.maxHitPoints = self.hitPoints;
self.update = function () {
self.y += self.speed;
self.rotation += 0.05;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset(equippedSkin, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.shootCooldown = 0;
self.updateSkin = function (newSkin) {
self.removeChildren();
playerGraphics = self.attachAsset(newSkin, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
self.rotation += 0.1;
// Pulse effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
self.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state management
var gameState = 'menu'; // 'menu', 'playing', or 'shop'
// Shop variables
var totalEarnings = storage.totalEarnings || 0;
var currentShopSection = 'upgrades'; // Track current shop section
var shopUpgrades = {
doubleDamagePrice: storage.savedDoubleDamage || 100,
unlimitedShootingPrice: storage.savedUnlimitedShooting || 150,
extraLifePrice: storage.savedExtraLife || 200,
fastShootingPrice: storage.savedFastShooting || 120,
shieldPrice: storage.savedShield || 180,
damageUpgradePrice: storage.savedDamageUpgradePrice || 150
};
// Skin system variables
var ownedSkins = storage.ownedSkins || ['player']; // Default skin is always owned
var equippedSkin = storage.equippedSkin || 'player';
var skinPrices = {
player2: 100
};
// Add blue background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
// Menu elements
var titleText = new Text2('Dodge & Destroy', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 2 - 200;
game.addChild(titleText);
var playButton = new Text2('PLAY', {
size: 80,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 2048 / 2;
playButton.y = 2732 / 2 + 100;
game.addChild(playButton);
var shopButton = new Text2('SHOP', {
size: 80,
fill: 0xFFD700
});
shopButton.anchor.set(0.5, 0.5);
shopButton.x = 2048 / 2;
shopButton.y = 2732 / 2 + 200;
game.addChild(shopButton);
var saveButton = new Text2('SAVE', {
size: 60,
fill: 0x00FFFF
});
saveButton.anchor.set(0.5, 0.5);
saveButton.x = 2048 / 2 - 200;
saveButton.y = 2732 / 2 + 300;
game.addChild(saveButton);
var loadButton = new Text2('LOAD', {
size: 60,
fill: 0xFF00FF
});
loadButton.anchor.set(0.5, 0.5);
loadButton.x = 2048 / 2 + 200;
loadButton.y = 2732 / 2 + 300;
game.addChild(loadButton);
// Save confirmation message
var saveMessageText = new Text2('PROGRESS SAVED', {
size: 70,
fill: 0x00FF00
});
saveMessageText.anchor.set(0.5, 0.5);
saveMessageText.x = 2048 / 2;
saveMessageText.y = 2732 / 2 - 100;
saveMessageText.visible = false;
game.addChild(saveMessageText);
// Load confirmation message
var loadMessageText = new Text2('PROGRESS RESTORED', {
size: 70,
fill: 0x00FFFF
});
loadMessageText.anchor.set(0.5, 0.5);
loadMessageText.x = 2048 / 2;
loadMessageText.y = 2732 / 2 - 100;
loadMessageText.visible = false;
game.addChild(loadMessageText);
// Game version text
var versionText = new Text2('Game version: V1.00', {
size: 40,
fill: 0xFFFFFF
});
versionText.anchor.set(0, 1);
versionText.x = 120;
versionText.y = 2732 - 20;
game.addChild(versionText);
// Shop UI elements (initially hidden)
var shopTitle = new Text2('SHOP', {
size: 100,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 300;
shopTitle.visible = false;
game.addChild(shopTitle);
var coinsText = new Text2('Coins: ' + totalEarnings, {
size: 60,
fill: 0xFFFFFF
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 2048 / 2;
coinsText.y = 400;
coinsText.visible = false;
game.addChild(coinsText);
// Shop upgrades
var upgrade1Text = new Text2('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade1Text.anchor.set(0.5, 0.5);
upgrade1Text.x = 2048 / 2;
upgrade1Text.y = 600;
upgrade1Text.visible = false;
game.addChild(upgrade1Text);
var upgrade2Text = new Text2('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade2Text.anchor.set(0.5, 0.5);
upgrade2Text.x = 2048 / 2;
upgrade2Text.y = 700;
upgrade2Text.visible = false;
game.addChild(upgrade2Text);
var upgrade3Text = new Text2('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade3Text.anchor.set(0.5, 0.5);
upgrade3Text.x = 2048 / 2;
upgrade3Text.y = 800;
upgrade3Text.visible = false;
game.addChild(upgrade3Text);
var upgrade4Text = new Text2('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade4Text.anchor.set(0.5, 0.5);
upgrade4Text.x = 2048 / 2;
upgrade4Text.y = 900;
upgrade4Text.visible = false;
game.addChild(upgrade4Text);
var upgrade5Text = new Text2('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade5Text.anchor.set(0.5, 0.5);
upgrade5Text.x = 2048 / 2;
upgrade5Text.y = 1000;
upgrade5Text.visible = false;
game.addChild(upgrade5Text);
var upgrade6Text = new Text2('+1 Damage - Price: 150 coins', {
size: 50,
fill: 0x00FF00
});
upgrade6Text.anchor.set(0.5, 0.5);
upgrade6Text.x = 2048 / 2;
upgrade6Text.y = 1100;
upgrade6Text.visible = false;
game.addChild(upgrade6Text);
// Shop section navigation
var upgradesSection = new Text2('UPGRADES', {
size: 60,
fill: 0x00FF00
});
upgradesSection.anchor.set(0.5, 0.5);
upgradesSection.x = 2048 / 2 - 300;
upgradesSection.y = 500;
upgradesSection.visible = false;
game.addChild(upgradesSection);
var skinsSection = new Text2('SKINS', {
size: 60,
fill: 0xFFFFFF
});
skinsSection.anchor.set(0.5, 0.5);
skinsSection.x = 2048 / 2;
skinsSection.y = 500;
skinsSection.visible = false;
game.addChild(skinsSection);
var projectilesSection = new Text2('PROJECTILES', {
size: 60,
fill: 0xFFFFFF
});
projectilesSection.anchor.set(0.5, 0.5);
projectilesSection.x = 2048 / 2 + 300;
projectilesSection.y = 500;
projectilesSection.visible = false;
game.addChild(projectilesSection);
// Skin shop elements
var skin1Text = new Text2('Player Skin 2 - Price: 100 coins', {
size: 50,
fill: 0x00FF00
});
skin1Text.anchor.set(0.5, 0.5);
skin1Text.x = 2048 / 2;
skin1Text.y = 600;
skin1Text.visible = false;
game.addChild(skin1Text);
var skin1EquipText = new Text2('EQUIP', {
size: 40,
fill: 0xFFD700
});
skin1EquipText.anchor.set(0.5, 0.5);
skin1EquipText.x = 2048 / 2;
skin1EquipText.y = 650;
skin1EquipText.visible = false;
game.addChild(skin1EquipText);
var backButton = new Text2('BACK', {
size: 70,
fill: 0xFF4444
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 2048 / 2;
backButton.y = 1200;
backButton.visible = false;
game.addChild(backButton);
// Start title music
LK.playMusic('title_music');
// Game elements (initially hidden)
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 200;
player.visible = false;
var bullets = [];
var fallingObjects = [];
var lives = 3;
var maxLives = 3;
var objectTypes = ['knife', 'sword', 'bat', 'stick'];
var spawnTimer = 0;
var spawnRate = 60;
var difficultyTimer = 0;
var maxBullets = 3;
// Challenge variables
var objectsDestroyed = 0;
var challengeTarget = 5;
var challengesCompleted = 0;
var rockActive = false;
var rockBatTimer = 0;
var rockBatSpawnRate = 420; // 7 seconds at 60 FPS
var challengeTimer = 0;
var challengeTimeLimit = 900; // 15 seconds at 60 FPS
var currentChallenge = 0; // Track current challenge number
// Power-up variables
var batsDestroyed = 0;
var swordsDestroyed = 0;
var knivesDestroyed = 0;
var sticksDestroyed = 0;
var powerUps = [];
var doubleDamageActive = false;
var doubleDamageTimer = 0;
var doubleDamageTimeLimit = 600; // 10 seconds at 60 FPS
var unlimitedShootingActive = false;
var unlimitedShootingTimer = 0;
var unlimitedShootingTimeLimit = 600; // 10 seconds at 60 FPS
var damageUpgrade = storage.damageUpgrade || 0;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
scoreText.y = 50;
scoreText.visible = false;
LK.gui.topLeft.addChild(scoreText);
var livesText = new Text2('Lives: 3', {
size: 60,
fill: 0xFF4444
});
livesText.anchor.set(1, 0);
livesText.visible = false;
LK.gui.topRight.addChild(livesText);
var timerText = new Text2('Target: 5', {
size: 50,
fill: 0xFFFF00
});
timerText.anchor.set(0.5, 0);
timerText.x = 0;
timerText.y = 50;
timerText.visible = false;
LK.gui.top.addChild(timerText);
var powerUpText = new Text2('', {
size: 45,
fill: 0x00FF00
});
powerUpText.anchor.set(0.5, 0);
powerUpText.x = 0;
powerUpText.y = 120;
powerUpText.visible = false;
LK.gui.top.addChild(powerUpText);
var dragActive = false;
var lastTouchX = 0;
var lastTouchY = 0;
function showShop() {
gameState = 'shop';
// Hide menu elements
titleText.visible = false;
playButton.visible = false;
shopButton.visible = false;
saveButton.visible = false;
loadButton.visible = false;
saveMessageText.visible = false;
loadMessageText.visible = false;
// Show shop elements
shopTitle.visible = true;
coinsText.visible = true;
upgradesSection.visible = true;
skinsSection.visible = true;
projectilesSection.visible = true;
backButton.visible = true;
// Show appropriate section elements
if (currentShopSection === 'upgrades') {
upgrade1Text.visible = true;
upgrade2Text.visible = true;
upgrade3Text.visible = true;
upgrade4Text.visible = true;
upgrade5Text.visible = true;
upgrade6Text.visible = true;
} else if (currentShopSection === 'skins') {
// Update skin text based on ownership
if (ownedSkins.indexOf('player2') >= 0) {
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
if (equippedSkin === 'player2') {
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
} else {
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
}
} else {
skin1Text.setText('Player Skin 2 - Price: 100 coins');
skin1EquipText.visible = false;
}
skin1Text.visible = true;
}
// Update section colors based on current section
if (currentShopSection === 'upgrades') {
upgradesSection.tint = 0x00FF00;
} else {
upgradesSection.tint = 0xFFFFFF;
}
if (currentShopSection === 'skins') {
skinsSection.tint = 0x00FF00;
} else {
skinsSection.tint = 0xFFFFFF;
}
projectilesSection.tint = 0xFFFFFF;
// Update coins display
coinsText.setText('Coins: ' + totalEarnings);
}
function hideShop() {
gameState = 'menu';
// Hide shop elements
shopTitle.visible = false;
coinsText.visible = false;
upgradesSection.visible = false;
skinsSection.visible = false;
projectilesSection.visible = false;
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
skin1Text.visible = false;
skin1EquipText.visible = false;
backButton.visible = false;
// Show menu elements
titleText.visible = true;
playButton.visible = true;
shopButton.visible = true;
saveButton.visible = true;
loadButton.visible = true;
}
function saveGame() {
// Save current upgrades and earnings using individual properties
storage.savedDoubleDamage = shopUpgrades.doubleDamagePrice;
storage.savedUnlimitedShooting = shopUpgrades.unlimitedShootingPrice;
storage.savedExtraLife = shopUpgrades.extraLifePrice;
storage.savedFastShooting = shopUpgrades.fastShootingPrice;
storage.savedShield = shopUpgrades.shieldPrice;
storage.savedDamageUpgradePrice = shopUpgrades.damageUpgradePrice;
storage.savedEarnings = totalEarnings;
storage.damageUpgrade = damageUpgrade;
storage.ownedSkins = ownedSkins;
storage.equippedSkin = equippedSkin;
storage.totalEarnings = totalEarnings;
}
function loadGame() {
// Load saved upgrades and earnings if they exist using individual properties
if (storage.savedDoubleDamage !== undefined) {
shopUpgrades.doubleDamagePrice = storage.savedDoubleDamage;
}
if (storage.savedUnlimitedShooting !== undefined) {
shopUpgrades.unlimitedShootingPrice = storage.savedUnlimitedShooting;
}
if (storage.savedExtraLife !== undefined) {
shopUpgrades.extraLifePrice = storage.savedExtraLife;
}
if (storage.savedFastShooting !== undefined) {
shopUpgrades.fastShootingPrice = storage.savedFastShooting;
}
if (storage.savedShield !== undefined) {
shopUpgrades.shieldPrice = storage.savedShield;
}
if (storage.savedDamageUpgradePrice !== undefined) {
shopUpgrades.damageUpgradePrice = storage.savedDamageUpgradePrice;
}
if (storage.savedEarnings !== undefined) {
totalEarnings = storage.savedEarnings;
}
if (storage.damageUpgrade !== undefined) {
damageUpgrade = storage.damageUpgrade;
}
if (storage.ownedSkins) {
ownedSkins = storage.ownedSkins;
}
if (storage.equippedSkin) {
equippedSkin = storage.equippedSkin;
}
// Update shop display texts
upgrade1Text.setText('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins');
upgrade2Text.setText('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins');
upgrade3Text.setText('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins');
upgrade4Text.setText('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins');
upgrade5Text.setText('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins');
upgrade6Text.setText('+1 Damage - Price: ' + shopUpgrades.damageUpgradePrice + ' coins');
// Update coins display in shop
coinsText.setText('Coins: ' + totalEarnings);
}
function showSaveMessage() {
// Show the save message
saveMessageText.visible = true;
saveMessageText.alpha = 1;
// Hide the message after 10 seconds using tween
tween(saveMessageText, {
alpha: 0
}, {
duration: 10000,
easing: tween.linear,
onFinish: function onFinish() {
saveMessageText.visible = false;
}
});
}
function showLoadMessage() {
// Show the load message
loadMessageText.visible = true;
loadMessageText.alpha = 1;
// Hide the message after 10 seconds using tween
tween(loadMessageText, {
alpha: 0
}, {
duration: 10000,
easing: tween.linear,
onFinish: function onFinish() {
loadMessageText.visible = false;
}
});
}
function startGame() {
gameState = 'playing';
// Hide menu elements
titleText.visible = false;
playButton.visible = false;
shopButton.visible = false;
saveButton.visible = false;
loadButton.visible = false;
saveMessageText.visible = false;
loadMessageText.visible = false;
// Show game elements
player.visible = true;
scoreText.visible = true;
livesText.visible = true;
timerText.visible = true;
powerUpText.visible = true;
// Stop title music and start survival piano music
LK.stopMusic();
LK.playMusic('survival_piano');
// Reset game variables
lives = maxLives;
objectsDestroyed = 0;
challengesCompleted = 0;
rockActive = false;
challengeTimer = 0;
// Reset power-up variables
batsDestroyed = 0;
swordsDestroyed = 0;
knivesDestroyed = 0;
sticksDestroyed = 0;
doubleDamageActive = false;
doubleDamageTimer = 0;
unlimitedShootingActive = false;
unlimitedShootingTimer = 0;
powerUps = [];
LK.setScore(0);
updateScore();
updateLives();
updateTimer();
}
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
}
function updateLives() {
livesText.setText('Lives: ' + lives);
}
function updateTimer() {
if (rockActive) {
timerText.setText('DESTROY THE ROCK!');
} else {
var remaining = Math.max(0, challengeTarget - objectsDestroyed);
var timeLeft = Math.ceil((challengeTimeLimit - challengeTimer) / 60);
timerText.setText('Target: ' + remaining + ' | Time: ' + timeLeft + 's');
}
}
function spawnFallingObject() {
var type = objectTypes[Math.floor(Math.random() * objectTypes.length)];
var obj = new FallingObject(type);
obj.x = Math.random() * (2048 - 100) + 50;
obj.y = -50;
fallingObjects.push(obj);
game.addChild(obj);
}
function spawnRock() {
var rock = new FallingObject('rock');
rock.x = 2048 / 2; // Center of screen
rock.y = 200; // Fixed Y position
rock.speed = 0; // No forward movement
rock.horizontalSpeed = 3; // Side to side movement speed
rock.direction = Math.random() < 0.5 ? -1 : 1; // Random initial direction
fallingObjects.push(rock);
game.addChild(rock);
rockActive = true;
updateTimer();
}
function resetChallenge() {
objectsDestroyed = 0;
challengeTimer = 0;
currentChallenge++;
updateTimer();
}
function spawnRockBats() {
for (var i = 0; i < 10; i++) {
var bat = new FallingObject('bat');
bat.x = 2048 / 11 * (i + 1); // Distribute evenly across screen
bat.y = -50;
fallingObjects.push(bat);
game.addChild(bat);
}
}
function spawnPowerUp(x, y, type) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
powerUp.powerUpType = type || 'doubleDamage';
powerUps.push(powerUp);
game.addChild(powerUp);
}
function updatePowerUpDisplay() {
if (doubleDamageActive && unlimitedShootingActive) {
var doubleDamageTimeLeft = Math.ceil((doubleDamageTimeLimit - doubleDamageTimer) / 60);
var unlimitedTimeLeft = Math.ceil((unlimitedShootingTimeLimit - unlimitedShootingTimer) / 60);
powerUpText.setText('DOUBLE DAMAGE: ' + doubleDamageTimeLeft + 's | UNLIMITED: ' + unlimitedTimeLeft + 's');
} else if (doubleDamageActive) {
var timeLeft = Math.ceil((doubleDamageTimeLimit - doubleDamageTimer) / 60);
powerUpText.setText('DOUBLE DAMAGE: ' + timeLeft + 's');
} else if (unlimitedShootingActive) {
var timeLeft = Math.ceil((unlimitedShootingTimeLimit - unlimitedShootingTimer) / 60);
powerUpText.setText('UNLIMITED SHOOTING: ' + timeLeft + 's');
} else {
powerUpText.setText('');
}
}
function shootBullet() {
var canShoot = unlimitedShootingActive || player.shootCooldown <= 0 && bullets.length < maxBullets;
if (canShoot) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y - 40;
bullets.push(bullet);
game.addChild(bullet);
if (!unlimitedShootingActive) {
player.shootCooldown = 15;
}
LK.getSound('shoot').play();
}
}
game.down = function (x, y, obj) {
if (gameState === 'menu') {
// Check if play button was tapped
var playButtonBounds = {
left: playButton.x - 100,
right: playButton.x + 100,
top: playButton.y - 50,
bottom: playButton.y + 50
};
if (x >= playButtonBounds.left && x <= playButtonBounds.right && y >= playButtonBounds.top && y <= playButtonBounds.bottom) {
startGame();
}
// Check if shop button was tapped
var shopButtonBounds = {
left: shopButton.x - 100,
right: shopButton.x + 100,
top: shopButton.y - 50,
bottom: shopButton.y + 50
};
if (x >= shopButtonBounds.left && x <= shopButtonBounds.right && y >= shopButtonBounds.top && y <= shopButtonBounds.bottom) {
showShop();
}
// Check if save button was tapped
var saveButtonBounds = {
left: saveButton.x - 80,
right: saveButton.x + 80,
top: saveButton.y - 40,
bottom: saveButton.y + 40
};
if (x >= saveButtonBounds.left && x <= saveButtonBounds.right && y >= saveButtonBounds.top && y <= saveButtonBounds.bottom) {
saveGame();
showSaveMessage();
}
// Check if load button was tapped
var loadButtonBounds = {
left: loadButton.x - 80,
right: loadButton.x + 80,
top: loadButton.y - 40,
bottom: loadButton.y + 40
};
if (x >= loadButtonBounds.left && x <= loadButtonBounds.right && y >= loadButtonBounds.top && y <= loadButtonBounds.bottom) {
loadGame();
showLoadMessage();
}
} else if (gameState === 'shop') {
// Check upgrade buttons
var upgradeHeight = 50;
var upgradeWidth = 800;
// Back button
var backButtonBounds = {
left: backButton.x - 100,
right: backButton.x + 100,
top: backButton.y - 40,
bottom: backButton.y + 40
};
if (x >= backButtonBounds.left && x <= backButtonBounds.right && y >= backButtonBounds.top && y <= backButtonBounds.bottom) {
hideShop();
return;
}
// Check section navigation
var sectionHeight = 30;
var sectionWidth = 150;
// Upgrades section
if (x >= upgradesSection.x - sectionWidth && x <= upgradesSection.x + sectionWidth && y >= upgradesSection.y - sectionHeight && y <= upgradesSection.y + sectionHeight) {
currentShopSection = 'upgrades';
upgradesSection.tint = 0x00FF00;
skinsSection.tint = 0xFFFFFF;
projectilesSection.tint = 0xFFFFFF;
// Show upgrades, hide others
upgrade1Text.visible = true;
upgrade2Text.visible = true;
upgrade3Text.visible = true;
upgrade4Text.visible = true;
upgrade5Text.visible = true;
upgrade6Text.visible = true;
return;
}
// Skins section
if (x >= skinsSection.x - sectionWidth && x <= skinsSection.x + sectionWidth && y >= skinsSection.y - sectionHeight && y <= skinsSection.y + sectionHeight) {
currentShopSection = 'skins';
upgradesSection.tint = 0xFFFFFF;
skinsSection.tint = 0x00FF00;
projectilesSection.tint = 0xFFFFFF;
// Hide upgrades and show skins
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
// Show skin elements
if (ownedSkins.indexOf('player2') >= 0) {
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
if (equippedSkin === 'player2') {
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
} else {
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
}
} else {
skin1Text.setText('Player Skin 2 - Price: 100 coins');
skin1EquipText.visible = false;
}
skin1Text.visible = true;
return;
}
// Projectiles section
if (x >= projectilesSection.x - sectionWidth && x <= projectilesSection.x + sectionWidth && y >= projectilesSection.y - sectionHeight && y <= projectilesSection.y + sectionHeight) {
currentShopSection = 'projectiles';
upgradesSection.tint = 0xFFFFFF;
skinsSection.tint = 0xFFFFFF;
projectilesSection.tint = 0x00FF00;
// Hide upgrades for now (projectiles not implemented yet)
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
return;
}
// Check upgrade purchases when in upgrades section
if (currentShopSection === 'upgrades') {
// Upgrade 1 - Double Damage Start
if (x >= upgrade1Text.x - upgradeWidth / 2 && x <= upgrade1Text.x + upgradeWidth / 2 && y >= upgrade1Text.y - upgradeHeight / 2 && y <= upgrade1Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.doubleDamagePrice) {
totalEarnings -= shopUpgrades.doubleDamagePrice;
shopUpgrades.doubleDamagePrice += 50;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade1Text.setText('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 2 - Unlimited Shooting Start
if (x >= upgrade2Text.x - upgradeWidth / 2 && x <= upgrade2Text.x + upgradeWidth / 2 && y >= upgrade2Text.y - upgradeHeight / 2 && y <= upgrade2Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.unlimitedShootingPrice) {
totalEarnings -= shopUpgrades.unlimitedShootingPrice;
shopUpgrades.unlimitedShootingPrice += 75;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade2Text.setText('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 3 - Extra Life
if (x >= upgrade3Text.x - upgradeWidth / 2 && x <= upgrade3Text.x + upgradeWidth / 2 && y >= upgrade3Text.y - upgradeHeight / 2 && y <= upgrade3Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.extraLifePrice) {
totalEarnings -= shopUpgrades.extraLifePrice;
shopUpgrades.extraLifePrice += 100;
maxLives += 1; // Increase max lives by 1
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade3Text.setText('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 4 - More Projectile
if (x >= upgrade4Text.x - upgradeWidth / 2 && x <= upgrade4Text.x + upgradeWidth / 2 && y >= upgrade4Text.y - upgradeHeight / 2 && y <= upgrade4Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.fastShootingPrice) {
totalEarnings -= shopUpgrades.fastShootingPrice;
shopUpgrades.fastShootingPrice += 60;
maxBullets += 1; // Increase max bullets by 1
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade4Text.setText('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 5 - Shield Power
if (x >= upgrade5Text.x - upgradeWidth / 2 && x <= upgrade5Text.x + upgradeWidth / 2 && y >= upgrade5Text.y - upgradeHeight / 2 && y <= upgrade5Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.shieldPrice) {
totalEarnings -= shopUpgrades.shieldPrice;
shopUpgrades.shieldPrice += 90;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade5Text.setText('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 6 - +1 Damage
if (x >= upgrade6Text.x - upgradeWidth / 2 && x <= upgrade6Text.x + upgradeWidth / 2 && y >= upgrade6Text.y - upgradeHeight / 2 && y <= upgrade6Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.damageUpgradePrice) {
totalEarnings -= shopUpgrades.damageUpgradePrice;
shopUpgrades.damageUpgradePrice += 125;
damageUpgrade += 1;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
storage.damageUpgrade = damageUpgrade;
upgrade6Text.setText('+1 Damage - Price: ' + shopUpgrades.damageUpgradePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
}
// Handle skin section interactions
if (currentShopSection === 'skins') {
// Skin purchase/equip button
if (x >= skin1Text.x - upgradeWidth / 2 && x <= skin1Text.x + upgradeWidth / 2 && y >= skin1Text.y - upgradeHeight / 2 && y <= skin1Text.y + upgradeHeight / 2) {
if (ownedSkins.indexOf('player2') < 0 && totalEarnings >= skinPrices.player2) {
// Purchase skin
totalEarnings -= skinPrices.player2;
ownedSkins.push('player2');
storage.totalEarnings = totalEarnings;
storage.ownedSkins = ownedSkins;
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Equip/Unequip button
if (skin1EquipText.visible && x >= skin1EquipText.x - 100 && x <= skin1EquipText.x + 100 && y >= skin1EquipText.y - 20 && y <= skin1EquipText.y + 20) {
if (equippedSkin === 'player2') {
// Unequip (revert to default)
equippedSkin = 'player';
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
} else {
// Equip this skin
equippedSkin = 'player2';
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
}
storage.equippedSkin = equippedSkin;
// Update player graphics immediately using the updateSkin method
player.updateSkin(equippedSkin);
}
return;
}
} else if (gameState === 'playing') {
dragActive = true;
lastTouchX = x;
lastTouchY = y;
shootBullet();
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && dragActive) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
player.x += deltaX;
player.y += deltaY;
// Keep player within screen bounds
if (player.x < 40) {
player.x = 40;
}
if (player.x > 2048 - 40) {
player.x = 2048 - 40;
}
if (player.y < 40) {
player.y = 40;
}
if (player.y > 2732 - 40) {
player.y = 2732 - 40;
}
lastTouchX = x;
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
dragActive = false;
}
};
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Handle challenge timer (only when not in rock mode)
if (!rockActive) {
challengeTimer++;
if (challengeTimer >= challengeTimeLimit) {
// Time limit reached - game over
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
updateTimer();
}
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer % 400 === 0 && spawnRate > 20) {
spawnRate -= 3;
}
// Check if there's a rock to determine if we should spawn normal objects
var hasRockForSpawning = false;
for (var rs = 0; rs < fallingObjects.length; rs++) {
if (fallingObjects[rs].type === 'rock') {
hasRockForSpawning = true;
break;
}
}
// Spawn falling objects with consistent timing only if no rock is present
if (!hasRockForSpawning) {
spawnTimer++;
if (spawnTimer >= spawnRate) {
spawnFallingObject();
spawnTimer = 0;
}
} else {
spawnTimer = 0; // Reset spawn timer when rock is present
}
// Handle double damage timer
if (doubleDamageActive) {
doubleDamageTimer++;
if (doubleDamageTimer >= doubleDamageTimeLimit) {
doubleDamageActive = false;
doubleDamageTimer = 0;
}
}
// Handle unlimited shooting timer
if (unlimitedShootingActive) {
unlimitedShootingTimer++;
if (unlimitedShootingTimer >= unlimitedShootingTimeLimit) {
unlimitedShootingActive = false;
unlimitedShootingTimer = 0;
}
}
updatePowerUpDisplay();
// Update power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
if (powerUp.lastY === undefined) {
powerUp.lastY = powerUp.y;
}
// Remove power-ups that fall off screen
if (powerUp.lastY <= 2732 + 50 && powerUp.y > 2732 + 50) {
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
// Check power-up type and activate accordingly
if (powerUp.powerUpType === 'doubleDamage') {
doubleDamageActive = true;
doubleDamageTimer = 0;
} else if (powerUp.powerUpType === 'unlimitedShooting') {
unlimitedShootingActive = true;
unlimitedShootingTimer = 0;
} else if (powerUp.powerUpType === 'health') {
if (lives < maxLives) {
lives++;
updateLives();
}
} else if (powerUp.powerUpType === 'clearScreen') {
// Destroy all objects except rocks and swords
for (var cs = fallingObjects.length - 1; cs >= 0; cs--) {
var objToClear = fallingObjects[cs];
// Check if object still exists before clearing
if (!objToClear || !objToClear.parent) {
fallingObjects.splice(cs, 1);
continue;
}
if (objToClear.type !== 'rock') {
// Create explosion effect for cleared objects
tween(objToClear, {
scaleX: 2,
scaleY: 2,
alpha: 0,
tint: 0xffaa00
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
objToClear.destroy();
}
});
fallingObjects.splice(cs, 1);
}
}
}
// Visual effect
tween(powerUp, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
powerUp.destroy();
}
});
powerUps.splice(p, 1);
continue;
}
powerUp.lastY = powerUp.y;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet still exists and hasn't been destroyed
if (!bullet || !bullet.parent) {
bullets.splice(i, 1);
continue;
}
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -50 && bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet collision with falling objects
for (var j = fallingObjects.length - 1; j >= 0; j--) {
var obj = fallingObjects[j];
// Check if objects still exist before checking intersection
if (!obj || !obj.parent || !bullet || !bullet.parent) {
continue;
}
if (bullet.intersects(obj)) {
// Reduce hit points (double damage if power-up is active, plus upgrade damage)
var baseDamage = 1 + damageUpgrade;
var damage = doubleDamageActive ? baseDamage * 2 : baseDamage;
obj.hitPoints -= damage;
// Flash object to show it was hit
var hitTint = 0xff0000;
var originalTint = obj.tint || 0xffffff;
tween(obj, {
tint: hitTint
}, {
duration: 100,
onFinish: function onFinish() {
tween(obj, {
tint: originalTint
}, {
duration: 100
});
}
});
// Destroy bullet
bullet.destroy();
bullets.splice(i, 1);
// Check if object should be destroyed
if (obj.hitPoints <= 0) {
if (obj.type === 'rock') {
LK.setScore(LK.getScore() + 50);
lives = maxLives; // Restore full health
updateLives();
rockActive = false;
resetChallenge();
} else {
LK.setScore(LK.getScore() + 1);
objectsDestroyed++;
// Track bat destruction for power-up
if (obj.type === 'bat') {
batsDestroyed++;
// Spawn power-up every 10 bats destroyed
if (batsDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'doubleDamage');
}
}
// Track sword destruction for power-up
if (obj.type === 'sword') {
swordsDestroyed++;
// Spawn unlimited shooting power-up every 10 swords destroyed
if (swordsDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'unlimitedShooting');
}
}
// Track knife destruction for health power-up
if (obj.type === 'knife') {
knivesDestroyed++;
// Spawn health power-up every 10 knives destroyed
if (knivesDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'health');
}
}
// Track stick destruction for clear screen power-up
if (obj.type === 'stick') {
sticksDestroyed++;
// Spawn clear screen power-up every 10 sticks destroyed
if (sticksDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'clearScreen');
}
}
// Check if challenge is completed (only when no rock is active)
if (!rockActive && objectsDestroyed >= challengeTarget) {
challengesCompleted++;
if (challengesCompleted % 5 === 0) {
spawnRock();
} else {
resetChallenge();
}
}
// Add coins based on score when objects are destroyed
totalEarnings += 1;
storage.totalEarnings = totalEarnings;
}
updateScore();
LK.getSound('destroy').play();
// Create explosion effect
tween(obj, {
scaleX: 3,
scaleY: 3,
alpha: 0,
tint: 0xffaa00
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
obj.destroy();
}
});
fallingObjects.splice(j, 1);
} else {
LK.getSound('hit').play();
}
break;
}
}
if (bullets[i]) {
bullet.lastY = bullet.y;
}
}
// Check if there's a rock and handle bat spawning timer
var hasRock = false;
for (var r = 0; r < fallingObjects.length; r++) {
if (fallingObjects[r].type === 'rock') {
hasRock = true;
break;
}
}
if (hasRock) {
rockBatTimer++;
if (rockBatTimer >= rockBatSpawnRate) {
spawnRockBats();
rockBatTimer = 0;
}
} else {
rockBatTimer = 0;
}
// Update falling objects
for (var k = fallingObjects.length - 1; k >= 0; k--) {
var fallingObj = fallingObjects[k];
// Check if object still exists and hasn't been destroyed
if (!fallingObj || !fallingObj.parent) {
fallingObjects.splice(k, 1);
continue;
}
if (fallingObj.lastY === undefined) {
fallingObj.lastY = fallingObj.y;
}
// Handle rock horizontal movement
if (fallingObj.type === 'rock') {
fallingObj.x += fallingObj.horizontalSpeed * fallingObj.direction;
// Bounce off screen edges
if (fallingObj.x <= 50 || fallingObj.x >= 2048 - 50) {
fallingObj.direction *= -1;
}
}
// Remove objects that fall off screen
if (fallingObj.lastY <= 2732 + 50 && fallingObj.y > 2732 + 50) {
fallingObj.destroy();
fallingObjects.splice(k, 1);
continue;
}
// Check collision with player
if (fallingObj.intersects(player)) {
// If player touches rock, instant game over
if (fallingObj.type === 'rock') {
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
lives--;
updateLives();
LK.getSound('hit').play();
// Flash player red
tween(player, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(player, {
tint: 0xffffff
}, {
duration: 200
});
}
});
fallingObj.destroy();
fallingObjects.splice(k, 1);
if (lives <= 0) {
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
continue;
}
fallingObj.lastY = fallingObj.y;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
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.update = function () {
self.y += self.speed;
};
return self;
});
var FallingObject = Container.expand(function (type) {
var self = Container.call(this);
var objectGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = (Math.random() * 3 + 2) * 2;
self.type = type;
// Set hit points based on object type
if (type === 'bat') {
self.hitPoints = 2;
} else if (type === 'stick') {
self.hitPoints = 1;
} else if (type === 'knife') {
self.hitPoints = 1;
} else if (type === 'sword') {
self.hitPoints = 4;
} else if (type === 'rock') {
self.hitPoints = 25;
}
self.maxHitPoints = self.hitPoints;
self.update = function () {
self.y += self.speed;
self.rotation += 0.05;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset(equippedSkin, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.shootCooldown = 0;
self.updateSkin = function (newSkin) {
self.removeChildren();
playerGraphics = self.attachAsset(newSkin, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.update = function () {
self.y += self.speed;
self.rotation += 0.1;
// Pulse effect
self.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
self.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state management
var gameState = 'menu'; // 'menu', 'playing', or 'shop'
// Shop variables
var totalEarnings = storage.totalEarnings || 0;
var currentShopSection = 'upgrades'; // Track current shop section
var shopUpgrades = {
doubleDamagePrice: storage.savedDoubleDamage || 100,
unlimitedShootingPrice: storage.savedUnlimitedShooting || 150,
extraLifePrice: storage.savedExtraLife || 200,
fastShootingPrice: storage.savedFastShooting || 120,
shieldPrice: storage.savedShield || 180,
damageUpgradePrice: storage.savedDamageUpgradePrice || 150
};
// Skin system variables
var ownedSkins = storage.ownedSkins || ['player']; // Default skin is always owned
var equippedSkin = storage.equippedSkin || 'player';
var skinPrices = {
player2: 100
};
// Add blue background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
// Menu elements
var titleText = new Text2('Dodge & Destroy', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 2732 / 2 - 200;
game.addChild(titleText);
var playButton = new Text2('PLAY', {
size: 80,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0.5);
playButton.x = 2048 / 2;
playButton.y = 2732 / 2 + 100;
game.addChild(playButton);
var shopButton = new Text2('SHOP', {
size: 80,
fill: 0xFFD700
});
shopButton.anchor.set(0.5, 0.5);
shopButton.x = 2048 / 2;
shopButton.y = 2732 / 2 + 200;
game.addChild(shopButton);
var saveButton = new Text2('SAVE', {
size: 60,
fill: 0x00FFFF
});
saveButton.anchor.set(0.5, 0.5);
saveButton.x = 2048 / 2 - 200;
saveButton.y = 2732 / 2 + 300;
game.addChild(saveButton);
var loadButton = new Text2('LOAD', {
size: 60,
fill: 0xFF00FF
});
loadButton.anchor.set(0.5, 0.5);
loadButton.x = 2048 / 2 + 200;
loadButton.y = 2732 / 2 + 300;
game.addChild(loadButton);
// Save confirmation message
var saveMessageText = new Text2('PROGRESS SAVED', {
size: 70,
fill: 0x00FF00
});
saveMessageText.anchor.set(0.5, 0.5);
saveMessageText.x = 2048 / 2;
saveMessageText.y = 2732 / 2 - 100;
saveMessageText.visible = false;
game.addChild(saveMessageText);
// Load confirmation message
var loadMessageText = new Text2('PROGRESS RESTORED', {
size: 70,
fill: 0x00FFFF
});
loadMessageText.anchor.set(0.5, 0.5);
loadMessageText.x = 2048 / 2;
loadMessageText.y = 2732 / 2 - 100;
loadMessageText.visible = false;
game.addChild(loadMessageText);
// Game version text
var versionText = new Text2('Game version: V1.00', {
size: 40,
fill: 0xFFFFFF
});
versionText.anchor.set(0, 1);
versionText.x = 120;
versionText.y = 2732 - 20;
game.addChild(versionText);
// Shop UI elements (initially hidden)
var shopTitle = new Text2('SHOP', {
size: 100,
fill: 0xFFD700
});
shopTitle.anchor.set(0.5, 0.5);
shopTitle.x = 2048 / 2;
shopTitle.y = 300;
shopTitle.visible = false;
game.addChild(shopTitle);
var coinsText = new Text2('Coins: ' + totalEarnings, {
size: 60,
fill: 0xFFFFFF
});
coinsText.anchor.set(0.5, 0.5);
coinsText.x = 2048 / 2;
coinsText.y = 400;
coinsText.visible = false;
game.addChild(coinsText);
// Shop upgrades
var upgrade1Text = new Text2('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade1Text.anchor.set(0.5, 0.5);
upgrade1Text.x = 2048 / 2;
upgrade1Text.y = 600;
upgrade1Text.visible = false;
game.addChild(upgrade1Text);
var upgrade2Text = new Text2('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade2Text.anchor.set(0.5, 0.5);
upgrade2Text.x = 2048 / 2;
upgrade2Text.y = 700;
upgrade2Text.visible = false;
game.addChild(upgrade2Text);
var upgrade3Text = new Text2('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade3Text.anchor.set(0.5, 0.5);
upgrade3Text.x = 2048 / 2;
upgrade3Text.y = 800;
upgrade3Text.visible = false;
game.addChild(upgrade3Text);
var upgrade4Text = new Text2('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade4Text.anchor.set(0.5, 0.5);
upgrade4Text.x = 2048 / 2;
upgrade4Text.y = 900;
upgrade4Text.visible = false;
game.addChild(upgrade4Text);
var upgrade5Text = new Text2('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins', {
size: 50,
fill: 0x00FF00
});
upgrade5Text.anchor.set(0.5, 0.5);
upgrade5Text.x = 2048 / 2;
upgrade5Text.y = 1000;
upgrade5Text.visible = false;
game.addChild(upgrade5Text);
var upgrade6Text = new Text2('+1 Damage - Price: 150 coins', {
size: 50,
fill: 0x00FF00
});
upgrade6Text.anchor.set(0.5, 0.5);
upgrade6Text.x = 2048 / 2;
upgrade6Text.y = 1100;
upgrade6Text.visible = false;
game.addChild(upgrade6Text);
// Shop section navigation
var upgradesSection = new Text2('UPGRADES', {
size: 60,
fill: 0x00FF00
});
upgradesSection.anchor.set(0.5, 0.5);
upgradesSection.x = 2048 / 2 - 300;
upgradesSection.y = 500;
upgradesSection.visible = false;
game.addChild(upgradesSection);
var skinsSection = new Text2('SKINS', {
size: 60,
fill: 0xFFFFFF
});
skinsSection.anchor.set(0.5, 0.5);
skinsSection.x = 2048 / 2;
skinsSection.y = 500;
skinsSection.visible = false;
game.addChild(skinsSection);
var projectilesSection = new Text2('PROJECTILES', {
size: 60,
fill: 0xFFFFFF
});
projectilesSection.anchor.set(0.5, 0.5);
projectilesSection.x = 2048 / 2 + 300;
projectilesSection.y = 500;
projectilesSection.visible = false;
game.addChild(projectilesSection);
// Skin shop elements
var skin1Text = new Text2('Player Skin 2 - Price: 100 coins', {
size: 50,
fill: 0x00FF00
});
skin1Text.anchor.set(0.5, 0.5);
skin1Text.x = 2048 / 2;
skin1Text.y = 600;
skin1Text.visible = false;
game.addChild(skin1Text);
var skin1EquipText = new Text2('EQUIP', {
size: 40,
fill: 0xFFD700
});
skin1EquipText.anchor.set(0.5, 0.5);
skin1EquipText.x = 2048 / 2;
skin1EquipText.y = 650;
skin1EquipText.visible = false;
game.addChild(skin1EquipText);
var backButton = new Text2('BACK', {
size: 70,
fill: 0xFF4444
});
backButton.anchor.set(0.5, 0.5);
backButton.x = 2048 / 2;
backButton.y = 1200;
backButton.visible = false;
game.addChild(backButton);
// Start title music
LK.playMusic('title_music');
// Game elements (initially hidden)
var player = game.addChild(new Player());
player.x = 2048 / 2;
player.y = 2732 - 200;
player.visible = false;
var bullets = [];
var fallingObjects = [];
var lives = 3;
var maxLives = 3;
var objectTypes = ['knife', 'sword', 'bat', 'stick'];
var spawnTimer = 0;
var spawnRate = 60;
var difficultyTimer = 0;
var maxBullets = 3;
// Challenge variables
var objectsDestroyed = 0;
var challengeTarget = 5;
var challengesCompleted = 0;
var rockActive = false;
var rockBatTimer = 0;
var rockBatSpawnRate = 420; // 7 seconds at 60 FPS
var challengeTimer = 0;
var challengeTimeLimit = 900; // 15 seconds at 60 FPS
var currentChallenge = 0; // Track current challenge number
// Power-up variables
var batsDestroyed = 0;
var swordsDestroyed = 0;
var knivesDestroyed = 0;
var sticksDestroyed = 0;
var powerUps = [];
var doubleDamageActive = false;
var doubleDamageTimer = 0;
var doubleDamageTimeLimit = 600; // 10 seconds at 60 FPS
var unlimitedShootingActive = false;
var unlimitedShootingTimer = 0;
var unlimitedShootingTimeLimit = 600; // 10 seconds at 60 FPS
var damageUpgrade = storage.damageUpgrade || 0;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
scoreText.y = 50;
scoreText.visible = false;
LK.gui.topLeft.addChild(scoreText);
var livesText = new Text2('Lives: 3', {
size: 60,
fill: 0xFF4444
});
livesText.anchor.set(1, 0);
livesText.visible = false;
LK.gui.topRight.addChild(livesText);
var timerText = new Text2('Target: 5', {
size: 50,
fill: 0xFFFF00
});
timerText.anchor.set(0.5, 0);
timerText.x = 0;
timerText.y = 50;
timerText.visible = false;
LK.gui.top.addChild(timerText);
var powerUpText = new Text2('', {
size: 45,
fill: 0x00FF00
});
powerUpText.anchor.set(0.5, 0);
powerUpText.x = 0;
powerUpText.y = 120;
powerUpText.visible = false;
LK.gui.top.addChild(powerUpText);
var dragActive = false;
var lastTouchX = 0;
var lastTouchY = 0;
function showShop() {
gameState = 'shop';
// Hide menu elements
titleText.visible = false;
playButton.visible = false;
shopButton.visible = false;
saveButton.visible = false;
loadButton.visible = false;
saveMessageText.visible = false;
loadMessageText.visible = false;
// Show shop elements
shopTitle.visible = true;
coinsText.visible = true;
upgradesSection.visible = true;
skinsSection.visible = true;
projectilesSection.visible = true;
backButton.visible = true;
// Show appropriate section elements
if (currentShopSection === 'upgrades') {
upgrade1Text.visible = true;
upgrade2Text.visible = true;
upgrade3Text.visible = true;
upgrade4Text.visible = true;
upgrade5Text.visible = true;
upgrade6Text.visible = true;
} else if (currentShopSection === 'skins') {
// Update skin text based on ownership
if (ownedSkins.indexOf('player2') >= 0) {
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
if (equippedSkin === 'player2') {
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
} else {
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
}
} else {
skin1Text.setText('Player Skin 2 - Price: 100 coins');
skin1EquipText.visible = false;
}
skin1Text.visible = true;
}
// Update section colors based on current section
if (currentShopSection === 'upgrades') {
upgradesSection.tint = 0x00FF00;
} else {
upgradesSection.tint = 0xFFFFFF;
}
if (currentShopSection === 'skins') {
skinsSection.tint = 0x00FF00;
} else {
skinsSection.tint = 0xFFFFFF;
}
projectilesSection.tint = 0xFFFFFF;
// Update coins display
coinsText.setText('Coins: ' + totalEarnings);
}
function hideShop() {
gameState = 'menu';
// Hide shop elements
shopTitle.visible = false;
coinsText.visible = false;
upgradesSection.visible = false;
skinsSection.visible = false;
projectilesSection.visible = false;
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
skin1Text.visible = false;
skin1EquipText.visible = false;
backButton.visible = false;
// Show menu elements
titleText.visible = true;
playButton.visible = true;
shopButton.visible = true;
saveButton.visible = true;
loadButton.visible = true;
}
function saveGame() {
// Save current upgrades and earnings using individual properties
storage.savedDoubleDamage = shopUpgrades.doubleDamagePrice;
storage.savedUnlimitedShooting = shopUpgrades.unlimitedShootingPrice;
storage.savedExtraLife = shopUpgrades.extraLifePrice;
storage.savedFastShooting = shopUpgrades.fastShootingPrice;
storage.savedShield = shopUpgrades.shieldPrice;
storage.savedDamageUpgradePrice = shopUpgrades.damageUpgradePrice;
storage.savedEarnings = totalEarnings;
storage.damageUpgrade = damageUpgrade;
storage.ownedSkins = ownedSkins;
storage.equippedSkin = equippedSkin;
storage.totalEarnings = totalEarnings;
}
function loadGame() {
// Load saved upgrades and earnings if they exist using individual properties
if (storage.savedDoubleDamage !== undefined) {
shopUpgrades.doubleDamagePrice = storage.savedDoubleDamage;
}
if (storage.savedUnlimitedShooting !== undefined) {
shopUpgrades.unlimitedShootingPrice = storage.savedUnlimitedShooting;
}
if (storage.savedExtraLife !== undefined) {
shopUpgrades.extraLifePrice = storage.savedExtraLife;
}
if (storage.savedFastShooting !== undefined) {
shopUpgrades.fastShootingPrice = storage.savedFastShooting;
}
if (storage.savedShield !== undefined) {
shopUpgrades.shieldPrice = storage.savedShield;
}
if (storage.savedDamageUpgradePrice !== undefined) {
shopUpgrades.damageUpgradePrice = storage.savedDamageUpgradePrice;
}
if (storage.savedEarnings !== undefined) {
totalEarnings = storage.savedEarnings;
}
if (storage.damageUpgrade !== undefined) {
damageUpgrade = storage.damageUpgrade;
}
if (storage.ownedSkins) {
ownedSkins = storage.ownedSkins;
}
if (storage.equippedSkin) {
equippedSkin = storage.equippedSkin;
}
// Update shop display texts
upgrade1Text.setText('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins');
upgrade2Text.setText('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins');
upgrade3Text.setText('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins');
upgrade4Text.setText('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins');
upgrade5Text.setText('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins');
upgrade6Text.setText('+1 Damage - Price: ' + shopUpgrades.damageUpgradePrice + ' coins');
// Update coins display in shop
coinsText.setText('Coins: ' + totalEarnings);
}
function showSaveMessage() {
// Show the save message
saveMessageText.visible = true;
saveMessageText.alpha = 1;
// Hide the message after 10 seconds using tween
tween(saveMessageText, {
alpha: 0
}, {
duration: 10000,
easing: tween.linear,
onFinish: function onFinish() {
saveMessageText.visible = false;
}
});
}
function showLoadMessage() {
// Show the load message
loadMessageText.visible = true;
loadMessageText.alpha = 1;
// Hide the message after 10 seconds using tween
tween(loadMessageText, {
alpha: 0
}, {
duration: 10000,
easing: tween.linear,
onFinish: function onFinish() {
loadMessageText.visible = false;
}
});
}
function startGame() {
gameState = 'playing';
// Hide menu elements
titleText.visible = false;
playButton.visible = false;
shopButton.visible = false;
saveButton.visible = false;
loadButton.visible = false;
saveMessageText.visible = false;
loadMessageText.visible = false;
// Show game elements
player.visible = true;
scoreText.visible = true;
livesText.visible = true;
timerText.visible = true;
powerUpText.visible = true;
// Stop title music and start survival piano music
LK.stopMusic();
LK.playMusic('survival_piano');
// Reset game variables
lives = maxLives;
objectsDestroyed = 0;
challengesCompleted = 0;
rockActive = false;
challengeTimer = 0;
// Reset power-up variables
batsDestroyed = 0;
swordsDestroyed = 0;
knivesDestroyed = 0;
sticksDestroyed = 0;
doubleDamageActive = false;
doubleDamageTimer = 0;
unlimitedShootingActive = false;
unlimitedShootingTimer = 0;
powerUps = [];
LK.setScore(0);
updateScore();
updateLives();
updateTimer();
}
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
}
function updateLives() {
livesText.setText('Lives: ' + lives);
}
function updateTimer() {
if (rockActive) {
timerText.setText('DESTROY THE ROCK!');
} else {
var remaining = Math.max(0, challengeTarget - objectsDestroyed);
var timeLeft = Math.ceil((challengeTimeLimit - challengeTimer) / 60);
timerText.setText('Target: ' + remaining + ' | Time: ' + timeLeft + 's');
}
}
function spawnFallingObject() {
var type = objectTypes[Math.floor(Math.random() * objectTypes.length)];
var obj = new FallingObject(type);
obj.x = Math.random() * (2048 - 100) + 50;
obj.y = -50;
fallingObjects.push(obj);
game.addChild(obj);
}
function spawnRock() {
var rock = new FallingObject('rock');
rock.x = 2048 / 2; // Center of screen
rock.y = 200; // Fixed Y position
rock.speed = 0; // No forward movement
rock.horizontalSpeed = 3; // Side to side movement speed
rock.direction = Math.random() < 0.5 ? -1 : 1; // Random initial direction
fallingObjects.push(rock);
game.addChild(rock);
rockActive = true;
updateTimer();
}
function resetChallenge() {
objectsDestroyed = 0;
challengeTimer = 0;
currentChallenge++;
updateTimer();
}
function spawnRockBats() {
for (var i = 0; i < 10; i++) {
var bat = new FallingObject('bat');
bat.x = 2048 / 11 * (i + 1); // Distribute evenly across screen
bat.y = -50;
fallingObjects.push(bat);
game.addChild(bat);
}
}
function spawnPowerUp(x, y, type) {
var powerUp = new PowerUp();
powerUp.x = x;
powerUp.y = y;
powerUp.powerUpType = type || 'doubleDamage';
powerUps.push(powerUp);
game.addChild(powerUp);
}
function updatePowerUpDisplay() {
if (doubleDamageActive && unlimitedShootingActive) {
var doubleDamageTimeLeft = Math.ceil((doubleDamageTimeLimit - doubleDamageTimer) / 60);
var unlimitedTimeLeft = Math.ceil((unlimitedShootingTimeLimit - unlimitedShootingTimer) / 60);
powerUpText.setText('DOUBLE DAMAGE: ' + doubleDamageTimeLeft + 's | UNLIMITED: ' + unlimitedTimeLeft + 's');
} else if (doubleDamageActive) {
var timeLeft = Math.ceil((doubleDamageTimeLimit - doubleDamageTimer) / 60);
powerUpText.setText('DOUBLE DAMAGE: ' + timeLeft + 's');
} else if (unlimitedShootingActive) {
var timeLeft = Math.ceil((unlimitedShootingTimeLimit - unlimitedShootingTimer) / 60);
powerUpText.setText('UNLIMITED SHOOTING: ' + timeLeft + 's');
} else {
powerUpText.setText('');
}
}
function shootBullet() {
var canShoot = unlimitedShootingActive || player.shootCooldown <= 0 && bullets.length < maxBullets;
if (canShoot) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y - 40;
bullets.push(bullet);
game.addChild(bullet);
if (!unlimitedShootingActive) {
player.shootCooldown = 15;
}
LK.getSound('shoot').play();
}
}
game.down = function (x, y, obj) {
if (gameState === 'menu') {
// Check if play button was tapped
var playButtonBounds = {
left: playButton.x - 100,
right: playButton.x + 100,
top: playButton.y - 50,
bottom: playButton.y + 50
};
if (x >= playButtonBounds.left && x <= playButtonBounds.right && y >= playButtonBounds.top && y <= playButtonBounds.bottom) {
startGame();
}
// Check if shop button was tapped
var shopButtonBounds = {
left: shopButton.x - 100,
right: shopButton.x + 100,
top: shopButton.y - 50,
bottom: shopButton.y + 50
};
if (x >= shopButtonBounds.left && x <= shopButtonBounds.right && y >= shopButtonBounds.top && y <= shopButtonBounds.bottom) {
showShop();
}
// Check if save button was tapped
var saveButtonBounds = {
left: saveButton.x - 80,
right: saveButton.x + 80,
top: saveButton.y - 40,
bottom: saveButton.y + 40
};
if (x >= saveButtonBounds.left && x <= saveButtonBounds.right && y >= saveButtonBounds.top && y <= saveButtonBounds.bottom) {
saveGame();
showSaveMessage();
}
// Check if load button was tapped
var loadButtonBounds = {
left: loadButton.x - 80,
right: loadButton.x + 80,
top: loadButton.y - 40,
bottom: loadButton.y + 40
};
if (x >= loadButtonBounds.left && x <= loadButtonBounds.right && y >= loadButtonBounds.top && y <= loadButtonBounds.bottom) {
loadGame();
showLoadMessage();
}
} else if (gameState === 'shop') {
// Check upgrade buttons
var upgradeHeight = 50;
var upgradeWidth = 800;
// Back button
var backButtonBounds = {
left: backButton.x - 100,
right: backButton.x + 100,
top: backButton.y - 40,
bottom: backButton.y + 40
};
if (x >= backButtonBounds.left && x <= backButtonBounds.right && y >= backButtonBounds.top && y <= backButtonBounds.bottom) {
hideShop();
return;
}
// Check section navigation
var sectionHeight = 30;
var sectionWidth = 150;
// Upgrades section
if (x >= upgradesSection.x - sectionWidth && x <= upgradesSection.x + sectionWidth && y >= upgradesSection.y - sectionHeight && y <= upgradesSection.y + sectionHeight) {
currentShopSection = 'upgrades';
upgradesSection.tint = 0x00FF00;
skinsSection.tint = 0xFFFFFF;
projectilesSection.tint = 0xFFFFFF;
// Show upgrades, hide others
upgrade1Text.visible = true;
upgrade2Text.visible = true;
upgrade3Text.visible = true;
upgrade4Text.visible = true;
upgrade5Text.visible = true;
upgrade6Text.visible = true;
return;
}
// Skins section
if (x >= skinsSection.x - sectionWidth && x <= skinsSection.x + sectionWidth && y >= skinsSection.y - sectionHeight && y <= skinsSection.y + sectionHeight) {
currentShopSection = 'skins';
upgradesSection.tint = 0xFFFFFF;
skinsSection.tint = 0x00FF00;
projectilesSection.tint = 0xFFFFFF;
// Hide upgrades and show skins
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
// Show skin elements
if (ownedSkins.indexOf('player2') >= 0) {
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
if (equippedSkin === 'player2') {
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
} else {
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
}
} else {
skin1Text.setText('Player Skin 2 - Price: 100 coins');
skin1EquipText.visible = false;
}
skin1Text.visible = true;
return;
}
// Projectiles section
if (x >= projectilesSection.x - sectionWidth && x <= projectilesSection.x + sectionWidth && y >= projectilesSection.y - sectionHeight && y <= projectilesSection.y + sectionHeight) {
currentShopSection = 'projectiles';
upgradesSection.tint = 0xFFFFFF;
skinsSection.tint = 0xFFFFFF;
projectilesSection.tint = 0x00FF00;
// Hide upgrades for now (projectiles not implemented yet)
upgrade1Text.visible = false;
upgrade2Text.visible = false;
upgrade3Text.visible = false;
upgrade4Text.visible = false;
upgrade5Text.visible = false;
upgrade6Text.visible = false;
return;
}
// Check upgrade purchases when in upgrades section
if (currentShopSection === 'upgrades') {
// Upgrade 1 - Double Damage Start
if (x >= upgrade1Text.x - upgradeWidth / 2 && x <= upgrade1Text.x + upgradeWidth / 2 && y >= upgrade1Text.y - upgradeHeight / 2 && y <= upgrade1Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.doubleDamagePrice) {
totalEarnings -= shopUpgrades.doubleDamagePrice;
shopUpgrades.doubleDamagePrice += 50;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade1Text.setText('Double Damage Start - Price: ' + shopUpgrades.doubleDamagePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 2 - Unlimited Shooting Start
if (x >= upgrade2Text.x - upgradeWidth / 2 && x <= upgrade2Text.x + upgradeWidth / 2 && y >= upgrade2Text.y - upgradeHeight / 2 && y <= upgrade2Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.unlimitedShootingPrice) {
totalEarnings -= shopUpgrades.unlimitedShootingPrice;
shopUpgrades.unlimitedShootingPrice += 75;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade2Text.setText('Unlimited Shooting Start - Price: ' + shopUpgrades.unlimitedShootingPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 3 - Extra Life
if (x >= upgrade3Text.x - upgradeWidth / 2 && x <= upgrade3Text.x + upgradeWidth / 2 && y >= upgrade3Text.y - upgradeHeight / 2 && y <= upgrade3Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.extraLifePrice) {
totalEarnings -= shopUpgrades.extraLifePrice;
shopUpgrades.extraLifePrice += 100;
maxLives += 1; // Increase max lives by 1
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade3Text.setText('Extra Life - Price: ' + shopUpgrades.extraLifePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 4 - More Projectile
if (x >= upgrade4Text.x - upgradeWidth / 2 && x <= upgrade4Text.x + upgradeWidth / 2 && y >= upgrade4Text.y - upgradeHeight / 2 && y <= upgrade4Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.fastShootingPrice) {
totalEarnings -= shopUpgrades.fastShootingPrice;
shopUpgrades.fastShootingPrice += 60;
maxBullets += 1; // Increase max bullets by 1
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade4Text.setText('More Projectile - Price: ' + shopUpgrades.fastShootingPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 5 - Shield Power
if (x >= upgrade5Text.x - upgradeWidth / 2 && x <= upgrade5Text.x + upgradeWidth / 2 && y >= upgrade5Text.y - upgradeHeight / 2 && y <= upgrade5Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.shieldPrice) {
totalEarnings -= shopUpgrades.shieldPrice;
shopUpgrades.shieldPrice += 90;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
upgrade5Text.setText('Shield (2 hits = 1 life) - Price: ' + shopUpgrades.shieldPrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Upgrade 6 - +1 Damage
if (x >= upgrade6Text.x - upgradeWidth / 2 && x <= upgrade6Text.x + upgradeWidth / 2 && y >= upgrade6Text.y - upgradeHeight / 2 && y <= upgrade6Text.y + upgradeHeight / 2) {
if (totalEarnings >= shopUpgrades.damageUpgradePrice) {
totalEarnings -= shopUpgrades.damageUpgradePrice;
shopUpgrades.damageUpgradePrice += 125;
damageUpgrade += 1;
storage.totalEarnings = totalEarnings;
// Removed invalid nested object assignment - use individual properties instead
storage.damageUpgrade = damageUpgrade;
upgrade6Text.setText('+1 Damage - Price: ' + shopUpgrades.damageUpgradePrice + ' coins');
coinsText.setText('Coins: ' + totalEarnings);
}
}
}
// Handle skin section interactions
if (currentShopSection === 'skins') {
// Skin purchase/equip button
if (x >= skin1Text.x - upgradeWidth / 2 && x <= skin1Text.x + upgradeWidth / 2 && y >= skin1Text.y - upgradeHeight / 2 && y <= skin1Text.y + upgradeHeight / 2) {
if (ownedSkins.indexOf('player2') < 0 && totalEarnings >= skinPrices.player2) {
// Purchase skin
totalEarnings -= skinPrices.player2;
ownedSkins.push('player2');
storage.totalEarnings = totalEarnings;
storage.ownedSkins = ownedSkins;
skin1Text.setText('Player Skin 2 - OWNED');
skin1EquipText.visible = true;
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
coinsText.setText('Coins: ' + totalEarnings);
}
}
// Equip/Unequip button
if (skin1EquipText.visible && x >= skin1EquipText.x - 100 && x <= skin1EquipText.x + 100 && y >= skin1EquipText.y - 20 && y <= skin1EquipText.y + 20) {
if (equippedSkin === 'player2') {
// Unequip (revert to default)
equippedSkin = 'player';
skin1EquipText.setText('EQUIP');
skin1EquipText.tint = 0xFFD700;
} else {
// Equip this skin
equippedSkin = 'player2';
skin1EquipText.setText('UNEQUIP');
skin1EquipText.tint = 0xFF4444;
}
storage.equippedSkin = equippedSkin;
// Update player graphics immediately using the updateSkin method
player.updateSkin(equippedSkin);
}
return;
}
} else if (gameState === 'playing') {
dragActive = true;
lastTouchX = x;
lastTouchY = y;
shootBullet();
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && dragActive) {
var deltaX = x - lastTouchX;
var deltaY = y - lastTouchY;
player.x += deltaX;
player.y += deltaY;
// Keep player within screen bounds
if (player.x < 40) {
player.x = 40;
}
if (player.x > 2048 - 40) {
player.x = 2048 - 40;
}
if (player.y < 40) {
player.y = 40;
}
if (player.y > 2732 - 40) {
player.y = 2732 - 40;
}
lastTouchX = x;
lastTouchY = y;
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
dragActive = false;
}
};
game.update = function () {
if (gameState !== 'playing') {
return;
}
// Handle challenge timer (only when not in rock mode)
if (!rockActive) {
challengeTimer++;
if (challengeTimer >= challengeTimeLimit) {
// Time limit reached - game over
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
updateTimer();
}
// Increase difficulty over time
difficultyTimer++;
if (difficultyTimer % 400 === 0 && spawnRate > 20) {
spawnRate -= 3;
}
// Check if there's a rock to determine if we should spawn normal objects
var hasRockForSpawning = false;
for (var rs = 0; rs < fallingObjects.length; rs++) {
if (fallingObjects[rs].type === 'rock') {
hasRockForSpawning = true;
break;
}
}
// Spawn falling objects with consistent timing only if no rock is present
if (!hasRockForSpawning) {
spawnTimer++;
if (spawnTimer >= spawnRate) {
spawnFallingObject();
spawnTimer = 0;
}
} else {
spawnTimer = 0; // Reset spawn timer when rock is present
}
// Handle double damage timer
if (doubleDamageActive) {
doubleDamageTimer++;
if (doubleDamageTimer >= doubleDamageTimeLimit) {
doubleDamageActive = false;
doubleDamageTimer = 0;
}
}
// Handle unlimited shooting timer
if (unlimitedShootingActive) {
unlimitedShootingTimer++;
if (unlimitedShootingTimer >= unlimitedShootingTimeLimit) {
unlimitedShootingActive = false;
unlimitedShootingTimer = 0;
}
}
updatePowerUpDisplay();
// Update power-ups
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
if (powerUp.lastY === undefined) {
powerUp.lastY = powerUp.y;
}
// Remove power-ups that fall off screen
if (powerUp.lastY <= 2732 + 50 && powerUp.y > 2732 + 50) {
powerUp.destroy();
powerUps.splice(p, 1);
continue;
}
// Check collision with player
if (powerUp.intersects(player)) {
// Check power-up type and activate accordingly
if (powerUp.powerUpType === 'doubleDamage') {
doubleDamageActive = true;
doubleDamageTimer = 0;
} else if (powerUp.powerUpType === 'unlimitedShooting') {
unlimitedShootingActive = true;
unlimitedShootingTimer = 0;
} else if (powerUp.powerUpType === 'health') {
if (lives < maxLives) {
lives++;
updateLives();
}
} else if (powerUp.powerUpType === 'clearScreen') {
// Destroy all objects except rocks and swords
for (var cs = fallingObjects.length - 1; cs >= 0; cs--) {
var objToClear = fallingObjects[cs];
// Check if object still exists before clearing
if (!objToClear || !objToClear.parent) {
fallingObjects.splice(cs, 1);
continue;
}
if (objToClear.type !== 'rock') {
// Create explosion effect for cleared objects
tween(objToClear, {
scaleX: 2,
scaleY: 2,
alpha: 0,
tint: 0xffaa00
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
objToClear.destroy();
}
});
fallingObjects.splice(cs, 1);
}
}
}
// Visual effect
tween(powerUp, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
powerUp.destroy();
}
});
powerUps.splice(p, 1);
continue;
}
powerUp.lastY = powerUp.y;
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
// Check if bullet still exists and hasn't been destroyed
if (!bullet || !bullet.parent) {
bullets.splice(i, 1);
continue;
}
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -50 && bullet.y < -50) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check bullet collision with falling objects
for (var j = fallingObjects.length - 1; j >= 0; j--) {
var obj = fallingObjects[j];
// Check if objects still exist before checking intersection
if (!obj || !obj.parent || !bullet || !bullet.parent) {
continue;
}
if (bullet.intersects(obj)) {
// Reduce hit points (double damage if power-up is active, plus upgrade damage)
var baseDamage = 1 + damageUpgrade;
var damage = doubleDamageActive ? baseDamage * 2 : baseDamage;
obj.hitPoints -= damage;
// Flash object to show it was hit
var hitTint = 0xff0000;
var originalTint = obj.tint || 0xffffff;
tween(obj, {
tint: hitTint
}, {
duration: 100,
onFinish: function onFinish() {
tween(obj, {
tint: originalTint
}, {
duration: 100
});
}
});
// Destroy bullet
bullet.destroy();
bullets.splice(i, 1);
// Check if object should be destroyed
if (obj.hitPoints <= 0) {
if (obj.type === 'rock') {
LK.setScore(LK.getScore() + 50);
lives = maxLives; // Restore full health
updateLives();
rockActive = false;
resetChallenge();
} else {
LK.setScore(LK.getScore() + 1);
objectsDestroyed++;
// Track bat destruction for power-up
if (obj.type === 'bat') {
batsDestroyed++;
// Spawn power-up every 10 bats destroyed
if (batsDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'doubleDamage');
}
}
// Track sword destruction for power-up
if (obj.type === 'sword') {
swordsDestroyed++;
// Spawn unlimited shooting power-up every 10 swords destroyed
if (swordsDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'unlimitedShooting');
}
}
// Track knife destruction for health power-up
if (obj.type === 'knife') {
knivesDestroyed++;
// Spawn health power-up every 10 knives destroyed
if (knivesDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'health');
}
}
// Track stick destruction for clear screen power-up
if (obj.type === 'stick') {
sticksDestroyed++;
// Spawn clear screen power-up every 10 sticks destroyed
if (sticksDestroyed % 10 === 0) {
spawnPowerUp(obj.x, obj.y, 'clearScreen');
}
}
// Check if challenge is completed (only when no rock is active)
if (!rockActive && objectsDestroyed >= challengeTarget) {
challengesCompleted++;
if (challengesCompleted % 5 === 0) {
spawnRock();
} else {
resetChallenge();
}
}
// Add coins based on score when objects are destroyed
totalEarnings += 1;
storage.totalEarnings = totalEarnings;
}
updateScore();
LK.getSound('destroy').play();
// Create explosion effect
tween(obj, {
scaleX: 3,
scaleY: 3,
alpha: 0,
tint: 0xffaa00
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
obj.destroy();
}
});
fallingObjects.splice(j, 1);
} else {
LK.getSound('hit').play();
}
break;
}
}
if (bullets[i]) {
bullet.lastY = bullet.y;
}
}
// Check if there's a rock and handle bat spawning timer
var hasRock = false;
for (var r = 0; r < fallingObjects.length; r++) {
if (fallingObjects[r].type === 'rock') {
hasRock = true;
break;
}
}
if (hasRock) {
rockBatTimer++;
if (rockBatTimer >= rockBatSpawnRate) {
spawnRockBats();
rockBatTimer = 0;
}
} else {
rockBatTimer = 0;
}
// Update falling objects
for (var k = fallingObjects.length - 1; k >= 0; k--) {
var fallingObj = fallingObjects[k];
// Check if object still exists and hasn't been destroyed
if (!fallingObj || !fallingObj.parent) {
fallingObjects.splice(k, 1);
continue;
}
if (fallingObj.lastY === undefined) {
fallingObj.lastY = fallingObj.y;
}
// Handle rock horizontal movement
if (fallingObj.type === 'rock') {
fallingObj.x += fallingObj.horizontalSpeed * fallingObj.direction;
// Bounce off screen edges
if (fallingObj.x <= 50 || fallingObj.x >= 2048 - 50) {
fallingObj.direction *= -1;
}
}
// Remove objects that fall off screen
if (fallingObj.lastY <= 2732 + 50 && fallingObj.y > 2732 + 50) {
fallingObj.destroy();
fallingObjects.splice(k, 1);
continue;
}
// Check collision with player
if (fallingObj.intersects(player)) {
// If player touches rock, instant game over
if (fallingObj.type === 'rock') {
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
lives--;
updateLives();
LK.getSound('hit').play();
// Flash player red
tween(player, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(player, {
tint: 0xffffff
}, {
duration: 200
});
}
});
fallingObj.destroy();
fallingObjects.splice(k, 1);
if (lives <= 0) {
LK.stopMusic();
LK.playMusic('game_over_music');
LK.showGameOver();
return;
}
continue;
}
fallingObj.lastY = fallingObj.y;
}
};
Quiero qie sea como un bate de béisbol de color cafe, en estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero un cuchillo de color metal en estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero una roca de color gris, circular, en estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero un palo o rama de color cafe, en estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero una espada de metal, estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero una manzana roja, en estilo 32 bits. In-Game asset. 2d. High contrast. No shadows
Quiero un arbusto visto desde abajo, en 32 bits. In-Game asset. 2d. High contrast. No shadows
Una luz fuerte de color amarillo, en 32 bits. In-Game asset. 2d. High contrast. No shadows
Un coco, visto desde arriba, en 32 bits. In-Game asset. 2d. High contrast. No shadows