/**** * 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.health = 40; self.speed = 2 + Math.random() * 2; self.lastY = 0; self.lastIntersecting = false; self.update = function () { self.lastY = self.y; self.y += self.speed; // Add slight horizontal movement self.x += Math.sin(LK.ticks / 20 + self.y / 100) * 2; }; self.damage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xFFFF00, 200); if (self.health <= 0) { return true; // Enemy is dead } return false; }; return self; }); var FireParticle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 20 + Math.random() * 20; self.speedX = Math.random() * 4 - 2; self.speedY = Math.random() * 2 + 1; self.update = function () { self.x += self.speedX; self.y += self.speedY; self.lifetime--; particleGraphics.alpha = self.lifetime / 40; particleGraphics.scaleX = particleGraphics.scaleY = self.lifetime / 40; }; return self; }); var Fireball = Container.expand(function () { var self = Container.call(this); var fireballGraphics = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.damage = 20; self.particles = []; self.speedX = 0; self.speedY = -15; // Default is upward self.targetX = 0; self.targetY = 0; self.lastY = 0; self.update = function () { self.lastY = self.y; // Use directional movement if speedX and speedY are set, otherwise fall back to default vertical movement if (self.speedX !== undefined && self.speedY !== undefined) { self.x += self.speedX; self.y += self.speedY; } else { self.y -= self.speed; } // Create fire trail particles if (LK.ticks % 3 === 0) { self.createParticle(); } // Rotate the fireball fireballGraphics.rotation += 0.1; }; self.createParticle = function () { var particle = new FireParticle(); particle.x = self.x + (Math.random() * 20 - 10); particle.y = self.y + (Math.random() * 20 - 10); game.addChild(particle); particles.push(particle); }; return self; }); var Flame = Container.expand(function () { var self = Container.call(this); var flameGraphics = self.attachAsset('flame', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 300; self.power = 1; self.selected = false; self.originX = 0; self.originY = 0; self.lastIntersecting = false; self.init = function (x, y) { self.x = x; self.y = y; self.originX = x; self.originY = y; }; self.update = function () { // Animate flame if (!self.selected) { flameGraphics.scaleX = 0.8 + Math.sin(LK.ticks / 10) * 0.2; flameGraphics.scaleY = 0.8 + Math.cos(LK.ticks / 8) * 0.2; // Random movement around origin self.x = self.originX + Math.sin(LK.ticks / 15) * 10; self.y = self.originY + Math.cos(LK.ticks / 12) * 10; } // Decrease lifetime self.lifetime--; if (self.lifetime <= 50) { // Fade out when about to disappear flameGraphics.alpha = self.lifetime / 50; } }; self.select = function () { self.selected = true; tween(flameGraphics, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut }); }; self.deselect = function () { self.selected = false; tween(flameGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeOut }); }; self.move = function (x, y) { if (self.selected) { self.x = x; self.y = y; } }; return self; }); var FlameTrap = Container.expand(function () { var self = Container.call(this); var trapGraphics = self.attachAsset('flameTrap', { anchorX: 0.5, anchorY: 0.5 }); self.active = false; self.cooldown = 0; self.lastIntersecting = false; self.activate = function () { if (!self.active && self.cooldown <= 0) { self.active = true; LK.effects.flashObject(self, 0xFF6600, 500); LK.getSound('flameWhoosh').play(); // Create flames for (var i = 0; i < 5; i++) { var flame = new Flame(); flame.init(self.x + i * 40 - 80, self.y - 50); game.addChild(flame); flames.push(flame); } // Set cooldown self.cooldown = 300; self.active = false; } }; self.update = function () { if (self.cooldown > 0) { self.cooldown--; trapGraphics.alpha = 0.3 + (1 - self.cooldown / 300) * 0.7; } }; return self; }); var Pyromancer = Container.expand(function () { var self = Container.call(this); var pyromancerGraphics = self.attachAsset('pyromancer', { anchorX: 0.5, anchorY: 0.5 }); self.health = 100; self.fireballCooldown = 0; self.fireballCooldownMax = 15; self.flameManipulationActive = false; self.targetFlame = null; self.shoot = function () { if (self.fireballCooldown <= 0) { var fireball = new Fireball(); fireball.x = self.x; fireball.y = self.y - 50; // Modify fireball's trajectory to go above the red line fireball.targetY = Math.random() * (2732 / 2 - 200) + 100; // Random position in upper half fireball.targetX = Math.random() * 2048; // Random horizontal position // Calculate direction vector var dirX = fireball.targetX - fireball.x; var dirY = fireball.targetY - fireball.y; var length = Math.sqrt(dirX * dirX + dirY * dirY); // Normalize and set velocity fireball.speedX = dirX / length * 15; fireball.speedY = dirY / length * 15; game.addChild(fireball); fireballs.push(fireball); self.fireballCooldown = self.fireballCooldownMax; LK.getSound('fireballLaunch').play(); } }; self.update = function () { if (self.fireballCooldown > 0) { self.fireballCooldown--; } }; self.damage = function (amount) { self.health -= amount; LK.effects.flashObject(self, 0xFF0000, 300); if (self.health <= 0) { LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Set background to dark blue game.setBackgroundColor(0x1A1A2E); // Create a red line divider var redLine = game.addChild(LK.getAsset('flameTrap', { anchorX: 0.5, anchorY: 0.5, scaleX: 10.24, // Cover the full width of the screen scaleY: 0.5, tint: 0xFF0000 // Red color })); redLine.y = 2732 / 2; // Middle of the screen redLine.x = 2048 / 2; // Center horizontally // Game variables var pyromancer; var fireballs = []; var enemies = []; var flames = []; var particles = []; var flameTraps = []; var wave = 1; var enemiesDefeated = 0; var enemiesInWave = 5; var waveInterval = 600; // 10 seconds between waves var waveTimer = 0; var dragTarget = null; var selectedFlame = null; // Create UI var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFF9900 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var waveTxt = new Text2('Wave: 1', { size: 80, fill: 0xFFFFFF }); waveTxt.anchor.set(0.5, 0); waveTxt.y = 100; LK.gui.top.addChild(waveTxt); var healthTxt = new Text2('Health: 100', { size: 80, fill: 0xFF5555 }); healthTxt.anchor.set(0, 0); healthTxt.x = 50; healthTxt.y = 50; LK.gui.topRight.addChild(healthTxt); // Create pyromancer pyromancer = new Pyromancer(); pyromancer.x = 2048 / 2; pyromancer.y = 2732 - 200; game.addChild(pyromancer); // Create flame traps for (var i = 0; i < 3; i++) { var trap = new FlameTrap(); trap.x = (i + 1) * (2048 / 4); trap.y = 2732 / 2; game.addChild(trap); flameTraps.push(trap); } // Play background music LK.playMusic('battleTheme', { fade: { start: 0, end: 0.7, duration: 2000 } }); // Handle touch input for moving pyromancer function handleMove(x, y, obj) { if (dragTarget === pyromancer) { // Limit pyromancer to bottom half of screen pyromancer.x = x; pyromancer.y = Math.max(2732 / 2, Math.min(y, 2732 - 100)); } else if (selectedFlame) { // Move selected flame selectedFlame.move(x, y); } } game.down = function (x, y, obj) { // Check if tapping on an existing flame to control it var flameSelected = false; for (var i = 0; i < flames.length; i++) { var flame = flames[i]; var localPos = flame.toLocal({ x: x, y: y }); if (Math.abs(localPos.x) < 40 && Math.abs(localPos.y) < 60) { // Select this flame if (selectedFlame) { selectedFlame.deselect(); } selectedFlame = flame; selectedFlame.select(); flameSelected = true; LK.getSound('flameWhoosh').play(); break; } } // Check if tapping a flame trap for (var i = 0; i < flameTraps.length; i++) { var trap = flameTraps[i]; if (Math.abs(x - trap.x) < 100 && Math.abs(y - trap.y) < 30) { trap.activate(); return; } } // If not selecting a flame and in lower half of screen, control pyromancer if (!flameSelected && y > 2732 / 2) { dragTarget = pyromancer; handleMove(x, y, obj); } else if (!flameSelected && !selectedFlame && y < 2732 / 2) { // Shoot fireball when tapping in upper half, and make it target that location pyromancer.shoot(); // Set the target for the most recently shot fireball if (fireballs.length > 0) { var lastFireball = fireballs[fireballs.length - 1]; lastFireball.targetX = x; lastFireball.targetY = y; // Recalculate direction vector var dirX = lastFireball.targetX - lastFireball.x; var dirY = lastFireball.targetY - lastFireball.y; var length = Math.sqrt(dirX * dirX + dirY * dirY); // Normalize and set velocity lastFireball.speedX = dirX / length * 15; lastFireball.speedY = dirY / length * 15; } } }; game.up = function (x, y, obj) { dragTarget = null; // Deselect flame if we have one if (selectedFlame) { selectedFlame.deselect(); selectedFlame = null; } }; game.move = handleMove; // Create a new enemy function spawnEnemy() { var enemy = new Enemy(); enemy.x = Math.random() * (2048 - 200) + 100; enemy.y = -100; game.addChild(enemy); enemies.push(enemy); } // Start a new wave function startNewWave() { wave++; waveTxt.setText('Wave: ' + wave); enemiesInWave = 5 + wave * 2; waveTimer = 0; // Spawn first enemy of wave spawnEnemy(); } // Update game every frame game.update = function () { // Update UI scoreTxt.setText('Score: ' + LK.getScore()); healthTxt.setText('Health: ' + pyromancer.health); // Update pyromancer pyromancer.update(); // Enemy wave management waveTimer++; if (enemies.length === 0 && waveTimer >= waveInterval) { startNewWave(); } else if (enemies.length < enemiesInWave && waveTimer % 60 === 0 && waveTimer < waveInterval) { spawnEnemy(); } // Update fireballs for (var i = fireballs.length - 1; i >= 0; i--) { var fireball = fireballs[i]; fireball.update(); // Remove fireballs that go off screen if (fireball.y < -100) { fireball.destroy(); fireballs.splice(i, 1); } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.lastY = enemy.y; enemy.update(); // Check for collision with fireballs for (var j = fireballs.length - 1; j >= 0; j--) { var fireball = fireballs[j]; if (enemy.intersects(fireball)) { // Enemy hit by fireball if (enemy.damage(fireball.damage)) { // Enemy destroyed LK.getSound('enemyHit').play(); enemy.destroy(); enemies.splice(i, 1); LK.setScore(LK.getScore() + 100); enemiesDefeated++; // Create flames where enemy was destroyed var flame = new Flame(); flame.init(enemy.x, enemy.y); game.addChild(flame); flames.push(flame); i--; break; } // Remove fireball fireball.destroy(); fireballs.splice(j, 1); } } // Check for enemies that reach bottom of screen if (enemy.y > 2732 + 50) { pyromancer.damage(10); enemy.destroy(); enemies.splice(i, 1); } // Check for collision with flames if (enemy && selectedFlame && enemy.intersects(selectedFlame)) { if (enemy.damage(0.5)) { // Enemy destroyed by flame LK.getSound('enemyHit').play(); enemy.destroy(); enemies.splice(i, 1); LK.setScore(LK.getScore() + 150); enemiesDefeated++; } } // Check for collision with pyromancer if (enemy && enemy.intersects(pyromancer)) { pyromancer.damage(20); enemy.destroy(); enemies.splice(i, 1); } } // Update flames for (var i = flames.length - 1; i >= 0; i--) { var flame = flames[i]; flame.update(); // Remove flames that have expired if (flame.lifetime <= 0) { // Don't remove if it's currently selected if (flame === selectedFlame) { flame.lifetime = 60; // Give it a little more time } else { flame.destroy(); flames.splice(i, 1); } } } // Update flame traps for (var i = 0; i < flameTraps.length; i++) { flameTraps[i].update(); } // Update particles for (var i = particles.length - 1; i >= 0; i--) { var particle = particles[i]; particle.update(); // Remove particles that have expired if (particle.lifetime <= 0) { particle.destroy(); particles.splice(i, 1); } } // Check for win condition if (enemiesDefeated >= 50) { LK.showYouWin(); } };
===================================================================
--- original.js
+++ change.js
@@ -59,12 +59,22 @@
});
self.speed = 15;
self.damage = 20;
self.particles = [];
+ self.speedX = 0;
+ self.speedY = -15; // Default is upward
+ self.targetX = 0;
+ self.targetY = 0;
self.lastY = 0;
self.update = function () {
self.lastY = self.y;
- self.y -= self.speed;
+ // Use directional movement if speedX and speedY are set, otherwise fall back to default vertical movement
+ if (self.speedX !== undefined && self.speedY !== undefined) {
+ self.x += self.speedX;
+ self.y += self.speedY;
+ } else {
+ self.y -= self.speed;
+ }
// Create fire trail particles
if (LK.ticks % 3 === 0) {
self.createParticle();
}
@@ -191,8 +201,18 @@
if (self.fireballCooldown <= 0) {
var fireball = new Fireball();
fireball.x = self.x;
fireball.y = self.y - 50;
+ // Modify fireball's trajectory to go above the red line
+ fireball.targetY = Math.random() * (2732 / 2 - 200) + 100; // Random position in upper half
+ fireball.targetX = Math.random() * 2048; // Random horizontal position
+ // Calculate direction vector
+ var dirX = fireball.targetX - fireball.x;
+ var dirY = fireball.targetY - fireball.y;
+ var length = Math.sqrt(dirX * dirX + dirY * dirY);
+ // Normalize and set velocity
+ fireball.speedX = dirX / length * 15;
+ fireball.speedY = dirY / length * 15;
game.addChild(fireball);
fireballs.push(fireball);
self.fireballCooldown = self.fireballCooldownMax;
LK.getSound('fireballLaunch').play();
@@ -225,8 +245,19 @@
* Game Code
****/
// Set background to dark blue
game.setBackgroundColor(0x1A1A2E);
+// Create a red line divider
+var redLine = game.addChild(LK.getAsset('flameTrap', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 10.24,
+ // Cover the full width of the screen
+ scaleY: 0.5,
+ tint: 0xFF0000 // Red color
+}));
+redLine.y = 2732 / 2; // Middle of the screen
+redLine.x = 2048 / 2; // Center horizontally
// Game variables
var pyromancer;
var fireballs = [];
var enemies = [];
@@ -326,11 +357,24 @@
// If not selecting a flame and in lower half of screen, control pyromancer
if (!flameSelected && y > 2732 / 2) {
dragTarget = pyromancer;
handleMove(x, y, obj);
- } else if (!flameSelected && !selectedFlame) {
- // Shoot fireball when tapping in upper half
+ } else if (!flameSelected && !selectedFlame && y < 2732 / 2) {
+ // Shoot fireball when tapping in upper half, and make it target that location
pyromancer.shoot();
+ // Set the target for the most recently shot fireball
+ if (fireballs.length > 0) {
+ var lastFireball = fireballs[fireballs.length - 1];
+ lastFireball.targetX = x;
+ lastFireball.targetY = y;
+ // Recalculate direction vector
+ var dirX = lastFireball.targetX - lastFireball.x;
+ var dirY = lastFireball.targetY - lastFireball.y;
+ var length = Math.sqrt(dirX * dirX + dirY * dirY);
+ // Normalize and set velocity
+ lastFireball.speedX = dirX / length * 15;
+ lastFireball.speedY = dirY / length * 15;
+ }
}
};
game.up = function (x, y, obj) {
dragTarget = null;