/****
* 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);
}
};