/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Asteroid var Asteroid = Container.expand(function () { var self = Container.call(this); var asteroid = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5 }); // Randomize rotation asteroid.rotation = Math.random() * Math.PI * 2; // Speed and direction self.speedY = 3 + Math.random() * 2; // 3-5 px/frame (slower) self.speedX = (Math.random() - 0.5) * 2; // -1 to 1 px/frame (slower) // For collision self.radius = asteroid.width * 0.5; // For rotation animation self.rotSpeed = (Math.random() - 0.5) * 0.04; // Update method self.update = function () { self.y += self.speedY; self.x += self.speedX; asteroid.rotation += self.rotSpeed; }; return self; }); // Dog Ship (Player) var DogShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('dogShip', { anchorX: 0.5, anchorY: 0.5 }); // For collision, use the container itself self.radius = ship.width * 0.5; // For drag effect self.isDragging = false; return self; }); // Large Asteroid (rare, big, dangerous) var LargeAsteroid = Container.expand(function () { var self = Container.call(this); var asteroid = self.attachAsset('asteroid', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.1, scaleY: 2.1 }); // Randomize rotation asteroid.rotation = Math.random() * Math.PI * 2; // Slower speed, but still moves self.speedY = 2 + Math.random() * 1.5; // 2-3.5 px/frame self.speedX = (Math.random() - 0.5) * 1.2; // -0.6 to 0.6 px/frame self.radius = asteroid.width * 0.5 * 2.1; // scale radius self.rotSpeed = (Math.random() - 0.5) * 0.025; self.isLargeAsteroid = true; // Add hit points for large asteroid self.hp = 10; self.update = function () { self.y += self.speedY; self.x += self.speedX; asteroid.rotation += self.rotSpeed; }; // Method to take damage self.takeDamage = function () { self.hp--; // Optionally, you could add a visual effect here (e.g. flash) if (self.hp <= 0) { self.destroy(); return true; // destroyed } return false; // not destroyed }; return self; }); // Laser var Laser = Container.expand(function () { var self = Container.call(this); var laser = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5 }); self.speedY = -22; // Fast upward // For collision self.radius = laser.width * 0.5; self.update = function () { self.y += self.speedY; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0a0a1a }); /**** * Game Code ****/ // Play background music // Spaceship (dog ship) // Asteroid // Laser // Sound for shooting // Sound for asteroid destroyed // Music (background) LK.playMusic('spaceMusic'); // --- Space background: animated twinkling stars --- var starCount = 60; var stars = []; for (var i = 0; i < starCount; i++) { var star = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.18 + Math.random() * 0.12, scaleY: 0.18 + Math.random() * 0.12, x: Math.random() * 2048, y: Math.random() * 2732 }); star.alpha = 0.5 + Math.random() * 0.5; star._twinkleSpeed = 0.008 + Math.random() * 0.012; star._twinklePhase = Math.random() * Math.PI * 2; stars.push(star); // Add behind everything game.addChildAt(star, 0); } // Score display var scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Game variables var dogShip; var asteroids = []; var lasers = []; var dragNode = null; var lastGameOver = false; var asteroidSpawnTick = 0; // Player lives var lives = 5; // Lives display var livesTxt = new Text2('Lives: 5', { size: 90, fill: "#fff" }); livesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(livesTxt); livesTxt.y = 120; // Place below score // Place dog ship at bottom center, above bottom edge dogShip = new DogShip(); game.addChild(dogShip); dogShip.x = 2048 / 2; dogShip.y = 2732 - 320; // Prevent dogShip from going off screen function clampShipPosition() { var margin = dogShip.radius + 30; if (dogShip.x < margin) dogShip.x = margin; if (dogShip.x > 2048 - margin) dogShip.x = 2048 - margin; if (dogShip.y < margin + 120) dogShip.y = margin + 120; // Don't go under score if (dogShip.y > 2732 - margin) dogShip.y = 2732 - margin; } // Touch/mouse drag to move dog ship function handleMove(x, y, obj) { if (dragNode) { dragNode.x = x; dragNode.y = y; clampShipPosition(); } } game.move = handleMove; game.down = function (x, y, obj) { // Only start drag if touch is on the ship var dx = x - dogShip.x; var dy = y - dogShip.y; if (dx * dx + dy * dy < dogShip.radius * dogShip.radius) { dragNode = dogShip; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; // Laser will now fire automatically every 2 seconds (see interval below) // For mobile, treat down as tap if not dragging game.down = function (x, y, obj) { var dx = x - dogShip.x; var dy = y - dogShip.y; if (dx * dx + dy * dy < dogShip.radius * dogShip.radius) { dragNode = dogShip; handleMove(x, y, obj); } else { // Not on ship: tap left/right to move // Define left/right/center regions var leftEdge = 0; var rightEdge = 2048; var centerWidth = 400; var leftRegion = (rightEdge - centerWidth) / 2; var rightRegion = (rightEdge + centerWidth) / 2; if (x < leftRegion) { // Move ship left by a fixed amount dogShip.x -= 220; clampShipPosition(); } else if (x > rightRegion) { // Move ship right by a fixed amount dogShip.x += 220; clampShipPosition(); } // No shooting on tap, as laser is now automatic } }; // Fire laser every 0.3 seconds automatically var laserInterval = LK.setInterval(function () { if (lastGameOver) return; var laser = new Laser(); laser.x = dogShip.x; laser.y = dogShip.y - dogShip.radius - 30; lasers.push(laser); game.addChild(laser); LK.getSound('laserShoot').play(); }, 300); // Asteroid spawn logic function spawnAsteroid() { // 30% chance for a large asteroid var isLarge = Math.random() < 0.3; var asteroid; if (isLarge) { asteroid = new LargeAsteroid(); } else { asteroid = new Asteroid(); } // Spawn at random X, just above top var margin = asteroid.radius + 40; asteroid.x = margin + Math.random() * (2048 - margin * 2); asteroid.y = -asteroid.radius - 40; asteroids.push(asteroid); game.addChild(asteroid); } // Collision detection (circle vs circle) function circlesIntersect(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var r = a.radius + b.radius - 10; // -10 for some forgiveness return dx * dx + dy * dy < r * r; } // Main game update game.update = function () { // Animate stars (twinkle) for (var si = 0; si < stars.length; si++) { var s = stars[si]; s.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * s._twinkleSpeed + s._twinklePhase); } // Asteroid spawn rate: every 40-70 ticks, randomize for tension asteroidSpawnTick--; if (asteroidSpawnTick <= 0) { spawnAsteroid(); asteroidSpawnTick = 40 + Math.floor(Math.random() * 30); } // Update asteroids for (var i = asteroids.length - 1; i >= 0; i--) { var a = asteroids[i]; a.update(); // Remove if off screen if (a.y - a.radius > 2732 + 60) { a.destroy(); asteroids.splice(i, 1); continue; } // Check collision with dogShip if (!lastGameOver && circlesIntersect(a, dogShip)) { if (a.isLargeAsteroid) { // Large asteroid: lose all lives instantly lives = 0; livesTxt.setText('Lives: 0'); LK.effects.flashScreen(0xff0000, 1200); tween(dogShip, { alpha: 0.2 }, { duration: 500, easing: tween.easeOut }); // Remove asteroid a.destroy(); asteroids.splice(i, 1); lastGameOver = true; LK.showGameOver(); return; } else { // Normal asteroid: lose one life lives--; livesTxt.setText('Lives: ' + lives); LK.effects.flashScreen(0xff0000, 900); tween(dogShip, { alpha: 0.2 }, { duration: 400, easing: tween.easeOut }); // Remove asteroid a.destroy(); asteroids.splice(i, 1); if (lives <= 0) { lastGameOver = true; LK.showGameOver(); return; } else { // Briefly flash ship, restore alpha tween(dogShip, { alpha: 1 }, { duration: 400, easing: tween.easeOut }); } } } } // Update lasers for (var j = lasers.length - 1; j >= 0; j--) { var l = lasers[j]; l.update(); // Remove if off screen if (l.y + l.radius < -60) { l.destroy(); lasers.splice(j, 1); continue; } // Check collision with asteroids for (var k = asteroids.length - 1; k >= 0; k--) { var a2 = asteroids[k]; if (circlesIntersect(l, a2)) { LK.getSound('asteroidHit').play(); if (a2.isLargeAsteroid) { // Only destroy laser, decrement hp, destroy asteroid if hp reaches 0 l.destroy(); lasers.splice(j, 1); var destroyed = a2.takeDamage(); if (destroyed) { asteroids.splice(k, 1); LK.setScore(LK.getScore() + 100); scoreTxt.setText(LK.getScore()); // Extra life! lives++; livesTxt.setText('Lives: ' + lives); // Big explosion effect LK.effects.flashObject(dogShip, 0xffe000, 400); } } else { // Normal asteroid: destroy both a2.destroy(); asteroids.splice(k, 1); l.destroy(); lasers.splice(j, 1); LK.setScore(LK.getScore() + 10); scoreTxt.setText(LK.getScore()); // Small asteroid explosion effect LK.effects.flashObject(dogShip, 0x00e0ff, 200); } break; } } } }; // Reset state on new game LK.on('gameStart', function () { // Remove all asteroids and lasers for (var i = 0; i < asteroids.length; i++) asteroids[i].destroy(); for (var j = 0; j < lasers.length; j++) lasers[j].destroy(); asteroids = []; lasers = []; // Reset dogShip dogShip.x = 2048 / 2; dogShip.y = 2732 - 320; dogShip.alpha = 1; lastGameOver = false; scoreTxt.setText('0'); LK.setScore(0); asteroidSpawnTick = 30; clampShipPosition(); // Reset lives lives = 5; livesTxt.setText('Lives: ' + lives); // Restart music LK.playMusic('spaceMusic'); // Restart laser interval if (typeof laserInterval !== "undefined") { LK.clearInterval(laserInterval); } laserInterval = LK.setInterval(function () { if (lastGameOver) return; var laser = new Laser(); laser.x = dogShip.x; laser.y = dogShip.y - dogShip.radius - 30; lasers.push(laser); game.addChild(laser); LK.getSound('laserShoot').play(); }, 300); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Asteroid
var Asteroid = Container.expand(function () {
var self = Container.call(this);
var asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5
});
// Randomize rotation
asteroid.rotation = Math.random() * Math.PI * 2;
// Speed and direction
self.speedY = 3 + Math.random() * 2; // 3-5 px/frame (slower)
self.speedX = (Math.random() - 0.5) * 2; // -1 to 1 px/frame (slower)
// For collision
self.radius = asteroid.width * 0.5;
// For rotation animation
self.rotSpeed = (Math.random() - 0.5) * 0.04;
// Update method
self.update = function () {
self.y += self.speedY;
self.x += self.speedX;
asteroid.rotation += self.rotSpeed;
};
return self;
});
// Dog Ship (Player)
var DogShip = Container.expand(function () {
var self = Container.call(this);
var ship = self.attachAsset('dogShip', {
anchorX: 0.5,
anchorY: 0.5
});
// For collision, use the container itself
self.radius = ship.width * 0.5;
// For drag effect
self.isDragging = false;
return self;
});
// Large Asteroid (rare, big, dangerous)
var LargeAsteroid = Container.expand(function () {
var self = Container.call(this);
var asteroid = self.attachAsset('asteroid', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.1,
scaleY: 2.1
});
// Randomize rotation
asteroid.rotation = Math.random() * Math.PI * 2;
// Slower speed, but still moves
self.speedY = 2 + Math.random() * 1.5; // 2-3.5 px/frame
self.speedX = (Math.random() - 0.5) * 1.2; // -0.6 to 0.6 px/frame
self.radius = asteroid.width * 0.5 * 2.1; // scale radius
self.rotSpeed = (Math.random() - 0.5) * 0.025;
self.isLargeAsteroid = true;
// Add hit points for large asteroid
self.hp = 10;
self.update = function () {
self.y += self.speedY;
self.x += self.speedX;
asteroid.rotation += self.rotSpeed;
};
// Method to take damage
self.takeDamage = function () {
self.hp--;
// Optionally, you could add a visual effect here (e.g. flash)
if (self.hp <= 0) {
self.destroy();
return true; // destroyed
}
return false; // not destroyed
};
return self;
});
// Laser
var Laser = Container.expand(function () {
var self = Container.call(this);
var laser = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedY = -22; // Fast upward
// For collision
self.radius = laser.width * 0.5;
self.update = function () {
self.y += self.speedY;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0a1a
});
/****
* Game Code
****/
// Play background music
// Spaceship (dog ship)
// Asteroid
// Laser
// Sound for shooting
// Sound for asteroid destroyed
// Music (background)
LK.playMusic('spaceMusic');
// --- Space background: animated twinkling stars ---
var starCount = 60;
var stars = [];
for (var i = 0; i < starCount; i++) {
var star = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.18 + Math.random() * 0.12,
scaleY: 0.18 + Math.random() * 0.12,
x: Math.random() * 2048,
y: Math.random() * 2732
});
star.alpha = 0.5 + Math.random() * 0.5;
star._twinkleSpeed = 0.008 + Math.random() * 0.012;
star._twinklePhase = Math.random() * Math.PI * 2;
stars.push(star);
// Add behind everything
game.addChildAt(star, 0);
}
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Game variables
var dogShip;
var asteroids = [];
var lasers = [];
var dragNode = null;
var lastGameOver = false;
var asteroidSpawnTick = 0;
// Player lives
var lives = 5;
// Lives display
var livesTxt = new Text2('Lives: 5', {
size: 90,
fill: "#fff"
});
livesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(livesTxt);
livesTxt.y = 120; // Place below score
// Place dog ship at bottom center, above bottom edge
dogShip = new DogShip();
game.addChild(dogShip);
dogShip.x = 2048 / 2;
dogShip.y = 2732 - 320;
// Prevent dogShip from going off screen
function clampShipPosition() {
var margin = dogShip.radius + 30;
if (dogShip.x < margin) dogShip.x = margin;
if (dogShip.x > 2048 - margin) dogShip.x = 2048 - margin;
if (dogShip.y < margin + 120) dogShip.y = margin + 120; // Don't go under score
if (dogShip.y > 2732 - margin) dogShip.y = 2732 - margin;
}
// Touch/mouse drag to move dog ship
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
clampShipPosition();
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only start drag if touch is on the ship
var dx = x - dogShip.x;
var dy = y - dogShip.y;
if (dx * dx + dy * dy < dogShip.radius * dogShip.radius) {
dragNode = dogShip;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Laser will now fire automatically every 2 seconds (see interval below)
// For mobile, treat down as tap if not dragging
game.down = function (x, y, obj) {
var dx = x - dogShip.x;
var dy = y - dogShip.y;
if (dx * dx + dy * dy < dogShip.radius * dogShip.radius) {
dragNode = dogShip;
handleMove(x, y, obj);
} else {
// Not on ship: tap left/right to move
// Define left/right/center regions
var leftEdge = 0;
var rightEdge = 2048;
var centerWidth = 400;
var leftRegion = (rightEdge - centerWidth) / 2;
var rightRegion = (rightEdge + centerWidth) / 2;
if (x < leftRegion) {
// Move ship left by a fixed amount
dogShip.x -= 220;
clampShipPosition();
} else if (x > rightRegion) {
// Move ship right by a fixed amount
dogShip.x += 220;
clampShipPosition();
}
// No shooting on tap, as laser is now automatic
}
};
// Fire laser every 0.3 seconds automatically
var laserInterval = LK.setInterval(function () {
if (lastGameOver) return;
var laser = new Laser();
laser.x = dogShip.x;
laser.y = dogShip.y - dogShip.radius - 30;
lasers.push(laser);
game.addChild(laser);
LK.getSound('laserShoot').play();
}, 300);
// Asteroid spawn logic
function spawnAsteroid() {
// 30% chance for a large asteroid
var isLarge = Math.random() < 0.3;
var asteroid;
if (isLarge) {
asteroid = new LargeAsteroid();
} else {
asteroid = new Asteroid();
}
// Spawn at random X, just above top
var margin = asteroid.radius + 40;
asteroid.x = margin + Math.random() * (2048 - margin * 2);
asteroid.y = -asteroid.radius - 40;
asteroids.push(asteroid);
game.addChild(asteroid);
}
// Collision detection (circle vs circle)
function circlesIntersect(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
var r = a.radius + b.radius - 10; // -10 for some forgiveness
return dx * dx + dy * dy < r * r;
}
// Main game update
game.update = function () {
// Animate stars (twinkle)
for (var si = 0; si < stars.length; si++) {
var s = stars[si];
s.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * s._twinkleSpeed + s._twinklePhase);
}
// Asteroid spawn rate: every 40-70 ticks, randomize for tension
asteroidSpawnTick--;
if (asteroidSpawnTick <= 0) {
spawnAsteroid();
asteroidSpawnTick = 40 + Math.floor(Math.random() * 30);
}
// Update asteroids
for (var i = asteroids.length - 1; i >= 0; i--) {
var a = asteroids[i];
a.update();
// Remove if off screen
if (a.y - a.radius > 2732 + 60) {
a.destroy();
asteroids.splice(i, 1);
continue;
}
// Check collision with dogShip
if (!lastGameOver && circlesIntersect(a, dogShip)) {
if (a.isLargeAsteroid) {
// Large asteroid: lose all lives instantly
lives = 0;
livesTxt.setText('Lives: 0');
LK.effects.flashScreen(0xff0000, 1200);
tween(dogShip, {
alpha: 0.2
}, {
duration: 500,
easing: tween.easeOut
});
// Remove asteroid
a.destroy();
asteroids.splice(i, 1);
lastGameOver = true;
LK.showGameOver();
return;
} else {
// Normal asteroid: lose one life
lives--;
livesTxt.setText('Lives: ' + lives);
LK.effects.flashScreen(0xff0000, 900);
tween(dogShip, {
alpha: 0.2
}, {
duration: 400,
easing: tween.easeOut
});
// Remove asteroid
a.destroy();
asteroids.splice(i, 1);
if (lives <= 0) {
lastGameOver = true;
LK.showGameOver();
return;
} else {
// Briefly flash ship, restore alpha
tween(dogShip, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
}
}
}
}
// Update lasers
for (var j = lasers.length - 1; j >= 0; j--) {
var l = lasers[j];
l.update();
// Remove if off screen
if (l.y + l.radius < -60) {
l.destroy();
lasers.splice(j, 1);
continue;
}
// Check collision with asteroids
for (var k = asteroids.length - 1; k >= 0; k--) {
var a2 = asteroids[k];
if (circlesIntersect(l, a2)) {
LK.getSound('asteroidHit').play();
if (a2.isLargeAsteroid) {
// Only destroy laser, decrement hp, destroy asteroid if hp reaches 0
l.destroy();
lasers.splice(j, 1);
var destroyed = a2.takeDamage();
if (destroyed) {
asteroids.splice(k, 1);
LK.setScore(LK.getScore() + 100);
scoreTxt.setText(LK.getScore());
// Extra life!
lives++;
livesTxt.setText('Lives: ' + lives);
// Big explosion effect
LK.effects.flashObject(dogShip, 0xffe000, 400);
}
} else {
// Normal asteroid: destroy both
a2.destroy();
asteroids.splice(k, 1);
l.destroy();
lasers.splice(j, 1);
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Small asteroid explosion effect
LK.effects.flashObject(dogShip, 0x00e0ff, 200);
}
break;
}
}
}
};
// Reset state on new game
LK.on('gameStart', function () {
// Remove all asteroids and lasers
for (var i = 0; i < asteroids.length; i++) asteroids[i].destroy();
for (var j = 0; j < lasers.length; j++) lasers[j].destroy();
asteroids = [];
lasers = [];
// Reset dogShip
dogShip.x = 2048 / 2;
dogShip.y = 2732 - 320;
dogShip.alpha = 1;
lastGameOver = false;
scoreTxt.setText('0');
LK.setScore(0);
asteroidSpawnTick = 30;
clampShipPosition();
// Reset lives
lives = 5;
livesTxt.setText('Lives: ' + lives);
// Restart music
LK.playMusic('spaceMusic');
// Restart laser interval
if (typeof laserInterval !== "undefined") {
LK.clearInterval(laserInterval);
}
laserInterval = LK.setInterval(function () {
if (lastGameOver) return;
var laser = new Laser();
laser.x = dogShip.x;
laser.y = dogShip.y - dogShip.radius - 30;
lasers.push(laser);
game.addChild(laser);
LK.getSound('laserShoot').play();
}, 300);
});
Modern App Store icon, high definition, square with rounded corners, for a game titled "Space Dog: Asteroid Blaster" and with the description "Control a spacefaring dog, shoot asteroids, and avoid collisions to survive and score points.". No text on icon!
A BIG GRAY ASTEROID. In-Game asset. 2d. High contrast. No shadows. Retro 8bt
16 bit super nintendo