/****
* 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