/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
score: 0,
highScore: 0
});
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
// Track if the alien was hit
self.lastWasIntersecting = false;
// Motion pattern variables
self.amplitude = Math.random() * 50 + 30;
self.frequency = Math.random() * 0.05 + 0.02;
self.baseX = 0;
self.time = Math.random() * 100;
self.points = 50;
self.rotationSpeed = (Math.random() - 0.5) * 0.03;
// Pulsate and color effect
tween(alienGraphics, {
alpha: 0.7
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
// Update alien position with sine wave motion and rotation
self.update = function () {
if (game.isPaused) {
return;
}
self.time += 0.05;
self.x = self.baseX + Math.sin(self.time * self.frequency) * self.amplitude;
// Slowly rotate for visual effect
self.rotation += self.rotationSpeed;
};
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Create trail effect
var trailEnabled = true;
var trailInterval = 3; // Create trail every N frames
var trailCount = 0;
var trails = [];
var maxTrails = 5;
// Initial speed properties
self.speedX = 5;
self.speedY = 5;
self.baseSpeed = 5;
self.maxSpeed = 15;
// Track previous position for collision detection
self.lastX = 0;
self.lastY = 0;
// Pulse effect for the ball
tween(ballGraphics, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
// Increase ball speed with limits
self.accelerate = function (amount) {
// Stop any ongoing speed tweens
tween.stop(self, {
speedX: true,
speedY: true
});
// Calculate new speed maintaining direction
var directionX = self.speedX >= 0 ? 1 : -1;
var directionY = self.speedY >= 0 ? 1 : -1;
var currentSpeed = Math.abs(self.speedX);
var newSpeed = Math.min(currentSpeed + amount, self.maxSpeed);
// Apply the new speed with tween effect
tween(self, {
speedX: newSpeed * directionX,
speedY: newSpeed * directionY
}, {
duration: 300,
easing: tween.easeOut
});
// Visual feedback for speed increase
ballGraphics.tint = 0xFFFF00; // Yellow tint
LK.setTimeout(function () {
ballGraphics.tint = 0xFFFFFF; // Reset to white
}, 500);
};
// Toggle trail effect
self.enableTrail = function () {
trailEnabled = true;
};
self.disableTrail = function () {
trailEnabled = false;
// Remove existing trails
for (var i = 0; i < trails.length; i++) {
if (trails[i].parent) {
trails[i].parent.removeChild(trails[i]);
}
}
trails = [];
};
// Reset ball speed to base value
self.resetSpeed = function () {
var directionX = self.speedX >= 0 ? 1 : -1;
var directionY = self.speedY >= 0 ? 1 : -1;
self.speedX = self.baseSpeed * directionX;
self.speedY = self.baseSpeed * directionY;
// Reset visual properties
ballGraphics.tint = 0xFFFFFF;
};
// Update ball position and handle boundary collisions
self.update = function () {
// Skip updates if game is paused
if (game.isPaused) {
return;
}
// Create trail effect
if (trailEnabled) {
trailCount++;
if (trailCount >= trailInterval) {
trailCount = 0;
// Create trail particle
if (self.parent) {
// Make sure ball is attached to something
var trail = LK.getAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
tint: 0xf5e642
});
trail.x = self.x;
trail.y = self.y;
trail.scale.set(0.5);
self.parent.addChild(trail);
trails.push(trail);
// Fade out and remove trail
tween(trail, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeOut,
onComplete: function onComplete() {
if (trail.parent) {
trail.parent.removeChild(trail);
}
var index = trails.indexOf(trail);
if (index !== -1) {
trails.splice(index, 1);
}
}
});
// Limit number of trails
if (trails.length > maxTrails) {
var oldestTrail = trails.shift();
if (oldestTrail.parent) {
oldestTrail.parent.removeChild(oldestTrail);
}
}
}
}
}
// Store last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Update position based on speed
self.x += self.speedX;
self.y += self.speedY;
// Handle wall collisions
if (self.x <= 0 || self.x >= 2048) {
self.speedX *= -1;
// Visual feedback for wall bounce
LK.effects.flashObject(self, 0x00FFFF, 200);
}
if (self.y <= 0) {
self.speedY *= -1;
// Visual feedback for wall bounce
LK.effects.flashObject(self, 0x00FFFF, 200);
}
};
return self;
});
var Button = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.label = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.setText = function (text) {
self.label.setText(text);
};
self.down = function () {
if (self.onPress) {
self.onPress();
}
LK.effects.flashObject(self, 0xFFFFFF, 300);
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glow effect to paddle
var glowEnabled = true;
function updateGlow() {
if (!glowEnabled) {
return;
}
// Pulse effect
tween(paddleGraphics, {
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
// Call it once to start the effect
updateGlow();
// Add methods to enable/disable glow
self.enableGlow = function () {
glowEnabled = true;
updateGlow();
};
self.disableGlow = function () {
glowEnabled = false;
paddleGraphics.alpha = 1;
};
// Handle paddle movement with constraints to keep paddle on screen
self.move = function (x, y) {
// Constrain paddle to screen bounds
var halfWidth = paddleGraphics.width * self.scale.x / 2;
if (x < halfWidth) {
x = halfWidth;
} else if (x > 2048 - halfWidth) {
x = 2048 - halfWidth;
}
// Smooth movement with tween
if (Math.abs(self.x - x) > 10) {
tween.stop(self, {
x: true
});
tween(self, {
x: x
}, {
duration: 100,
easing: tween.easeOut
});
} else {
self.x = x;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// PowerUp properties
self.fallSpeed = 3;
self.type = "speed"; // Default type
self.lastWasIntersecting = false;
// Set the type and color of the power-up
self.setType = function (type) {
self.type = type;
// Set different colors based on power-up type
switch (type) {
case "speed":
powerUpGraphics.tint = 0xFF0000; // Red
break;
case "multiball":
powerUpGraphics.tint = 0x00FF00; // Green
break;
case "expand":
powerUpGraphics.tint = 0x0000FF; // Blue
break;
default:
powerUpGraphics.tint = 0xFFFFFF;
// White
}
};
// Update PowerUp position
self.update = function () {
if (game.isPaused) {
return;
}
// Fall down
self.y += self.fallSpeed;
// Rotate slightly for visual effect
self.rotation += 0.01;
// Remove if off screen
if (self.y > 2732) {
self.parent.removeChild(self);
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize with random speed
self.speed = Math.random() * 2 + 1;
// Update star position, looping from bottom to top
self.update = function () {
if (game.isPaused) {
return;
}
self.y += self.speed;
// Loop back to top when star goes off screen
if (self.y > 2732) {
self.y = 0;
self.x = Math.random() * 2048;
self.speed = Math.random() * 2 + 1;
self.alpha = Math.random() * 0.5 + 0.5;
self.scale.set(Math.random() * 2 + 0.5);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Create starry background
var stars = [];
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.alpha = Math.random() * 0.5 + 0.5;
star.scale.set(Math.random() * 2 + 0.5);
stars.push(star);
game.addChild(star);
}
// Create alien targets
var aliens = [];
var alienRows = 3;
var aliensPerRow = 7;
var alienSpacingX = 250;
var alienSpacingY = 120;
var alienStartY = 400;
for (var row = 0; row < alienRows; row++) {
for (var col = 0; col < aliensPerRow; col++) {
var alien = new Alien();
alien.baseX = 2048 / 2 - (aliensPerRow - 1) * alienSpacingX / 2 + col * alienSpacingX;
alien.y = alienStartY + row * alienSpacingY;
alien.x = alien.baseX;
alien.points = 50 - row * 10; // First row worth more points
alien.scale.set(0.8 - row * 0.1); // First row bigger
aliens.push(alien);
game.addChild(alien);
}
}
// Create the game ball
var ball = new Ball();
ball.x = 2048 / 2;
ball.y = 2732 / 2;
game.addChild(ball);
// Create the player paddle
var paddle = new Paddle();
paddle.x = 2048 / 2;
paddle.y = 2732 - 100;
game.addChild(paddle);
// Tracking variables
var score = storage.score || 0; // Load saved score or start at 0
var speedUpTimer = null;
var consecutiveHits = 0;
var powerUps = [];
var alienCount = aliens.length;
game.isPaused = false; // Initialize game paused state
var paddleOriginalWidth = paddle.width;
// Create score display
var scoreText = new Text2('Score: ' + score, {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create speed indicator
var speedText = new Text2('Ball Speed: Normal', {
size: 60,
fill: 0xFFFF00
});
speedText.anchor.set(0.5, 0);
speedText.y = 100;
LK.gui.top.addChild(speedText);
// Create high score display
var highScoreText = new Text2('High Score: ' + storage.highScore, {
size: 60,
fill: 0xFFA500
});
highScoreText.anchor.set(0.5, 0);
highScoreText.y = 200;
LK.gui.top.addChild(highScoreText);
// Create game status text
var statusText = new Text2('', {
size: 70,
fill: 0x00FFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2732 / 2;
game.addChild(statusText);
// Create hits counter display
var hitsText = new Text2('Consecutive Hits: 0', {
size: 50,
fill: 0x00FF00
});
hitsText.anchor.set(0, 0);
hitsText.x = 50;
hitsText.y = 100;
LK.gui.left.addChild(hitsText);
// Update score display
function updateScore(points) {
score += points;
scoreText.setText('Score: ' + score);
LK.setScore(score);
// Save current score to storage
storage.score = score;
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
}
// Update speed display
function updateSpeedDisplay() {
var currentSpeed = Math.abs(ball.speedX);
var speedLabel = "Normal";
if (currentSpeed >= ball.maxSpeed) {
speedLabel = "MAX!";
} else if (currentSpeed > ball.baseSpeed + 6) {
speedLabel = "Super Fast";
} else if (currentSpeed > ball.baseSpeed + 3) {
speedLabel = "Fast";
}
speedText.setText('Ball Speed: ' + speedLabel);
}
// Speed up the ball with visual effect
function speedUpBall() {
ball.accelerate(1);
updateSpeedDisplay();
// Visual feedback for speed increase
LK.effects.flashObject(ball, 0xff0000, 500);
// Reset timer countdown
lastSpeedUpTick = LK.ticks;
}
// Create a speed up button
var speedUpButton = new Button();
speedUpButton.x = 2048 - 100;
speedUpButton.y = 200;
speedUpButton.setText("Speed");
game.addChild(speedUpButton);
// Create a reset button
var resetButton = new Button();
resetButton.x = 2048 - 100;
resetButton.y = 300;
resetButton.setText("Reset");
game.addChild(resetButton);
// Create a pause button
var pauseButton = new Button();
pauseButton.x = 2048 - 100;
pauseButton.y = 400;
pauseButton.setText("Pause");
game.addChild(pauseButton);
// Event handlers
speedUpButton.onPress = function () {
speedUpBall();
};
resetButton.onPress = function () {
// Reset ball position
ball.x = 2048 / 2;
ball.y = 2732 / 2;
ball.resetSpeed();
updateSpeedDisplay();
};
pauseButton.onPress = function () {
// Toggle game paused state
var isPaused = !game.isPaused;
game.isPaused = isPaused;
pauseButton.setText(isPaused ? "Resume" : "Pause");
};
// Track paddle movement
game.move = function (x, y) {
paddle.move(x, y);
};
// Collision detection
function checkCollisions() {
// Ball-paddle collision
if (ball.lastY <= paddle.y - paddle.height / 2 && ball.y > paddle.y - paddle.height / 2 && ball.x >= paddle.x - paddle.width / 2 && ball.x <= paddle.x + paddle.width / 2) {
// Bounce the ball
ball.speedY *= -1;
// Adjust horizontal speed based on where the ball hits the paddle
var hitPoint = (ball.x - paddle.x) / (paddle.width / 2);
ball.speedX = ball.speedX * 0.5 + hitPoint * 5;
// Increase consecutive hits counter
consecutiveHits++;
// Update hits text
hitsText.setText('Consecutive Hits: ' + consecutiveHits);
// Speed up after certain number of consecutive hits
if (consecutiveHits >= 3) {
speedUpBall();
consecutiveHits = 0;
statusText.setText('SPEED BOOST!');
// Flash status and make it disappear
LK.effects.flashObject(statusText, 0xFFFF00, 500);
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
// Update hits text again
hitsText.setText('Consecutive Hits: ' + consecutiveHits);
}
// Score points
updateScore(10);
// Play hit animation
LK.effects.flashObject(paddle, 0x00FFFF, 300);
}
// Check ball-alien collisions
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
var currentIntersecting = ball.intersects(alien);
if (!alien.lastWasIntersecting && currentIntersecting) {
// Bounce ball
ball.speedY *= -1;
// Add points based on alien value
updateScore(alien.points);
// Visual feedback
LK.effects.flashObject(alien, 0xFFFFFF, 200);
// Remove alien
game.removeChild(alien);
aliens.splice(i, 1);
alienCount--;
// Drop power-up with 20% chance
if (Math.random() < 0.2) {
var powerUp = new PowerUp();
powerUp.x = alien.x;
powerUp.y = alien.y;
// Randomly select power-up type
var types = ["speed", "multiball", "expand"];
var randomType = types[Math.floor(Math.random() * types.length)];
powerUp.setType(randomType);
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Check if all aliens are destroyed
if (alienCount === 0) {
statusText.setText('LEVEL COMPLETE!');
LK.effects.flashScreen(0x00FF00, 800);
// Add bonus points
updateScore(500);
// Respawn aliens after delay
LK.setTimeout(function () {
respawnAliens();
statusText.setText('');
}, 2000);
}
}
// Update last intersecting state
alien.lastWasIntersecting = currentIntersecting;
}
// Check paddle-powerup collisions
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var isIntersecting = powerUp.intersects(paddle);
if (!powerUp.lastWasIntersecting && isIntersecting) {
// Apply power-up effect
applyPowerUp(powerUp.type);
// Visual feedback
LK.effects.flashObject(paddle, 0xFFFF00, 500);
// Remove power-up
game.removeChild(powerUp);
powerUps.splice(j, 1);
}
// Update last intersecting state
powerUp.lastWasIntersecting = isIntersecting;
}
// Ball off bottom of screen (game over condition)
if (ball.y > 2732) {
// Show game over notification
statusText.setText('GAME OVER!');
LK.effects.flashObject(statusText, 0xFF0000, 800);
// Save high score before game ends
if (score > storage.highScore) {
storage.highScore = score;
// Show new high score notification
statusText.setText('NEW HIGH SCORE!');
}
// Reset current score to 0 in storage
storage.score = 0;
// Short delay before showing game over screen
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Apply power-up effects
function applyPowerUp(type) {
switch (type) {
case "speed":
// Speed boost
speedUpBall();
statusText.setText('SPEED BOOST!');
break;
case "multiball":
// Multiball feature would go here
// For simplicity, let's just add points
updateScore(100);
statusText.setText('BONUS POINTS!');
break;
case "expand":
// Expand paddle
var originalWidth = paddle.width;
tween.stop(paddle.scale);
tween(paddle.scale, {
x: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Reset after 10 seconds
LK.setTimeout(function () {
tween(paddle.scale, {
x: 1
}, {
duration: 300,
easing: tween.easeIn
});
}, 10000);
statusText.setText('PADDLE EXPANDED!');
break;
}
// Clear status text after delay
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
}
// Respawn aliens
function respawnAliens() {
// Clear any remaining aliens
for (var i = aliens.length - 1; i >= 0; i--) {
game.removeChild(aliens[i]);
}
aliens = [];
// Respawn with more difficulty
aliensPerRow += 1; // More aliens per row
for (var row = 0; row < alienRows; row++) {
for (var col = 0; col < aliensPerRow; col++) {
var alien = new Alien();
alien.baseX = 2048 / 2 - (aliensPerRow - 1) * alienSpacingX / 2 + col * alienSpacingX;
alien.y = alienStartY + row * alienSpacingY;
alien.x = alien.baseX;
alien.points = (50 - row * 10) * 1.5; // Increased points
alien.scale.set(0.8 - row * 0.1);
alien.frequency += 0.01; // Faster movement
aliens.push(alien);
game.addChild(alien);
}
}
alienCount = aliens.length;
// Speed up ball slightly
speedUpBall();
}
// Auto speed up every 30 seconds
var speedUpInterval = LK.setInterval(function () {
speedUpBall();
// Visual feedback for automatic speed up
statusText.setText('AUTO SPEED BOOST!');
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
}, 30000);
// Track time until next speed up
var nextSpeedUpTime = 30000;
var lastSpeedUpTick = LK.ticks;
// Main game update loop
game.update = function () {
// Skip updates if game is paused
if (game.isPaused) {
return;
}
// Update all stars
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Update all aliens
for (var j = 0; j < aliens.length; j++) {
aliens[j].update();
}
// Update all power-ups
for (var k = powerUps.length - 1; k >= 0; k--) {
powerUps[k].update();
// Remove power-ups that have gone off screen
if (powerUps[k].y > 2732) {
game.removeChild(powerUps[k]);
powerUps.splice(k, 1);
}
}
checkCollisions();
updateSpeedDisplay();
// Update speed up timer display
if (!game.isPaused) {
var elapsedTicks = LK.ticks - lastSpeedUpTick;
var elapsedMs = elapsedTicks * (1000 / 60); // Convert ticks to ms at 60fps
var remainingTime = Math.max(0, Math.ceil((nextSpeedUpTime - elapsedMs) / 1000));
// Display countdown when less than 10 seconds
if (remainingTime <= 10) {
// Get the current speed label without trying to parse the existing text
var currentSpeed = Math.abs(ball.speedX);
var speedLabel = "Normal";
if (currentSpeed >= ball.maxSpeed) {
speedLabel = "MAX!";
} else if (currentSpeed > ball.baseSpeed + 6) {
speedLabel = "Super Fast";
} else if (currentSpeed > ball.baseSpeed + 3) {
speedLabel = "Fast";
}
speedText.setText('Ball Speed: ' + speedLabel + ' (Speed up in ' + remainingTime + ')');
speedText.tint = 0xFF0000; // Red for emphasis
} else {
speedText.tint = 0xFFFF00; // Default yellow
}
// Check if it's time for speed boost (handles missed intervals)
if (elapsedMs >= nextSpeedUpTime) {
speedUpBall();
statusText.setText('AUTO SPEED BOOST!');
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
lastSpeedUpTick = LK.ticks;
}
}
// Fancy visual effect - pulsate active power-ups
if (paddle.scale.x > 1) {
paddle.alpha = 0.7 + Math.sin(LK.ticks * 0.1) * 0.3;
} else {
paddle.alpha = 1;
}
};
// Create speed up keyboard shortcut for testing
LK.setTimeout(function () {
// Initial speed boost to make the game more exciting from the start
speedUpBall();
}, 3000); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
score: 0,
highScore: 0
});
/****
* Classes
****/
var Alien = Container.expand(function () {
var self = Container.call(this);
var alienGraphics = self.attachAsset('alien', {
anchorX: 0.5,
anchorY: 0.5
});
// Track if the alien was hit
self.lastWasIntersecting = false;
// Motion pattern variables
self.amplitude = Math.random() * 50 + 30;
self.frequency = Math.random() * 0.05 + 0.02;
self.baseX = 0;
self.time = Math.random() * 100;
self.points = 50;
self.rotationSpeed = (Math.random() - 0.5) * 0.03;
// Pulsate and color effect
tween(alienGraphics, {
alpha: 0.7
}, {
duration: 1000 + Math.random() * 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
// Update alien position with sine wave motion and rotation
self.update = function () {
if (game.isPaused) {
return;
}
self.time += 0.05;
self.x = self.baseX + Math.sin(self.time * self.frequency) * self.amplitude;
// Slowly rotate for visual effect
self.rotation += self.rotationSpeed;
};
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
// Create trail effect
var trailEnabled = true;
var trailInterval = 3; // Create trail every N frames
var trailCount = 0;
var trails = [];
var maxTrails = 5;
// Initial speed properties
self.speedX = 5;
self.speedY = 5;
self.baseSpeed = 5;
self.maxSpeed = 15;
// Track previous position for collision detection
self.lastX = 0;
self.lastY = 0;
// Pulse effect for the ball
tween(ballGraphics, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
// Increase ball speed with limits
self.accelerate = function (amount) {
// Stop any ongoing speed tweens
tween.stop(self, {
speedX: true,
speedY: true
});
// Calculate new speed maintaining direction
var directionX = self.speedX >= 0 ? 1 : -1;
var directionY = self.speedY >= 0 ? 1 : -1;
var currentSpeed = Math.abs(self.speedX);
var newSpeed = Math.min(currentSpeed + amount, self.maxSpeed);
// Apply the new speed with tween effect
tween(self, {
speedX: newSpeed * directionX,
speedY: newSpeed * directionY
}, {
duration: 300,
easing: tween.easeOut
});
// Visual feedback for speed increase
ballGraphics.tint = 0xFFFF00; // Yellow tint
LK.setTimeout(function () {
ballGraphics.tint = 0xFFFFFF; // Reset to white
}, 500);
};
// Toggle trail effect
self.enableTrail = function () {
trailEnabled = true;
};
self.disableTrail = function () {
trailEnabled = false;
// Remove existing trails
for (var i = 0; i < trails.length; i++) {
if (trails[i].parent) {
trails[i].parent.removeChild(trails[i]);
}
}
trails = [];
};
// Reset ball speed to base value
self.resetSpeed = function () {
var directionX = self.speedX >= 0 ? 1 : -1;
var directionY = self.speedY >= 0 ? 1 : -1;
self.speedX = self.baseSpeed * directionX;
self.speedY = self.baseSpeed * directionY;
// Reset visual properties
ballGraphics.tint = 0xFFFFFF;
};
// Update ball position and handle boundary collisions
self.update = function () {
// Skip updates if game is paused
if (game.isPaused) {
return;
}
// Create trail effect
if (trailEnabled) {
trailCount++;
if (trailCount >= trailInterval) {
trailCount = 0;
// Create trail particle
if (self.parent) {
// Make sure ball is attached to something
var trail = LK.getAsset('ball', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
tint: 0xf5e642
});
trail.x = self.x;
trail.y = self.y;
trail.scale.set(0.5);
self.parent.addChild(trail);
trails.push(trail);
// Fade out and remove trail
tween(trail, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeOut,
onComplete: function onComplete() {
if (trail.parent) {
trail.parent.removeChild(trail);
}
var index = trails.indexOf(trail);
if (index !== -1) {
trails.splice(index, 1);
}
}
});
// Limit number of trails
if (trails.length > maxTrails) {
var oldestTrail = trails.shift();
if (oldestTrail.parent) {
oldestTrail.parent.removeChild(oldestTrail);
}
}
}
}
}
// Store last position for collision detection
self.lastX = self.x;
self.lastY = self.y;
// Update position based on speed
self.x += self.speedX;
self.y += self.speedY;
// Handle wall collisions
if (self.x <= 0 || self.x >= 2048) {
self.speedX *= -1;
// Visual feedback for wall bounce
LK.effects.flashObject(self, 0x00FFFF, 200);
}
if (self.y <= 0) {
self.speedY *= -1;
// Visual feedback for wall bounce
LK.effects.flashObject(self, 0x00FFFF, 200);
}
};
return self;
});
var Button = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.label = new Text2('', {
size: 20,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.setText = function (text) {
self.label.setText(text);
};
self.down = function () {
if (self.onPress) {
self.onPress();
}
LK.effects.flashObject(self, 0xFFFFFF, 300);
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var paddleGraphics = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
// Add glow effect to paddle
var glowEnabled = true;
function updateGlow() {
if (!glowEnabled) {
return;
}
// Pulse effect
tween(paddleGraphics, {
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeInOut,
repeat: -1,
yoyo: true
});
}
// Call it once to start the effect
updateGlow();
// Add methods to enable/disable glow
self.enableGlow = function () {
glowEnabled = true;
updateGlow();
};
self.disableGlow = function () {
glowEnabled = false;
paddleGraphics.alpha = 1;
};
// Handle paddle movement with constraints to keep paddle on screen
self.move = function (x, y) {
// Constrain paddle to screen bounds
var halfWidth = paddleGraphics.width * self.scale.x / 2;
if (x < halfWidth) {
x = halfWidth;
} else if (x > 2048 - halfWidth) {
x = 2048 - halfWidth;
}
// Smooth movement with tween
if (Math.abs(self.x - x) > 10) {
tween.stop(self, {
x: true
});
tween(self, {
x: x
}, {
duration: 100,
easing: tween.easeOut
});
} else {
self.x = x;
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// PowerUp properties
self.fallSpeed = 3;
self.type = "speed"; // Default type
self.lastWasIntersecting = false;
// Set the type and color of the power-up
self.setType = function (type) {
self.type = type;
// Set different colors based on power-up type
switch (type) {
case "speed":
powerUpGraphics.tint = 0xFF0000; // Red
break;
case "multiball":
powerUpGraphics.tint = 0x00FF00; // Green
break;
case "expand":
powerUpGraphics.tint = 0x0000FF; // Blue
break;
default:
powerUpGraphics.tint = 0xFFFFFF;
// White
}
};
// Update PowerUp position
self.update = function () {
if (game.isPaused) {
return;
}
// Fall down
self.y += self.fallSpeed;
// Rotate slightly for visual effect
self.rotation += 0.01;
// Remove if off screen
if (self.y > 2732) {
self.parent.removeChild(self);
}
};
return self;
});
var Star = Container.expand(function () {
var self = Container.call(this);
var starGraphics = self.attachAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize with random speed
self.speed = Math.random() * 2 + 1;
// Update star position, looping from bottom to top
self.update = function () {
if (game.isPaused) {
return;
}
self.y += self.speed;
// Loop back to top when star goes off screen
if (self.y > 2732) {
self.y = 0;
self.x = Math.random() * 2048;
self.speed = Math.random() * 2 + 1;
self.alpha = Math.random() * 0.5 + 0.5;
self.scale.set(Math.random() * 2 + 0.5);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Create starry background
var stars = [];
for (var i = 0; i < 100; i++) {
var star = new Star();
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
star.alpha = Math.random() * 0.5 + 0.5;
star.scale.set(Math.random() * 2 + 0.5);
stars.push(star);
game.addChild(star);
}
// Create alien targets
var aliens = [];
var alienRows = 3;
var aliensPerRow = 7;
var alienSpacingX = 250;
var alienSpacingY = 120;
var alienStartY = 400;
for (var row = 0; row < alienRows; row++) {
for (var col = 0; col < aliensPerRow; col++) {
var alien = new Alien();
alien.baseX = 2048 / 2 - (aliensPerRow - 1) * alienSpacingX / 2 + col * alienSpacingX;
alien.y = alienStartY + row * alienSpacingY;
alien.x = alien.baseX;
alien.points = 50 - row * 10; // First row worth more points
alien.scale.set(0.8 - row * 0.1); // First row bigger
aliens.push(alien);
game.addChild(alien);
}
}
// Create the game ball
var ball = new Ball();
ball.x = 2048 / 2;
ball.y = 2732 / 2;
game.addChild(ball);
// Create the player paddle
var paddle = new Paddle();
paddle.x = 2048 / 2;
paddle.y = 2732 - 100;
game.addChild(paddle);
// Tracking variables
var score = storage.score || 0; // Load saved score or start at 0
var speedUpTimer = null;
var consecutiveHits = 0;
var powerUps = [];
var alienCount = aliens.length;
game.isPaused = false; // Initialize game paused state
var paddleOriginalWidth = paddle.width;
// Create score display
var scoreText = new Text2('Score: ' + score, {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Create speed indicator
var speedText = new Text2('Ball Speed: Normal', {
size: 60,
fill: 0xFFFF00
});
speedText.anchor.set(0.5, 0);
speedText.y = 100;
LK.gui.top.addChild(speedText);
// Create high score display
var highScoreText = new Text2('High Score: ' + storage.highScore, {
size: 60,
fill: 0xFFA500
});
highScoreText.anchor.set(0.5, 0);
highScoreText.y = 200;
LK.gui.top.addChild(highScoreText);
// Create game status text
var statusText = new Text2('', {
size: 70,
fill: 0x00FFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2732 / 2;
game.addChild(statusText);
// Create hits counter display
var hitsText = new Text2('Consecutive Hits: 0', {
size: 50,
fill: 0x00FF00
});
hitsText.anchor.set(0, 0);
hitsText.x = 50;
hitsText.y = 100;
LK.gui.left.addChild(hitsText);
// Update score display
function updateScore(points) {
score += points;
scoreText.setText('Score: ' + score);
LK.setScore(score);
// Save current score to storage
storage.score = score;
// Update high score if needed
if (score > storage.highScore) {
storage.highScore = score;
}
}
// Update speed display
function updateSpeedDisplay() {
var currentSpeed = Math.abs(ball.speedX);
var speedLabel = "Normal";
if (currentSpeed >= ball.maxSpeed) {
speedLabel = "MAX!";
} else if (currentSpeed > ball.baseSpeed + 6) {
speedLabel = "Super Fast";
} else if (currentSpeed > ball.baseSpeed + 3) {
speedLabel = "Fast";
}
speedText.setText('Ball Speed: ' + speedLabel);
}
// Speed up the ball with visual effect
function speedUpBall() {
ball.accelerate(1);
updateSpeedDisplay();
// Visual feedback for speed increase
LK.effects.flashObject(ball, 0xff0000, 500);
// Reset timer countdown
lastSpeedUpTick = LK.ticks;
}
// Create a speed up button
var speedUpButton = new Button();
speedUpButton.x = 2048 - 100;
speedUpButton.y = 200;
speedUpButton.setText("Speed");
game.addChild(speedUpButton);
// Create a reset button
var resetButton = new Button();
resetButton.x = 2048 - 100;
resetButton.y = 300;
resetButton.setText("Reset");
game.addChild(resetButton);
// Create a pause button
var pauseButton = new Button();
pauseButton.x = 2048 - 100;
pauseButton.y = 400;
pauseButton.setText("Pause");
game.addChild(pauseButton);
// Event handlers
speedUpButton.onPress = function () {
speedUpBall();
};
resetButton.onPress = function () {
// Reset ball position
ball.x = 2048 / 2;
ball.y = 2732 / 2;
ball.resetSpeed();
updateSpeedDisplay();
};
pauseButton.onPress = function () {
// Toggle game paused state
var isPaused = !game.isPaused;
game.isPaused = isPaused;
pauseButton.setText(isPaused ? "Resume" : "Pause");
};
// Track paddle movement
game.move = function (x, y) {
paddle.move(x, y);
};
// Collision detection
function checkCollisions() {
// Ball-paddle collision
if (ball.lastY <= paddle.y - paddle.height / 2 && ball.y > paddle.y - paddle.height / 2 && ball.x >= paddle.x - paddle.width / 2 && ball.x <= paddle.x + paddle.width / 2) {
// Bounce the ball
ball.speedY *= -1;
// Adjust horizontal speed based on where the ball hits the paddle
var hitPoint = (ball.x - paddle.x) / (paddle.width / 2);
ball.speedX = ball.speedX * 0.5 + hitPoint * 5;
// Increase consecutive hits counter
consecutiveHits++;
// Update hits text
hitsText.setText('Consecutive Hits: ' + consecutiveHits);
// Speed up after certain number of consecutive hits
if (consecutiveHits >= 3) {
speedUpBall();
consecutiveHits = 0;
statusText.setText('SPEED BOOST!');
// Flash status and make it disappear
LK.effects.flashObject(statusText, 0xFFFF00, 500);
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
// Update hits text again
hitsText.setText('Consecutive Hits: ' + consecutiveHits);
}
// Score points
updateScore(10);
// Play hit animation
LK.effects.flashObject(paddle, 0x00FFFF, 300);
}
// Check ball-alien collisions
for (var i = aliens.length - 1; i >= 0; i--) {
var alien = aliens[i];
var currentIntersecting = ball.intersects(alien);
if (!alien.lastWasIntersecting && currentIntersecting) {
// Bounce ball
ball.speedY *= -1;
// Add points based on alien value
updateScore(alien.points);
// Visual feedback
LK.effects.flashObject(alien, 0xFFFFFF, 200);
// Remove alien
game.removeChild(alien);
aliens.splice(i, 1);
alienCount--;
// Drop power-up with 20% chance
if (Math.random() < 0.2) {
var powerUp = new PowerUp();
powerUp.x = alien.x;
powerUp.y = alien.y;
// Randomly select power-up type
var types = ["speed", "multiball", "expand"];
var randomType = types[Math.floor(Math.random() * types.length)];
powerUp.setType(randomType);
powerUps.push(powerUp);
game.addChild(powerUp);
}
// Check if all aliens are destroyed
if (alienCount === 0) {
statusText.setText('LEVEL COMPLETE!');
LK.effects.flashScreen(0x00FF00, 800);
// Add bonus points
updateScore(500);
// Respawn aliens after delay
LK.setTimeout(function () {
respawnAliens();
statusText.setText('');
}, 2000);
}
}
// Update last intersecting state
alien.lastWasIntersecting = currentIntersecting;
}
// Check paddle-powerup collisions
for (var j = powerUps.length - 1; j >= 0; j--) {
var powerUp = powerUps[j];
var isIntersecting = powerUp.intersects(paddle);
if (!powerUp.lastWasIntersecting && isIntersecting) {
// Apply power-up effect
applyPowerUp(powerUp.type);
// Visual feedback
LK.effects.flashObject(paddle, 0xFFFF00, 500);
// Remove power-up
game.removeChild(powerUp);
powerUps.splice(j, 1);
}
// Update last intersecting state
powerUp.lastWasIntersecting = isIntersecting;
}
// Ball off bottom of screen (game over condition)
if (ball.y > 2732) {
// Show game over notification
statusText.setText('GAME OVER!');
LK.effects.flashObject(statusText, 0xFF0000, 800);
// Save high score before game ends
if (score > storage.highScore) {
storage.highScore = score;
// Show new high score notification
statusText.setText('NEW HIGH SCORE!');
}
// Reset current score to 0 in storage
storage.score = 0;
// Short delay before showing game over screen
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
}
// Apply power-up effects
function applyPowerUp(type) {
switch (type) {
case "speed":
// Speed boost
speedUpBall();
statusText.setText('SPEED BOOST!');
break;
case "multiball":
// Multiball feature would go here
// For simplicity, let's just add points
updateScore(100);
statusText.setText('BONUS POINTS!');
break;
case "expand":
// Expand paddle
var originalWidth = paddle.width;
tween.stop(paddle.scale);
tween(paddle.scale, {
x: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Reset after 10 seconds
LK.setTimeout(function () {
tween(paddle.scale, {
x: 1
}, {
duration: 300,
easing: tween.easeIn
});
}, 10000);
statusText.setText('PADDLE EXPANDED!');
break;
}
// Clear status text after delay
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
}
// Respawn aliens
function respawnAliens() {
// Clear any remaining aliens
for (var i = aliens.length - 1; i >= 0; i--) {
game.removeChild(aliens[i]);
}
aliens = [];
// Respawn with more difficulty
aliensPerRow += 1; // More aliens per row
for (var row = 0; row < alienRows; row++) {
for (var col = 0; col < aliensPerRow; col++) {
var alien = new Alien();
alien.baseX = 2048 / 2 - (aliensPerRow - 1) * alienSpacingX / 2 + col * alienSpacingX;
alien.y = alienStartY + row * alienSpacingY;
alien.x = alien.baseX;
alien.points = (50 - row * 10) * 1.5; // Increased points
alien.scale.set(0.8 - row * 0.1);
alien.frequency += 0.01; // Faster movement
aliens.push(alien);
game.addChild(alien);
}
}
alienCount = aliens.length;
// Speed up ball slightly
speedUpBall();
}
// Auto speed up every 30 seconds
var speedUpInterval = LK.setInterval(function () {
speedUpBall();
// Visual feedback for automatic speed up
statusText.setText('AUTO SPEED BOOST!');
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
}, 30000);
// Track time until next speed up
var nextSpeedUpTime = 30000;
var lastSpeedUpTick = LK.ticks;
// Main game update loop
game.update = function () {
// Skip updates if game is paused
if (game.isPaused) {
return;
}
// Update all stars
for (var i = 0; i < stars.length; i++) {
stars[i].update();
}
// Update all aliens
for (var j = 0; j < aliens.length; j++) {
aliens[j].update();
}
// Update all power-ups
for (var k = powerUps.length - 1; k >= 0; k--) {
powerUps[k].update();
// Remove power-ups that have gone off screen
if (powerUps[k].y > 2732) {
game.removeChild(powerUps[k]);
powerUps.splice(k, 1);
}
}
checkCollisions();
updateSpeedDisplay();
// Update speed up timer display
if (!game.isPaused) {
var elapsedTicks = LK.ticks - lastSpeedUpTick;
var elapsedMs = elapsedTicks * (1000 / 60); // Convert ticks to ms at 60fps
var remainingTime = Math.max(0, Math.ceil((nextSpeedUpTime - elapsedMs) / 1000));
// Display countdown when less than 10 seconds
if (remainingTime <= 10) {
// Get the current speed label without trying to parse the existing text
var currentSpeed = Math.abs(ball.speedX);
var speedLabel = "Normal";
if (currentSpeed >= ball.maxSpeed) {
speedLabel = "MAX!";
} else if (currentSpeed > ball.baseSpeed + 6) {
speedLabel = "Super Fast";
} else if (currentSpeed > ball.baseSpeed + 3) {
speedLabel = "Fast";
}
speedText.setText('Ball Speed: ' + speedLabel + ' (Speed up in ' + remainingTime + ')');
speedText.tint = 0xFF0000; // Red for emphasis
} else {
speedText.tint = 0xFFFF00; // Default yellow
}
// Check if it's time for speed boost (handles missed intervals)
if (elapsedMs >= nextSpeedUpTime) {
speedUpBall();
statusText.setText('AUTO SPEED BOOST!');
LK.setTimeout(function () {
statusText.setText('');
}, 1500);
lastSpeedUpTick = LK.ticks;
}
}
// Fancy visual effect - pulsate active power-ups
if (paddle.scale.x > 1) {
paddle.alpha = 0.7 + Math.sin(LK.ticks * 0.1) * 0.3;
} else {
paddle.alpha = 1;
}
};
// Create speed up keyboard shortcut for testing
LK.setTimeout(function () {
// Initial speed boost to make the game more exciting from the start
speedUpBall();
}, 3000);