/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); // Create enemy graphic var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Enemy properties self.health = 100; self.speedX = 0; self.speedY = 0; self.attackRange = 300; self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; self.enemyType = 'normal'; // Enemy type: normal, fast, heavy self.maxSpeed = 2; // Default speed for normal enemies // Initialize enemy with properties self.init = function (health, speedX, speedY, type) { self.health = health || 100; self.speedX = speedX || 0; self.speedY = speedY || 0; // Set enemy type and properties self.enemyType = type || ['normal', 'fast', 'heavy'][Math.floor(Math.random() * 3)]; // Set properties based on type switch (self.enemyType) { case 'fast': self.maxSpeed = 1.8; // Slowed down from 3.5 self.health = health * 0.7 || 70; enemyGraphics.tint = 0xFF00FF; // Pink enemyGraphics.scale.set(0.8, 0.8); // Smaller break; case 'heavy': self.maxSpeed = 0.5; // Slowed down from 1.2 self.health = health * 1.8 || 180; enemyGraphics.tint = 0x880000; // Dark red enemyGraphics.scale.set(1.3, 1.3); // Larger break; default: // normal self.maxSpeed = 0.8; // Slowed down from 2 enemyGraphics.tint = 0xFF6347; // Default color break; } }; // Take damage from water self.takeDamage = function (amount) { self.health -= amount; // Visual feedback LK.effects.flashObject(self, 0xFF0000, 500); // Play sound LK.getSound('enemyHit').play(); // Check if enemy is defeated if (self.health <= 0) { return true; } return false; }; // Move toward target self.moveToward = function (targetX, targetY, speed) { // Calculate direction vector var dirX = targetX - self.x; var dirY = targetY - self.y; // Calculate distance var distance = Math.sqrt(dirX * dirX + dirY * dirY); // Only move if not too close if (distance > 10) { // Normalize direction vector dirX /= distance; dirY /= distance; // Adjust speed based on enemy type var actualSpeed = speed * self.maxSpeed; // Add some randomness to movement for normal and fast enemies if (self.enemyType !== 'heavy') { // Add slight oscillation or randomness to movement var time = LK.ticks / 30; var randomFactor = 0.2; if (self.enemyType === 'fast') { // Fast enemies zigzag more aggressively dirX += Math.sin(time) * randomFactor; dirY += Math.cos(time) * randomFactor; // Renormalize direction var newLen = Math.sqrt(dirX * dirX + dirY * dirY); dirX /= newLen; dirY /= newLen; } } // Set velocity self.speedX = dirX * actualSpeed; self.speedY = dirY * actualSpeed; } else { // Stop if close enough self.speedX = 0; self.speedY = 0; } }; // Update method called every tick self.update = function () { // Store last position self.lastX = self.x; self.lastY = self.y; // Move enemy self.x += self.speedX; self.y += self.speedY; // Keep enemy within game bounds if (self.x < 50) self.x = 50; if (self.x > 2048 - 50) self.x = 2048 - 50; if (self.y < 50) self.y = 50; if (self.y > 2732 - 50) self.y = 2732 - 50; // Find waterMaster and move toward it if not already moving if (waterMaster && self.speedX === 0 && self.speedY === 0) { // Move toward player automatically self.moveToward(waterMaster.x, waterMaster.y, 1); } }; return self; }); var WaterMaster = Container.expand(function () { var self = Container.call(this); // Create character graphic var characterGraphics = self.attachAsset('waterMaster', { anchorX: 0.5, anchorY: 0.5 }); // Water power properties self.waterReserve = 300; // Maximum water reserve (increased from 100) self.currentWater = 300; // Current water level (increased from 100) self.waterRegenRate = 0.5; // Water regeneration rate per tick (increased) self.shootCost = 15; // Cost of shooting water (adjusted for higher reserve) self.lastShootTime = 0; // Track last shoot time for cooldown self.shootCooldown = 15; // Cooldown between shots in ticks self.isCharging = false; // Track if charging a water shot self.chargeAmount = 0; // Current charge amount self.chargeMax = 60; // Maximum charge amount self.lastX = 0; self.lastY = 0; // Create water shield self.shield = self.addChild(LK.getAsset('waterShield', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })); // Event handlers for touch interactions self.down = function (x, y, obj) { self.isCharging = true; self.chargeAmount = 0; }; self.up = function (x, y, obj) { if (self.isCharging && self.currentWater >= self.shootCost) { // Calculate direction based on charge time var chargeRatio = Math.min(self.chargeAmount / self.chargeMax, 1); var power = 5 + 15 * chargeRatio * chargeRatio; // Exponential power increase based on charge // Create water projectile self.shootWater(power); // Reset charging self.isCharging = false; self.chargeAmount = 0; } }; // Shoot water in direction self.shootWater = function (power) { if (LK.ticks - self.lastShootTime < self.shootCooldown || self.currentWater < self.shootCost) { return; } // Create water projectile if (typeof game !== 'undefined' && game.createWaterProjectile) { // Determine direction vector from center to touch point var touchX = game.lastTouchX || self.x; var touchY = game.lastTouchY || self.y; // Calculate direction vector var dirX = touchX - self.x; var dirY = touchY - self.y; // Normalize direction vector var length = Math.sqrt(dirX * dirX + dirY * dirY); if (length > 0) { dirX /= length; dirY /= length; } else { dirX = 0; dirY = -1; // Default direction up } // Create projectile with increased power (2x) game.createWaterProjectile(self.x, self.y, dirX * power * 2, dirY * power * 2); // Reduce water reserve self.currentWater -= self.shootCost; // Play sound LK.getSound('waterShoot').play(); // Track last shoot time self.lastShootTime = LK.ticks; } }; // Activate shield self.activateShield = function () { if (self.currentWater >= 40) { self.shield.alpha = 0.7; self.currentWater -= 40; // Auto-disable shield after 3 seconds LK.setTimeout(function () { self.shield.alpha = 0; }, 3000); } }; // Refill water reserve self.refillWater = function (amount) { self.currentWater = Math.min(self.currentWater + amount, self.waterReserve); }; // Update method called every tick self.update = function () { // Store last position self.lastX = self.x; self.lastY = self.y; // Slowly regenerate water if (self.currentWater < self.waterReserve) { self.currentWater += self.waterRegenRate; if (self.currentWater > self.waterReserve) { self.currentWater = self.waterReserve; } } // Update charging if (self.isCharging) { self.chargeAmount++; if (self.chargeAmount > self.chargeMax) { self.chargeAmount = self.chargeMax; } } }; return self; }); var WaterProjectile = Container.expand(function () { var self = Container.call(this); // Create projectile graphic var projectileGraphics = self.attachAsset('waterProjectile', { anchorX: 0.5, anchorY: 0.5 }); // Projectile properties self.speedX = 0; self.speedY = 0; self.power = 1; self.lifespan = 240; // Extended projectile lifespan in ticks self.age = 0; self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; // Initialize projectile with direction and speed self.init = function (speedX, speedY, power) { self.speedX = speedX; self.speedY = speedY; self.power = power || 1; // Scale based on power var scale = 0.5 + self.power * 0.1; projectileGraphics.scale.set(scale, scale); }; // Update method called every tick self.update = function () { // Store last position self.lastX = self.x; self.lastY = self.y; // Move projectile self.x += self.speedX; self.y += self.speedY; // Age the projectile self.age++; // Make projectile gradually fade out if (self.age > self.lifespan * 0.7) { var fadeRatio = 1 - (self.age - self.lifespan * 0.7) / (self.lifespan * 0.3); self.alpha = Math.max(fadeRatio, 0); } }; return self; }); var WaterSource = Container.expand(function () { var self = Container.call(this); // Create water source graphic var sourceGraphics = self.attachAsset('waterSource', { anchorX: 0.5, anchorY: 0.5 }); // Water source properties self.refillAmount = 150; self.refillCooldown = 180; // 3 seconds at 60 FPS self.lastRefillTime = 0; self.lastWasIntersecting = false; // Pulsating animation function startPulsating() { tween(sourceGraphics.scale, { x: 1.1, y: 1.1 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(sourceGraphics.scale, { x: 0.9, y: 0.9 }, { duration: 1000, easing: tween.easeInOut, onFinish: startPulsating }); } }); } // Start pulsating animation startPulsating(); // Provide water to player self.refillPlayerWater = function () { if (LK.ticks - self.lastRefillTime > self.refillCooldown) { self.lastRefillTime = LK.ticks; LK.getSound('waterRefill').play(); return self.refillAmount; } return 0; }; return self; }); /**** * Initialize Game ****/ // Set water-themed background color var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Import tween plugin for animations // Initialize assets for the water elementalist game // Set water-themed background color game.setBackgroundColor(0x1A75FF); // Game variables var waterMaster; var waterProjectiles = []; var enemies = []; var waterSources = []; var score = 0; var level = 1; var gameActive = true; // UI elements var waterBar; var scoreText; var levelText; // Initialize game UI function initializeUI() { // Create water bar background var waterBarBg = new Container(); var waterBarBgGraphic = waterBarBg.addChild(LK.getAsset('bullet', { anchorX: 0, anchorY: 0, width: 400, height: 40, tint: 0x555555 })); // Create water bar waterBar = new Container(); var waterBarGraphic = waterBar.addChild(LK.getAsset('bullet', { anchorX: 0, anchorY: 0, width: 396, height: 36, tint: 0x00BFFF })); // Position water bar waterBarBg.x = 20; waterBarBg.y = 20; waterBar.x = 22; waterBar.y = 22; // Add to GUI LK.gui.topLeft.addChild(waterBarBg); LK.gui.topLeft.addChild(waterBar); // Create score text scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); scoreText.x = -20; scoreText.y = 20; LK.gui.topRight.addChild(scoreText); // Create level text levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.y = 20; LK.gui.top.addChild(levelText); } // Initialize player character function initializePlayer() { waterMaster = game.addChild(new WaterMaster()); waterMaster.x = 2048 / 2; waterMaster.y = 2732 - 300; } // Initialize water sources function initializeWaterSources() { // Add water sources at different locations var positions = [{ x: 300, y: 500 }, { x: 1700, y: 500 }, { x: 1000, y: 1500 }]; for (var i = 0; i < positions.length; i++) { var waterSource = new WaterSource(); waterSource.x = positions[i].x; waterSource.y = positions[i].y; waterSource.lastWasIntersecting = false; waterSources.push(waterSource); game.addChild(waterSource); } } // Create a water projectile game.createWaterProjectile = function (x, y, speedX, speedY) { var projectile = new WaterProjectile(); projectile.x = x; projectile.y = y; projectile.lastX = x; projectile.lastY = y; projectile.init(speedX, speedY, 1.5 + level * 0.4); projectile.lastWasIntersecting = false; waterProjectiles.push(projectile); game.addChild(projectile); }; // Spawn enemies function spawnEnemies() { // Determine number of enemies based on level var enemyCount = Math.min(2 + level, 8); // Clear any existing enemies for (var i = 0; i < enemies.length; i++) { if (enemies[i].parent) { enemies[i].parent.removeChild(enemies[i]); } } enemies = []; // Create new enemies for (var i = 0; i < enemyCount; i++) { var enemy = new Enemy(); // Position enemy randomly but not too close to player do { enemy.x = Math.random() * 1848 + 100; enemy.y = Math.random() * 1500 + 100; } while (Math.sqrt(Math.pow(enemy.x - waterMaster.x, 2) + Math.pow(enemy.y - waterMaster.y, 2)) < 500); enemy.lastX = enemy.x; enemy.lastY = enemy.y; // Determine enemy type distribution based on level var normalProb = Math.max(0.8 - level * 0.1, 0.3); // Decrease normal enemies as level increases var fastProb = Math.min(0.1 + level * 0.05, 0.4); // Increase fast enemies as level increases var heavyProb = Math.min(0.1 + level * 0.05, 0.3); // Increase heavy enemies as level increases var rand = Math.random(); var enemyType; if (rand < normalProb) { enemyType = 'normal'; } else if (rand < normalProb + fastProb) { enemyType = 'fast'; } else { enemyType = 'heavy'; } enemy.init(80 + level * 20, 0, 0, enemyType); enemy.lastWasIntersecting = false; enemies.push(enemy); game.addChild(enemy); } } // Update score and level function updateScore(points) { score += points; scoreText.setText('Score: ' + score); // Check for level up if (score >= level * 100) { levelUp(); } } // Level up function levelUp() { level++; levelText.setText('Level: ' + level); // Flash screen to indicate level up LK.effects.flashScreen(0x00FFFF, 500); // Spawn new enemies for the level spawnEnemies(); } // Game initialization initializeUI(); initializePlayer(); initializeWaterSources(); spawnEnemies(); // Game touch handling game.lastTouchX = 0; game.lastTouchY = 0; // Dragging functionality var isDragging = false; // Touch down event game.down = function (x, y, obj) { // Store touch position game.lastTouchX = x; game.lastTouchY = y; // Check if touching water master if (waterMaster) { var touchPoint = { x: x, y: y }; var distance = Math.sqrt(Math.pow(touchPoint.x - waterMaster.x, 2) + Math.pow(touchPoint.y - waterMaster.y, 2)); if (distance < 100) { // Start dragging player isDragging = true; } else { // Start charging water shot waterMaster.down(x, y, obj); } } }; // Touch move event game.move = function (x, y, obj) { // Store touch position game.lastTouchX = x; game.lastTouchY = y; if (isDragging && waterMaster) { // Move water master with touch waterMaster.x = x; waterMaster.y = y; // Keep within game bounds if (waterMaster.x < 100) waterMaster.x = 100; if (waterMaster.x > 2048 - 100) waterMaster.x = 2048 - 100; if (waterMaster.y < 100) waterMaster.y = 100; if (waterMaster.y > 2732 - 100) waterMaster.y = 2732 - 100; } }; // Touch up event game.up = function (x, y, obj) { // If was charging water shot if (!isDragging && waterMaster) { waterMaster.up(x, y, obj); } // Stop dragging isDragging = false; }; // Double tap to activate shield var lastTapTime = 0; var originalDown = game.down; // Store the original down handler game.down = function (x, y, obj) { var currentTime = Date.now(); // Check for double tap (within 300ms) if (currentTime - lastTapTime < 300) { if (waterMaster) { waterMaster.activateShield(); } } lastTapTime = currentTime; // Call the original down handler instead of recursively calling itself if (originalDown) { // Store touch position and handle dragging game.lastTouchX = x; game.lastTouchY = y; // Check if touching water master if (waterMaster) { var touchPoint = { x: x, y: y }; var distance = Math.sqrt(Math.pow(touchPoint.x - waterMaster.x, 2) + Math.pow(touchPoint.y - waterMaster.y, 2)); if (distance < 100) { // Start dragging player isDragging = true; } else { // Start charging water shot waterMaster.down(x, y, obj); } } } }; // Timer for spawning additional enemies var lastEnemySpawnTime = 0; var enemySpawnInterval = 600; // 10 seconds at 60 FPS // Game update loop game.update = function () { if (!gameActive) return; // Spawn additional enemies every 10 seconds if (LK.ticks - lastEnemySpawnTime > enemySpawnInterval && enemies.length < 10 + level) { lastEnemySpawnTime = LK.ticks; // Create a new enemy var enemy = new Enemy(); // Position enemy randomly on the edges of the screen var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left switch (side) { case 0: // Top enemy.x = Math.random() * 1848 + 100; enemy.y = -50; break; case 1: // Right enemy.x = 2048 + 50; enemy.y = Math.random() * 2532 + 100; break; case 2: // Bottom enemy.x = Math.random() * 1848 + 100; enemy.y = 2732 + 50; break; case 3: // Left enemy.x = -50; enemy.y = Math.random() * 2532 + 100; break; } enemy.lastX = enemy.x; enemy.lastY = enemy.y; enemy.init(80 + level * 20, 0, 0); enemy.lastWasIntersecting = false; enemies.push(enemy); game.addChild(enemy); } // Update water master if (waterMaster) { waterMaster.update(); // Update water bar UI if (waterBar) { var waterRatio = waterMaster.currentWater / waterMaster.waterReserve; waterBar.children[0].width = 396 * waterRatio; } // Check water master collisions with water sources for (var i = 0; i < waterSources.length; i++) { var source = waterSources[i]; var isIntersecting = waterMaster.intersects(source); // Refill water if touching a water source for the first time if (!source.lastWasIntersecting && isIntersecting) { var refillAmount = source.refillPlayerWater(); if (refillAmount > 0) { waterMaster.refillWater(refillAmount); // Visual feedback LK.effects.flashObject(source, 0x00FFFF, 500); } } source.lastWasIntersecting = isIntersecting; } } // Update water projectiles for (var i = waterProjectiles.length - 1; i >= 0; i--) { var projectile = waterProjectiles[i]; projectile.update(); // Check if projectile is out of bounds or expired if (projectile.x < -100 || projectile.x > 2148 || projectile.y < -100 || projectile.y > 2832 || projectile.age > projectile.lifespan) { if (projectile.parent) { projectile.parent.removeChild(projectile); } waterProjectiles.splice(i, 1); continue; } // Check collisions with enemies for (var j = 0; j < enemies.length; j++) { var enemy = enemies[j]; var isIntersecting = projectile.intersects(enemy); // Handle collision if not already intersecting if (!projectile.lastWasIntersecting && isIntersecting) { // Enemy takes damage based on projectile power var isDefeated = enemy.takeDamage(20 * projectile.power); // Remove projectile if (projectile.parent) { projectile.parent.removeChild(projectile); } waterProjectiles.splice(i, 1); // Play hit sound LK.getSound('waterHit').play(); // If enemy was defeated if (isDefeated) { if (enemy.parent) { enemy.parent.removeChild(enemy); } enemies.splice(j, 1); updateScore(10); } break; } if (projectile.lastWasIntersecting !== undefined) { projectile.lastWasIntersecting = isIntersecting; } } } // Update enemies for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; // Move toward player if in range var distanceToPlayer = Math.sqrt(Math.pow(enemy.x - waterMaster.x, 2) + Math.pow(enemy.y - waterMaster.y, 2)); if (distanceToPlayer < 800) { enemy.moveToward(waterMaster.x, waterMaster.y, 1 + level * 0.2); } enemy.update(); // Check collision with player var isIntersecting = enemy.intersects(waterMaster); // Handle collision if not already intersecting and shield is not active if (!enemy.lastWasIntersecting && isIntersecting && waterMaster.shield.alpha < 0.1) { // Game over if no shield LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); gameActive = false; } else if (!enemy.lastWasIntersecting && isIntersecting && waterMaster.shield.alpha >= 0.1) { // Push enemy away if shield is active var dirX = enemy.x - waterMaster.x; var dirY = enemy.y - waterMaster.y; var length = Math.sqrt(dirX * dirX + dirY * dirY); if (length > 0) { dirX /= length; dirY /= length; } enemy.x += dirX * 200; enemy.y += dirY * 200; enemy.takeDamage(10); } enemy.lastWasIntersecting = isIntersecting; } // Check if all enemies are defeated if (enemies.length === 0) { // Spawn more enemies spawnEnemies(); updateScore(level * 20); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Create enemy graphic
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Enemy properties
self.health = 100;
self.speedX = 0;
self.speedY = 0;
self.attackRange = 300;
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.enemyType = 'normal'; // Enemy type: normal, fast, heavy
self.maxSpeed = 2; // Default speed for normal enemies
// Initialize enemy with properties
self.init = function (health, speedX, speedY, type) {
self.health = health || 100;
self.speedX = speedX || 0;
self.speedY = speedY || 0;
// Set enemy type and properties
self.enemyType = type || ['normal', 'fast', 'heavy'][Math.floor(Math.random() * 3)];
// Set properties based on type
switch (self.enemyType) {
case 'fast':
self.maxSpeed = 1.8; // Slowed down from 3.5
self.health = health * 0.7 || 70;
enemyGraphics.tint = 0xFF00FF; // Pink
enemyGraphics.scale.set(0.8, 0.8); // Smaller
break;
case 'heavy':
self.maxSpeed = 0.5; // Slowed down from 1.2
self.health = health * 1.8 || 180;
enemyGraphics.tint = 0x880000; // Dark red
enemyGraphics.scale.set(1.3, 1.3); // Larger
break;
default:
// normal
self.maxSpeed = 0.8; // Slowed down from 2
enemyGraphics.tint = 0xFF6347; // Default color
break;
}
};
// Take damage from water
self.takeDamage = function (amount) {
self.health -= amount;
// Visual feedback
LK.effects.flashObject(self, 0xFF0000, 500);
// Play sound
LK.getSound('enemyHit').play();
// Check if enemy is defeated
if (self.health <= 0) {
return true;
}
return false;
};
// Move toward target
self.moveToward = function (targetX, targetY, speed) {
// Calculate direction vector
var dirX = targetX - self.x;
var dirY = targetY - self.y;
// Calculate distance
var distance = Math.sqrt(dirX * dirX + dirY * dirY);
// Only move if not too close
if (distance > 10) {
// Normalize direction vector
dirX /= distance;
dirY /= distance;
// Adjust speed based on enemy type
var actualSpeed = speed * self.maxSpeed;
// Add some randomness to movement for normal and fast enemies
if (self.enemyType !== 'heavy') {
// Add slight oscillation or randomness to movement
var time = LK.ticks / 30;
var randomFactor = 0.2;
if (self.enemyType === 'fast') {
// Fast enemies zigzag more aggressively
dirX += Math.sin(time) * randomFactor;
dirY += Math.cos(time) * randomFactor;
// Renormalize direction
var newLen = Math.sqrt(dirX * dirX + dirY * dirY);
dirX /= newLen;
dirY /= newLen;
}
}
// Set velocity
self.speedX = dirX * actualSpeed;
self.speedY = dirY * actualSpeed;
} else {
// Stop if close enough
self.speedX = 0;
self.speedY = 0;
}
};
// Update method called every tick
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move enemy
self.x += self.speedX;
self.y += self.speedY;
// Keep enemy within game bounds
if (self.x < 50) self.x = 50;
if (self.x > 2048 - 50) self.x = 2048 - 50;
if (self.y < 50) self.y = 50;
if (self.y > 2732 - 50) self.y = 2732 - 50;
// Find waterMaster and move toward it if not already moving
if (waterMaster && self.speedX === 0 && self.speedY === 0) {
// Move toward player automatically
self.moveToward(waterMaster.x, waterMaster.y, 1);
}
};
return self;
});
var WaterMaster = Container.expand(function () {
var self = Container.call(this);
// Create character graphic
var characterGraphics = self.attachAsset('waterMaster', {
anchorX: 0.5,
anchorY: 0.5
});
// Water power properties
self.waterReserve = 300; // Maximum water reserve (increased from 100)
self.currentWater = 300; // Current water level (increased from 100)
self.waterRegenRate = 0.5; // Water regeneration rate per tick (increased)
self.shootCost = 15; // Cost of shooting water (adjusted for higher reserve)
self.lastShootTime = 0; // Track last shoot time for cooldown
self.shootCooldown = 15; // Cooldown between shots in ticks
self.isCharging = false; // Track if charging a water shot
self.chargeAmount = 0; // Current charge amount
self.chargeMax = 60; // Maximum charge amount
self.lastX = 0;
self.lastY = 0;
// Create water shield
self.shield = self.addChild(LK.getAsset('waterShield', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
}));
// Event handlers for touch interactions
self.down = function (x, y, obj) {
self.isCharging = true;
self.chargeAmount = 0;
};
self.up = function (x, y, obj) {
if (self.isCharging && self.currentWater >= self.shootCost) {
// Calculate direction based on charge time
var chargeRatio = Math.min(self.chargeAmount / self.chargeMax, 1);
var power = 5 + 15 * chargeRatio * chargeRatio; // Exponential power increase based on charge
// Create water projectile
self.shootWater(power);
// Reset charging
self.isCharging = false;
self.chargeAmount = 0;
}
};
// Shoot water in direction
self.shootWater = function (power) {
if (LK.ticks - self.lastShootTime < self.shootCooldown || self.currentWater < self.shootCost) {
return;
}
// Create water projectile
if (typeof game !== 'undefined' && game.createWaterProjectile) {
// Determine direction vector from center to touch point
var touchX = game.lastTouchX || self.x;
var touchY = game.lastTouchY || self.y;
// Calculate direction vector
var dirX = touchX - self.x;
var dirY = touchY - self.y;
// Normalize direction vector
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > 0) {
dirX /= length;
dirY /= length;
} else {
dirX = 0;
dirY = -1; // Default direction up
}
// Create projectile with increased power (2x)
game.createWaterProjectile(self.x, self.y, dirX * power * 2, dirY * power * 2);
// Reduce water reserve
self.currentWater -= self.shootCost;
// Play sound
LK.getSound('waterShoot').play();
// Track last shoot time
self.lastShootTime = LK.ticks;
}
};
// Activate shield
self.activateShield = function () {
if (self.currentWater >= 40) {
self.shield.alpha = 0.7;
self.currentWater -= 40;
// Auto-disable shield after 3 seconds
LK.setTimeout(function () {
self.shield.alpha = 0;
}, 3000);
}
};
// Refill water reserve
self.refillWater = function (amount) {
self.currentWater = Math.min(self.currentWater + amount, self.waterReserve);
};
// Update method called every tick
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Slowly regenerate water
if (self.currentWater < self.waterReserve) {
self.currentWater += self.waterRegenRate;
if (self.currentWater > self.waterReserve) {
self.currentWater = self.waterReserve;
}
}
// Update charging
if (self.isCharging) {
self.chargeAmount++;
if (self.chargeAmount > self.chargeMax) {
self.chargeAmount = self.chargeMax;
}
}
};
return self;
});
var WaterProjectile = Container.expand(function () {
var self = Container.call(this);
// Create projectile graphic
var projectileGraphics = self.attachAsset('waterProjectile', {
anchorX: 0.5,
anchorY: 0.5
});
// Projectile properties
self.speedX = 0;
self.speedY = 0;
self.power = 1;
self.lifespan = 240; // Extended projectile lifespan in ticks
self.age = 0;
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
// Initialize projectile with direction and speed
self.init = function (speedX, speedY, power) {
self.speedX = speedX;
self.speedY = speedY;
self.power = power || 1;
// Scale based on power
var scale = 0.5 + self.power * 0.1;
projectileGraphics.scale.set(scale, scale);
};
// Update method called every tick
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move projectile
self.x += self.speedX;
self.y += self.speedY;
// Age the projectile
self.age++;
// Make projectile gradually fade out
if (self.age > self.lifespan * 0.7) {
var fadeRatio = 1 - (self.age - self.lifespan * 0.7) / (self.lifespan * 0.3);
self.alpha = Math.max(fadeRatio, 0);
}
};
return self;
});
var WaterSource = Container.expand(function () {
var self = Container.call(this);
// Create water source graphic
var sourceGraphics = self.attachAsset('waterSource', {
anchorX: 0.5,
anchorY: 0.5
});
// Water source properties
self.refillAmount = 150;
self.refillCooldown = 180; // 3 seconds at 60 FPS
self.lastRefillTime = 0;
self.lastWasIntersecting = false;
// Pulsating animation
function startPulsating() {
tween(sourceGraphics.scale, {
x: 1.1,
y: 1.1
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sourceGraphics.scale, {
x: 0.9,
y: 0.9
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: startPulsating
});
}
});
}
// Start pulsating animation
startPulsating();
// Provide water to player
self.refillPlayerWater = function () {
if (LK.ticks - self.lastRefillTime > self.refillCooldown) {
self.lastRefillTime = LK.ticks;
LK.getSound('waterRefill').play();
return self.refillAmount;
}
return 0;
};
return self;
});
/****
* Initialize Game
****/
// Set water-themed background color
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Import tween plugin for animations
// Initialize assets for the water elementalist game
// Set water-themed background color
game.setBackgroundColor(0x1A75FF);
// Game variables
var waterMaster;
var waterProjectiles = [];
var enemies = [];
var waterSources = [];
var score = 0;
var level = 1;
var gameActive = true;
// UI elements
var waterBar;
var scoreText;
var levelText;
// Initialize game UI
function initializeUI() {
// Create water bar background
var waterBarBg = new Container();
var waterBarBgGraphic = waterBarBg.addChild(LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
width: 400,
height: 40,
tint: 0x555555
}));
// Create water bar
waterBar = new Container();
var waterBarGraphic = waterBar.addChild(LK.getAsset('bullet', {
anchorX: 0,
anchorY: 0,
width: 396,
height: 36,
tint: 0x00BFFF
}));
// Position water bar
waterBarBg.x = 20;
waterBarBg.y = 20;
waterBar.x = 22;
waterBar.y = 22;
// Add to GUI
LK.gui.topLeft.addChild(waterBarBg);
LK.gui.topLeft.addChild(waterBar);
// Create score text
scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
scoreText.y = 20;
LK.gui.topRight.addChild(scoreText);
// Create level text
levelText = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.y = 20;
LK.gui.top.addChild(levelText);
}
// Initialize player character
function initializePlayer() {
waterMaster = game.addChild(new WaterMaster());
waterMaster.x = 2048 / 2;
waterMaster.y = 2732 - 300;
}
// Initialize water sources
function initializeWaterSources() {
// Add water sources at different locations
var positions = [{
x: 300,
y: 500
}, {
x: 1700,
y: 500
}, {
x: 1000,
y: 1500
}];
for (var i = 0; i < positions.length; i++) {
var waterSource = new WaterSource();
waterSource.x = positions[i].x;
waterSource.y = positions[i].y;
waterSource.lastWasIntersecting = false;
waterSources.push(waterSource);
game.addChild(waterSource);
}
}
// Create a water projectile
game.createWaterProjectile = function (x, y, speedX, speedY) {
var projectile = new WaterProjectile();
projectile.x = x;
projectile.y = y;
projectile.lastX = x;
projectile.lastY = y;
projectile.init(speedX, speedY, 1.5 + level * 0.4);
projectile.lastWasIntersecting = false;
waterProjectiles.push(projectile);
game.addChild(projectile);
};
// Spawn enemies
function spawnEnemies() {
// Determine number of enemies based on level
var enemyCount = Math.min(2 + level, 8);
// Clear any existing enemies
for (var i = 0; i < enemies.length; i++) {
if (enemies[i].parent) {
enemies[i].parent.removeChild(enemies[i]);
}
}
enemies = [];
// Create new enemies
for (var i = 0; i < enemyCount; i++) {
var enemy = new Enemy();
// Position enemy randomly but not too close to player
do {
enemy.x = Math.random() * 1848 + 100;
enemy.y = Math.random() * 1500 + 100;
} while (Math.sqrt(Math.pow(enemy.x - waterMaster.x, 2) + Math.pow(enemy.y - waterMaster.y, 2)) < 500);
enemy.lastX = enemy.x;
enemy.lastY = enemy.y;
// Determine enemy type distribution based on level
var normalProb = Math.max(0.8 - level * 0.1, 0.3); // Decrease normal enemies as level increases
var fastProb = Math.min(0.1 + level * 0.05, 0.4); // Increase fast enemies as level increases
var heavyProb = Math.min(0.1 + level * 0.05, 0.3); // Increase heavy enemies as level increases
var rand = Math.random();
var enemyType;
if (rand < normalProb) {
enemyType = 'normal';
} else if (rand < normalProb + fastProb) {
enemyType = 'fast';
} else {
enemyType = 'heavy';
}
enemy.init(80 + level * 20, 0, 0, enemyType);
enemy.lastWasIntersecting = false;
enemies.push(enemy);
game.addChild(enemy);
}
}
// Update score and level
function updateScore(points) {
score += points;
scoreText.setText('Score: ' + score);
// Check for level up
if (score >= level * 100) {
levelUp();
}
}
// Level up
function levelUp() {
level++;
levelText.setText('Level: ' + level);
// Flash screen to indicate level up
LK.effects.flashScreen(0x00FFFF, 500);
// Spawn new enemies for the level
spawnEnemies();
}
// Game initialization
initializeUI();
initializePlayer();
initializeWaterSources();
spawnEnemies();
// Game touch handling
game.lastTouchX = 0;
game.lastTouchY = 0;
// Dragging functionality
var isDragging = false;
// Touch down event
game.down = function (x, y, obj) {
// Store touch position
game.lastTouchX = x;
game.lastTouchY = y;
// Check if touching water master
if (waterMaster) {
var touchPoint = {
x: x,
y: y
};
var distance = Math.sqrt(Math.pow(touchPoint.x - waterMaster.x, 2) + Math.pow(touchPoint.y - waterMaster.y, 2));
if (distance < 100) {
// Start dragging player
isDragging = true;
} else {
// Start charging water shot
waterMaster.down(x, y, obj);
}
}
};
// Touch move event
game.move = function (x, y, obj) {
// Store touch position
game.lastTouchX = x;
game.lastTouchY = y;
if (isDragging && waterMaster) {
// Move water master with touch
waterMaster.x = x;
waterMaster.y = y;
// Keep within game bounds
if (waterMaster.x < 100) waterMaster.x = 100;
if (waterMaster.x > 2048 - 100) waterMaster.x = 2048 - 100;
if (waterMaster.y < 100) waterMaster.y = 100;
if (waterMaster.y > 2732 - 100) waterMaster.y = 2732 - 100;
}
};
// Touch up event
game.up = function (x, y, obj) {
// If was charging water shot
if (!isDragging && waterMaster) {
waterMaster.up(x, y, obj);
}
// Stop dragging
isDragging = false;
};
// Double tap to activate shield
var lastTapTime = 0;
var originalDown = game.down; // Store the original down handler
game.down = function (x, y, obj) {
var currentTime = Date.now();
// Check for double tap (within 300ms)
if (currentTime - lastTapTime < 300) {
if (waterMaster) {
waterMaster.activateShield();
}
}
lastTapTime = currentTime;
// Call the original down handler instead of recursively calling itself
if (originalDown) {
// Store touch position and handle dragging
game.lastTouchX = x;
game.lastTouchY = y;
// Check if touching water master
if (waterMaster) {
var touchPoint = {
x: x,
y: y
};
var distance = Math.sqrt(Math.pow(touchPoint.x - waterMaster.x, 2) + Math.pow(touchPoint.y - waterMaster.y, 2));
if (distance < 100) {
// Start dragging player
isDragging = true;
} else {
// Start charging water shot
waterMaster.down(x, y, obj);
}
}
}
};
// Timer for spawning additional enemies
var lastEnemySpawnTime = 0;
var enemySpawnInterval = 600; // 10 seconds at 60 FPS
// Game update loop
game.update = function () {
if (!gameActive) return;
// Spawn additional enemies every 10 seconds
if (LK.ticks - lastEnemySpawnTime > enemySpawnInterval && enemies.length < 10 + level) {
lastEnemySpawnTime = LK.ticks;
// Create a new enemy
var enemy = new Enemy();
// Position enemy randomly on the edges of the screen
var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 1848 + 100;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2048 + 50;
enemy.y = Math.random() * 2532 + 100;
break;
case 2:
// Bottom
enemy.x = Math.random() * 1848 + 100;
enemy.y = 2732 + 50;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 2532 + 100;
break;
}
enemy.lastX = enemy.x;
enemy.lastY = enemy.y;
enemy.init(80 + level * 20, 0, 0);
enemy.lastWasIntersecting = false;
enemies.push(enemy);
game.addChild(enemy);
}
// Update water master
if (waterMaster) {
waterMaster.update();
// Update water bar UI
if (waterBar) {
var waterRatio = waterMaster.currentWater / waterMaster.waterReserve;
waterBar.children[0].width = 396 * waterRatio;
}
// Check water master collisions with water sources
for (var i = 0; i < waterSources.length; i++) {
var source = waterSources[i];
var isIntersecting = waterMaster.intersects(source);
// Refill water if touching a water source for the first time
if (!source.lastWasIntersecting && isIntersecting) {
var refillAmount = source.refillPlayerWater();
if (refillAmount > 0) {
waterMaster.refillWater(refillAmount);
// Visual feedback
LK.effects.flashObject(source, 0x00FFFF, 500);
}
}
source.lastWasIntersecting = isIntersecting;
}
}
// Update water projectiles
for (var i = waterProjectiles.length - 1; i >= 0; i--) {
var projectile = waterProjectiles[i];
projectile.update();
// Check if projectile is out of bounds or expired
if (projectile.x < -100 || projectile.x > 2148 || projectile.y < -100 || projectile.y > 2832 || projectile.age > projectile.lifespan) {
if (projectile.parent) {
projectile.parent.removeChild(projectile);
}
waterProjectiles.splice(i, 1);
continue;
}
// Check collisions with enemies
for (var j = 0; j < enemies.length; j++) {
var enemy = enemies[j];
var isIntersecting = projectile.intersects(enemy);
// Handle collision if not already intersecting
if (!projectile.lastWasIntersecting && isIntersecting) {
// Enemy takes damage based on projectile power
var isDefeated = enemy.takeDamage(20 * projectile.power);
// Remove projectile
if (projectile.parent) {
projectile.parent.removeChild(projectile);
}
waterProjectiles.splice(i, 1);
// Play hit sound
LK.getSound('waterHit').play();
// If enemy was defeated
if (isDefeated) {
if (enemy.parent) {
enemy.parent.removeChild(enemy);
}
enemies.splice(j, 1);
updateScore(10);
}
break;
}
if (projectile.lastWasIntersecting !== undefined) {
projectile.lastWasIntersecting = isIntersecting;
}
}
}
// Update enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
// Move toward player if in range
var distanceToPlayer = Math.sqrt(Math.pow(enemy.x - waterMaster.x, 2) + Math.pow(enemy.y - waterMaster.y, 2));
if (distanceToPlayer < 800) {
enemy.moveToward(waterMaster.x, waterMaster.y, 1 + level * 0.2);
}
enemy.update();
// Check collision with player
var isIntersecting = enemy.intersects(waterMaster);
// Handle collision if not already intersecting and shield is not active
if (!enemy.lastWasIntersecting && isIntersecting && waterMaster.shield.alpha < 0.1) {
// Game over if no shield
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
gameActive = false;
} else if (!enemy.lastWasIntersecting && isIntersecting && waterMaster.shield.alpha >= 0.1) {
// Push enemy away if shield is active
var dirX = enemy.x - waterMaster.x;
var dirY = enemy.y - waterMaster.y;
var length = Math.sqrt(dirX * dirX + dirY * dirY);
if (length > 0) {
dirX /= length;
dirY /= length;
}
enemy.x += dirX * 200;
enemy.y += dirY * 200;
enemy.takeDamage(10);
}
enemy.lastWasIntersecting = isIntersecting;
}
// Check if all enemies are defeated
if (enemies.length === 0) {
// Spawn more enemies
spawnEnemies();
updateScore(level * 20);
}
};