/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12; // Increased from 8 to 12 for faster enemy movement
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetLane = 1;
self.currentLane = 1;
self.health = 5;
self.shootTimer = 0;
self.shootCooldown = 90; // 1.5 seconds at 60fps for faster shooting
self.dodgeTimer = 0;
self.lastPlayerLane = 1;
self.predictiveTimer = 0;
self.setLane = function (lane) {
self.targetLane = Math.max(0, Math.min(2, lane));
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.update = function () {
// Move to target lane with improved speed
var targetX = lanePositions[self.targetLane];
var diff = targetX - self.x;
if (Math.abs(diff) > 5) {
self.x += diff * 0.18; // Faster lane switching
} else {
self.x = targetX;
self.currentLane = self.targetLane;
}
// Enhanced AI dodging behavior with prediction
if (vikingShip && vikingShip.currentLane !== self.lastPlayerLane) {
self.dodgeTimer = 40; // Faster dodge response
self.lastPlayerLane = vikingShip.currentLane;
}
if (self.dodgeTimer > 0) {
self.dodgeTimer--;
// Predictive dodging - try to avoid player's likely path
var playerLane = vikingShip.currentLane;
if (playerLane === self.currentLane) {
// Move to a different lane immediately
if (self.currentLane === 1) {
self.setLane(Math.random() < 0.5 ? 0 : 2);
} else if (self.currentLane === 0) {
self.setLane(Math.random() < 0.7 ? 2 : 1);
} else {
self.setLane(Math.random() < 0.7 ? 0 : 1);
}
} else {
// Dodge away from player with improved logic
if (playerLane < self.currentLane && self.currentLane < 2) {
self.setLane(self.currentLane + 1);
} else if (playerLane > self.currentLane && self.currentLane > 0) {
self.setLane(self.currentLane - 1);
}
}
}
// Occasional random movement to be unpredictable
self.predictiveTimer++;
if (self.predictiveTimer >= 180) {
// Every 3 seconds
self.predictiveTimer = 0;
if (Math.random() < 0.3) {
var randomLane = Math.floor(Math.random() * 3);
self.setLane(randomLane);
}
}
// Shooting behavior - enabled in level 2
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 100;
bullet.lastY = bullet.y;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var lightningGraphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.lastY = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Rune = Container.expand(function () {
var self = Container.call(this);
var runeGraphics = self.attachAsset('rune', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.rotation += 0.1;
};
return self;
});
var SeaSerpent = Container.expand(function () {
var self = Container.call(this);
var serpentGraphics = self.attachAsset('seaSerpent', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.x += Math.sin(self.y * 0.01) * 2;
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.rotation += 0.05;
};
return self;
});
var VikingShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('vikingShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetLane = 1;
self.currentLane = 1;
self.health = 3;
self.shields = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.setLane = function (lane) {
self.targetLane = Math.max(0, Math.min(2, lane));
};
self.takeDamage = function () {
if (self.invulnerable) return;
if (self.shields > 0) {
self.shields--;
updateShieldDisplay();
} else {
self.health--;
updateHealthDisplay();
LK.getSound('hit').play();
if (self.health <= 0) {
LK.showGameOver();
return;
}
}
self.invulnerable = true;
self.invulnerableTimer = 120;
LK.effects.flashObject(self, 0xff0000, 500);
};
self.update = function () {
var targetX = lanePositions[self.targetLane];
var diff = targetX - self.x;
if (Math.abs(diff) > 5) {
self.x += diff * 0.25;
} else {
self.x = targetX;
self.currentLane = self.targetLane;
}
if (self.invulnerable) {
self.invulnerableTimer--;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1e3a8a
});
/****
* Game Code
****/
var lanePositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75];
var vikingShip = null;
var enemies = [];
var runes = [];
var shields = [];
var lightnings = [];
var seaSerpents = [];
var enemyShip = null;
var enemyBullets = [];
var playerBullets = [];
var level = 1;
var score = 0;
var distance = 0;
var enemySpawnTimer = 0;
var runeSpawnTimer = 0;
var shieldSpawnTimer = 0;
var lightningSpawnTimer = 0;
var serpentSpawnTimer = 0;
var gameSpeed = 1;
var levelTimer = 0;
var levelDuration = 7200; // 2 minutes at 60fps
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var healthTxt = new Text2('Health: 3', {
size: 60,
fill: 0xFF0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -50;
healthTxt.y = 50;
LK.gui.topRight.addChild(healthTxt);
var shieldTxt = new Text2('Shields: 0', {
size: 60,
fill: 0x4169E1
});
shieldTxt.anchor.set(1, 0);
shieldTxt.x = -50;
shieldTxt.y = 120;
LK.gui.topRight.addChild(shieldTxt);
// Variables for swipe detection
var touchStartX = 0;
var touchStartY = 0;
var swipeMinDistance = 50;
function updateScore() {
scoreTxt.setText('Score: ' + score);
}
function updateLevel() {
levelTxt.setText('Level: ' + level);
}
function updateHealthDisplay() {
healthTxt.setText('Health: ' + vikingShip.health);
}
function updateShieldDisplay() {
shieldTxt.setText('Shields: ' + vikingShip.shields);
}
function spawnEnemy() {
var enemy = new Enemy();
var lane = Math.floor(Math.random() * 3);
enemy.x = lanePositions[lane];
enemy.y = -100;
enemy.lastY = enemy.y;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnRune() {
var rune = new Rune();
var lane = Math.floor(Math.random() * 3);
rune.x = lanePositions[lane];
rune.y = -100;
rune.lastY = rune.y;
runes.push(rune);
game.addChild(rune);
}
function spawnShield() {
var shield = new Shield();
var lane = Math.floor(Math.random() * 3);
shield.x = lanePositions[lane];
shield.y = -100;
shield.lastY = shield.y;
shields.push(shield);
game.addChild(shield);
}
function spawnLightning() {
var lightning = new Lightning();
var lane = Math.floor(Math.random() * 3);
lightning.x = lanePositions[lane];
lightning.y = -100;
lightning.lastY = lightning.y;
lightnings.push(lightning);
game.addChild(lightning);
}
function spawnSeaSerpent() {
var serpent = new SeaSerpent();
var lane = Math.floor(Math.random() * 3);
serpent.x = lanePositions[lane];
serpent.y = -200;
serpent.lastY = serpent.y;
seaSerpents.push(serpent);
game.addChild(serpent);
}
function checkCollisions() {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(vikingShip)) {
vikingShip.takeDamage();
enemy.destroy();
enemies.splice(i, 1);
}
}
for (var i = runes.length - 1; i >= 0; i--) {
var rune = runes[i];
if (rune.intersects(vikingShip)) {
score += 100;
updateScore();
LK.getSound('collect').play();
rune.destroy();
runes.splice(i, 1);
}
}
for (var i = shields.length - 1; i >= 0; i--) {
var shield = shields[i];
if (shield.intersects(vikingShip)) {
vikingShip.shields++;
updateShieldDisplay();
LK.getSound('collect').play();
shield.destroy();
shields.splice(i, 1);
}
}
for (var i = lightnings.length - 1; i >= 0; i--) {
var lightning = lightnings[i];
if (lightning.intersects(vikingShip)) {
vikingShip.takeDamage();
lightning.destroy();
lightnings.splice(i, 1);
}
}
for (var i = seaSerpents.length - 1; i >= 0; i--) {
var serpent = seaSerpents[i];
if (serpent.intersects(vikingShip)) {
vikingShip.takeDamage();
serpent.destroy();
seaSerpents.splice(i, 1);
}
}
// Check enemy bullet collisions
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.intersects(vikingShip)) {
vikingShip.takeDamage();
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Check player bullet collisions with enemy ship
if (enemyShip) {
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.intersects(enemyShip)) {
if (enemyShip.takeDamage()) {
enemyShip = null;
score += 1000;
updateScore();
// Victory condition - enemy ship defeated
LK.showYouWin();
}
bullet.destroy();
playerBullets.splice(i, 1);
}
}
}
}
function cleanupObjects() {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY < 2800 && enemy.y >= 2800) {
enemy.destroy();
enemies.splice(i, 1);
}
enemy.lastY = enemy.y;
}
for (var i = runes.length - 1; i >= 0; i--) {
var rune = runes[i];
if (rune.lastY < 2800 && rune.y >= 2800) {
rune.destroy();
runes.splice(i, 1);
}
rune.lastY = rune.y;
}
for (var i = shields.length - 1; i >= 0; i--) {
var shield = shields[i];
if (shield.lastY < 2800 && shield.y >= 2800) {
shield.destroy();
shields.splice(i, 1);
}
shield.lastY = shield.y;
}
for (var i = lightnings.length - 1; i >= 0; i--) {
var lightning = lightnings[i];
if (lightning.lastY < 2800 && lightning.y >= 2800) {
lightning.destroy();
lightnings.splice(i, 1);
}
lightning.lastY = lightning.y;
}
for (var i = seaSerpents.length - 1; i >= 0; i--) {
var serpent = seaSerpents[i];
if (serpent.lastY < 2800 && serpent.y >= 2800) {
serpent.destroy();
seaSerpents.splice(i, 1);
}
serpent.lastY = serpent.y;
}
// Cleanup enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY < 2800 && bullet.y >= 2800) {
bullet.destroy();
enemyBullets.splice(i, 1);
}
bullet.lastY = bullet.y;
}
// Cleanup player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY > -100 && bullet.y <= -100) {
bullet.destroy();
playerBullets.splice(i, 1);
}
bullet.lastY = bullet.y;
}
}
vikingShip = new VikingShip();
vikingShip.x = lanePositions[1];
vikingShip.y = 2200;
game.addChild(vikingShip);
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if it's a swipe (minimum distance moved)
if (swipeDistance >= swipeMinDistance) {
// Horizontal swipe for lane changes
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (deltaX > 0) {
// Swipe right - move to next lane
vikingShip.setLane(vikingShip.currentLane + 1);
} else {
// Swipe left - move to previous lane
vikingShip.setLane(vikingShip.currentLane - 1);
}
}
} else {
// It's a tap - shoot in level 2
if (level === 2) {
var bullet = new PlayerBullet();
bullet.x = vikingShip.x;
bullet.y = vikingShip.y - 100;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
}
};
game.update = function () {
distance++;
score += 1;
levelTimer++;
// Progressive speed increase in level 1
if (level === 1) {
var timeProgress = levelTimer / levelDuration;
gameSpeed = 1 + timeProgress * 2.0; // Speed increases from 1 to 3.0 over 2 minutes for higher difficulty
}
// Check for level progression based on time
if (levelTimer >= levelDuration) {
level++;
levelTimer = 0;
gameSpeed += 0.2;
updateLevel();
// Spawn enemy ship in level 2
if (level === 2 && !enemyShip) {
enemyShip = new EnemyShip();
enemyShip.x = lanePositions[1];
enemyShip.y = 300;
game.addChild(enemyShip);
}
}
// Ensure enemy ship exists in level 2 (in case it was destroyed or not spawned)
if (level === 2 && !enemyShip) {
enemyShip = new EnemyShip();
enemyShip.x = lanePositions[1];
enemyShip.y = 300;
game.addChild(enemyShip);
}
// Dynamic obstacle spawn timing based on level and time progression - only in level 1
if (level === 1) {
var baseEnemySpawnRate = 60; // Reduced from 90 to 60 for more frequent spawns
var timeProgress = levelTimer / levelDuration;
var difficultyMultiplier = 1 + timeProgress * 2.0; // Increased from 1.5 to 2.0 for faster difficulty ramp
var enemySpawnRate = Math.max(baseEnemySpawnRate / difficultyMultiplier, 8); // Reduced minimum from 15 to 8
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
}
// Adaptive rune spawn rate - made more scarce in level 1
var runeSpawnRate = level === 2 ? 80 : Math.max(300 - level * 20, 180); // Increased from 200/120 to 300/180
runeSpawnTimer++;
if (runeSpawnTimer >= runeSpawnRate) {
spawnRune();
runeSpawnTimer = 0;
}
shieldSpawnTimer++;
var shieldSpawnRate = level === 2 ? 300 : 600;
if (shieldSpawnTimer >= shieldSpawnRate) {
spawnShield();
shieldSpawnTimer = 0;
}
// Add sea serpent spawning in level 1 for extra difficulty
if (level === 1) {
var serpentSpawnRate = 400; // Spawn sea serpents occasionally in level 1
serpentSpawnTimer++;
if (serpentSpawnTimer >= serpentSpawnRate) {
spawnSeaSerpent();
serpentSpawnTimer = 0;
}
}
if (level === 2) {
var lightningSpawnRate = 80;
lightningSpawnTimer++;
if (lightningSpawnTimer >= lightningSpawnRate) {
spawnLightning();
lightningSpawnTimer = 0;
}
}
checkCollisions();
cleanupObjects();
if (LK.ticks % 10 === 0) {
updateScore();
}
};
LK.playMusic('vikingTheme'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12; // Increased from 8 to 12 for faster enemy movement
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var EnemyShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('enemyShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetLane = 1;
self.currentLane = 1;
self.health = 5;
self.shootTimer = 0;
self.shootCooldown = 90; // 1.5 seconds at 60fps for faster shooting
self.dodgeTimer = 0;
self.lastPlayerLane = 1;
self.predictiveTimer = 0;
self.setLane = function (lane) {
self.targetLane = Math.max(0, Math.min(2, lane));
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xff0000, 300);
if (self.health <= 0) {
self.destroy();
return true;
}
return false;
};
self.update = function () {
// Move to target lane with improved speed
var targetX = lanePositions[self.targetLane];
var diff = targetX - self.x;
if (Math.abs(diff) > 5) {
self.x += diff * 0.18; // Faster lane switching
} else {
self.x = targetX;
self.currentLane = self.targetLane;
}
// Enhanced AI dodging behavior with prediction
if (vikingShip && vikingShip.currentLane !== self.lastPlayerLane) {
self.dodgeTimer = 40; // Faster dodge response
self.lastPlayerLane = vikingShip.currentLane;
}
if (self.dodgeTimer > 0) {
self.dodgeTimer--;
// Predictive dodging - try to avoid player's likely path
var playerLane = vikingShip.currentLane;
if (playerLane === self.currentLane) {
// Move to a different lane immediately
if (self.currentLane === 1) {
self.setLane(Math.random() < 0.5 ? 0 : 2);
} else if (self.currentLane === 0) {
self.setLane(Math.random() < 0.7 ? 2 : 1);
} else {
self.setLane(Math.random() < 0.7 ? 0 : 1);
}
} else {
// Dodge away from player with improved logic
if (playerLane < self.currentLane && self.currentLane < 2) {
self.setLane(self.currentLane + 1);
} else if (playerLane > self.currentLane && self.currentLane > 0) {
self.setLane(self.currentLane - 1);
}
}
}
// Occasional random movement to be unpredictable
self.predictiveTimer++;
if (self.predictiveTimer >= 180) {
// Every 3 seconds
self.predictiveTimer = 0;
if (Math.random() < 0.3) {
var randomLane = Math.floor(Math.random() * 3);
self.setLane(randomLane);
}
}
// Shooting behavior - enabled in level 2
self.shootTimer++;
if (self.shootTimer >= self.shootCooldown) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 100;
bullet.lastY = bullet.y;
enemyBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
return self;
});
var Lightning = Container.expand(function () {
var self = Container.call(this);
var lightningGraphics = self.attachAsset('lightning', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -15;
self.lastY = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Rune = Container.expand(function () {
var self = Container.call(this);
var runeGraphics = self.attachAsset('rune', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.rotation += 0.1;
};
return self;
});
var SeaSerpent = Container.expand(function () {
var self = Container.call(this);
var serpentGraphics = self.attachAsset('seaSerpent', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.x += Math.sin(self.y * 0.01) * 2;
};
return self;
});
var Shield = Container.expand(function () {
var self = Container.call(this);
var shieldGraphics = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.lastY = 0;
self.update = function () {
self.y += self.speed * gameSpeed;
self.rotation += 0.05;
};
return self;
});
var VikingShip = Container.expand(function () {
var self = Container.call(this);
var shipGraphics = self.attachAsset('vikingShip', {
anchorX: 0.5,
anchorY: 0.5
});
self.targetLane = 1;
self.currentLane = 1;
self.health = 3;
self.shields = 0;
self.invulnerable = false;
self.invulnerableTimer = 0;
self.setLane = function (lane) {
self.targetLane = Math.max(0, Math.min(2, lane));
};
self.takeDamage = function () {
if (self.invulnerable) return;
if (self.shields > 0) {
self.shields--;
updateShieldDisplay();
} else {
self.health--;
updateHealthDisplay();
LK.getSound('hit').play();
if (self.health <= 0) {
LK.showGameOver();
return;
}
}
self.invulnerable = true;
self.invulnerableTimer = 120;
LK.effects.flashObject(self, 0xff0000, 500);
};
self.update = function () {
var targetX = lanePositions[self.targetLane];
var diff = targetX - self.x;
if (Math.abs(diff) > 5) {
self.x += diff * 0.25;
} else {
self.x = targetX;
self.currentLane = self.targetLane;
}
if (self.invulnerable) {
self.invulnerableTimer--;
if (self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1e3a8a
});
/****
* Game Code
****/
var lanePositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75];
var vikingShip = null;
var enemies = [];
var runes = [];
var shields = [];
var lightnings = [];
var seaSerpents = [];
var enemyShip = null;
var enemyBullets = [];
var playerBullets = [];
var level = 1;
var score = 0;
var distance = 0;
var enemySpawnTimer = 0;
var runeSpawnTimer = 0;
var shieldSpawnTimer = 0;
var lightningSpawnTimer = 0;
var serpentSpawnTimer = 0;
var gameSpeed = 1;
var levelTimer = 0;
var levelDuration = 7200; // 2 minutes at 60fps
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 150;
scoreTxt.y = 50;
LK.gui.topLeft.addChild(scoreTxt);
var levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var healthTxt = new Text2('Health: 3', {
size: 60,
fill: 0xFF0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -50;
healthTxt.y = 50;
LK.gui.topRight.addChild(healthTxt);
var shieldTxt = new Text2('Shields: 0', {
size: 60,
fill: 0x4169E1
});
shieldTxt.anchor.set(1, 0);
shieldTxt.x = -50;
shieldTxt.y = 120;
LK.gui.topRight.addChild(shieldTxt);
// Variables for swipe detection
var touchStartX = 0;
var touchStartY = 0;
var swipeMinDistance = 50;
function updateScore() {
scoreTxt.setText('Score: ' + score);
}
function updateLevel() {
levelTxt.setText('Level: ' + level);
}
function updateHealthDisplay() {
healthTxt.setText('Health: ' + vikingShip.health);
}
function updateShieldDisplay() {
shieldTxt.setText('Shields: ' + vikingShip.shields);
}
function spawnEnemy() {
var enemy = new Enemy();
var lane = Math.floor(Math.random() * 3);
enemy.x = lanePositions[lane];
enemy.y = -100;
enemy.lastY = enemy.y;
enemies.push(enemy);
game.addChild(enemy);
}
function spawnRune() {
var rune = new Rune();
var lane = Math.floor(Math.random() * 3);
rune.x = lanePositions[lane];
rune.y = -100;
rune.lastY = rune.y;
runes.push(rune);
game.addChild(rune);
}
function spawnShield() {
var shield = new Shield();
var lane = Math.floor(Math.random() * 3);
shield.x = lanePositions[lane];
shield.y = -100;
shield.lastY = shield.y;
shields.push(shield);
game.addChild(shield);
}
function spawnLightning() {
var lightning = new Lightning();
var lane = Math.floor(Math.random() * 3);
lightning.x = lanePositions[lane];
lightning.y = -100;
lightning.lastY = lightning.y;
lightnings.push(lightning);
game.addChild(lightning);
}
function spawnSeaSerpent() {
var serpent = new SeaSerpent();
var lane = Math.floor(Math.random() * 3);
serpent.x = lanePositions[lane];
serpent.y = -200;
serpent.lastY = serpent.y;
seaSerpents.push(serpent);
game.addChild(serpent);
}
function checkCollisions() {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(vikingShip)) {
vikingShip.takeDamage();
enemy.destroy();
enemies.splice(i, 1);
}
}
for (var i = runes.length - 1; i >= 0; i--) {
var rune = runes[i];
if (rune.intersects(vikingShip)) {
score += 100;
updateScore();
LK.getSound('collect').play();
rune.destroy();
runes.splice(i, 1);
}
}
for (var i = shields.length - 1; i >= 0; i--) {
var shield = shields[i];
if (shield.intersects(vikingShip)) {
vikingShip.shields++;
updateShieldDisplay();
LK.getSound('collect').play();
shield.destroy();
shields.splice(i, 1);
}
}
for (var i = lightnings.length - 1; i >= 0; i--) {
var lightning = lightnings[i];
if (lightning.intersects(vikingShip)) {
vikingShip.takeDamage();
lightning.destroy();
lightnings.splice(i, 1);
}
}
for (var i = seaSerpents.length - 1; i >= 0; i--) {
var serpent = seaSerpents[i];
if (serpent.intersects(vikingShip)) {
vikingShip.takeDamage();
serpent.destroy();
seaSerpents.splice(i, 1);
}
}
// Check enemy bullet collisions
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.intersects(vikingShip)) {
vikingShip.takeDamage();
bullet.destroy();
enemyBullets.splice(i, 1);
}
}
// Check player bullet collisions with enemy ship
if (enemyShip) {
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.intersects(enemyShip)) {
if (enemyShip.takeDamage()) {
enemyShip = null;
score += 1000;
updateScore();
// Victory condition - enemy ship defeated
LK.showYouWin();
}
bullet.destroy();
playerBullets.splice(i, 1);
}
}
}
}
function cleanupObjects() {
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.lastY < 2800 && enemy.y >= 2800) {
enemy.destroy();
enemies.splice(i, 1);
}
enemy.lastY = enemy.y;
}
for (var i = runes.length - 1; i >= 0; i--) {
var rune = runes[i];
if (rune.lastY < 2800 && rune.y >= 2800) {
rune.destroy();
runes.splice(i, 1);
}
rune.lastY = rune.y;
}
for (var i = shields.length - 1; i >= 0; i--) {
var shield = shields[i];
if (shield.lastY < 2800 && shield.y >= 2800) {
shield.destroy();
shields.splice(i, 1);
}
shield.lastY = shield.y;
}
for (var i = lightnings.length - 1; i >= 0; i--) {
var lightning = lightnings[i];
if (lightning.lastY < 2800 && lightning.y >= 2800) {
lightning.destroy();
lightnings.splice(i, 1);
}
lightning.lastY = lightning.y;
}
for (var i = seaSerpents.length - 1; i >= 0; i--) {
var serpent = seaSerpents[i];
if (serpent.lastY < 2800 && serpent.y >= 2800) {
serpent.destroy();
seaSerpents.splice(i, 1);
}
serpent.lastY = serpent.y;
}
// Cleanup enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY < 2800 && bullet.y >= 2800) {
bullet.destroy();
enemyBullets.splice(i, 1);
}
bullet.lastY = bullet.y;
}
// Cleanup player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
if (bullet.lastY > -100 && bullet.y <= -100) {
bullet.destroy();
playerBullets.splice(i, 1);
}
bullet.lastY = bullet.y;
}
}
vikingShip = new VikingShip();
vikingShip.x = lanePositions[1];
vikingShip.y = 2200;
game.addChild(vikingShip);
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if it's a swipe (minimum distance moved)
if (swipeDistance >= swipeMinDistance) {
// Horizontal swipe for lane changes
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (deltaX > 0) {
// Swipe right - move to next lane
vikingShip.setLane(vikingShip.currentLane + 1);
} else {
// Swipe left - move to previous lane
vikingShip.setLane(vikingShip.currentLane - 1);
}
}
} else {
// It's a tap - shoot in level 2
if (level === 2) {
var bullet = new PlayerBullet();
bullet.x = vikingShip.x;
bullet.y = vikingShip.y - 100;
bullet.lastY = bullet.y;
playerBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
}
}
};
game.update = function () {
distance++;
score += 1;
levelTimer++;
// Progressive speed increase in level 1
if (level === 1) {
var timeProgress = levelTimer / levelDuration;
gameSpeed = 1 + timeProgress * 2.0; // Speed increases from 1 to 3.0 over 2 minutes for higher difficulty
}
// Check for level progression based on time
if (levelTimer >= levelDuration) {
level++;
levelTimer = 0;
gameSpeed += 0.2;
updateLevel();
// Spawn enemy ship in level 2
if (level === 2 && !enemyShip) {
enemyShip = new EnemyShip();
enemyShip.x = lanePositions[1];
enemyShip.y = 300;
game.addChild(enemyShip);
}
}
// Ensure enemy ship exists in level 2 (in case it was destroyed or not spawned)
if (level === 2 && !enemyShip) {
enemyShip = new EnemyShip();
enemyShip.x = lanePositions[1];
enemyShip.y = 300;
game.addChild(enemyShip);
}
// Dynamic obstacle spawn timing based on level and time progression - only in level 1
if (level === 1) {
var baseEnemySpawnRate = 60; // Reduced from 90 to 60 for more frequent spawns
var timeProgress = levelTimer / levelDuration;
var difficultyMultiplier = 1 + timeProgress * 2.0; // Increased from 1.5 to 2.0 for faster difficulty ramp
var enemySpawnRate = Math.max(baseEnemySpawnRate / difficultyMultiplier, 8); // Reduced minimum from 15 to 8
enemySpawnTimer++;
if (enemySpawnTimer >= enemySpawnRate) {
spawnEnemy();
enemySpawnTimer = 0;
}
}
// Adaptive rune spawn rate - made more scarce in level 1
var runeSpawnRate = level === 2 ? 80 : Math.max(300 - level * 20, 180); // Increased from 200/120 to 300/180
runeSpawnTimer++;
if (runeSpawnTimer >= runeSpawnRate) {
spawnRune();
runeSpawnTimer = 0;
}
shieldSpawnTimer++;
var shieldSpawnRate = level === 2 ? 300 : 600;
if (shieldSpawnTimer >= shieldSpawnRate) {
spawnShield();
shieldSpawnTimer = 0;
}
// Add sea serpent spawning in level 1 for extra difficulty
if (level === 1) {
var serpentSpawnRate = 400; // Spawn sea serpents occasionally in level 1
serpentSpawnTimer++;
if (serpentSpawnTimer >= serpentSpawnRate) {
spawnSeaSerpent();
serpentSpawnTimer = 0;
}
}
if (level === 2) {
var lightningSpawnRate = 80;
lightningSpawnTimer++;
if (lightningSpawnTimer >= lightningSpawnRate) {
spawnLightning();
lightningSpawnTimer = 0;
}
}
checkCollisions();
cleanupObjects();
if (LK.ticks % 10 === 0) {
updateScore();
}
};
LK.playMusic('vikingTheme');
Barco viquingo visto desde arriba que viene de frente. In-Game asset. 2d. High contrast. No shadows
Runa nórdica. In-Game asset. 2d. High contrast. No shadows
Escudo viquingo. In-Game asset. 2d. High contrast. No shadows
Una flecha de arco. In-Game asset. 2d. High contrast. No shadows
Pequeño rayo. In-Game asset. 2d. High contrast. No shadows
Serpiente marina vista desde arriba que viene de frente. In-Game asset. 2d. High contrast. No shadows