/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Boss = Container.expand(function () { var self = Container.call(this); var bossGraphic = self.attachAsset('boss', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; self.health = 10; self.attackCooldown = 0; self.attackPattern = 0; self.scoreValue = 2000; self.active = true; self.init = function (x, y) { self.x = x; self.y = y; return self; }; self.takeDamage = function () { if (!self.active) { return; } // Boss takes 1 damage per hit, dies after 5 hits self.health -= 1; // Flash boss LK.effects.flashObject(self, 0xffffff, 300); LK.getSound('hit').play(); if (self.health <= 0) { self.die(); } else { // Speed up as health decreases self.speed = 1.5 + (5 - self.health) * 0.2; } }; self.die = function () { if (!self.active) { return; } self.active = false; LK.getSound('bossDeath').play(); // Flash and fade out LK.effects.flashObject(self, 0xffff00, 500); tween(self, { alpha: 0 }, { duration: 1000, onFinish: function onFinish() { self.destroy(); } }); currentWave++; bossDefeated = true; nextWaveTimer = 180; // 3 seconds until next wave return self.scoreValue; }; self.update = function () { if (!self.active) { return; } // Move toward hero but more intelligently if (hero) { var dx = hero.x - self.x; var dy = hero.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); // Different movement patterns if (self.attackPattern === 0) { // Direct approach if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } } else if (self.attackPattern === 1) { // Circle around var angle = Math.atan2(dy, dx) + Math.PI / 4; self.x += Math.cos(angle) * self.speed * 1.5; self.y += Math.sin(angle) * self.speed * 1.5; } else if (self.attackPattern === 2) { // Charge attack if (self.attackCooldown > 30) { self.x += dx / dist * self.speed * 2.5; self.y += dy / dist * self.speed * 2.5; } else { // Wait } } if (hero.invulnerable <= 0 && !hero.isDashing) { if (self.intersects(hero)) { hero.takeDamage(); } } } // Attack pattern cooldown self.attackCooldown--; if (self.attackCooldown <= 0) { self.attackPattern = (self.attackPattern + 1) % 3; self.attackCooldown = 120; // 2 seconds per pattern } // Keep within screen bounds self.x = Math.max(100, Math.min(2048 - 100, self.x)); self.y = Math.max(100, Math.min(2732 - 100, self.y)); }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphic = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); bulletGraphic.tint = 0xffffff; // White bullet for the hero self.speed = 15; self.damage = 1; self.active = true; self.init = function (x, y, direction) { self.x = x; self.y = y; self.direction = direction || { x: 0, y: -1 }; // Default direction is up return self; }; self.update = function () { if (!self.active) { return; } // Move in the specified direction self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; // Remove if off-screen if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) { self.destroy(); } }; return self; }); var DashTrail = Container.expand(function () { var self = Container.call(this); var trailGraphic = self.attachAsset('dashTrail', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.init = function (x, y) { self.x = x; self.y = y; self.lifetime = 20; // frames the trail will live return self; }; self.update = function () { self.lifetime--; trailGraphic.alpha = self.lifetime / 20 * 0.7; if (self.lifetime <= 0) { self.destroy(); } }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphic = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.health = 1; self.scoreValue = 100; self.active = true; self.init = function (x, y) { self.x = x; self.y = y; // Initialize last position for rotation tracking self.lastX = x; self.lastY = y; // Set initial rotation if (hero) { var dx = hero.x - self.x; var dy = hero.y - self.y; enemyGraphic.rotation = Math.atan2(dy, dx); } return self; }; self.takeDamage = function () { if (!self.active) { return; } // Enemies die from one hit self.health = 0; self.die(); }; self.die = function () { if (!self.active) { return; } self.active = false; LK.getSound('hit').play(); // Flash, fade out, and fall animation tween(self, { alpha: 0, y: self.y + 300, // Fall down animation rotation: Math.random() * Math.PI * 2, // Random rotation scaleX: 0.5, scaleY: 0.5 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); return self.scoreValue; }; self.update = function () { if (!self.active) { return; } // Move toward hero if (hero && !hero.isDashing) { var dx = hero.x - self.x; var dy = hero.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; // Spider walking animation if (LK.ticks % 10 === 0) { // Spider leg movement animation tween(enemyGraphic, { scaleX: 1.1, scaleY: 0.9, rotation: Math.atan2(dy, dx) + (Math.random() * 0.2 - 0.1) }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(enemyGraphic, { scaleX: 1, scaleY: 1, rotation: Math.atan2(dy, dx) }, { duration: 200, easing: tween.easeOut }); } }); } } } // Check for collision with hero if (hero && !hero.isDashing && hero.invulnerable <= 0) { if (self.intersects(hero)) { hero.takeDamage(); } } }; return self; }); var Hero = Container.expand(function () { var self = Container.call(this); var heroGraphic = self.attachAsset('hero', { anchorX: 0.5, anchorY: 0.5 }); // Simple click handler that does nothing (placeholder) self.down = function (x, y, obj) { // No auto-shoot toggle functionality }; self.shootSpeed = 15; // Bullet speed self.fireRate = 15; // Frames between shots self.shootCooldown = 0; self.health = 3; self.invulnerable = 0; self.combo = 0; self.score = 0; self.powerBoost = 1; // Base power multiplier self.shootBullet = function (targetX, targetY) { if (self.shootCooldown > 0) { return; } var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Normalize direction var dirX = dx / distance; var dirY = dy / distance; // Create bullet var bullet = new Bullet().init(self.x, self.y, { x: dirX, y: dirY }); bullet.damage = self.powerBoost; // Apply power boost to bullet damage // Visual shooting effect tween(heroGraphic, { scaleX: 1.2, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(heroGraphic, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); } }); // Set cooldown self.shootCooldown = self.fireRate; // Add bullet to game game.addChild(bullet); if (!bullets) { bullets = []; } bullets.push(bullet); // Play shoot sound LK.getSound('hit').play(); }; self.takeDamage = function () { if (self.invulnerable > 0) { return; } self.health--; self.invulnerable = 60; // invulnerable for 1 second self.combo = 0; // Reset combo // Flash hero red LK.effects.flashObject(self, 0xff0000, 500); // Play damage sound LK.getSound('damage').play(); if (self.health <= 0) { LK.showGameOver(); } }; self.addScore = function (points) { self.combo++; var comboMultiplier = Math.min(4, 1 + self.combo * 0.1); var scoreToAdd = Math.floor(points * comboMultiplier); self.score += scoreToAdd; LK.setScore(self.score); }; self.update = function () { // Keep within screen bounds self.x = Math.max(50, Math.min(2048 - 50, self.x)); self.y = Math.max(50, Math.min(2732 - 50, self.y)); // Cooldowns if (self.shootCooldown > 0) { self.shootCooldown--; } if (self.invulnerable > 0) { self.invulnerable--; // Flicker effect during invulnerability heroGraphic.alpha = LK.ticks % 6 < 3 ? 0.4 : 1; } else { // Normal appearance when not invulnerable heroGraphic.alpha = 1; heroGraphic.tint = 0xFFFFFF; // Normal color } }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphic = self.attachAsset('powerUp', { anchorX: 0.5, anchorY: 0.5 }); self.type = 'health'; // Default type self.active = true; self.lifetime = 300; // 5 seconds self.init = function (x, y, type) { self.x = x; self.y = y; self.type = type || self.type; // Set color based on type if (self.type === 'health') { powerUpGraphic.tint = 0x2ecc71; // Green } else if (self.type === 'speed') { powerUpGraphic.tint = 0x3498db; // Blue } else if (self.type === 'power') { powerUpGraphic.tint = 0xe74c3c; // Red } else if (self.type === 'strength') { powerUpGraphic.tint = 0x9b59b6; // Purple } return self; }; self.collect = function () { if (!self.active) { return; } self.active = false; LK.getSound('powerup').play(); if (self.type === 'health' && hero.health < 3) { hero.health++; } else if (self.type === 'speed') { hero.dashSpeed = 80; // Even faster dash hero.dashDistance = 900; // Even longer dash // Visual indicator of speed boost tween(hero, { alpha: 0.7 }, { duration: 200, onFinish: function onFinish() { tween(hero, { alpha: 1 }, { duration: 200 }); } }); // Reset after 10 seconds LK.setTimeout(function () { if (hero) { hero.dashSpeed = 60; hero.dashDistance = 700; } }, 10000); } else if (self.type === 'strength') { // Increase hero's attack strength more permanently hero.powerBoost = Math.min(5, hero.powerBoost + 1); // Visual indicator of strength boost tween(hero, { tint: 0x9b59b6 }, { duration: 500, onFinish: function onFinish() { tween(hero, { tint: 0xFFFFFF }, { duration: 500 }); } }); // Show strength level var strengthTxt = new Text2('STRENGTH +' + hero.powerBoost + '!', { size: 80, fill: 0x9b59b6 }); strengthTxt.anchor.set(0.5, 0.5); strengthTxt.x = 2048 / 2; strengthTxt.y = 2732 / 2; game.addChild(strengthTxt); // Fade out the text tween(strengthTxt, { alpha: 0, y: strengthTxt.y - 100 }, { duration: 1500, onFinish: function onFinish() { strengthTxt.destroy(); } }); } else if (self.type === 'power') { // Clear all enemies for (var i = enemies.length - 1; i >= 0; i--) { if (enemies[i].active) { var points = enemies[i].die(); hero.addScore(points); } } // Increase hero's attack strength hero.powerBoost = 3; // Visual indicator of power boost tween(hero, { tint: 0xFF0000 }, { duration: 300 }); // Reset after 10 seconds LK.setTimeout(function () { if (hero) { hero.powerBoost = 1; tween(hero, { tint: 0xFFFFFF }, { duration: 500 }); } }, 10000); } // Flash and fade out tween(self, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); }; self.update = function () { if (!self.active) { return; } // Floating animation self.y += Math.sin(LK.ticks * 0.1) * 0.5; // Rotate slowly powerUpGraphic.rotation += 0.02; // Check for collision with hero if (hero && (hero.intersects(self) || hero.isDashing && self.distanceTo(hero) < 100)) { self.collect(); } // Expire after lifetime self.lifetime--; if (self.lifetime <= 0) { tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.destroy(); } }); self.active = false; } }; self.distanceTo = function (target) { var dx = target.x - self.x; var dy = target.y - self.y; return Math.sqrt(dx * dx + dy * dy); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ // Game state variables var hero; var enemies = []; var bullets = []; var powerUps = []; var trails = []; var gameTime = 0; var spawnTimer = 0; var bossTimer = 0; var currentWave = 0; var bossDefeated = false; var nextWaveTimer = 0; var swipeStart = { x: 0, y: 0 }; var isSwipeActive = false; // UI elements var scoreTxt; var timeTxt; var healthTxt; var comboTxt; // Game constants var SPAWN_INTERVAL = 90; // Frames between enemy spawns var POWER_UP_CHANCE = 0.15; // Chance to spawn power-up on enemy defeat var BOSS_INTERVAL = 1800; // Spawn boss every 30 seconds (60fps * 30) var MAX_ENEMIES = 15; // Maximum enemies on screen at once // Initialize game elements function initGame() { // Add background var background = game.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Create hero hero = new Hero(); hero.x = 2048 / 2; hero.y = 2732 / 2; game.addChild(hero); // Auto-shoot indicator removed // Create UI elements scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); timeTxt = new Text2('Time: 0s', { size: 60, fill: 0xFFFFFF }); timeTxt.anchor.set(1, 0); LK.gui.top.addChild(timeTxt); healthTxt = new Text2('❤️❤️❤️', { size: 60, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); LK.gui.bottom.addChild(healthTxt); comboTxt = new Text2('Combo: 0x', { size: 60, fill: 0xFFFFFF }); comboTxt.anchor.set(1, 0); LK.gui.bottom.addChild(comboTxt); // Initialize game timers gameTime = 0; spawnTimer = 0; bossTimer = BOSS_INTERVAL; // Play background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.5, duration: 1000 } }); } // This function is no longer needed in endless mode // Spawn a regular enemy function spawnEnemy() { // Enforce a maximum number of enemies if (enemies.length >= MAX_ENEMIES) { return; } var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left var x, y; switch (edge) { case 0: // Top x = Math.random() * 2048; y = -50; break; case 1: // Right x = 2048 + 50; y = Math.random() * 2732; break; case 2: // Bottom x = Math.random() * 2048; y = 2732 + 50; break; case 3: // Left x = -50; y = Math.random() * 2732; break; } var enemy = new Enemy().init(x, y); var seconds = Math.floor(gameTime / 60); // Speed increases with game time enemy.speed = 2 + Math.min(3, seconds / 30); enemy.health = 1; // Enemies always have 1 health // Scale score value based on time played enemy.scoreValue = 100 + Math.floor(seconds / 30) * 20; game.addChild(enemy); enemies.push(enemy); } // Spawn a boss function spawnBoss() { var boss = new Boss().init(2048 / 2, -200); var seconds = Math.floor(gameTime / 60); // Boss health and score scale with game time boss.health = 5 + Math.floor(seconds / 60); boss.scoreValue = 2000 + seconds * 50; game.addChild(boss); enemies.push(boss); // Make a dramatic entrance tween(boss, { y: 400 }, { duration: 2000, easing: tween.bounceOut }); } // Spawn a power-up function spawnPowerUp(x, y) { var types = ['health', 'speed', 'power', 'strength']; var type = types[Math.floor(Math.random() * types.length)]; var powerUp = new PowerUp().init(x, y, type); game.addChild(powerUp); powerUps.push(powerUp); } // Handle touch/mouse down game.down = function (x, y, obj) { isSwipeActive = true; swipeStart.x = x; swipeStart.y = y; }; // Handle touch/mouse up game.up = function (x, y, obj) { if (isSwipeActive) { // Instead of dashing, shoot in the direction of the swipe var dx = x - swipeStart.x; var dy = y - swipeStart.y; var distance = Math.sqrt(dx * dx + dy * dy); // If it's a significant swipe, shoot in that direction if (distance > 20) { // Calculate target point to shoot towards var targetX = hero.x + dx * 10; var targetY = hero.y + dy * 10; hero.shootBullet(targetX, targetY); } else { // If it's just a tap, shoot upward hero.shootBullet(hero.x, hero.y - 100); } isSwipeActive = false; } }; // Handle touch/mouse move game.move = function (x, y, obj) { // We'll use swipe up/down instead of tracking movement }; // Main game update loop game.update = function () { // Update game time (in seconds) gameTime++; var seconds = Math.floor(gameTime / 60); timeTxt.setText('Time: ' + seconds + 's'); // Update UI scoreTxt.setText('Score: ' + LK.getScore()); comboTxt.setText('Combo: ' + hero.combo + 'x'); // Update health display var healthStr = ''; for (var i = 0; i < hero.health; i++) { healthStr += '❤️'; } healthTxt.setText(healthStr); // Spawn enemies - continuous spawn spawnTimer++; if (spawnTimer >= SPAWN_INTERVAL && enemies.length < MAX_ENEMIES) { // Spawn rate increases over time var difficulty = Math.min(0.9, 0.4 + seconds / 120); // Higher chance to spawn as time goes on if (Math.random() < difficulty) { spawnEnemy(); } spawnTimer = 0; } // Boss timer bossTimer--; if (bossTimer <= 0) { spawnBoss(); bossTimer = BOSS_INTERVAL; } // Increase difficulty based on time var speedIncrease = Math.min(3, seconds / 60); var enemySpeedModifier = 1 + speedIncrease * 0.5; // Update game objects updateGameObjects(); // Detect collisions between bullets and enemies for (var b = bullets.length - 1; b >= 0; b--) { var bullet = bullets[b]; if (!bullet.active) { continue; } var hitEnemy = false; for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; if (!enemy.active) { continue; } if (bullet.intersects(enemy)) { // Bullet hit enemy hitEnemy = true; // Call enemy's takeDamage method enemy.takeDamage(); // Visual feedback LK.effects.flashObject(enemy, 0xFFFFFF, 100); // Award points if enemy dead if (!enemy.active) { hero.addScore(enemy.scoreValue); // Maybe spawn a power-up if (Math.random() < POWER_UP_CHANCE) { spawnPowerUp(enemy.x, enemy.y); } } break; } } // Remove bullet if it hit something if (hitEnemy) { bullet.destroy(); bullets.splice(b, 1); } } // Clean up destroyed objects cleanupDestroyedObjects(); }; // Update all game objects function updateGameObjects() { // Update hero if (hero) { hero.update(); } // Update enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i]) { enemies[i].update(); } } // Update power-ups for (var i = 0; i < powerUps.length; i++) { if (powerUps[i]) { powerUps[i].update(); } } // Update bullets for (var i = 0; i < bullets.length; i++) { if (bullets[i]) { bullets[i].update(); } } // Update trails for (var i = 0; i < trails.length; i++) { if (trails[i]) { trails[i].update(); } } } // Clean up destroyed objects function cleanupDestroyedObjects() { // Clean up destroyed enemies for (var i = enemies.length - 1; i >= 0; i--) { if (!enemies[i] || !enemies[i].parent) { enemies.splice(i, 1); } } // Clean up destroyed power-ups for (var i = powerUps.length - 1; i >= 0; i--) { if (!powerUps[i] || !powerUps[i].parent) { powerUps.splice(i, 1); } } // Clean up destroyed trails for (var i = trails.length - 1; i >= 0; i--) { if (!trails[i] || !trails[i].parent) { trails.splice(i, 1); } } // Clean up destroyed bullets for (var i = bullets.length - 1; i >= 0; i--) { if (!bullets[i] || !bullets[i].parent) { bullets.splice(i, 1); } } } // Initialize the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var bossGraphic = self.attachAsset('boss', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.health = 10;
self.attackCooldown = 0;
self.attackPattern = 0;
self.scoreValue = 2000;
self.active = true;
self.init = function (x, y) {
self.x = x;
self.y = y;
return self;
};
self.takeDamage = function () {
if (!self.active) {
return;
}
// Boss takes 1 damage per hit, dies after 5 hits
self.health -= 1;
// Flash boss
LK.effects.flashObject(self, 0xffffff, 300);
LK.getSound('hit').play();
if (self.health <= 0) {
self.die();
} else {
// Speed up as health decreases
self.speed = 1.5 + (5 - self.health) * 0.2;
}
};
self.die = function () {
if (!self.active) {
return;
}
self.active = false;
LK.getSound('bossDeath').play();
// Flash and fade out
LK.effects.flashObject(self, 0xffff00, 500);
tween(self, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
self.destroy();
}
});
currentWave++;
bossDefeated = true;
nextWaveTimer = 180; // 3 seconds until next wave
return self.scoreValue;
};
self.update = function () {
if (!self.active) {
return;
}
// Move toward hero but more intelligently
if (hero) {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Different movement patterns
if (self.attackPattern === 0) {
// Direct approach
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
} else if (self.attackPattern === 1) {
// Circle around
var angle = Math.atan2(dy, dx) + Math.PI / 4;
self.x += Math.cos(angle) * self.speed * 1.5;
self.y += Math.sin(angle) * self.speed * 1.5;
} else if (self.attackPattern === 2) {
// Charge attack
if (self.attackCooldown > 30) {
self.x += dx / dist * self.speed * 2.5;
self.y += dy / dist * self.speed * 2.5;
} else {
// Wait
}
}
if (hero.invulnerable <= 0 && !hero.isDashing) {
if (self.intersects(hero)) {
hero.takeDamage();
}
}
}
// Attack pattern cooldown
self.attackCooldown--;
if (self.attackCooldown <= 0) {
self.attackPattern = (self.attackPattern + 1) % 3;
self.attackCooldown = 120; // 2 seconds per pattern
}
// Keep within screen bounds
self.x = Math.max(100, Math.min(2048 - 100, self.x));
self.y = Math.max(100, Math.min(2732 - 100, self.y));
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphic = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
bulletGraphic.tint = 0xffffff; // White bullet for the hero
self.speed = 15;
self.damage = 1;
self.active = true;
self.init = function (x, y, direction) {
self.x = x;
self.y = y;
self.direction = direction || {
x: 0,
y: -1
}; // Default direction is up
return self;
};
self.update = function () {
if (!self.active) {
return;
}
// Move in the specified direction
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
// Remove if off-screen
if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
self.destroy();
}
};
return self;
});
var DashTrail = Container.expand(function () {
var self = Container.call(this);
var trailGraphic = self.attachAsset('dashTrail', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.init = function (x, y) {
self.x = x;
self.y = y;
self.lifetime = 20; // frames the trail will live
return self;
};
self.update = function () {
self.lifetime--;
trailGraphic.alpha = self.lifetime / 20 * 0.7;
if (self.lifetime <= 0) {
self.destroy();
}
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.scoreValue = 100;
self.active = true;
self.init = function (x, y) {
self.x = x;
self.y = y;
// Initialize last position for rotation tracking
self.lastX = x;
self.lastY = y;
// Set initial rotation
if (hero) {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
enemyGraphic.rotation = Math.atan2(dy, dx);
}
return self;
};
self.takeDamage = function () {
if (!self.active) {
return;
}
// Enemies die from one hit
self.health = 0;
self.die();
};
self.die = function () {
if (!self.active) {
return;
}
self.active = false;
LK.getSound('hit').play();
// Flash, fade out, and fall animation
tween(self, {
alpha: 0,
y: self.y + 300,
// Fall down animation
rotation: Math.random() * Math.PI * 2,
// Random rotation
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
}
});
return self.scoreValue;
};
self.update = function () {
if (!self.active) {
return;
}
// Move toward hero
if (hero && !hero.isDashing) {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
// Spider walking animation
if (LK.ticks % 10 === 0) {
// Spider leg movement animation
tween(enemyGraphic, {
scaleX: 1.1,
scaleY: 0.9,
rotation: Math.atan2(dy, dx) + (Math.random() * 0.2 - 0.1)
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(enemyGraphic, {
scaleX: 1,
scaleY: 1,
rotation: Math.atan2(dy, dx)
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
}
}
// Check for collision with hero
if (hero && !hero.isDashing && hero.invulnerable <= 0) {
if (self.intersects(hero)) {
hero.takeDamage();
}
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphic = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
// Simple click handler that does nothing (placeholder)
self.down = function (x, y, obj) {
// No auto-shoot toggle functionality
};
self.shootSpeed = 15; // Bullet speed
self.fireRate = 15; // Frames between shots
self.shootCooldown = 0;
self.health = 3;
self.invulnerable = 0;
self.combo = 0;
self.score = 0;
self.powerBoost = 1; // Base power multiplier
self.shootBullet = function (targetX, targetY) {
if (self.shootCooldown > 0) {
return;
}
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize direction
var dirX = dx / distance;
var dirY = dy / distance;
// Create bullet
var bullet = new Bullet().init(self.x, self.y, {
x: dirX,
y: dirY
});
bullet.damage = self.powerBoost; // Apply power boost to bullet damage
// Visual shooting effect
tween(heroGraphic, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(heroGraphic, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
// Set cooldown
self.shootCooldown = self.fireRate;
// Add bullet to game
game.addChild(bullet);
if (!bullets) {
bullets = [];
}
bullets.push(bullet);
// Play shoot sound
LK.getSound('hit').play();
};
self.takeDamage = function () {
if (self.invulnerable > 0) {
return;
}
self.health--;
self.invulnerable = 60; // invulnerable for 1 second
self.combo = 0; // Reset combo
// Flash hero red
LK.effects.flashObject(self, 0xff0000, 500);
// Play damage sound
LK.getSound('damage').play();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.addScore = function (points) {
self.combo++;
var comboMultiplier = Math.min(4, 1 + self.combo * 0.1);
var scoreToAdd = Math.floor(points * comboMultiplier);
self.score += scoreToAdd;
LK.setScore(self.score);
};
self.update = function () {
// Keep within screen bounds
self.x = Math.max(50, Math.min(2048 - 50, self.x));
self.y = Math.max(50, Math.min(2732 - 50, self.y));
// Cooldowns
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
if (self.invulnerable > 0) {
self.invulnerable--;
// Flicker effect during invulnerability
heroGraphic.alpha = LK.ticks % 6 < 3 ? 0.4 : 1;
} else {
// Normal appearance when not invulnerable
heroGraphic.alpha = 1;
heroGraphic.tint = 0xFFFFFF; // Normal color
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphic = self.attachAsset('powerUp', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'health'; // Default type
self.active = true;
self.lifetime = 300; // 5 seconds
self.init = function (x, y, type) {
self.x = x;
self.y = y;
self.type = type || self.type;
// Set color based on type
if (self.type === 'health') {
powerUpGraphic.tint = 0x2ecc71; // Green
} else if (self.type === 'speed') {
powerUpGraphic.tint = 0x3498db; // Blue
} else if (self.type === 'power') {
powerUpGraphic.tint = 0xe74c3c; // Red
} else if (self.type === 'strength') {
powerUpGraphic.tint = 0x9b59b6; // Purple
}
return self;
};
self.collect = function () {
if (!self.active) {
return;
}
self.active = false;
LK.getSound('powerup').play();
if (self.type === 'health' && hero.health < 3) {
hero.health++;
} else if (self.type === 'speed') {
hero.dashSpeed = 80; // Even faster dash
hero.dashDistance = 900; // Even longer dash
// Visual indicator of speed boost
tween(hero, {
alpha: 0.7
}, {
duration: 200,
onFinish: function onFinish() {
tween(hero, {
alpha: 1
}, {
duration: 200
});
}
});
// Reset after 10 seconds
LK.setTimeout(function () {
if (hero) {
hero.dashSpeed = 60;
hero.dashDistance = 700;
}
}, 10000);
} else if (self.type === 'strength') {
// Increase hero's attack strength more permanently
hero.powerBoost = Math.min(5, hero.powerBoost + 1);
// Visual indicator of strength boost
tween(hero, {
tint: 0x9b59b6
}, {
duration: 500,
onFinish: function onFinish() {
tween(hero, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
});
// Show strength level
var strengthTxt = new Text2('STRENGTH +' + hero.powerBoost + '!', {
size: 80,
fill: 0x9b59b6
});
strengthTxt.anchor.set(0.5, 0.5);
strengthTxt.x = 2048 / 2;
strengthTxt.y = 2732 / 2;
game.addChild(strengthTxt);
// Fade out the text
tween(strengthTxt, {
alpha: 0,
y: strengthTxt.y - 100
}, {
duration: 1500,
onFinish: function onFinish() {
strengthTxt.destroy();
}
});
} else if (self.type === 'power') {
// Clear all enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i].active) {
var points = enemies[i].die();
hero.addScore(points);
}
}
// Increase hero's attack strength
hero.powerBoost = 3;
// Visual indicator of power boost
tween(hero, {
tint: 0xFF0000
}, {
duration: 300
});
// Reset after 10 seconds
LK.setTimeout(function () {
if (hero) {
hero.powerBoost = 1;
tween(hero, {
tint: 0xFFFFFF
}, {
duration: 500
});
}
}, 10000);
}
// Flash and fade out
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
};
self.update = function () {
if (!self.active) {
return;
}
// Floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
// Rotate slowly
powerUpGraphic.rotation += 0.02;
// Check for collision with hero
if (hero && (hero.intersects(self) || hero.isDashing && self.distanceTo(hero) < 100)) {
self.collect();
}
// Expire after lifetime
self.lifetime--;
if (self.lifetime <= 0) {
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
self.active = false;
}
};
self.distanceTo = function (target) {
var dx = target.x - self.x;
var dy = target.y - self.y;
return Math.sqrt(dx * dx + dy * dy);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
// Game state variables
var hero;
var enemies = [];
var bullets = [];
var powerUps = [];
var trails = [];
var gameTime = 0;
var spawnTimer = 0;
var bossTimer = 0;
var currentWave = 0;
var bossDefeated = false;
var nextWaveTimer = 0;
var swipeStart = {
x: 0,
y: 0
};
var isSwipeActive = false;
// UI elements
var scoreTxt;
var timeTxt;
var healthTxt;
var comboTxt;
// Game constants
var SPAWN_INTERVAL = 90; // Frames between enemy spawns
var POWER_UP_CHANCE = 0.15; // Chance to spawn power-up on enemy defeat
var BOSS_INTERVAL = 1800; // Spawn boss every 30 seconds (60fps * 30)
var MAX_ENEMIES = 15; // Maximum enemies on screen at once
// Initialize game elements
function initGame() {
// Add background
var background = game.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create hero
hero = new Hero();
hero.x = 2048 / 2;
hero.y = 2732 / 2;
game.addChild(hero);
// Auto-shoot indicator removed
// Create UI elements
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
timeTxt = new Text2('Time: 0s', {
size: 60,
fill: 0xFFFFFF
});
timeTxt.anchor.set(1, 0);
LK.gui.top.addChild(timeTxt);
healthTxt = new Text2('❤️❤️❤️', {
size: 60,
fill: 0xFFFFFF
});
healthTxt.anchor.set(0, 0);
LK.gui.bottom.addChild(healthTxt);
comboTxt = new Text2('Combo: 0x', {
size: 60,
fill: 0xFFFFFF
});
comboTxt.anchor.set(1, 0);
LK.gui.bottom.addChild(comboTxt);
// Initialize game timers
gameTime = 0;
spawnTimer = 0;
bossTimer = BOSS_INTERVAL;
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.5,
duration: 1000
}
});
}
// This function is no longer needed in endless mode
// Spawn a regular enemy
function spawnEnemy() {
// Enforce a maximum number of enemies
if (enemies.length >= MAX_ENEMIES) {
return;
}
var edge = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
var x, y;
switch (edge) {
case 0:
// Top
x = Math.random() * 2048;
y = -50;
break;
case 1:
// Right
x = 2048 + 50;
y = Math.random() * 2732;
break;
case 2:
// Bottom
x = Math.random() * 2048;
y = 2732 + 50;
break;
case 3:
// Left
x = -50;
y = Math.random() * 2732;
break;
}
var enemy = new Enemy().init(x, y);
var seconds = Math.floor(gameTime / 60);
// Speed increases with game time
enemy.speed = 2 + Math.min(3, seconds / 30);
enemy.health = 1; // Enemies always have 1 health
// Scale score value based on time played
enemy.scoreValue = 100 + Math.floor(seconds / 30) * 20;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn a boss
function spawnBoss() {
var boss = new Boss().init(2048 / 2, -200);
var seconds = Math.floor(gameTime / 60);
// Boss health and score scale with game time
boss.health = 5 + Math.floor(seconds / 60);
boss.scoreValue = 2000 + seconds * 50;
game.addChild(boss);
enemies.push(boss);
// Make a dramatic entrance
tween(boss, {
y: 400
}, {
duration: 2000,
easing: tween.bounceOut
});
}
// Spawn a power-up
function spawnPowerUp(x, y) {
var types = ['health', 'speed', 'power', 'strength'];
var type = types[Math.floor(Math.random() * types.length)];
var powerUp = new PowerUp().init(x, y, type);
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Handle touch/mouse down
game.down = function (x, y, obj) {
isSwipeActive = true;
swipeStart.x = x;
swipeStart.y = y;
};
// Handle touch/mouse up
game.up = function (x, y, obj) {
if (isSwipeActive) {
// Instead of dashing, shoot in the direction of the swipe
var dx = x - swipeStart.x;
var dy = y - swipeStart.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If it's a significant swipe, shoot in that direction
if (distance > 20) {
// Calculate target point to shoot towards
var targetX = hero.x + dx * 10;
var targetY = hero.y + dy * 10;
hero.shootBullet(targetX, targetY);
} else {
// If it's just a tap, shoot upward
hero.shootBullet(hero.x, hero.y - 100);
}
isSwipeActive = false;
}
};
// Handle touch/mouse move
game.move = function (x, y, obj) {
// We'll use swipe up/down instead of tracking movement
};
// Main game update loop
game.update = function () {
// Update game time (in seconds)
gameTime++;
var seconds = Math.floor(gameTime / 60);
timeTxt.setText('Time: ' + seconds + 's');
// Update UI
scoreTxt.setText('Score: ' + LK.getScore());
comboTxt.setText('Combo: ' + hero.combo + 'x');
// Update health display
var healthStr = '';
for (var i = 0; i < hero.health; i++) {
healthStr += '❤️';
}
healthTxt.setText(healthStr);
// Spawn enemies - continuous spawn
spawnTimer++;
if (spawnTimer >= SPAWN_INTERVAL && enemies.length < MAX_ENEMIES) {
// Spawn rate increases over time
var difficulty = Math.min(0.9, 0.4 + seconds / 120);
// Higher chance to spawn as time goes on
if (Math.random() < difficulty) {
spawnEnemy();
}
spawnTimer = 0;
}
// Boss timer
bossTimer--;
if (bossTimer <= 0) {
spawnBoss();
bossTimer = BOSS_INTERVAL;
}
// Increase difficulty based on time
var speedIncrease = Math.min(3, seconds / 60);
var enemySpeedModifier = 1 + speedIncrease * 0.5;
// Update game objects
updateGameObjects();
// Detect collisions between bullets and enemies
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
if (!bullet.active) {
continue;
}
var hitEnemy = false;
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (!enemy.active) {
continue;
}
if (bullet.intersects(enemy)) {
// Bullet hit enemy
hitEnemy = true;
// Call enemy's takeDamage method
enemy.takeDamage();
// Visual feedback
LK.effects.flashObject(enemy, 0xFFFFFF, 100);
// Award points if enemy dead
if (!enemy.active) {
hero.addScore(enemy.scoreValue);
// Maybe spawn a power-up
if (Math.random() < POWER_UP_CHANCE) {
spawnPowerUp(enemy.x, enemy.y);
}
}
break;
}
}
// Remove bullet if it hit something
if (hitEnemy) {
bullet.destroy();
bullets.splice(b, 1);
}
}
// Clean up destroyed objects
cleanupDestroyedObjects();
};
// Update all game objects
function updateGameObjects() {
// Update hero
if (hero) {
hero.update();
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
if (enemies[i]) {
enemies[i].update();
}
}
// Update power-ups
for (var i = 0; i < powerUps.length; i++) {
if (powerUps[i]) {
powerUps[i].update();
}
}
// Update bullets
for (var i = 0; i < bullets.length; i++) {
if (bullets[i]) {
bullets[i].update();
}
}
// Update trails
for (var i = 0; i < trails.length; i++) {
if (trails[i]) {
trails[i].update();
}
}
}
// Clean up destroyed objects
function cleanupDestroyedObjects() {
// Clean up destroyed enemies
for (var i = enemies.length - 1; i >= 0; i--) {
if (!enemies[i] || !enemies[i].parent) {
enemies.splice(i, 1);
}
}
// Clean up destroyed power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
if (!powerUps[i] || !powerUps[i].parent) {
powerUps.splice(i, 1);
}
}
// Clean up destroyed trails
for (var i = trails.length - 1; i >= 0; i--) {
if (!trails[i] || !trails[i].parent) {
trails.splice(i, 1);
}
}
// Clean up destroyed bullets
for (var i = bullets.length - 1; i >= 0; i--) {
if (!bullets[i] || !bullets[i].parent) {
bullets.splice(i, 1);
}
}
}
// Initialize the game
initGame();
colored spider. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
white silk web. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
amazing spider web on tree branch. anime image. green landscape Single Game Texture. In-Game asset. 2d.
flyn lady bug 2d cartoon objek. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
flyin evil woodpecker bird. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows