User prompt
Use POWERUP as powerup drops
User prompt
Make a go back to level 1 button under settings
User prompt
Too big asset... i said not too big
User prompt
Make player bullet asset a lot bigger but not too big and make minibosses easier
User prompt
Make controls default to left
User prompt
Remove skip tutorial and play tutorial no matter what
User prompt
Put settings in top right and just do tutorial without skip stuff
User prompt
I meant the skip tutorial button not settings put it back and move skip tutorial button (also it skipped tutorial and I didn't even press it)
User prompt
Put it in top left for that button
User prompt
Instead of skip tutorial in settings what about a button for it during tutorial
User prompt
Make a left hand or right hand selector in a settings tab that pauses game for left or right hand placing for move buttons and other settings. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make up/down/left/right buttons bigger
User prompt
Make arrow buttons to move instead of dragging
Code edit (1 edits merged)
Please save this source code
User prompt
Boss Blitz: Escalating Challenge
User prompt
Make bosses after 2 mini-bosses for first 2 levels and then the other ones are bosses. Make bosses and mini-bosswes get harder every time
Initial prompt
Space shooter game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentLevel: 1,
maxLevelReached: 1,
playerPowerups: {}
});
/****
* Classes
****/
var Boss = Container.expand(function (type, level) {
var self = Container.call(this);
self.type = type || 'miniBoss1';
self.level = level || 1;
var bossGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
// Boss stats scale with level
self.health = 100 * self.level;
self.maxHealth = self.health;
self.speed = 3 + self.level * 0.5;
self.shootCooldown = 0;
self.shootDelay = Math.max(30 - self.level * 5, 10); // Faster shooting at higher levels
self.attackPattern = 0;
self.phaseCounter = 0;
self.phases = ['entry', 'attack1', 'movement', 'attack2', 'rage'];
self.currentPhase = 'entry';
self.phaseTimer = 180; // 3 seconds per phase
self.moveDirection = 1;
self.targetX = 2048 / 2;
self.targetY = 300;
// Define movement patterns based on boss type
self.patterns = {
miniBoss1: {
entry: function entry() {
if (self.y < self.targetY) {
self.y += self.speed;
} else {
self.changePhase('attack1');
}
},
attack1: function attack1() {
// Simple straight shots
if (self.shootCooldown <= 0) {
self.shootBullets();
self.shootCooldown = self.shootDelay;
}
// Move side to side
self.x += self.speed * self.moveDirection;
if (self.x > 1800 || self.x < 248) {
self.moveDirection *= -1;
}
},
movement: function movement() {
// Circle pattern
self.x = self.targetX + Math.cos(self.phaseCounter / 30) * 300;
self.y = self.targetY + Math.sin(self.phaseCounter / 30) * 100;
},
attack2: function attack2() {
// Spread shots
if (self.shootCooldown <= 0) {
self.shootSpread(5, 0.2);
self.shootCooldown = self.shootDelay * 2;
}
},
rage: function rage() {
// Fast movements and frequent attacks
self.x += self.speed * 1.5 * self.moveDirection;
if (self.x > 1800 || self.x < 248) {
self.moveDirection *= -1;
}
if (self.shootCooldown <= 0) {
self.shootSpread(3, 0.3);
self.shootCooldown = self.shootDelay / 2;
}
}
},
miniBoss2: {
entry: function entry() {
if (self.y < self.targetY) {
self.y += self.speed;
} else {
self.changePhase('attack1');
}
},
attack1: function attack1() {
// Laser attacks
if (self.shootCooldown <= 0) {
self.shootLaser();
self.shootCooldown = self.shootDelay * 3;
}
// Slow tracking
if (player && self.phaseCounter % 30 === 0) {
self.targetX = player.x;
}
self.x += (self.targetX - self.x) * 0.02;
},
movement: function movement() {
// Quick dash to one side then the other
if (self.phaseCounter < self.phaseTimer / 2) {
self.x += self.speed * 2;
} else {
self.x -= self.speed * 2;
}
// Keep in bounds
self.x = Math.max(200, Math.min(1848, self.x));
},
attack2: function attack2() {
// Circular bullet pattern
if (self.shootCooldown <= 0) {
self.shootCircle(8);
self.shootCooldown = self.shootDelay * 2;
}
},
rage: function rage() {
// Erratic movement and mixed attacks
self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300;
if (self.shootCooldown <= 0) {
if (self.phaseCounter % 120 < 60) {
self.shootSpread(7, 0.15);
} else {
self.shootLaser();
}
self.shootCooldown = self.shootDelay;
}
}
},
boss1: {
// More complex patterns for main bosses
entry: function entry() {
if (self.y < self.targetY) {
self.y += self.speed;
} else {
self.changePhase('attack1');
}
},
attack1: function attack1() {
// Wave pattern with bursts of bullets
self.x = self.targetX + Math.sin(self.phaseCounter / 20) * 400;
if (self.shootCooldown <= 0) {
if (self.phaseCounter % 60 < 30) {
self.shootBullets();
} else {
self.shootSpread(3, 0.2);
}
self.shootCooldown = self.shootDelay;
}
},
movement: function movement() {
// Quick charge toward player
if (player && self.phaseCounter % 60 === 0) {
self.targetX = player.x;
self.targetY = player.y - 300;
}
self.x += (self.targetX - self.x) * 0.05;
self.y += (self.targetY - self.y) * 0.05;
// Don't get too close to player
self.y = Math.min(self.y, 500);
},
attack2: function attack2() {
// Laser attacks with bullet spray
if (self.shootCooldown <= 0) {
if (self.phaseCounter % 120 < 60) {
self.shootLaser();
} else {
self.shootCircle(12);
}
self.shootCooldown = self.shootDelay * 1.5;
}
// Slow side-to-side movement
self.x += Math.sin(self.phaseCounter / 30) * 5;
},
rage: function rage() {
// Fast erratic movement with constant attacks
self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 300 + Math.cos(self.phaseCounter / 15) * 200;
self.y = self.targetY + Math.sin(self.phaseCounter / 12) * 100;
if (self.shootCooldown <= 0) {
// Alternate between different attack patterns
switch (Math.floor(self.phaseCounter / 40) % 3) {
case 0:
self.shootSpread(5, 0.15);
break;
case 1:
self.shootLaser();
break;
case 2:
self.shootCircle(8);
break;
}
self.shootCooldown = self.shootDelay * 0.7;
}
}
},
boss2: {
// Similar structure, different patterns
entry: function entry() {
if (self.y < self.targetY) {
self.y += self.speed;
} else {
self.changePhase('attack1');
}
},
attack1: function attack1() {
// Spiral bullet pattern
if (self.shootCooldown <= 0) {
self.shootSpiral(self.phaseCounter / 10);
self.shootCooldown = Math.max(5, self.shootDelay / 2);
}
// Slow rotation around center
self.x = self.targetX + Math.cos(self.phaseCounter / 60) * 200;
self.y = self.targetY + Math.sin(self.phaseCounter / 60) * 100;
},
movement: function movement() {
// Quick teleport movements
if (self.phaseCounter % 60 === 0) {
// Flash effect for teleport
LK.effects.flashObject(self, 0xFFFFFF, 200);
// Choose random position in top third of screen
self.targetX = 300 + Math.random() * (2048 - 600);
self.targetY = 150 + Math.random() * 250;
}
// Quick movement to target
self.x += (self.targetX - self.x) * 0.1;
self.y += (self.targetY - self.y) * 0.1;
},
attack2: function attack2() {
// Multiple lasers
if (self.shootCooldown <= 0) {
for (var i = 0; i < 3; i++) {
var offset = (i - 1) * 200;
self.shootLaser(offset);
}
self.shootCooldown = self.shootDelay * 2;
}
// Small jittery movements
self.x += (Math.random() - 0.5) * 10;
self.y += (Math.random() - 0.5) * 5;
// Keep in bounds
self.x = Math.max(200, Math.min(1848, self.x));
self.y = Math.max(100, Math.min(500, self.y));
},
rage: function rage() {
// Screen-filling attacks and fast movement
if (self.shootCooldown <= 0) {
// Alternate between massive spreads and laser curtains
if (self.phaseCounter % 180 < 90) {
self.shootSpread(15, 0.1);
} else {
for (var i = 0; i < 5; i++) {
var offset = (i - 2) * 150;
self.shootLaser(offset);
}
}
self.shootCooldown = self.shootDelay * 0.6;
}
// Aggressive tracking of player
if (player) {
self.targetX = player.x;
self.x += (self.targetX - self.x) * 0.03;
}
// Vertical bobbing
self.y = self.targetY + Math.sin(self.phaseCounter / 20) * 100;
}
},
boss3: {
// More extreme patterns
entry: function entry() {
if (self.y < self.targetY) {
self.y += self.speed;
} else {
self.changePhase('attack1');
}
},
attack1: function attack1() {
// 360-degree bullet hell
if (self.shootCooldown <= 0) {
self.shootCircle(16);
self.shootCooldown = self.shootDelay;
}
// Slow pulsing movement
self.x = self.targetX + Math.sin(self.phaseCounter / 30) * 300;
self.y = self.targetY + Math.cos(self.phaseCounter / 30) * 100;
},
movement: function movement() {
// Aggressive dash toward player position then retreat
if (self.phaseCounter % 90 < 45 && player) {
// Dash toward player
self.targetX = player.x;
self.targetY = player.y - 150;
self.x += (self.targetX - self.x) * 0.08;
self.y += (self.targetY - self.y) * 0.08;
} else {
// Retreat to top
self.targetY = 250;
self.y += (self.targetY - self.y) * 0.05;
}
},
attack2: function attack2() {
// Multiple attack types simultaneously
if (self.shootCooldown <= 0) {
// Lasers + bullets combo
self.shootLaser(0);
self.shootSpread(9, 0.15);
self.shootCooldown = self.shootDelay * 1.2;
}
// Side-to-side sweep
self.x += self.speed * 2 * self.moveDirection;
if (self.x > 1800 || self.x < 248) {
self.moveDirection *= -1;
}
},
rage: function rage() {
// Total bullet hell mode
if (self.shootCooldown <= 0) {
// Spiral + lasers + directed shots
self.shootSpiral(self.phaseCounter / 5);
if (self.phaseCounter % 60 === 0) {
// Multiple lasers in fan pattern
for (var i = -2; i <= 2; i++) {
self.shootLaser(i * 120);
}
}
// Direct shots at player
if (player && self.phaseCounter % 30 === 0) {
self.shootAtPlayer();
}
self.shootCooldown = Math.max(3, self.shootDelay / 3);
}
// Chaotic movement
self.x = self.targetX + Math.sin(self.phaseCounter / 10) * 400 + Math.cos(self.phaseCounter / 7) * 200;
self.y = self.targetY + Math.sin(self.phaseCounter / 8) * 150;
}
}
};
// Shooting methods
self.shootBullets = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 50;
bullet.angle = Math.PI / 2; // Straight down
bullets.push(bullet);
game.addChild(bullet);
};
self.shootSpread = function (count, spreadAngle) {
var startAngle = Math.PI / 2 - spreadAngle * (count - 1) / 2;
for (var i = 0; i < count; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 50;
bullet.angle = startAngle + spreadAngle * i;
bullets.push(bullet);
game.addChild(bullet);
}
};
self.shootCircle = function (count) {
var angleStep = Math.PI * 2 / count;
for (var i = 0; i < count; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.angle = angleStep * i;
bullets.push(bullet);
game.addChild(bullet);
}
};
self.shootSpiral = function (baseAngle) {
var count = 8;
var angleStep = Math.PI * 2 / count;
for (var i = 0; i < count; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
bullet.angle = baseAngle + angleStep * i;
bullets.push(bullet);
game.addChild(bullet);
}
};
self.shootLaser = function (xOffset) {
xOffset = xOffset || 0;
var laser = new EnemyLaser();
laser.x = self.x + xOffset;
laser.y = self.y;
lasers.push(laser);
game.addChild(laser);
};
self.shootAtPlayer = function () {
if (!player) return;
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 50;
// Calculate angle to player
var dx = player.x - self.x;
var dy = player.y - self.y;
bullet.angle = Math.atan2(dy, dx);
bullets.push(bullet);
game.addChild(bullet);
};
self.changePhase = function (newPhase) {
self.currentPhase = newPhase;
self.phaseCounter = 0;
// Adjust phase timer based on phase
if (newPhase === 'rage') {
self.phaseTimer = 360; // Longer rage phase
} else {
self.phaseTimer = 180; // Normal phases
}
};
self.takeDamage = function (damage) {
self.health -= damage;
// Flash boss when hit
LK.effects.flashObject(bossGraphics, 0xFFFFFF, 200);
LK.getSound('bossHit').play();
// Check for phase change based on health percentage
var healthPercent = self.health / self.maxHealth;
if (healthPercent <= 0.25 && self.currentPhase !== 'rage') {
self.changePhase('rage');
} else if (healthPercent <= 0.5 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2') {
self.changePhase('attack2');
} else if (healthPercent <= 0.75 && self.currentPhase !== 'rage' && self.currentPhase !== 'attack2' && self.currentPhase !== 'movement') {
self.changePhase('movement');
}
return self.health <= 0;
};
self.update = function () {
// Update based on current phase
if (self.patterns[self.type] && self.patterns[self.type][self.currentPhase]) {
self.patterns[self.type][self.currentPhase]();
}
// Update counters
self.phaseCounter++;
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
// Check for phase timeout
if (self.phaseCounter >= self.phaseTimer && self.currentPhase !== 'rage' && self.health > self.maxHealth * 0.25) {
// Cycle to next phase
var currentPhaseIndex = self.phases.indexOf(self.currentPhase);
var nextPhaseIndex = (currentPhaseIndex + 1) % (self.phases.length - 1); // Skip rage phase
self.changePhase(self.phases[nextPhaseIndex]);
}
};
return self;
});
var ControlButton = Container.expand(function (direction) {
var self = Container.call(this);
// Different color for each direction button
var color;
switch (direction) {
case 'up':
color = 0x4285F4;
break;
// Blue
case 'down':
color = 0xEA4335;
break;
// Red
case 'left':
color = 0xFBBC05;
break;
// Yellow
case 'right':
color = 0x34A853;
break;
// Green
default:
color = 0xFFFFFF;
// White
}
// Create button shape
var buttonGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Set button color
buttonGraphics.tint = color;
// Arrow display (using text as a simple way to show direction)
var arrowSymbol;
switch (direction) {
case 'up':
arrowSymbol = '▲';
break;
case 'down':
arrowSymbol = '▼';
break;
case 'left':
arrowSymbol = '◀';
break;
case 'right':
arrowSymbol = '▶';
break;
default:
arrowSymbol = '•';
}
var arrow = new Text2(arrowSymbol, {
size: 40,
fill: 0xFFFFFF
});
arrow.anchor.set(0.5, 0.5);
self.addChild(arrow);
// Store direction for later use
self.direction = direction;
// Handle button press
self.down = function (x, y, obj) {
// Visual feedback - shrink slightly when pressed
buttonGraphics.scale.set(0.75);
// Start moving in this direction
if (player && gameState === 'playing') {
movePlayer(self.direction, true);
}
};
// Handle button release
self.up = function (x, y, obj) {
// Visual feedback - return to normal size
buttonGraphics.scale.set(0.8);
// Stop moving in this direction
if (player && gameState === 'playing') {
movePlayer(self.direction, false);
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.damage = 1;
self.angle = 0; // Direction in radians
self.update = function () {
self.x += Math.cos(self.angle) * self.speed;
self.y += Math.sin(self.angle) * self.speed;
// Remove if off screen
if (self.y > 2732 + 50 || self.y < -50 || self.x > 2048 + 50 || self.x < -50) {
self.shouldRemove = true;
}
};
return self;
});
var EnemyLaser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('enemyLaser', {
anchorX: 0.5,
anchorY: 0
});
self.damage = 2;
self.duration = 120; // 2 seconds at 60fps
self.counter = 0;
self.warningCounter = 60; // 1 second warning
// Start with low alpha for warning
laserGraphics.alpha = 0.3;
self.update = function () {
self.counter++;
if (self.counter < self.warningCounter) {
// Warning phase
if (self.counter % 10 < 5) {
laserGraphics.alpha = 0.5;
} else {
laserGraphics.alpha = 0.3;
}
} else if (self.counter === self.warningCounter) {
// Activate laser
laserGraphics.alpha = 0.8;
// Expand width
tween(laserGraphics, {
width: 80
}, {
duration: 100
});
} else if (self.counter >= self.duration) {
// Remove laser
self.shouldRemove = true;
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.shootCooldown = 0;
self.shootDelay = 15; // 4 shots per second
self.health = 100;
self.maxHealth = 100;
self.invincible = false;
self.invincibleTimer = 0;
self.shield = null;
self.powerups = {};
// Track movement directions
self.moving = {
up: false,
down: false,
left: false,
right: false
};
// Initialize shield (hidden at first)
self.createShield = function () {
if (self.shield) return;
self.shield = self.attachAsset('playerShield', {
anchorX: 0.5,
anchorY: 0.5
});
self.shield.alpha = 0;
};
self.activateShield = function (duration) {
if (!self.shield) self.createShield();
self.shield.alpha = 0.7;
self.invincible = true;
// Fade out shield over duration
tween(self.shield, {
alpha: 0
}, {
duration: duration,
onFinish: function onFinish() {
self.invincible = false;
}
});
};
self.takeDamage = function (damage) {
if (self.invincible) return false;
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
return true; // Player died
}
// Flash player and make invincible briefly
LK.effects.flashObject(playerGraphics, 0xFF0000, 500);
self.invincible = true;
self.invincibleTimer = 60; // 1 second invincibility
LK.getSound('playerHit').play();
return false; // Player alive
};
self.shoot = function () {
if (self.shootCooldown > 0) return null;
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
// Apply powerups
if (self.powerups.doubleDamage) {
bullet.damage *= 2;
bullet.tint = 0xFFFF00; // Yellow for double damage
}
// Triple shot powerup
if (self.powerups.tripleShot) {
// Create two additional bullets
var bulletLeft = new PlayerBullet();
bulletLeft.x = self.x - 30;
bulletLeft.y = self.y - 20;
var bulletRight = new PlayerBullet();
bulletRight.x = self.x + 30;
bulletRight.y = self.y - 20;
self.shootCooldown = self.shootDelay;
LK.getSound('playerShoot').play();
return [bullet, bulletLeft, bulletRight];
}
self.shootCooldown = self.shootDelay;
LK.getSound('playerShoot').play();
return [bullet];
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.invincible && self.invincibleTimer > 0) {
self.invincibleTimer--;
if (self.invincibleTimer <= 0) {
self.invincible = false;
}
}
// Handle movement based on pressed direction buttons
if (gameState === 'playing') {
if (self.moving.up) {
self.y -= self.speed;
}
if (self.moving.down) {
self.y += self.speed;
}
if (self.moving.left) {
self.x -= self.speed;
}
if (self.moving.right) {
self.x += self.speed;
}
// Keep player within screen bounds
self.x = Math.max(50, Math.min(2048 - 50, self.x));
self.y = Math.max(100, Math.min(2732 - 100, self.y));
}
};
self.down = function (x, y, obj) {
// This is handled in the game's touch handler
};
self.up = function (x, y, obj) {
// This is handled in the game's touch handler
};
self.createShield();
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.damage = 1;
self.update = function () {
self.y -= self.speed;
// Remove if off screen
if (self.y < -50) {
self.shouldRemove = true;
}
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'shield';
var color;
switch (self.type) {
case 'shield':
color = 0x00FFFF;
break;
case 'doubleDamage':
color = 0xFFFF00;
break;
case 'tripleShot':
color = 0xFF00FF;
break;
default:
color = 0xFFFFFF;
}
var powerupGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
// Set color based on powerup type
powerupGraphics.tint = color;
self.speed = 3;
self.duration = type === 'shield' ? 300 : 600; // Shield lasts 5 seconds, others 10
self.update = function () {
self.y += self.speed;
// Remove if off screen
if (self.y > 2732 + 50) {
self.shouldRemove = true;
}
};
self.applyEffect = function (player) {
LK.getSound('powerUp').play();
switch (self.type) {
case 'shield':
player.activateShield(5000); // 5 seconds
break;
case 'doubleDamage':
player.powerups.doubleDamage = true;
// Clear previous timeout if exists
if (player.powerups.doubleDamageTimer) {
LK.clearTimeout(player.powerups.doubleDamageTimer);
}
// Set timeout to clear powerup
player.powerups.doubleDamageTimer = LK.setTimeout(function () {
player.powerups.doubleDamage = false;
}, 10000); // 10 seconds
break;
case 'tripleShot':
player.powerups.tripleShot = true;
// Clear previous timeout if exists
if (player.powerups.tripleShotTimer) {
LK.clearTimeout(player.powerups.tripleShotTimer);
}
// Set timeout to clear powerup
player.powerups.tripleShotTimer = LK.setTimeout(function () {
player.powerups.tripleShot = false;
}, 10000); // 10 seconds
break;
}
self.shouldRemove = true;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Core game variables
// Player, bosses, projectiles, UI elements, and effects
// Mini bosses
// Main bosses
// Boss projectiles
// Health bars and UI
// Sound effects
// Background music
var player;
var currentBoss;
var bullets = [];
var lasers = [];
var playerBullets = [];
var powerups = [];
var currentLevel = storage.currentLevel || 1;
var gameState = 'tutorial'; // tutorial, playing, bossDead, gameOver
var tutorialStep = 0;
var lastShootTime = 0;
var controlButtons = [];
// UI Elements
var scoreText;
var levelText;
var playerHealthBar;
var playerHealthBarBg;
var bossHealthBar;
var bossHealthBarBg;
var tutorialText;
// Initialize game
function initGame() {
// Background
game.setBackgroundColor(0x111133);
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Initialize UI
createUI();
// Start with tutorial if first level
if (currentLevel === 1 && !storage.skipTutorial) {
showTutorial();
} else {
startLevel();
}
// Play background music
LK.playMusic('battleMusic');
}
function createUI() {
// Score and level display
scoreText = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.top.addChild(scoreText);
scoreText.x = 150;
scoreText.y = 30;
levelText = new Text2('LEVEL ' + currentLevel, {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -50;
levelText.y = 30;
// Create directional control buttons
createControlButtons();
// Player health bar
playerHealthBarBg = LK.getAsset('healthBarBackground', {
anchorX: 0,
anchorY: 0.5
});
playerHealthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0.5
});
playerHealthBarBg.x = 50;
playerHealthBarBg.y = 100;
playerHealthBar.x = 50;
playerHealthBar.y = 100;
game.addChild(playerHealthBarBg);
game.addChild(playerHealthBar);
// Boss health bar (hidden initially)
bossHealthBarBg = LK.getAsset('bossHealthBarBackground', {
anchorX: 0.5,
anchorY: 0.5
});
bossHealthBar = LK.getAsset('bossHealthBar', {
anchorX: 0,
anchorY: 0.5
});
bossHealthBarBg.x = 2048 / 2;
bossHealthBarBg.y = 50;
bossHealthBar.x = 2048 / 2 - bossHealthBarBg.width / 2;
bossHealthBar.y = 50;
bossHealthBarBg.visible = false;
bossHealthBar.visible = false;
game.addChild(bossHealthBarBg);
game.addChild(bossHealthBar);
// Tutorial text (hidden initially)
tutorialText = new Text2('', {
size: 70,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0.5);
tutorialText.x = 2048 / 2;
tutorialText.y = 2732 / 2;
tutorialText.visible = false;
game.addChild(tutorialText);
}
function showTutorial() {
gameState = 'tutorial';
tutorialText.visible = true;
var tutorialMessages = ["Welcome to Boss Blitz!\n\nUse the arrow buttons to move your ship.", "Tap anywhere to shoot.\n\nDestroy the bosses to progress.", "Collect power-ups dropped by bosses\nto gain special abilities.", "Survive long enough to defeat\nall boss levels.", "Good luck!\n\nTap to begin..."];
tutorialText.setText(tutorialMessages[tutorialStep]);
// Make tutorial text pulsate
tween(tutorialText, {
alpha: 0.7
}, {
duration: 1000,
easing: tween.sinceOut,
onFinish: function onFinish() {
tween(tutorialText, {
alpha: 1
}, {
duration: 1000,
easing: tween.sinceIn
});
}
});
}
function advanceTutorial() {
tutorialStep++;
if (tutorialStep >= 5) {
// End tutorial
tutorialText.visible = false;
startLevel();
} else {
showTutorial();
}
}
function startLevel() {
gameState = 'playing';
// Reset player position
player.x = 2048 / 2;
player.y = 2732 - 200;
// Clear any existing projectiles
clearProjectiles();
// Create boss based on current level
var bossType;
if (currentLevel === 1) {
bossType = 'miniBoss1';
} else if (currentLevel === 2) {
bossType = 'miniBoss2';
} else if (currentLevel === 3) {
bossType = 'boss1';
} else if (currentLevel === 4) {
bossType = 'boss2';
} else {
bossType = 'boss3';
}
currentBoss = new Boss(bossType, currentLevel);
currentBoss.x = 2048 / 2;
currentBoss.y = -200; // Start above screen
game.addChild(currentBoss);
// Show boss health bar
bossHealthBarBg.visible = true;
bossHealthBar.visible = true;
// Update UI
updateScore();
levelText.setText('LEVEL ' + currentLevel);
}
function updateScore() {
scoreText.setText('SCORE: ' + LK.getScore());
}
function clearProjectiles() {
// Remove all bullets, lasers, and powerups
bullets.forEach(function (bullet) {
bullet.parent.removeChild(bullet);
});
bullets = [];
lasers.forEach(function (laser) {
laser.parent.removeChild(laser);
});
lasers = [];
playerBullets.forEach(function (bullet) {
bullet.parent.removeChild(bullet);
});
playerBullets = [];
powerups.forEach(function (powerup) {
powerup.parent.removeChild(powerup);
});
powerups = [];
}
function checkCollisions() {
// Player bullets hitting boss
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.intersects(currentBoss)) {
// Boss hit
var bossDead = currentBoss.takeDamage(bullet.damage);
// Remove bullet
bullet.parent.removeChild(bullet);
playerBullets.splice(i, 1);
// Update boss health bar
updateBossHealthBar();
// Check if boss defeated
if (bossDead) {
handleBossDefeat();
}
}
}
// Enemy bullets hitting player
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.intersects(player)) {
// Player hit
var playerDied = player.takeDamage(bullet.damage);
// Remove bullet
bullet.parent.removeChild(bullet);
bullets.splice(i, 1);
// Update health bar
updatePlayerHealthBar();
// Check if player died
if (playerDied) {
handlePlayerDefeat();
}
}
}
// Lasers hitting player
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
// Only check active lasers (not in warning phase)
if (laser.counter >= laser.warningCounter && laser.intersects(player)) {
// Player hit
var playerDied = player.takeDamage(laser.damage);
// Update health bar
updatePlayerHealthBar();
// Check if player died
if (playerDied) {
handlePlayerDefeat();
}
// Don't remove laser on hit, it persists
}
}
// Power-ups being collected by player
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (powerup.intersects(player)) {
// Apply powerup effect
powerup.applyEffect(player);
// Remove powerup
powerup.parent.removeChild(powerup);
powerups.splice(i, 1);
}
}
}
function updatePlayerHealthBar() {
// Update width of health bar based on player health percentage
var healthPercent = player.health / player.maxHealth;
playerHealthBar.width = playerHealthBarBg.width * healthPercent;
// Change color based on health remaining
if (healthPercent > 0.6) {
playerHealthBar.tint = 0x34A853; // Green
} else if (healthPercent > 0.3) {
playerHealthBar.tint = 0xFBBC05; // Yellow
} else {
playerHealthBar.tint = 0xEA4335; // Red
}
}
function updateBossHealthBar() {
// Update width of health bar based on boss health percentage
var healthPercent = currentBoss.health / currentBoss.maxHealth;
bossHealthBar.width = bossHealthBarBg.width * healthPercent;
// Change color based on health remaining
if (healthPercent > 0.6) {
bossHealthBar.tint = 0xEA4335; // Red
} else if (healthPercent > 0.3) {
bossHealthBar.tint = 0xFF5733; // Orange
} else {
bossHealthBar.tint = 0xC70039; // Dark red
}
}
function handleBossDefeat() {
gameState = 'bossDead';
// Play defeat sound
LK.getSound('bossDefeat').play();
// Flash screen
LK.effects.flashScreen(0xFFFFFF, 500);
// Create explosion effect at boss position
LK.effects.flashObject(currentBoss, 0xFFFFFF, 1000);
LK.getSound('explosion').play();
// Remove boss
LK.setTimeout(function () {
game.removeChild(currentBoss);
currentBoss = null;
// Hide boss health bar
bossHealthBarBg.visible = false;
bossHealthBar.visible = false;
// Spawn powerups
spawnPowerups();
// Award score based on level
var scoreIncrease = currentLevel * 1000;
LK.setScore(LK.getScore() + scoreIncrease);
updateScore();
// Show level complete message
tutorialText.setText("LEVEL " + currentLevel + " COMPLETE!\n\nTap to continue...");
tutorialText.visible = true;
// Make text appear with effect
tutorialText.alpha = 0;
tween(tutorialText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}, 1000);
}
function spawnPowerups() {
// Spawn 1-3 random powerups
var count = Math.floor(Math.random() * 3) + 1;
var types = ['shield', 'doubleDamage', 'tripleShot'];
for (var i = 0; i < count; i++) {
var type = types[Math.floor(Math.random() * types.length)];
var powerup = new PowerUp(type);
// Position near where boss was defeated
powerup.x = 2048 / 2 + (Math.random() * 400 - 200);
powerup.y = 300 + (Math.random() * 200 - 100);
game.addChild(powerup);
powerups.push(powerup);
}
}
function advanceToNextLevel() {
currentLevel++;
storage.currentLevel = currentLevel;
// Update max level reached
if (currentLevel > storage.maxLevelReached) {
storage.maxLevelReached = currentLevel;
}
// Hide tutorial text
tutorialText.visible = false;
// Start new level
startLevel();
}
function handlePlayerDefeat() {
gameState = 'gameOver';
// Play explosion
LK.getSound('explosion').play();
// Flash screen red
LK.effects.flashScreen(0xFF0000, 1000);
// Show game over message
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
function playerShoot() {
if (gameState !== 'playing') return;
var bullets = player.shoot();
if (bullets) {
bullets.forEach(function (bullet) {
game.addChild(bullet);
playerBullets.push(bullet);
});
}
}
// Event handlers
function handleDown(x, y, obj) {
// Handle tutorial advancement
if (gameState === 'tutorial') {
advanceTutorial();
return;
}
// Handle level advancement after boss defeat
if (gameState === 'bossDead' && tutorialText.visible) {
advanceToNextLevel();
return;
}
// In playing state, any tap triggers shooting
if (gameState === 'playing') {
// Check if the tap is on any of the control buttons
var isOnControlButton = false;
for (var i = 0; i < controlButtons.length; i++) {
if (obj === controlButtons[i]) {
isOnControlButton = true;
break;
}
}
// Only shoot if not tapping a control button
if (!isOnControlButton) {
playerShoot();
}
}
}
function handleMove(x, y, obj) {
// No longer need to handle dragging movement
}
function handleUp(x, y, obj) {
// No longer need to handle dragging release
}
game.down = handleDown;
game.move = handleMove;
game.up = handleUp;
// Main game loop
game.update = function () {
// Skip updates for non-playing states
if (gameState === 'tutorial' || gameState === 'gameOver') {
return;
}
// Auto-shoot for player
if (gameState === 'playing' && LK.ticks % 30 === 0) {
playerShoot();
}
// Update player
player.update();
// Update boss
if (currentBoss && gameState === 'playing') {
currentBoss.update();
}
// Update projectiles
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
if (bullet.shouldRemove) {
bullet.parent.removeChild(bullet);
playerBullets.splice(i, 1);
}
}
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
if (bullet.shouldRemove) {
bullet.parent.removeChild(bullet);
bullets.splice(i, 1);
}
}
for (var i = lasers.length - 1; i >= 0; i--) {
var laser = lasers[i];
laser.update();
if (laser.shouldRemove) {
laser.parent.removeChild(laser);
lasers.splice(i, 1);
}
}
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
if (powerup.shouldRemove) {
powerup.parent.removeChild(powerup);
powerups.splice(i, 1);
}
}
// Check for collisions
if (gameState === 'playing') {
checkCollisions();
}
// Update UI elements
updatePlayerHealthBar();
if (currentBoss) {
updateBossHealthBar();
}
};
// Initialize game
initGame();
function createControlButtons() {
// Create the direction buttons
var btnSize = 120;
var spacing = 20;
// Create buttons for each direction
var upButton = new ControlButton('up');
var downButton = new ControlButton('down');
var leftButton = new ControlButton('left');
var rightButton = new ControlButton('right');
// Position the buttons in a D-pad layout
upButton.x = 2048 / 4;
upButton.y = 2732 - 3 * btnSize - 2 * spacing;
downButton.x = 2048 / 4;
downButton.y = 2732 - btnSize - spacing;
leftButton.x = 2048 / 4 - btnSize - spacing;
leftButton.y = 2732 - 2 * btnSize - 1.5 * spacing;
rightButton.x = 2048 / 4 + btnSize + spacing;
rightButton.y = 2732 - 2 * btnSize - 1.5 * spacing;
// Add buttons to the game
game.addChild(upButton);
game.addChild(downButton);
game.addChild(leftButton);
game.addChild(rightButton);
// Store buttons for reference
controlButtons = [upButton, downButton, leftButton, rightButton];
}
// Function to handle player movement based on button presses
function movePlayer(direction, isPressed) {
if (!player || gameState !== 'playing') return;
// Update the movement state for the player
player.moving[direction] = isPressed;
} ===================================================================
--- original.js
+++ change.js
@@ -444,8 +444,88 @@
}
};
return self;
});
+var ControlButton = Container.expand(function (direction) {
+ var self = Container.call(this);
+ // Different color for each direction button
+ var color;
+ switch (direction) {
+ case 'up':
+ color = 0x4285F4;
+ break;
+ // Blue
+ case 'down':
+ color = 0xEA4335;
+ break;
+ // Red
+ case 'left':
+ color = 0xFBBC05;
+ break;
+ // Yellow
+ case 'right':
+ color = 0x34A853;
+ break;
+ // Green
+ default:
+ color = 0xFFFFFF;
+ // White
+ }
+ // Create button shape
+ var buttonGraphics = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.8,
+ scaleY: 0.8
+ });
+ // Set button color
+ buttonGraphics.tint = color;
+ // Arrow display (using text as a simple way to show direction)
+ var arrowSymbol;
+ switch (direction) {
+ case 'up':
+ arrowSymbol = '▲';
+ break;
+ case 'down':
+ arrowSymbol = '▼';
+ break;
+ case 'left':
+ arrowSymbol = '◀';
+ break;
+ case 'right':
+ arrowSymbol = '▶';
+ break;
+ default:
+ arrowSymbol = '•';
+ }
+ var arrow = new Text2(arrowSymbol, {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ arrow.anchor.set(0.5, 0.5);
+ self.addChild(arrow);
+ // Store direction for later use
+ self.direction = direction;
+ // Handle button press
+ self.down = function (x, y, obj) {
+ // Visual feedback - shrink slightly when pressed
+ buttonGraphics.scale.set(0.75);
+ // Start moving in this direction
+ if (player && gameState === 'playing') {
+ movePlayer(self.direction, true);
+ }
+ };
+ // Handle button release
+ self.up = function (x, y, obj) {
+ // Visual feedback - return to normal size
+ buttonGraphics.scale.set(0.8);
+ // Stop moving in this direction
+ if (player && gameState === 'playing') {
+ movePlayer(self.direction, false);
+ }
+ };
+ return self;
+});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
@@ -515,8 +595,15 @@
self.invincible = false;
self.invincibleTimer = 0;
self.shield = null;
self.powerups = {};
+ // Track movement directions
+ self.moving = {
+ up: false,
+ down: false,
+ left: false,
+ right: false
+ };
// Initialize shield (hidden at first)
self.createShield = function () {
if (self.shield) return;
self.shield = self.attachAsset('playerShield', {
@@ -589,8 +676,26 @@
if (self.invincibleTimer <= 0) {
self.invincible = false;
}
}
+ // Handle movement based on pressed direction buttons
+ if (gameState === 'playing') {
+ if (self.moving.up) {
+ self.y -= self.speed;
+ }
+ if (self.moving.down) {
+ self.y += self.speed;
+ }
+ if (self.moving.left) {
+ self.x -= self.speed;
+ }
+ if (self.moving.right) {
+ self.x += self.speed;
+ }
+ // Keep player within screen bounds
+ self.x = Math.max(50, Math.min(2048 - 50, self.x));
+ self.y = Math.max(100, Math.min(2732 - 100, self.y));
+ }
};
self.down = function (x, y, obj) {
// This is handled in the game's touch handler
};
@@ -694,16 +799,16 @@
/****
* Game Code
****/
-// Background music
-// Sound effects
-// Health bars and UI
-// Boss projectiles
-// Main bosses
-// Mini bosses
-// Player, bosses, projectiles, UI elements, and effects
// Core game variables
+// Player, bosses, projectiles, UI elements, and effects
+// Mini bosses
+// Main bosses
+// Boss projectiles
+// Health bars and UI
+// Sound effects
+// Background music
var player;
var currentBoss;
var bullets = [];
var lasers = [];
@@ -712,9 +817,9 @@
var currentLevel = storage.currentLevel || 1;
var gameState = 'tutorial'; // tutorial, playing, bossDead, gameOver
var tutorialStep = 0;
var lastShootTime = 0;
-var dragNode = null;
+var controlButtons = [];
// UI Elements
var scoreText;
var levelText;
var playerHealthBar;
@@ -759,8 +864,10 @@
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -50;
levelText.y = 30;
+ // Create directional control buttons
+ createControlButtons();
// Player health bar
playerHealthBarBg = LK.getAsset('healthBarBackground', {
anchorX: 0,
anchorY: 0.5
@@ -805,9 +912,9 @@
}
function showTutorial() {
gameState = 'tutorial';
tutorialText.visible = true;
- var tutorialMessages = ["Welcome to Boss Blitz!\n\nDrag to move your ship.", "Tap anywhere to shoot.\n\nDestroy the bosses to progress.", "Collect power-ups dropped by bosses\nto gain special abilities.", "Survive long enough to defeat\nall boss levels.", "Good luck!\n\nTap to begin..."];
+ var tutorialMessages = ["Welcome to Boss Blitz!\n\nUse the arrow buttons to move your ship.", "Tap anywhere to shoot.\n\nDestroy the bosses to progress.", "Collect power-ups dropped by bosses\nto gain special abilities.", "Survive long enough to defeat\nall boss levels.", "Good luck!\n\nTap to begin..."];
tutorialText.setText(tutorialMessages[tutorialStep]);
// Make tutorial text pulsate
tween(tutorialText, {
alpha: 0.7
@@ -1069,28 +1176,29 @@
if (gameState === 'bossDead' && tutorialText.visible) {
advanceToNextLevel();
return;
}
- // Start dragging player
+ // In playing state, any tap triggers shooting
if (gameState === 'playing') {
- // Check if click is on player
- if (obj === player || player.intersects(obj)) {
- dragNode = player;
- } else {
- // Shoot when clicking elsewhere
+ // Check if the tap is on any of the control buttons
+ var isOnControlButton = false;
+ for (var i = 0; i < controlButtons.length; i++) {
+ if (obj === controlButtons[i]) {
+ isOnControlButton = true;
+ break;
+ }
+ }
+ // Only shoot if not tapping a control button
+ if (!isOnControlButton) {
playerShoot();
}
}
}
function handleMove(x, y, obj) {
- if (dragNode && gameState === 'playing') {
- // Move player, keeping within screen bounds
- dragNode.x = Math.max(50, Math.min(2048 - 50, x));
- dragNode.y = Math.max(100, Math.min(2732 - 100, y));
- }
+ // No longer need to handle dragging movement
}
function handleUp(x, y, obj) {
- dragNode = null;
+ // No longer need to handle dragging release
}
game.down = handleDown;
game.move = handleMove;
game.up = handleUp;
@@ -1153,5 +1261,37 @@
updateBossHealthBar();
}
};
// Initialize game
-initGame();
\ No newline at end of file
+initGame();
+function createControlButtons() {
+ // Create the direction buttons
+ var btnSize = 120;
+ var spacing = 20;
+ // Create buttons for each direction
+ var upButton = new ControlButton('up');
+ var downButton = new ControlButton('down');
+ var leftButton = new ControlButton('left');
+ var rightButton = new ControlButton('right');
+ // Position the buttons in a D-pad layout
+ upButton.x = 2048 / 4;
+ upButton.y = 2732 - 3 * btnSize - 2 * spacing;
+ downButton.x = 2048 / 4;
+ downButton.y = 2732 - btnSize - spacing;
+ leftButton.x = 2048 / 4 - btnSize - spacing;
+ leftButton.y = 2732 - 2 * btnSize - 1.5 * spacing;
+ rightButton.x = 2048 / 4 + btnSize + spacing;
+ rightButton.y = 2732 - 2 * btnSize - 1.5 * spacing;
+ // Add buttons to the game
+ game.addChild(upButton);
+ game.addChild(downButton);
+ game.addChild(leftButton);
+ game.addChild(rightButton);
+ // Store buttons for reference
+ controlButtons = [upButton, downButton, leftButton, rightButton];
+}
+// Function to handle player movement based on button presses
+function movePlayer(direction, isPressed) {
+ if (!player || gameState !== 'playing') return;
+ // Update the movement state for the player
+ player.moving[direction] = isPressed;
+}
\ No newline at end of file