User prompt
Add SSR spawns to the guide. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add enemy SSR bias (MiG-23, Yak-38 and Drones in Ukraine, MiG-23, Su-15, SAMs in Russia, Yak-38 (swarms), drones and Shilkas in Kazakhstan and SAMs, Su-15s, Shilkas and MiG-23s in Belarus)
User prompt
Add a Shilka SPAA enemy (Behaves similarly to a drone, but shoots in bursts (bursts include 5x 3-bullet groups) and rolls vertically)
User prompt
Now make a guide with 2 tips on each enemy, how to use travel and upgrades and Basic maneuvers.
User prompt
Now the Interceptor Split (MiG-23, Su-15, Yak-38) ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
You can do a Enemy CODEX, as I'm planning the Interceptor Type Split. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add traveling to different Soviet SSRs.
User prompt
No, the popup for the store is either invisible or does not show.
User prompt
Upgrade store won't show.
User prompt
Add upgrades for the Viggen that you buy with score ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make SAM spawning rarer, it's the main challenge
User prompt
Add powerups
User prompt
Make the viggen shoot bullets at the enemies
User prompt
Clean up shots from interceptor after a bit, should help
User prompt
Game starts lagging significantly after a few dodges
Code edit (1 edits merged)
Please save this source code
User prompt
Viggen Strike: Soviet Skies
Initial prompt
A bullet hell videogame where you control an Saab 37 Viggen through Soviet airspace while dodging interceptors, SAMs and drones.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Drone = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('drone', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; self.direction = 1; self.fireTimer = 0; self.fireRate = 45; self.update = function () { self.x += self.speed * self.direction; self.y += self.speed * 0.5; if (self.x <= 50 || self.x >= 1998) { self.direction *= -1; } self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } graphics.rotation += 0.05; }; return self; }); var EnemyBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; self.targetX = 0; self.targetY = 0; self.update = function () { self.age = (self.age || 0) + 1; var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } }; return self; }); var Interceptor = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('interceptor', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.fireTimer = 0; self.fireRate = 60; self.update = function () { self.y += self.speed; self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y; bullet.targetX = viggen.x; bullet.targetY = viggen.y; bullet.age = 0; game.addChild(bullet); enemyBullets.push(bullet); } }; return self; }); var SAMMissile = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('samMissile', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.targetX = 0; self.targetY = 0; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } graphics.rotation += 0.1; }; return self; }); var SAMSite = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('sam', { anchorX: 0.5, anchorY: 0.5 }); self.fireTimer = 0; self.fireRate = 90; self.update = function () { self.fireTimer++; if (self.fireTimer >= self.fireRate) { self.fireTimer = 0; var missile = new SAMMissile(); missile.x = self.x; missile.y = self.y; missile.targetX = viggen.x; missile.targetY = viggen.y; game.addChild(missile); samMissiles.push(missile); LK.getSound('missile').play(); } }; return self; }); var Viggen = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('viggen', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var ViggenBullet = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('viggenBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.update = function () { self.y -= self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ var viggen = game.addChild(new Viggen()); viggen.x = 1024; viggen.y = 2400; var interceptors = []; var samSites = []; var drones = []; var enemyBullets = []; var samMissiles = []; var viggenBullets = []; var spawnTimer = 0; var fireTimer = 0; var difficultyTimer = 0; var survivalTime = 0; var baseSpawnRate = 180; var currentSpawnRate = baseSpawnRate; var dragNode = null; var lastIntersecting = false; var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var timeTxt = new Text2('Time: 0s', { size: 50, fill: 0xFFFFFF }); timeTxt.anchor.set(1, 0); timeTxt.x = -20; timeTxt.y = 20; LK.gui.topRight.addChild(timeTxt); function handleMove(x, y, obj) { if (dragNode) { dragNode.x = Math.max(40, Math.min(2008, x)); dragNode.y = Math.max(60, Math.min(2672, y)); } // Check viggen bullets vs enemies for (var i = viggenBullets.length - 1; i >= 0; i--) { var bullet = viggenBullets[i]; var hit = false; // Check vs interceptors for (var j = interceptors.length - 1; j >= 0; j--) { if (bullet.intersects(interceptors[j])) { LK.effects.flashObject(interceptors[j], 0xff0000, 200); interceptors[j].destroy(); interceptors.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); LK.setScore(LK.getScore() + 100); hit = true; break; } } if (hit) continue; // Check vs drones for (var j = drones.length - 1; j >= 0; j--) { if (bullet.intersects(drones[j])) { LK.effects.flashObject(drones[j], 0xff0000, 200); drones[j].destroy(); drones.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); LK.setScore(LK.getScore() + 150); hit = true; break; } } if (hit) continue; // Check vs SAM sites for (var j = samSites.length - 1; j >= 0; j--) { if (bullet.intersects(samSites[j])) { LK.effects.flashObject(samSites[j], 0xff0000, 200); samSites[j].destroy(); samSites.splice(j, 1); bullet.destroy(); viggenBullets.splice(i, 1); LK.setScore(LK.getScore() + 200); hit = true; break; } } } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = viggen; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; function spawnInterceptor() { var interceptor = new Interceptor(); interceptor.x = Math.random() * 1848 + 100; interceptor.y = -100; game.addChild(interceptor); interceptors.push(interceptor); } function spawnSAMSite() { var sam = new SAMSite(); sam.x = Math.random() * 1848 + 100; sam.y = Math.random() * 400 + 100; game.addChild(sam); samSites.push(sam); } function spawnDrone() { var drone = new Drone(); drone.x = Math.random() * 1848 + 100; drone.y = -50; game.addChild(drone); drones.push(drone); } function checkCollisions() { for (var i = 0; i < enemyBullets.length; i++) { if (viggen.intersects(enemyBullets[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < samMissiles.length; i++) { if (viggen.intersects(samMissiles[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < interceptors.length; i++) { if (viggen.intersects(interceptors[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } for (var i = 0; i < drones.length; i++) { if (viggen.intersects(drones[i])) { LK.effects.flashScreen(0xff0000, 1000); LK.getSound('explosion').play(); LK.showGameOver(); return; } } } function cleanupOffscreenEntities() { for (var i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i].y > 2800) { interceptors[i].destroy(); interceptors.splice(i, 1); } } for (var i = drones.length - 1; i >= 0; i--) { if (drones[i].y > 2800) { drones[i].destroy(); drones.splice(i, 1); } } for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; if (bullet.x < -20 || bullet.x > 2068 || bullet.y < -20 || bullet.y > 2752 || bullet.age && bullet.age > 300) { bullet.destroy(); enemyBullets.splice(i, 1); } } for (var i = samMissiles.length - 1; i >= 0; i--) { var missile = samMissiles[i]; if (missile.x < -50 || missile.x > 2098 || missile.y < -50 || missile.y > 2782) { missile.destroy(); samMissiles.splice(i, 1); } } for (var i = samSites.length - 1; i >= 0; i--) { if (samSites[i].y > 2800 || samSites[i].x < -100 || samSites[i].x > 2148) { samSites[i].destroy(); samSites.splice(i, 1); } } // Clean up viggen bullets for (var i = viggenBullets.length - 1; i >= 0; i--) { if (viggenBullets[i].y < -50) { viggenBullets[i].destroy(); viggenBullets.splice(i, 1); } } } game.update = function () { survivalTime++; difficultyTimer++; spawnTimer++; if (LK.ticks % 60 === 0) { var timeInSeconds = Math.floor(survivalTime / 60); timeTxt.setText('Time: ' + timeInSeconds + 's'); var score = timeInSeconds * 10 + Math.floor(survivalTime / 6); LK.setScore(score); scoreTxt.setText('Score: ' + score); } if (difficultyTimer >= 300) { difficultyTimer = 0; currentSpawnRate = Math.max(60, currentSpawnRate - 10); } if (spawnTimer >= currentSpawnRate) { spawnTimer = 0; var spawnType = Math.random(); if (spawnType < 0.4) { spawnInterceptor(); } else if (spawnType < 0.7) { spawnDrone(); } else { spawnSAMSite(); } } // Fire viggen bullets fireTimer++; if (fireTimer >= 15) { // Fire every 15 ticks (4 times per second) fireTimer = 0; var bullet = new ViggenBullet(); bullet.x = viggen.x; bullet.y = viggen.y - 60; game.addChild(bullet); viggenBullets.push(bullet); LK.getSound('shoot').play(); } checkCollisions(); cleanupOffscreenEntities(); if (enemyBullets.length > 200) { for (var i = 0; i < 50; i++) { if (enemyBullets[i]) { enemyBullets[i].destroy(); enemyBullets.splice(i, 1); } } } if (samMissiles.length > 100) { for (var i = 0; i < 25; i++) { if (samMissiles[i]) { samMissiles[i].destroy(); samMissiles.splice(i, 1); } } } }; LK.playMusic('combat');
===================================================================
--- original.js
+++ change.js
@@ -137,8 +137,20 @@
anchorY: 0.5
});
return self;
});
+var ViggenBullet = Container.expand(function () {
+ var self = Container.call(this);
+ var graphics = self.attachAsset('viggenBullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 8;
+ self.update = function () {
+ self.y -= self.speed;
+ };
+ return self;
+});
/****
* Initialize Game
****/
@@ -156,9 +168,11 @@
var samSites = [];
var drones = [];
var enemyBullets = [];
var samMissiles = [];
+var viggenBullets = [];
var spawnTimer = 0;
+var fireTimer = 0;
var difficultyTimer = 0;
var survivalTime = 0;
var baseSpawnRate = 180;
var currentSpawnRate = baseSpawnRate;
@@ -182,8 +196,54 @@
if (dragNode) {
dragNode.x = Math.max(40, Math.min(2008, x));
dragNode.y = Math.max(60, Math.min(2672, y));
}
+ // Check viggen bullets vs enemies
+ for (var i = viggenBullets.length - 1; i >= 0; i--) {
+ var bullet = viggenBullets[i];
+ var hit = false;
+ // Check vs interceptors
+ for (var j = interceptors.length - 1; j >= 0; j--) {
+ if (bullet.intersects(interceptors[j])) {
+ LK.effects.flashObject(interceptors[j], 0xff0000, 200);
+ interceptors[j].destroy();
+ interceptors.splice(j, 1);
+ bullet.destroy();
+ viggenBullets.splice(i, 1);
+ LK.setScore(LK.getScore() + 100);
+ hit = true;
+ break;
+ }
+ }
+ if (hit) continue;
+ // Check vs drones
+ for (var j = drones.length - 1; j >= 0; j--) {
+ if (bullet.intersects(drones[j])) {
+ LK.effects.flashObject(drones[j], 0xff0000, 200);
+ drones[j].destroy();
+ drones.splice(j, 1);
+ bullet.destroy();
+ viggenBullets.splice(i, 1);
+ LK.setScore(LK.getScore() + 150);
+ hit = true;
+ break;
+ }
+ }
+ if (hit) continue;
+ // Check vs SAM sites
+ for (var j = samSites.length - 1; j >= 0; j--) {
+ if (bullet.intersects(samSites[j])) {
+ LK.effects.flashObject(samSites[j], 0xff0000, 200);
+ samSites[j].destroy();
+ samSites.splice(j, 1);
+ bullet.destroy();
+ viggenBullets.splice(i, 1);
+ LK.setScore(LK.getScore() + 200);
+ hit = true;
+ break;
+ }
+ }
+ }
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = viggen;
@@ -279,8 +339,15 @@
samSites[i].destroy();
samSites.splice(i, 1);
}
}
+ // Clean up viggen bullets
+ for (var i = viggenBullets.length - 1; i >= 0; i--) {
+ if (viggenBullets[i].y < -50) {
+ viggenBullets[i].destroy();
+ viggenBullets.splice(i, 1);
+ }
+ }
}
game.update = function () {
survivalTime++;
difficultyTimer++;
@@ -306,8 +373,20 @@
} else {
spawnSAMSite();
}
}
+ // Fire viggen bullets
+ fireTimer++;
+ if (fireTimer >= 15) {
+ // Fire every 15 ticks (4 times per second)
+ fireTimer = 0;
+ var bullet = new ViggenBullet();
+ bullet.x = viggen.x;
+ bullet.y = viggen.y - 60;
+ game.addChild(bullet);
+ viggenBullets.push(bullet);
+ LK.getSound('shoot').play();
+ }
checkCollisions();
cleanupOffscreenEntities();
if (enemyBullets.length > 200) {
for (var i = 0; i < 50; i++) {
Modern App Store icon, high definition, square with rounded corners, for a game titled "Viggen Strike: Soviet Skies" and with the description "Pilot a Saab 37 Viggen through Soviet airspace in this intense bullet hell game, dodging interceptors, SAMs, and drones in a test of aerial survival.". No text on icon!
A Saab 37 Viggen fighter jet.. In-Game asset. 2d. High contrast. No shadows. Top down view
A surface-to-air (SAM) missile.. In-Game asset. 2d. High contrast. No shadows
A surface-to-air (SAM) missile launcher.. In-Game asset. 2d. High contrast. No shadows. Top down view
A Orion fighter UAV.. In-Game asset. 2d. High contrast. No shadows. Top down view
A Su-15 Flagon heavy Interceptor aircraft.. In-Game asset. 2d. High contrast. No shadows. Top down view