/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var size = 40 + Math.random() * 60;
var asteroidGraphic = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 80,
scaleY: size / 80
});
// Randomly tint the asteroid to give variety
var grayTint = 0x777777 + Math.floor(Math.random() * 0x444444);
asteroidGraphic.tint = grayTint;
self.health = Math.ceil(size / 30);
self.speed = 2 + Math.random() * 3;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
self.hitSize = size; // Store the hit size for collision detection
self.update = function () {
self.y += self.speed;
asteroidGraphic.rotation += self.rotationSpeed;
// Check if asteroid is out of screen
if (self.y > 2732 + 100) {
self.destroy();
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 2;
self.shootTimer = 0;
self.shootInterval = 120 + Math.floor(Math.random() * 60);
self.moveType = Math.floor(Math.random() * 3); // 0: straight, 1: sine, 2: zigzag
self.initialX = 0;
self.moveCounter = 0;
self.update = function () {
// Movement patterns
if (self.moveType === 0) {
// Straight down
self.y += self.speed;
} else if (self.moveType === 1) {
// Sine wave
self.y += self.speed;
self.x = self.initialX + Math.sin(self.moveCounter * 0.05) * 150;
self.moveCounter++;
} else if (self.moveType === 2) {
// Zigzag
self.y += self.speed;
if (self.moveCounter % 60 < 30) {
self.x += 2;
} else {
self.x -= 2;
}
self.moveCounter++;
}
// Shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
if (gameActive) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
}
}
// Check if enemy is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
// Check if bullet is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.lifetime = 0;
self.maxLifetime = 30;
self.update = function () {
self.lifetime++;
var progress = self.lifetime / self.maxLifetime;
explosionGraphic.scaleX = 1 + progress;
explosionGraphic.scaleY = 1 + progress;
explosionGraphic.alpha = 0.8 * (1 - progress);
if (self.lifetime >= self.maxLifetime) {
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var shipGraphic = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
var thruster = self.attachAsset('playerThruster', {
anchorX: 0.5,
anchorY: 0,
y: 50,
alpha: 0.7
});
self.shootTimer = 0;
self.shootInterval = 15; // 4 shots per second at 60fps
self.shootType = 0; // 0: single, 1: triple
self.speedMultiplier = 1;
self.tripleTimer = 0;
self.speedTimer = 0;
// Thruster animation
LK.setInterval(function () {
var scale = 0.8 + Math.random() * 0.4;
tween(thruster, {
scaleX: scale,
scaleY: scale
}, {
duration: 100
});
}, 150);
self.update = function () {
// Countdown powerup timers
if (self.tripleTimer > 0) {
self.tripleTimer--;
if (self.tripleTimer === 0) {
self.shootType = 0;
}
}
if (self.speedTimer > 0) {
self.speedTimer--;
if (self.speedTimer === 0) {
self.speedMultiplier = 1;
}
}
// Auto-shooting
if (gameActive) {
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
if (self.shootType === 0) {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
game.addChild(bullet);
playerBullets.push(bullet);
LK.getSound('playerShoot').play();
} else {
// Triple shot
for (var i = -1; i <= 1; i++) {
var bullet = new PlayerBullet();
bullet.x = self.x + i * 20;
bullet.y = self.y - 40;
game.addChild(bullet);
playerBullets.push(bullet);
}
LK.getSound('playerShoot').play();
}
}
}
};
self.activateTripleShot = function () {
self.shootType = 1;
self.tripleTimer = 300; // 5 seconds at 60fps
};
self.activateSpeedBoost = function () {
self.speedMultiplier = 1.5;
self.speedTimer = 300; // 5 seconds at 60fps
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.damage = 1;
self.update = function () {
self.y += self.speed;
// Check if bullet is out of screen
if (self.y < -50) {
self.destroy();
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.floor(Math.random() * 3); // 0: triple shot, 1: shield, 2: speed
if (self.type === 0) {
powerupGraphic.tint = 0xff00ff; // Purple for triple shot
} else if (self.type === 1) {
powerupGraphic.tint = 0x00ffff; // Cyan for shield
} else {
powerupGraphic.tint = 0xffff00; // Yellow for speed
}
self.speed = 3;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
powerupGraphic.rotation += self.rotationSpeed;
// Check if power-up is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphic = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.update = function () {
self.timer++;
// Flash when about to end
if (self.timer > self.duration - 60) {
shieldGraphic.alpha = 0.5 * (1 + Math.sin(self.timer * 0.2));
}
if (self.timer >= self.duration) {
self.destroy();
playerHasShield = false;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphic = self.attachAsset('starParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 5;
self.alpha = 0.3 + Math.random() * 0.7;
starGraphic.alpha = self.alpha;
self.update = function () {
self.y += self.speed;
if (self.y > 2732) {
self.y = -10;
self.x = Math.random() * 2048;
self.speed = 1 + Math.random() * 5;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
/*
Supported Types:
1. Shape:
- Simple geometric figures with these properties:
* width: (required) pixel width of the shape.
* height: (required) pixel height of the shape.
* color: (required) color of the shape.
* shape: (required) type of shape. Valid options: 'box', 'ellipse'.
2. Image:
- Imported images with these properties:
* width: (required) pixel resolution width.
* height: (required) pixel resolution height.
* id: (required) identifier for the image.
* flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip).
* flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip).
* orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values:
- 0: No rotation.
- 1: Rotate 90 degrees.
- 2: Rotate 180 degrees.
- 3: Rotate 270 degrees.
Note: Width and height remain unchanged upon flipping.
3. Sound:
- Sound effects with these properties:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
4. Music:
- In contract to sound effects, only one music can be played at a time
- Music is using the same API to initilize just like sound.
- Music loops by default
- Music with these config options:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
* start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping
* end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping
*/
// Game state variables
var gameActive = true;
var score = 0;
var lives = 3;
var level = 1;
var spawnCounter = 0;
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var asteroids = [];
var powerups = [];
var stars = [];
var explosions = [];
var playerHasShield = false;
var shield = null;
var lastTouch = {
x: 0,
y: 0
};
var touchActive = false;
// Create UI
var scoreTxt = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -300;
scoreTxt.y = 30;
var livesTxt = new Text2('LIVES: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesTxt);
livesTxt.x = 120; // Avoiding top-left 100x100px
livesTxt.y = 30;
var levelTxt = new Text2('LEVEL: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 30;
// Create player
var player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Create star background
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
game.addChild(star);
stars.push(star);
}
// Start game music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Increase score and update display
function addScore(points) {
score += points;
scoreTxt.setText('SCORE: ' + score);
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = -100;
enemy.initialX = enemy.x;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
asteroid.x = Math.random() * 2048;
asteroid.y = -100;
game.addChild(asteroid);
asteroids.push(asteroid);
}
// Spawn power-up
function spawnPowerUp() {
var powerup = new PowerUp();
powerup.x = 200 + Math.random() * (2048 - 400);
powerup.y = -100;
game.addChild(powerup);
powerups.push(powerup);
}
// Create explosion
function createExplosion(x, y) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
}
// Handle player hits
function hitPlayer() {
if (playerHasShield) {
playerHasShield = false;
if (shield) {
shield.destroy();
shield = null;
}
return;
}
lives--;
livesTxt.setText('LIVES: ' + lives);
LK.getSound('playerHit').play();
LK.effects.flashScreen(0xff0000, 500);
if (lives <= 0) {
gameActive = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Touch handlers
game.down = function (x, y, obj) {
touchActive = true;
lastTouch.x = x;
lastTouch.y = y;
};
game.move = function (x, y, obj) {
if (touchActive && gameActive) {
// Calculate delta movement
var dx = x - lastTouch.x;
// Apply movement with speed multiplier
player.x += dx * player.speedMultiplier;
// Keep player within bounds
if (player.x < 50) {
player.x = 50;
}
if (player.x > 2048 - 50) {
player.x = 2048 - 50;
}
// Update last touch position
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
touchActive = false;
};
// Game update loop
game.update = function () {
// Process spawning logic
if (gameActive) {
spawnCounter++;
// Enemy spawning - frequency based on level
if (spawnCounter % Math.max(180 - level * 10, 60) === 0) {
spawnEnemy();
}
// Asteroid spawning - frequency based on level
if (spawnCounter % Math.max(240 - level * 15, 90) === 0) {
spawnAsteroid();
}
// Power-up spawning - rare
if (spawnCounter % 600 === 0) {
spawnPowerUp();
}
// Level up every 1000 points
if (score >= level * 1000) {
level++;
levelTxt.setText('LEVEL: ' + level);
}
}
// Update all stars
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Update player
player.update();
// Update shield if active
if (shield) {
shield.update();
shield.x = player.x;
shield.y = player.y;
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Check if bullet is destroyed
if (!bullet.parent) {
playerBullets.splice(i, 1);
continue;
}
// Check collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.health--;
if (enemy.health <= 0) {
createExplosion(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
addScore(100);
} else {
// Flash enemy when hit
LK.effects.flashObject(enemy, 0xffffff, 200);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
// Check collisions with asteroids (if bullet still exists)
if (bullet.parent) {
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (bullet.intersects(asteroid)) {
asteroid.health--;
if (asteroid.health <= 0) {
createExplosion(asteroid.x, asteroid.y);
asteroid.destroy();
asteroids.splice(j, 1);
addScore(50);
} else {
// Flash asteroid when hit
LK.effects.flashObject(asteroid, 0xffffff, 200);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Check if bullet is destroyed
if (!bullet.parent) {
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && bullet.intersects(player)) {
hitPlayer();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check if enemy is destroyed
if (!enemy.parent) {
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && enemy.intersects(player)) {
hitPlayer();
createExplosion(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
asteroid.update();
// Check if asteroid is destroyed
if (!asteroid.parent) {
asteroids.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && asteroid.intersects(player)) {
hitPlayer();
createExplosion(asteroid.x, asteroid.y);
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
// Check if power-up is destroyed
if (!powerup.parent) {
powerups.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && powerup.intersects(player)) {
LK.getSound('powerupCollect').play();
// Apply power-up effect
if (powerup.type === 0) {
player.activateTripleShot();
} else if (powerup.type === 1) {
playerHasShield = true;
if (shield) {
shield.destroy();
}
shield = new Shield();
shield.x = player.x;
shield.y = player.y;
game.addChild(shield);
} else {
player.activateSpeedBoost();
}
addScore(25);
powerup.destroy();
powerups.splice(i, 1);
}
}
// Update explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
explosion.update();
// Check if explosion is destroyed
if (!explosion.parent) {
explosions.splice(i, 1);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var size = 40 + Math.random() * 60;
var asteroidGraphic = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 80,
scaleY: size / 80
});
// Randomly tint the asteroid to give variety
var grayTint = 0x777777 + Math.floor(Math.random() * 0x444444);
asteroidGraphic.tint = grayTint;
self.health = Math.ceil(size / 30);
self.speed = 2 + Math.random() * 3;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
self.hitSize = size; // Store the hit size for collision detection
self.update = function () {
self.y += self.speed;
asteroidGraphic.rotation += self.rotationSpeed;
// Check if asteroid is out of screen
if (self.y > 2732 + 100) {
self.destroy();
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 2;
self.speed = 2;
self.shootTimer = 0;
self.shootInterval = 120 + Math.floor(Math.random() * 60);
self.moveType = Math.floor(Math.random() * 3); // 0: straight, 1: sine, 2: zigzag
self.initialX = 0;
self.moveCounter = 0;
self.update = function () {
// Movement patterns
if (self.moveType === 0) {
// Straight down
self.y += self.speed;
} else if (self.moveType === 1) {
// Sine wave
self.y += self.speed;
self.x = self.initialX + Math.sin(self.moveCounter * 0.05) * 150;
self.moveCounter++;
} else if (self.moveType === 2) {
// Zigzag
self.y += self.speed;
if (self.moveCounter % 60 < 30) {
self.x += 2;
} else {
self.x -= 2;
}
self.moveCounter++;
}
// Shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
if (gameActive) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 40;
game.addChild(bullet);
enemyBullets.push(bullet);
LK.getSound('enemyShoot').play();
}
}
// Check if enemy is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.update = function () {
self.y += self.speed;
// Check if bullet is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var Explosion = Container.expand(function () {
var self = Container.call(this);
var explosionGraphic = self.attachAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.lifetime = 0;
self.maxLifetime = 30;
self.update = function () {
self.lifetime++;
var progress = self.lifetime / self.maxLifetime;
explosionGraphic.scaleX = 1 + progress;
explosionGraphic.scaleY = 1 + progress;
explosionGraphic.alpha = 0.8 * (1 - progress);
if (self.lifetime >= self.maxLifetime) {
self.destroy();
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var shipGraphic = self.attachAsset('playerShip', {
anchorX: 0.5,
anchorY: 0.5
});
var thruster = self.attachAsset('playerThruster', {
anchorX: 0.5,
anchorY: 0,
y: 50,
alpha: 0.7
});
self.shootTimer = 0;
self.shootInterval = 15; // 4 shots per second at 60fps
self.shootType = 0; // 0: single, 1: triple
self.speedMultiplier = 1;
self.tripleTimer = 0;
self.speedTimer = 0;
// Thruster animation
LK.setInterval(function () {
var scale = 0.8 + Math.random() * 0.4;
tween(thruster, {
scaleX: scale,
scaleY: scale
}, {
duration: 100
});
}, 150);
self.update = function () {
// Countdown powerup timers
if (self.tripleTimer > 0) {
self.tripleTimer--;
if (self.tripleTimer === 0) {
self.shootType = 0;
}
}
if (self.speedTimer > 0) {
self.speedTimer--;
if (self.speedTimer === 0) {
self.speedMultiplier = 1;
}
}
// Auto-shooting
if (gameActive) {
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
if (self.shootType === 0) {
// Single shot
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 40;
game.addChild(bullet);
playerBullets.push(bullet);
LK.getSound('playerShoot').play();
} else {
// Triple shot
for (var i = -1; i <= 1; i++) {
var bullet = new PlayerBullet();
bullet.x = self.x + i * 20;
bullet.y = self.y - 40;
game.addChild(bullet);
playerBullets.push(bullet);
}
LK.getSound('playerShoot').play();
}
}
}
};
self.activateTripleShot = function () {
self.shootType = 1;
self.tripleTimer = 300; // 5 seconds at 60fps
};
self.activateSpeedBoost = function () {
self.speedMultiplier = 1.5;
self.speedTimer = 300; // 5 seconds at 60fps
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.damage = 1;
self.update = function () {
self.y += self.speed;
// Check if bullet is out of screen
if (self.y < -50) {
self.destroy();
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphic = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = Math.floor(Math.random() * 3); // 0: triple shot, 1: shield, 2: speed
if (self.type === 0) {
powerupGraphic.tint = 0xff00ff; // Purple for triple shot
} else if (self.type === 1) {
powerupGraphic.tint = 0x00ffff; // Cyan for shield
} else {
powerupGraphic.tint = 0xffff00; // Yellow for speed
}
self.speed = 3;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.update = function () {
self.y += self.speed;
powerupGraphic.rotation += self.rotationSpeed;
// Check if power-up is out of screen
if (self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphic = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.duration = 300; // 5 seconds at 60fps
self.timer = 0;
self.update = function () {
self.timer++;
// Flash when about to end
if (self.timer > self.duration - 60) {
shieldGraphic.alpha = 0.5 * (1 + Math.sin(self.timer * 0.2));
}
if (self.timer >= self.duration) {
self.destroy();
playerHasShield = false;
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphic = self.attachAsset('starParticle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1 + Math.random() * 5;
self.alpha = 0.3 + Math.random() * 0.7;
starGraphic.alpha = self.alpha;
self.update = function () {
self.y += self.speed;
if (self.y > 2732) {
self.y = -10;
self.x = Math.random() * 2048;
self.speed = 1 + Math.random() * 5;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
/*
Supported Types:
1. Shape:
- Simple geometric figures with these properties:
* width: (required) pixel width of the shape.
* height: (required) pixel height of the shape.
* color: (required) color of the shape.
* shape: (required) type of shape. Valid options: 'box', 'ellipse'.
2. Image:
- Imported images with these properties:
* width: (required) pixel resolution width.
* height: (required) pixel resolution height.
* id: (required) identifier for the image.
* flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip).
* flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip).
* orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values:
- 0: No rotation.
- 1: Rotate 90 degrees.
- 2: Rotate 180 degrees.
- 3: Rotate 270 degrees.
Note: Width and height remain unchanged upon flipping.
3. Sound:
- Sound effects with these properties:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
4. Music:
- In contract to sound effects, only one music can be played at a time
- Music is using the same API to initilize just like sound.
- Music loops by default
- Music with these config options:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
* start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping
* end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping
*/
// Game state variables
var gameActive = true;
var score = 0;
var lives = 3;
var level = 1;
var spawnCounter = 0;
var playerBullets = [];
var enemyBullets = [];
var enemies = [];
var asteroids = [];
var powerups = [];
var stars = [];
var explosions = [];
var playerHasShield = false;
var shield = null;
var lastTouch = {
x: 0,
y: 0
};
var touchActive = false;
// Create UI
var scoreTxt = new Text2('SCORE: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -300;
scoreTxt.y = 30;
var livesTxt = new Text2('LIVES: 3', {
size: 60,
fill: 0xFFFFFF
});
livesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(livesTxt);
livesTxt.x = 120; // Avoiding top-left 100x100px
livesTxt.y = 30;
var levelTxt = new Text2('LEVEL: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 30;
// Create player
var player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 200;
game.addChild(player);
// Create star background
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
game.addChild(star);
stars.push(star);
}
// Start game music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Increase score and update display
function addScore(points) {
score += points;
scoreTxt.setText('SCORE: ' + score);
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = -100;
enemy.initialX = enemy.x;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn asteroid
function spawnAsteroid() {
var asteroid = new Asteroid();
asteroid.x = Math.random() * 2048;
asteroid.y = -100;
game.addChild(asteroid);
asteroids.push(asteroid);
}
// Spawn power-up
function spawnPowerUp() {
var powerup = new PowerUp();
powerup.x = 200 + Math.random() * (2048 - 400);
powerup.y = -100;
game.addChild(powerup);
powerups.push(powerup);
}
// Create explosion
function createExplosion(x, y) {
var explosion = new Explosion();
explosion.x = x;
explosion.y = y;
game.addChild(explosion);
explosions.push(explosion);
LK.getSound('explosion').play();
}
// Handle player hits
function hitPlayer() {
if (playerHasShield) {
playerHasShield = false;
if (shield) {
shield.destroy();
shield = null;
}
return;
}
lives--;
livesTxt.setText('LIVES: ' + lives);
LK.getSound('playerHit').play();
LK.effects.flashScreen(0xff0000, 500);
if (lives <= 0) {
gameActive = false;
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Touch handlers
game.down = function (x, y, obj) {
touchActive = true;
lastTouch.x = x;
lastTouch.y = y;
};
game.move = function (x, y, obj) {
if (touchActive && gameActive) {
// Calculate delta movement
var dx = x - lastTouch.x;
// Apply movement with speed multiplier
player.x += dx * player.speedMultiplier;
// Keep player within bounds
if (player.x < 50) {
player.x = 50;
}
if (player.x > 2048 - 50) {
player.x = 2048 - 50;
}
// Update last touch position
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
touchActive = false;
};
// Game update loop
game.update = function () {
// Process spawning logic
if (gameActive) {
spawnCounter++;
// Enemy spawning - frequency based on level
if (spawnCounter % Math.max(180 - level * 10, 60) === 0) {
spawnEnemy();
}
// Asteroid spawning - frequency based on level
if (spawnCounter % Math.max(240 - level * 15, 90) === 0) {
spawnAsteroid();
}
// Power-up spawning - rare
if (spawnCounter % 600 === 0) {
spawnPowerUp();
}
// Level up every 1000 points
if (score >= level * 1000) {
level++;
levelTxt.setText('LEVEL: ' + level);
}
}
// Update all stars
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Update player
player.update();
// Update shield if active
if (shield) {
shield.update();
shield.x = player.x;
shield.y = player.y;
}
// Update player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Check if bullet is destroyed
if (!bullet.parent) {
playerBullets.splice(i, 1);
continue;
}
// Check collisions with enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.health--;
if (enemy.health <= 0) {
createExplosion(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(j, 1);
addScore(100);
} else {
// Flash enemy when hit
LK.effects.flashObject(enemy, 0xffffff, 200);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
// Check collisions with asteroids (if bullet still exists)
if (bullet.parent) {
for (var j = asteroids.length - 1; j >= 0; j--) {
var asteroid = asteroids[j];
if (bullet.intersects(asteroid)) {
asteroid.health--;
if (asteroid.health <= 0) {
createExplosion(asteroid.x, asteroid.y);
asteroid.destroy();
asteroids.splice(j, 1);
addScore(50);
} else {
// Flash asteroid when hit
LK.effects.flashObject(asteroid, 0xffffff, 200);
}
// Remove bullet
bullet.destroy();
playerBullets.splice(i, 1);
break;
}
}
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Check if bullet is destroyed
if (!bullet.parent) {
enemyBullets.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && bullet.intersects(player)) {
hitPlayer();
// Remove bullet
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check if enemy is destroyed
if (!enemy.parent) {
enemies.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && enemy.intersects(player)) {
hitPlayer();
createExplosion(enemy.x, enemy.y);
enemy.destroy();
enemies.splice(i, 1);
}
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var asteroid = asteroids[i];
asteroid.update();
// Check if asteroid is destroyed
if (!asteroid.parent) {
asteroids.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && asteroid.intersects(player)) {
hitPlayer();
createExplosion(asteroid.x, asteroid.y);
asteroid.destroy();
asteroids.splice(i, 1);
}
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.update();
// Check if power-up is destroyed
if (!powerup.parent) {
powerups.splice(i, 1);
continue;
}
// Check collision with player
if (gameActive && powerup.intersects(player)) {
LK.getSound('powerupCollect').play();
// Apply power-up effect
if (powerup.type === 0) {
player.activateTripleShot();
} else if (powerup.type === 1) {
playerHasShield = true;
if (shield) {
shield.destroy();
}
shield = new Shield();
shield.x = player.x;
shield.y = player.y;
game.addChild(shield);
} else {
player.activateSpeedBoost();
}
addScore(25);
powerup.destroy();
powerups.splice(i, 1);
}
}
// Update explosions
for (var i = explosions.length - 1; i >= 0; i--) {
var explosion = explosions[i];
explosion.update();
// Check if explosion is destroyed
if (!explosion.parent) {
explosions.splice(i, 1);
}
}
};