/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Enemy var Enemy = Container.expand(function () { var self = Container.call(this); // type: 1,2,3 self.type = 1; self.row = 0; self.col = 0; self.isDiving = false; self.diveTargetX = 0; self.diveTargetY = 0; self.diveStep = 0; self.diveSpeed = 0; self.baseX = 0; self.baseY = 0; self.direction = 1; // 1: right, -1: left self.bulletCooldown = 0; self.alive = true; self.asset = null; self.init = function (type) { self.type = type; var assetId = 'enemy' + type; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.width = self.asset.width; self.height = self.asset.height; }; self.startDive = function (targetX, targetY, speed) { self.isDiving = true; self.diveTargetX = targetX; self.diveTargetY = targetY; self.diveStep = 0; self.diveSpeed = speed; }; self.update = function () { if (!self.alive) return; if (self.isDiving) { // Dive movement: curve towards player, then return var dx = self.diveTargetX - self.x; var dy = self.diveTargetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 40) { // Dive finished, return to base self.isDiving = false; tween(self, { x: self.baseX, y: self.baseY }, { duration: 600, easing: tween.cubicOut }); } else { var step = self.diveSpeed; self.x += dx / dist * step; self.y += dy / dist * step; } } // Bullet cooldown if (self.bulletCooldown > 0) self.bulletCooldown--; }; return self; }); // Enemy Bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.update = function () { self.y += self.speed; }; return self; }); // Player Bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bullet = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -38; self.update = function () { self.y += self.speed; }; return self; }); // Player Ship var PlayerShip = Container.expand(function () { var self = Container.call(this); var ship = self.attachAsset('playerShip', { anchorX: 0.5, anchorY: 0.5 }); self.width = ship.width; self.height = ship.height; self.speed = 22; self.canShoot = true; self.shootCooldown = 0; self.update = function () { // Cooldown for shooting if (self.shootCooldown > 0) { self.shootCooldown--; if (self.shootCooldown === 0) self.canShoot = true; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000010 }); /**** * Game Code ****/ // Sounds // Bullets // Enemy types // Spaceship (player) // Game constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var ENEMY_ROWS = 5; var ENEMY_COLS = 8; var ENEMY_SPACING_X = 180; var ENEMY_SPACING_Y = 160; var ENEMY_START_Y = 320; var ENEMY_START_X = (GAME_WIDTH - (ENEMY_COLS - 1) * ENEMY_SPACING_X) / 2 + ENEMY_SPACING_X / 2; var ENEMY_MOVE_STEP = 32; var ENEMY_MOVE_DOWN = 60; var ENEMY_MOVE_INTERVAL = 32; // ticks var ENEMY_DIVE_INTERVAL = 120; // ticks var ENEMY_BULLET_CHANCE = 0.012; // per update per enemy var PLAYER_Y = GAME_HEIGHT - 220; var PLAYER_SHOOT_COOLDOWN = 18; // ticks // Game state var playerShip = null; var playerBullets = []; var enemyBullets = []; var enemies = []; var enemyDirection = 1; // 1: right, -1: left var enemyMoveTick = 0; var enemyDiveTick = 0; var dragNode = null; var scoreTxt = null; var lastIntersecting = false; var gameOver = false; var wave = 1; // Score display scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Wave display var waveTxt = new Text2('Wave 1', { size: 80, fill: "#fff" }); waveTxt.anchor.set(0.5, 0); LK.gui.top.addChild(waveTxt); waveTxt.y = 120; // Initialize player playerShip = new PlayerShip(); game.addChild(playerShip); playerShip.x = GAME_WIDTH / 2; playerShip.y = PLAYER_Y; // Initialize enemies function spawnEnemies() { for (var row = 0; row < ENEMY_ROWS; row++) { for (var col = 0; col < ENEMY_COLS; col++) { var type = row === 0 ? 3 : row < 3 ? 2 : 1; var enemy = new Enemy(); enemy.init(type); enemy.row = row; enemy.col = col; enemy.baseX = ENEMY_START_X + col * ENEMY_SPACING_X; enemy.baseY = ENEMY_START_Y + row * ENEMY_SPACING_Y; enemy.x = enemy.baseX; enemy.y = enemy.baseY; enemy.direction = 1; enemy.isDiving = false; enemy.alive = true; enemies.push(enemy); game.addChild(enemy); } } } spawnEnemies(); // Handle player movement (dragging) function handleMove(x, y, obj) { if (gameOver) return; if (dragNode === playerShip) { // Clamp to game area, avoid left 100px for menu var minX = Math.max(playerShip.width / 2 + 100, 100 + playerShip.width / 2); var maxX = GAME_WIDTH - playerShip.width / 2; var newX = Math.max(minX, Math.min(maxX, x)); playerShip.x = newX; } } game.move = handleMove; game.down = function (x, y, obj) { if (gameOver) return; // Only allow drag if touch is on player ship var local = playerShip.toLocal(game.toGlobal({ x: x, y: y })); if (local.x >= -playerShip.width / 2 && local.x <= playerShip.width / 2 && local.y >= -playerShip.height / 2 && local.y <= playerShip.height / 2) { dragNode = playerShip; } }; game.up = function (x, y, obj) { dragNode = null; }; // Handle shooting (tap anywhere) game.tap = function (x, y, obj) { if (gameOver) return; shootPlayerBullet(); }; // For mobile, also allow shooting on down if not dragging game.down = function (x, y, obj) { if (gameOver) return; var local = playerShip.toLocal(game.toGlobal({ x: x, y: y })); if (local.x >= -playerShip.width / 2 && local.x <= playerShip.width / 2 && local.y >= -playerShip.height / 2 && local.y <= playerShip.height / 2) { dragNode = playerShip; } else { shootPlayerBullet(); } }; // Player shooting function shootPlayerBullet() { if (!playerShip.canShoot || gameOver) return; var bullet = new PlayerBullet(); bullet.x = playerShip.x; bullet.y = playerShip.y - playerShip.height / 2 - 20; playerBullets.push(bullet); game.addChild(bullet); playerShip.canShoot = false; playerShip.shootCooldown = PLAYER_SHOOT_COOLDOWN; LK.getSound('shoot').play(); } // Enemy shooting function shootEnemyBullet(enemy) { var bullet = new EnemyBullet(); bullet.x = enemy.x; bullet.y = enemy.y + enemy.height / 2 + 20; enemyBullets.push(bullet); game.addChild(bullet); LK.getSound('enemyShoot').play(); } // Enemy movement and dive logic function updateEnemies() { // Move formation if (enemyMoveTick <= 0) { // Find leftmost and rightmost alive enemy var minX = GAME_WIDTH, maxX = 0; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (!e.alive || e.isDiving) continue; if (e.x < minX) minX = e.x; if (e.x > maxX) maxX = e.x; } var moveEdge = false; if (enemyDirection === 1 && maxX + ENEMY_MOVE_STEP > GAME_WIDTH - 40) moveEdge = true; if (enemyDirection === -1 && minX - ENEMY_MOVE_STEP < 140) moveEdge = true; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (!e.alive || e.isDiving) continue; if (moveEdge) { e.y += ENEMY_MOVE_DOWN; } else { e.x += ENEMY_MOVE_STEP * enemyDirection; e.baseX = e.x; } } if (moveEdge) enemyDirection *= -1; enemyMoveTick = Math.max(ENEMY_MOVE_INTERVAL - wave * 2, 10); } else { enemyMoveTick--; } // Dive logic if (enemyDiveTick <= 0) { // Pick a random front-row enemy to dive var frontEnemies = []; for (var col = 0; col < ENEMY_COLS; col++) { for (var row = ENEMY_ROWS - 1; row >= 0; row--) { var idx = row * ENEMY_COLS + col; if (enemies[idx] && enemies[idx].alive && !enemies[idx].isDiving) { frontEnemies.push(enemies[idx]); break; } } } if (frontEnemies.length > 0) { var diveEnemy = frontEnemies[Math.floor(Math.random() * frontEnemies.length)]; if (diveEnemy && !diveEnemy.isDiving) { var targetX = playerShip.x + (Math.random() - 0.5) * 200; var targetY = playerShip.y - 100; diveEnemy.startDive(targetX, targetY, 32 + wave * 2); } } enemyDiveTick = Math.max(ENEMY_DIVE_INTERVAL - wave * 8, 40); } else { enemyDiveTick--; } // Enemy shooting for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (!e.alive) continue; if (e.isDiving && e.bulletCooldown <= 0 && Math.random() < 0.18) { shootEnemyBullet(e); e.bulletCooldown = 32 + Math.floor(Math.random() * 32); } else if (!e.isDiving && e.bulletCooldown <= 0 && Math.random() < ENEMY_BULLET_CHANCE) { shootEnemyBullet(e); e.bulletCooldown = 64 + Math.floor(Math.random() * 32); } } } // Collision detection function checkCollision(a, b) { // Simple AABB return a.x - a.width / 2 < b.x + b.width / 2 && a.x + a.width / 2 > b.x - b.width / 2 && a.y - a.height / 2 < b.y + b.height / 2 && a.y + a.height / 2 > b.y - b.height / 2; } // Game update game.update = function () { if (gameOver) return; // Player update playerShip.update(); // Enemies update for (var i = 0; i < enemies.length; i++) { enemies[i].update(); } updateEnemies(); // Player bullets update for (var i = playerBullets.length - 1; i >= 0; i--) { var b = playerBullets[i]; b.update(); // Remove if off screen if (b.y < -80) { b.destroy(); playerBullets.splice(i, 1); continue; } // Check collision with enemies for (var j = 0; j < enemies.length; j++) { var e = enemies[j]; if (!e.alive) continue; if (checkCollision(b, e)) { // Enemy hit e.alive = false; e.visible = false; b.destroy(); playerBullets.splice(i, 1); LK.setScore(LK.getScore() + 10 * e.type); scoreTxt.setText(LK.getScore()); LK.getSound('explosion').play(); break; } } } // Enemy bullets update for (var i = enemyBullets.length - 1; i >= 0; i--) { var b = enemyBullets[i]; b.update(); if (b.y > GAME_HEIGHT + 80) { b.destroy(); enemyBullets.splice(i, 1); continue; } // Check collision with player if (checkCollision(b, playerShip)) { // Player hit b.destroy(); enemyBullets.splice(i, 1); playerDeath(); return; } } // Enemy dive collision with player for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; if (!e.alive) continue; if (checkCollision(e, playerShip)) { playerDeath(); return; } } // Check win condition var anyAlive = false; for (var i = 0; i < enemies.length; i++) { if (enemies[i].alive) { anyAlive = true; break; } } if (!anyAlive) { // Next wave wave++; waveTxt.setText('Wave ' + wave); // Remove old enemies for (var i = 0; i < enemies.length; i++) { enemies[i].destroy(); } enemies = []; enemyMoveTick = 0; enemyDiveTick = 0; spawnEnemies(); } }; // Player death function playerDeath() { if (gameOver) return; gameOver = true; LK.effects.flashScreen(0xff0000, 1000); tween(playerShip, { alpha: 0 }, { duration: 600, easing: tween.cubicOut }); LK.setTimeout(function () { LK.showGameOver(); }, 900); } // Score LK.setScore(0); scoreTxt.setText(LK.getScore()); /* End of file */
===================================================================
--- original.js
+++ change.js
@@ -75,9 +75,9 @@
var bullet = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
- self.speed = 22;
+ self.speed = 12;
self.update = function () {
self.y += self.speed;
};
return self;