User prompt
Only one person
User prompt
Only one person that controls wind
User prompt
Only one person in the game
User prompt
If they get to the middle you lose
User prompt
If they get to the circle in the middle, you lose
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(210); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(211); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 315 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
May only be one person that controls the wind
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(210); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(211); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 315
User prompt
Make the enemies attack you and not go to the circle in the middle
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(206); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(207); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 309
User prompt
Make the enemy attack you
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(206); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(207); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 309 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make their only be one person that controls wind
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(206); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(207); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 309 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
May there be only one person that controls wind
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(206); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(207); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 308
User prompt
The enemies attackers and make only one person that controls the wind
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500, onComplete: function onFinish() { __$(203); tween.to(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000, onComplete: function onFinish() { __$(204); levelNotification.destroy(); } }); } })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 303
User prompt
Make there be only one person that controls wind and make the enemies attack us
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500 })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 303 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make therapy be only one person that controls the wind and more enemies and less leaves
User prompt
Please fix the bug: 'undefined is not an object (evaluating 'tween(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500 }).then')' in or related to this line: 'tween(levelNotification, {' Line Number: 303
User prompt
Please fix the bug: 'tween.to is not a function. (In 'tween.to(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500 })', 'tween.to' is undefined)' in or related to this line: 'tween.to(levelNotification, {' Line Number: 303
User prompt
Please fix the bug: 'undefined is not an object (evaluating 'tween(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500 }).then')' in or related to this line: 'tween(levelNotification, {' Line Number: 303
User prompt
Make five enemies and make levels and make wind when hating enemies
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AirParticle = Container.expand(function () { var self = Container.call(this); var particleGraphic = self.attachAsset('airParticle', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.vx = 0; self.vy = 0; self.lifespan = 100; self.lastX = 0; self.lastY = 0; self.init = function (x, y, vx, vy, lifespan) { self.x = x; self.y = y; self.lastX = x; self.lastY = y; self.vx = vx; self.vy = vy; self.lifespan = lifespan || 100; self.alpha = 1; self.scale.set(Math.random() * 0.5 + 0.5); }; self.update = function () { self.lastX = self.x; self.lastY = self.y; self.x += self.vx; self.y += self.vy; self.lifespan--; self.alpha = self.lifespan / 100; if (self.lifespan <= 0) { return false; // Signal to remove the particle } return true; }; return self; }); var AirShrine = Container.expand(function () { var self = Container.call(this); var shrineGraphic = self.attachAsset('airShrine', { anchorX: 0.5, anchorY: 0.5 }); var targetArea = self.attachAsset('targetArea', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); self.health = 100; self.lastHealth = 100; self.pulseDirection = 1; self.pulseValue = 0; self.update = function () { self.lastHealth = self.health; // Visual pulse effect self.pulseValue += 0.02 * self.pulseDirection; if (self.pulseValue >= 1) { self.pulseValue = 1; self.pulseDirection = -1; } else if (self.pulseValue <= 0) { self.pulseValue = 0; self.pulseDirection = 1; } targetArea.alpha = 0.15 + self.pulseValue * 0.15; shrineGraphic.alpha = 0.8 + self.pulseValue * 0.2; }; self.damage = function (amount) { self.health -= amount; if (self.health < 0) self.health = 0; // Visual feedback LK.effects.flashObject(shrineGraphic, 0xff0000, 300); }; self.heal = function (amount) { self.health += amount; if (self.health > 100) self.health = 100; // Visual feedback LK.effects.flashObject(shrineGraphic, 0x00ff00, 300); }; return self; }); var Cloud = Container.expand(function () { var self = Container.call(this); var cloudGraphic = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5, alpha: 0.85 }); self.vx = 0; self.vy = 0; self.friction = 0.99; self.mass = 5 + Math.random() * 3; self.type = "normal"; // normal or threat self.lastX = 0; self.lastY = 0; self.lastIntersecting = false; self.init = function (x, y, type) { self.x = x; self.y = y; self.lastX = x; self.lastY = y; self.type = type || "normal"; if (self.type === "threat") { cloudGraphic.tint = 0x555555; } }; self.update = function () { self.lastX = self.x; self.lastY = self.y; self.lastIntersecting = false; self.x += self.vx; self.y += self.vy; // Apply friction self.vx *= self.friction; self.vy *= self.friction; // Boundary checks with bounce if (self.x < 100) { self.x = 100; self.vx = Math.abs(self.vx) * 0.3; } else if (self.x > 1948) { self.x = 1948; self.vx = -Math.abs(self.vx) * 0.3; } if (self.y < 100) { self.y = 100; self.vy = Math.abs(self.vy) * 0.3; } else if (self.y > 2632) { self.y = 2632; self.vy = -Math.abs(self.vy) * 0.3; } }; // Apply wind force from swipe self.applyWind = function (dirX, dirY, strength) { self.vx += dirX * strength / self.mass; self.vy += dirY * strength / self.mass; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphic = self.attachAsset('airParticle', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, tint: 0xff3030 }); self.speed = 1 + Math.random(); self.health = 3; self.lastX = 0; self.lastY = 0; self.lastIntersecting = false; self.init = function (x, y, health, speed) { self.x = x; self.y = y; self.lastX = x; self.lastY = y; self.alpha = 1; if (health) self.health = health; if (speed) self.speed = speed; }; self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move towards shrine if (airShrine) { var dx = airShrine.x - self.x; var dy = airShrine.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } // Pulse effect self.scale.x = 1.8 + Math.sin(LK.ticks * 0.1) * 0.2; self.scale.y = 1.8 + Math.sin(LK.ticks * 0.1) * 0.2; return true; }; self.damage = function () { self.health--; LK.effects.flashObject(self, 0xffffff, 200); return self.health <= 0; }; return self; }); var Leaf = Container.expand(function () { var self = Container.call(this); var leafGraphic = self.attachAsset('leaf', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.rotation = Math.random() * Math.PI * 2; self.rotationSpeed = (Math.random() - 0.5) * 0.1; self.friction = 0.97; self.mass = 1 + Math.random(); self.lastX = 0; self.lastY = 0; self.lastIntersecting = false; self.update = function () { self.lastX = self.x; self.lastY = self.y; self.x += self.vx; self.y += self.vy; // Apply friction self.vx *= self.friction; self.vy *= self.friction; // Rotate the leaf self.rotation += self.rotationSpeed; // Boundary checks if (self.x < 0) { self.x = 0; self.vx = Math.abs(self.vx) * 0.5; } else if (self.x > 2048) { self.x = 2048; self.vx = -Math.abs(self.vx) * 0.5; } if (self.y < 0) { self.y = 0; self.vy = Math.abs(self.vy) * 0.5; } else if (self.y > 2732) { self.y = 2732; self.vy = -Math.abs(self.vy) * 0.5; } }; // Apply wind force from swipe self.applyWind = function (dirX, dirY, strength) { self.vx += dirX * strength / self.mass; self.vy += dirY * strength / self.mass; }; return self; }); var Level = Container.expand(function () { var self = Container.call(this); self.currentLevel = 1; self.enemyCount = 5; self.threatChance = 0.2; self.cloudInterval = 300; self.leafInterval = 180; self.enemyInterval = 500; self.enemyHealth = 3; self.enemySpeed = 1; self.startLevel = function (level) { self.currentLevel = level; self.enemyCount = 5 * level; self.threatChance = Math.min(0.5, 0.2 + level * 0.05); self.cloudInterval = Math.max(100, 300 - level * 20); self.leafInterval = Math.max(100, 180 - level * 5); self.enemyInterval = Math.max(200, 500 - level * 30); self.enemyHealth = 3 + Math.floor(level / 2); self.enemySpeed = 1 + level * 0.2; // Create level notification self.showLevelNotification(); return self; }; self.showLevelNotification = function () { var levelNotification = new Text2('Level ' + self.currentLevel, { size: 150, fill: 0xFFFFFF }); levelNotification.anchor.set(0.5, 0.5); levelNotification.x = GAME_WIDTH / 2; levelNotification.y = GAME_HEIGHT / 2; levelNotification.alpha = 0; game.addChild(levelNotification); // Animate level notification tween(levelNotification, { alpha: 1, y: GAME_HEIGHT / 2 - 100 }, { duration: 500 }).then(function () { return tween(levelNotification, { alpha: 0, y: GAME_HEIGHT / 2 - 200 }, { duration: 500, delay: 1000 }); }).then(function () { levelNotification.destroy(); }); }; return self; }); var PlayerHand = Container.expand(function () { var self = Container.call(this); var handGraphic = self.attachAsset('playerHand', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.active = false; self.trailPoints = []; self.maxTrailPoints = 10; self.lastX = 0; self.lastY = 0; self.vx = 0; self.vy = 0; self.init = function (x, y) { self.x = x; self.y = y; self.lastX = x; self.lastY = y; self.active = true; self.trailPoints = []; self.scale.set(1); self.alpha = 0; // Fade in animation tween(self, { alpha: 1 }, { duration: 200 }); }; self.update = function () { if (!self.active) return; // Calculate velocity from position change self.vx = self.x - self.lastX; self.vy = self.y - self.lastY; // Store trail points for gesture recognition if (self.trailPoints.length >= self.maxTrailPoints) { self.trailPoints.shift(); } self.trailPoints.push({ x: self.x, y: self.y }); // Store last position self.lastX = self.x; self.lastY = self.y; }; self.deactivate = function () { self.active = false; // Fade out animation tween(self, { alpha: 0, scale: 0.5 }, { duration: 200 }); }; // Check if the hand movement forms a circular motion self.isCircularMotion = function () { if (self.trailPoints.length < 8) return false; // Calculate center of points var centerX = 0, centerY = 0; for (var i = 0; i < self.trailPoints.length; i++) { centerX += self.trailPoints[i].x; centerY += self.trailPoints[i].y; } centerX /= self.trailPoints.length; centerY /= self.trailPoints.length; // Calculate average radius and deviation var radius = 0; for (var i = 0; i < self.trailPoints.length; i++) { var dx = self.trailPoints[i].x - centerX; var dy = self.trailPoints[i].y - centerY; radius += Math.sqrt(dx * dx + dy * dy); } radius /= self.trailPoints.length; // Check if points form a circle var radiusDeviation = 0; for (var i = 0; i < self.trailPoints.length; i++) { var dx = self.trailPoints[i].x - centerX; var dy = self.trailPoints[i].y - centerY; var distance = Math.sqrt(dx * dx + dy * dy); radiusDeviation += Math.abs(distance - radius); } radiusDeviation /= self.trailPoints.length; // Check if deviation is low enough to consider it a circle return radiusDeviation < radius * 0.3 && radius > 50; }; // Get the center of the circular motion self.getCircleCenter = function () { var centerX = 0, centerY = 0; for (var i = 0; i < self.trailPoints.length; i++) { centerX += self.trailPoints[i].x; centerY += self.trailPoints[i].y; } return { x: centerX / self.trailPoints.length, y: centerY / self.trailPoints.length }; }; return self; }); // Game size constants var Tornado = Container.expand(function () { var self = Container.call(this); var tornadoGraphic = self.attachAsset('tornadoBase', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 }); self.strength = 0; self.maxStrength = 10; self.radius = 150; self.lifespan = 120; self.active = false; self.init = function (x, y) { self.x = x; self.y = y; self.strength = 1; self.lifespan = 120; self.active = true; self.scale.set(0.5); // Play tornado sound LK.getSound('tornado').play(); }; self.update = function () { if (!self.active) return false; self.lifespan--; if (self.strength < self.maxStrength) { self.strength += 0.2; } // Visual effects self.scale.set(0.5 + self.strength / self.maxStrength * 0.5); self.rotation += 0.05; if (self.lifespan <= 30) { self.alpha = self.lifespan / 30; } if (self.lifespan <= 0) { self.active = false; return false; } return true; }; // Apply tornado force to an object self.applyForce = function (object) { var dx = self.x - object.x; var dy = self.y - object.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.radius * self.scale.x) { // Calculate force direction (toward tornado center) var forceX = dx / distance; var forceY = dy / distance; // Apply force inversely proportional to distance var forceMagnitude = self.strength * (1 - distance / (self.radius * self.scale.x)); object.vx += forceX * forceMagnitude; object.vy += forceY * forceMagnitude; // Add some rotation effect object.rotationSpeed = (object.rotationSpeed || 0) + 0.05; return true; } return false; }; return self; }); var WindEffect = Container.expand(function () { var self = Container.call(this); var windGraphic = self.attachAsset('whirlwind', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 }); self.directionX = 0; self.directionY = 0; self.strength = 0; self.lifespan = 30; self.active = false; self.init = function (x, y, dirX, dirY, strength) { self.x = x; self.y = y; self.directionX = dirX; self.directionY = dirY; self.strength = strength || 1; self.lifespan = 30; self.active = true; self.alpha = 0.7; // Set rotation based on wind direction self.rotation = Math.atan2(dirY, dirX); // Set scale based on strength self.scale.set(0.5 + self.strength * 0.2); // Elongate in direction of movement windGraphic.scale.x = 1 + self.strength * 0.3; windGraphic.scale.y = 0.5; }; self.update = function () { if (!self.active) return false; self.lifespan--; // Move in direction self.x += self.directionX * self.strength * 2; self.y += self.directionY * self.strength * 2; // Fade out gradually if (self.lifespan < 15) { self.alpha = self.lifespan / 15 * 0.7; } if (self.lifespan <= 0) { self.active = false; return false; } return true; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game size constants var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; // Change background color to a light sky blue game.setBackgroundColor(0xc2e6ff); // Game variables var airParticles = []; var leaves = []; var clouds = []; var tornados = []; var playerHands = []; var enemies = []; var windEffects = []; var airShrine; var levelManager; var score = 0; var nextCloudTime = 0; var cloudInterval = 300; var nextLeafTime = 0; var leafInterval = 180; var nextEnemyTime = 0; var enemyInterval = 500; var threatChance = 0.2; var remainingEnemies = 0; // UI elements var scoreText = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topLeft.addChild(scoreText); scoreText.x = 120; scoreText.y = 50; var levelText = new Text2('Level: 1', { size: 80, fill: 0xFFFFFF }); levelText.anchor.set(1, 0); LK.gui.topRight.addChild(levelText); levelText.x = -50; levelText.y = 50; var healthBar = new Container(); var healthBarBg = LK.getAsset('airParticle', { anchorX: 0, anchorY: 0.5, scaleX: 40, scaleY: 0.8, alpha: 0.5, tint: 0x000000 }); var healthBarFill = LK.getAsset('airParticle', { anchorX: 0, anchorY: 0.5, scaleX: 40, scaleY: 0.8, tint: 0x42f5a7 }); healthBar.addChild(healthBarBg); healthBar.addChild(healthBarFill); LK.gui.top.addChild(healthBar); healthBar.y = 50; // Initialize game elements function initializeGame() { // Initialize level manager levelManager = new Level(); levelManager.startLevel(1); remainingEnemies = levelManager.enemyCount; // Create air shrine in the center airShrine = new AirShrine(); airShrine.x = GAME_WIDTH / 2; airShrine.y = GAME_HEIGHT / 2; game.addChild(airShrine); // Create initial leaves for (var i = 0; i < 10; i++) { createLeaf(); } // Create initial clouds for (var i = 0; i < 3; i++) { createCloud(); } // Start ambient wind music LK.playMusic('ambientWind', { fade: { start: 0, end: 0.4, duration: 2000 } }); } // Create a new leaf at a random position function createLeaf() { var leaf = new Leaf(); leaf.x = Math.random() * GAME_WIDTH; leaf.y = Math.random() * GAME_HEIGHT; leaf.vx = (Math.random() - 0.5) * 2; leaf.vy = (Math.random() - 0.5) * 2; leaves.push(leaf); game.addChild(leaf); } // Create a new cloud function createCloud() { var cloud = new Cloud(); var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left var type = Math.random() < threatChance ? "threat" : "normal"; switch (side) { case 0: // top cloud.init(Math.random() * GAME_WIDTH, -100, type); cloud.vy = Math.random() * 1 + 0.5; break; case 1: // right cloud.init(GAME_WIDTH + 100, Math.random() * GAME_HEIGHT, type); cloud.vx = -(Math.random() * 1 + 0.5); break; case 2: // bottom cloud.init(Math.random() * GAME_WIDTH, GAME_HEIGHT + 100, type); cloud.vy = -(Math.random() * 1 + 0.5); break; case 3: // left cloud.init(-100, Math.random() * GAME_HEIGHT, type); cloud.vx = Math.random() * 1 + 0.5; break; } clouds.push(cloud); game.addChild(cloud); } // Create air particles function createAirParticles(x, y, dirX, dirY, count, speed) { for (var i = 0; i < count; i++) { var particle = new AirParticle(); var angle = Math.atan2(dirY, dirX) + (Math.random() - 0.5) * 1; var particleSpeed = speed * (0.5 + Math.random() * 0.5); particle.init(x + (Math.random() - 0.5) * 40, y + (Math.random() - 0.5) * 40, Math.cos(angle) * particleSpeed, Math.sin(angle) * particleSpeed, 50 + Math.random() * 50); airParticles.push(particle); game.addChild(particle); } } // Create a tornado function createTornado(x, y) { var tornado = new Tornado(); tornado.init(x, y); tornados.push(tornado); game.addChild(tornado); } // Create an enemy function createEnemy() { if (remainingEnemies <= 0) return; // Don't create enemies if level quota reached var enemy = new Enemy(); var angle = Math.random() * Math.PI * 2; var distance = 1200; // Spawn outside the player's immediate view var x = airShrine.x + Math.cos(angle) * distance; var y = airShrine.y + Math.sin(angle) * distance; // Ensure enemy is spawned within game bounds + margin x = Math.max(-100, Math.min(GAME_WIDTH + 100, x)); y = Math.max(-100, Math.min(GAME_HEIGHT + 100, y)); enemy.init(x, y, levelManager.enemyHealth, levelManager.enemySpeed); enemies.push(enemy); game.addChild(enemy); remainingEnemies--; } // Handle pointer down event game.down = function (x, y, obj) { var hand = new PlayerHand(); hand.init(x, y); playerHands.push(hand); game.addChild(hand); // Play wind sound LK.getSound('wind').play(); // Create initial air particles createAirParticles(x, y, 0, 0, 5, 1); }; // Handle pointer move event game.move = function (x, y, obj) { // Update the most recent hand position if (playerHands.length > 0) { var hand = playerHands[playerHands.length - 1]; // Calculate direction and speed var dirX = x - hand.x; var dirY = y - hand.y; var speed = Math.sqrt(dirX * dirX + dirY * dirY); // Only update if the hand has moved enough if (speed > 1) { hand.x = x; hand.y = y; // Create air particles based on movement speed if (speed > 10) { var normalizedDirX = dirX / speed; var normalizedDirY = dirY / speed; createAirParticles(x, y, normalizedDirX, normalizedDirY, Math.min(5, speed / 5), speed / 10); // Create wind effect if (speed > 20 && LK.ticks % 5 === 0) { var windEffect = new WindEffect(); windEffect.init(x, y, normalizedDirX, normalizedDirY, speed / 20); windEffects.push(windEffect); game.addChild(windEffect); } // Apply wind force to nearby leaves and clouds var windRadius = 200 + speed * 2; var windStrength = speed / 30; for (var i = 0; i < leaves.length; i++) { var leaf = leaves[i]; var dx = leaf.x - x; var dy = leaf.y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < windRadius) { leaf.applyWind(normalizedDirX, normalizedDirY, windStrength * (1 - distance / windRadius)); } } for (var i = 0; i < clouds.length; i++) { var cloud = clouds[i]; var dx = cloud.x - x; var dy = cloud.y - y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < windRadius * 1.5) { cloud.applyWind(normalizedDirX, normalizedDirY, windStrength * 0.5 * (1 - distance / (windRadius * 1.5))); } } } // Check for circular motion (tornado creation) if (hand.isCircularMotion()) { var center = hand.getCircleCenter(); createTornado(center.x, center.y); hand.trailPoints = []; // Reset trail after creating tornado } } } }; // Handle pointer up event game.up = function (x, y, obj) { if (playerHands.length > 0) { var hand = playerHands[playerHands.length - 1]; hand.deactivate(); } }; // Main game update loop game.update = function () { // Update all game objects // Update air particles for (var i = airParticles.length - 1; i >= 0; i--) { if (!airParticles[i].update()) { airParticles[i].destroy(); airParticles.splice(i, 1); } } // Update player hands for (var i = playerHands.length - 1; i >= 0; i--) { var hand = playerHands[i]; hand.update(); if (!hand.active && hand.alpha <= 0) { hand.destroy(); playerHands.splice(i, 1); } } // Update leaves for (var i = 0; i < leaves.length; i++) { leaves[i].update(); } // Update clouds and check for collisions with shrine for (var i = clouds.length - 1; i >= 0; i--) { var cloud = clouds[i]; cloud.update(); // Check if cloud is off screen by a large margin if (cloud.x < -300 || cloud.x > GAME_WIDTH + 300 || cloud.y < -300 || cloud.y > GAME_HEIGHT + 300) { cloud.destroy(); clouds.splice(i, 1); continue; } // Check for threat clouds intersecting with shrine if (cloud.type === "threat") { cloud.lastIntersecting = cloud.intersects(airShrine); if (cloud.lastIntersecting) { airShrine.damage(0.1); // Visual feedback createAirParticles(cloud.x, cloud.y, 0, 0, 5, 2); } } } // Update tornados and apply forces for (var i = tornados.length - 1; i >= 0; i--) { var tornado = tornados[i]; if (!tornado.update()) { tornado.destroy(); tornados.splice(i, 1); continue; } // Apply tornado forces to leaves and clouds for (var j = 0; j < leaves.length; j++) { tornado.applyForce(leaves[j]); } for (var j = 0; j < clouds.length; j++) { if (tornado.applyForce(clouds[j]) && clouds[j].type === "threat") { // Destroy threat clouds caught in tornados score += 5; scoreText.setText("Score: " + score); // Create particle effect createAirParticles(clouds[j].x, clouds[j].y, 0, 0, 20, 3); // Play success sound LK.getSound('success').play(); // Remove the cloud clouds[j].destroy(); clouds.splice(j, 1); j--; } } } // Update air shrine airShrine.update(); // Check for game over condition if (airShrine.health <= 0 && airShrine.lastHealth > 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } // Update wind effects for (var i = windEffects.length - 1; i >= 0; i--) { if (!windEffects[i].update()) { windEffects[i].destroy(); windEffects.splice(i, 1); } } // Check for level completion (all enemies defeated) if (remainingEnemies <= 0 && enemies.length === 0) { levelManager.startLevel(levelManager.currentLevel + 1); levelText.setText("Level: " + levelManager.currentLevel); remainingEnemies = levelManager.enemyCount; // Update game parameters threatChance = levelManager.threatChance; cloudInterval = levelManager.cloudInterval; leafInterval = levelManager.leafInterval; enemyInterval = levelManager.enemyInterval; // Heal shrine a bit airShrine.heal(20); // Visual feedback LK.effects.flashScreen(0x00ff00, 500); } // Update health bar healthBarFill.scale.x = 40 * (airShrine.health / 100); if (airShrine.health < 30) { healthBarFill.tint = 0xff3030; } else if (airShrine.health < 60) { healthBarFill.tint = 0xffff30; } else { healthBarFill.tint = 0x42f5a7; } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Check if enemy reached the shrine if (enemy.intersects(airShrine)) { if (!enemy.lastIntersecting) { airShrine.damage(5); createAirParticles(enemy.x, enemy.y, 0, 0, 15, 3); LK.effects.flashObject(enemy, 0xff0000, 300); } enemy.lastIntersecting = true; } else { enemy.lastIntersecting = false; } // Check if enemy is hit by wind for (var j = 0; j < playerHands.length; j++) { var hand = playerHands[j]; if (hand.active && hand.vx * hand.vx + hand.vy * hand.vy > 25) { var dx = enemy.x - hand.x; var dy = enemy.y - hand.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { if (enemy.damage()) { score += 10; scoreText.setText("Score: " + score); createAirParticles(enemy.x, enemy.y, hand.vx / 10, hand.vy / 10, 20, 2); LK.getSound('success').play(); enemy.destroy(); enemies.splice(i, 1); break; } else { // Knockback effect enemy.x += hand.vx * 0.5; enemy.y += hand.vy * 0.5; createAirParticles(enemy.x, enemy.y, hand.vx / 20, hand.vy / 20, 5, 1); } } } } // Check if enemy is caught in tornado for (var j = 0; j < tornados.length; j++) { if (tornados[j].applyForce(enemy)) { if (enemy.damage()) { score += 15; scoreText.setText("Score: " + score); createAirParticles(enemy.x, enemy.y, 0, 0, 25, 3); LK.getSound('success').play(); enemy.destroy(); enemies.splice(i, 1); break; } } } } // Spawn new clouds, leaves and enemies at intervals if (LK.ticks >= nextCloudTime) { createCloud(); nextCloudTime = LK.ticks + cloudInterval; } if (LK.ticks >= nextLeafTime) { createLeaf(); nextLeafTime = LK.ticks + leafInterval; } if (LK.ticks >= nextEnemyTime && remainingEnemies > 0) { createEnemy(); nextEnemyTime = LK.ticks + enemyInterval; } // Set score for LK system LK.setScore(score); }; // Initialize the game initializeGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AirParticle = Container.expand(function () {
var self = Container.call(this);
var particleGraphic = self.attachAsset('airParticle', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.vx = 0;
self.vy = 0;
self.lifespan = 100;
self.lastX = 0;
self.lastY = 0;
self.init = function (x, y, vx, vy, lifespan) {
self.x = x;
self.y = y;
self.lastX = x;
self.lastY = y;
self.vx = vx;
self.vy = vy;
self.lifespan = lifespan || 100;
self.alpha = 1;
self.scale.set(Math.random() * 0.5 + 0.5);
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
self.lifespan--;
self.alpha = self.lifespan / 100;
if (self.lifespan <= 0) {
return false; // Signal to remove the particle
}
return true;
};
return self;
});
var AirShrine = Container.expand(function () {
var self = Container.call(this);
var shrineGraphic = self.attachAsset('airShrine', {
anchorX: 0.5,
anchorY: 0.5
});
var targetArea = self.attachAsset('targetArea', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.health = 100;
self.lastHealth = 100;
self.pulseDirection = 1;
self.pulseValue = 0;
self.update = function () {
self.lastHealth = self.health;
// Visual pulse effect
self.pulseValue += 0.02 * self.pulseDirection;
if (self.pulseValue >= 1) {
self.pulseValue = 1;
self.pulseDirection = -1;
} else if (self.pulseValue <= 0) {
self.pulseValue = 0;
self.pulseDirection = 1;
}
targetArea.alpha = 0.15 + self.pulseValue * 0.15;
shrineGraphic.alpha = 0.8 + self.pulseValue * 0.2;
};
self.damage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
// Visual feedback
LK.effects.flashObject(shrineGraphic, 0xff0000, 300);
};
self.heal = function (amount) {
self.health += amount;
if (self.health > 100) self.health = 100;
// Visual feedback
LK.effects.flashObject(shrineGraphic, 0x00ff00, 300);
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudGraphic = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.85
});
self.vx = 0;
self.vy = 0;
self.friction = 0.99;
self.mass = 5 + Math.random() * 3;
self.type = "normal"; // normal or threat
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = false;
self.init = function (x, y, type) {
self.x = x;
self.y = y;
self.lastX = x;
self.lastY = y;
self.type = type || "normal";
if (self.type === "threat") {
cloudGraphic.tint = 0x555555;
}
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.lastIntersecting = false;
self.x += self.vx;
self.y += self.vy;
// Apply friction
self.vx *= self.friction;
self.vy *= self.friction;
// Boundary checks with bounce
if (self.x < 100) {
self.x = 100;
self.vx = Math.abs(self.vx) * 0.3;
} else if (self.x > 1948) {
self.x = 1948;
self.vx = -Math.abs(self.vx) * 0.3;
}
if (self.y < 100) {
self.y = 100;
self.vy = Math.abs(self.vy) * 0.3;
} else if (self.y > 2632) {
self.y = 2632;
self.vy = -Math.abs(self.vy) * 0.3;
}
};
// Apply wind force from swipe
self.applyWind = function (dirX, dirY, strength) {
self.vx += dirX * strength / self.mass;
self.vy += dirY * strength / self.mass;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphic = self.attachAsset('airParticle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2,
tint: 0xff3030
});
self.speed = 1 + Math.random();
self.health = 3;
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = false;
self.init = function (x, y, health, speed) {
self.x = x;
self.y = y;
self.lastX = x;
self.lastY = y;
self.alpha = 1;
if (health) self.health = health;
if (speed) self.speed = speed;
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move towards shrine
if (airShrine) {
var dx = airShrine.x - self.x;
var dy = airShrine.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Pulse effect
self.scale.x = 1.8 + Math.sin(LK.ticks * 0.1) * 0.2;
self.scale.y = 1.8 + Math.sin(LK.ticks * 0.1) * 0.2;
return true;
};
self.damage = function () {
self.health--;
LK.effects.flashObject(self, 0xffffff, 200);
return self.health <= 0;
};
return self;
});
var Leaf = Container.expand(function () {
var self = Container.call(this);
var leafGraphic = self.attachAsset('leaf', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.rotation = Math.random() * Math.PI * 2;
self.rotationSpeed = (Math.random() - 0.5) * 0.1;
self.friction = 0.97;
self.mass = 1 + Math.random();
self.lastX = 0;
self.lastY = 0;
self.lastIntersecting = false;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
self.x += self.vx;
self.y += self.vy;
// Apply friction
self.vx *= self.friction;
self.vy *= self.friction;
// Rotate the leaf
self.rotation += self.rotationSpeed;
// Boundary checks
if (self.x < 0) {
self.x = 0;
self.vx = Math.abs(self.vx) * 0.5;
} else if (self.x > 2048) {
self.x = 2048;
self.vx = -Math.abs(self.vx) * 0.5;
}
if (self.y < 0) {
self.y = 0;
self.vy = Math.abs(self.vy) * 0.5;
} else if (self.y > 2732) {
self.y = 2732;
self.vy = -Math.abs(self.vy) * 0.5;
}
};
// Apply wind force from swipe
self.applyWind = function (dirX, dirY, strength) {
self.vx += dirX * strength / self.mass;
self.vy += dirY * strength / self.mass;
};
return self;
});
var Level = Container.expand(function () {
var self = Container.call(this);
self.currentLevel = 1;
self.enemyCount = 5;
self.threatChance = 0.2;
self.cloudInterval = 300;
self.leafInterval = 180;
self.enemyInterval = 500;
self.enemyHealth = 3;
self.enemySpeed = 1;
self.startLevel = function (level) {
self.currentLevel = level;
self.enemyCount = 5 * level;
self.threatChance = Math.min(0.5, 0.2 + level * 0.05);
self.cloudInterval = Math.max(100, 300 - level * 20);
self.leafInterval = Math.max(100, 180 - level * 5);
self.enemyInterval = Math.max(200, 500 - level * 30);
self.enemyHealth = 3 + Math.floor(level / 2);
self.enemySpeed = 1 + level * 0.2;
// Create level notification
self.showLevelNotification();
return self;
};
self.showLevelNotification = function () {
var levelNotification = new Text2('Level ' + self.currentLevel, {
size: 150,
fill: 0xFFFFFF
});
levelNotification.anchor.set(0.5, 0.5);
levelNotification.x = GAME_WIDTH / 2;
levelNotification.y = GAME_HEIGHT / 2;
levelNotification.alpha = 0;
game.addChild(levelNotification);
// Animate level notification
tween(levelNotification, {
alpha: 1,
y: GAME_HEIGHT / 2 - 100
}, {
duration: 500
}).then(function () {
return tween(levelNotification, {
alpha: 0,
y: GAME_HEIGHT / 2 - 200
}, {
duration: 500,
delay: 1000
});
}).then(function () {
levelNotification.destroy();
});
};
return self;
});
var PlayerHand = Container.expand(function () {
var self = Container.call(this);
var handGraphic = self.attachAsset('playerHand', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.active = false;
self.trailPoints = [];
self.maxTrailPoints = 10;
self.lastX = 0;
self.lastY = 0;
self.vx = 0;
self.vy = 0;
self.init = function (x, y) {
self.x = x;
self.y = y;
self.lastX = x;
self.lastY = y;
self.active = true;
self.trailPoints = [];
self.scale.set(1);
self.alpha = 0;
// Fade in animation
tween(self, {
alpha: 1
}, {
duration: 200
});
};
self.update = function () {
if (!self.active) return;
// Calculate velocity from position change
self.vx = self.x - self.lastX;
self.vy = self.y - self.lastY;
// Store trail points for gesture recognition
if (self.trailPoints.length >= self.maxTrailPoints) {
self.trailPoints.shift();
}
self.trailPoints.push({
x: self.x,
y: self.y
});
// Store last position
self.lastX = self.x;
self.lastY = self.y;
};
self.deactivate = function () {
self.active = false;
// Fade out animation
tween(self, {
alpha: 0,
scale: 0.5
}, {
duration: 200
});
};
// Check if the hand movement forms a circular motion
self.isCircularMotion = function () {
if (self.trailPoints.length < 8) return false;
// Calculate center of points
var centerX = 0,
centerY = 0;
for (var i = 0; i < self.trailPoints.length; i++) {
centerX += self.trailPoints[i].x;
centerY += self.trailPoints[i].y;
}
centerX /= self.trailPoints.length;
centerY /= self.trailPoints.length;
// Calculate average radius and deviation
var radius = 0;
for (var i = 0; i < self.trailPoints.length; i++) {
var dx = self.trailPoints[i].x - centerX;
var dy = self.trailPoints[i].y - centerY;
radius += Math.sqrt(dx * dx + dy * dy);
}
radius /= self.trailPoints.length;
// Check if points form a circle
var radiusDeviation = 0;
for (var i = 0; i < self.trailPoints.length; i++) {
var dx = self.trailPoints[i].x - centerX;
var dy = self.trailPoints[i].y - centerY;
var distance = Math.sqrt(dx * dx + dy * dy);
radiusDeviation += Math.abs(distance - radius);
}
radiusDeviation /= self.trailPoints.length;
// Check if deviation is low enough to consider it a circle
return radiusDeviation < radius * 0.3 && radius > 50;
};
// Get the center of the circular motion
self.getCircleCenter = function () {
var centerX = 0,
centerY = 0;
for (var i = 0; i < self.trailPoints.length; i++) {
centerX += self.trailPoints[i].x;
centerY += self.trailPoints[i].y;
}
return {
x: centerX / self.trailPoints.length,
y: centerY / self.trailPoints.length
};
};
return self;
});
// Game size constants
var Tornado = Container.expand(function () {
var self = Container.call(this);
var tornadoGraphic = self.attachAsset('tornadoBase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.strength = 0;
self.maxStrength = 10;
self.radius = 150;
self.lifespan = 120;
self.active = false;
self.init = function (x, y) {
self.x = x;
self.y = y;
self.strength = 1;
self.lifespan = 120;
self.active = true;
self.scale.set(0.5);
// Play tornado sound
LK.getSound('tornado').play();
};
self.update = function () {
if (!self.active) return false;
self.lifespan--;
if (self.strength < self.maxStrength) {
self.strength += 0.2;
}
// Visual effects
self.scale.set(0.5 + self.strength / self.maxStrength * 0.5);
self.rotation += 0.05;
if (self.lifespan <= 30) {
self.alpha = self.lifespan / 30;
}
if (self.lifespan <= 0) {
self.active = false;
return false;
}
return true;
};
// Apply tornado force to an object
self.applyForce = function (object) {
var dx = self.x - object.x;
var dy = self.y - object.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < self.radius * self.scale.x) {
// Calculate force direction (toward tornado center)
var forceX = dx / distance;
var forceY = dy / distance;
// Apply force inversely proportional to distance
var forceMagnitude = self.strength * (1 - distance / (self.radius * self.scale.x));
object.vx += forceX * forceMagnitude;
object.vy += forceY * forceMagnitude;
// Add some rotation effect
object.rotationSpeed = (object.rotationSpeed || 0) + 0.05;
return true;
}
return false;
};
return self;
});
var WindEffect = Container.expand(function () {
var self = Container.call(this);
var windGraphic = self.attachAsset('whirlwind', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.directionX = 0;
self.directionY = 0;
self.strength = 0;
self.lifespan = 30;
self.active = false;
self.init = function (x, y, dirX, dirY, strength) {
self.x = x;
self.y = y;
self.directionX = dirX;
self.directionY = dirY;
self.strength = strength || 1;
self.lifespan = 30;
self.active = true;
self.alpha = 0.7;
// Set rotation based on wind direction
self.rotation = Math.atan2(dirY, dirX);
// Set scale based on strength
self.scale.set(0.5 + self.strength * 0.2);
// Elongate in direction of movement
windGraphic.scale.x = 1 + self.strength * 0.3;
windGraphic.scale.y = 0.5;
};
self.update = function () {
if (!self.active) return false;
self.lifespan--;
// Move in direction
self.x += self.directionX * self.strength * 2;
self.y += self.directionY * self.strength * 2;
// Fade out gradually
if (self.lifespan < 15) {
self.alpha = self.lifespan / 15 * 0.7;
}
if (self.lifespan <= 0) {
self.active = false;
return false;
}
return true;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game size constants
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
// Change background color to a light sky blue
game.setBackgroundColor(0xc2e6ff);
// Game variables
var airParticles = [];
var leaves = [];
var clouds = [];
var tornados = [];
var playerHands = [];
var enemies = [];
var windEffects = [];
var airShrine;
var levelManager;
var score = 0;
var nextCloudTime = 0;
var cloudInterval = 300;
var nextLeafTime = 0;
var leafInterval = 180;
var nextEnemyTime = 0;
var enemyInterval = 500;
var threatChance = 0.2;
var remainingEnemies = 0;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topLeft.addChild(scoreText);
scoreText.x = 120;
scoreText.y = 50;
var levelText = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(1, 0);
LK.gui.topRight.addChild(levelText);
levelText.x = -50;
levelText.y = 50;
var healthBar = new Container();
var healthBarBg = LK.getAsset('airParticle', {
anchorX: 0,
anchorY: 0.5,
scaleX: 40,
scaleY: 0.8,
alpha: 0.5,
tint: 0x000000
});
var healthBarFill = LK.getAsset('airParticle', {
anchorX: 0,
anchorY: 0.5,
scaleX: 40,
scaleY: 0.8,
tint: 0x42f5a7
});
healthBar.addChild(healthBarBg);
healthBar.addChild(healthBarFill);
LK.gui.top.addChild(healthBar);
healthBar.y = 50;
// Initialize game elements
function initializeGame() {
// Initialize level manager
levelManager = new Level();
levelManager.startLevel(1);
remainingEnemies = levelManager.enemyCount;
// Create air shrine in the center
airShrine = new AirShrine();
airShrine.x = GAME_WIDTH / 2;
airShrine.y = GAME_HEIGHT / 2;
game.addChild(airShrine);
// Create initial leaves
for (var i = 0; i < 10; i++) {
createLeaf();
}
// Create initial clouds
for (var i = 0; i < 3; i++) {
createCloud();
}
// Start ambient wind music
LK.playMusic('ambientWind', {
fade: {
start: 0,
end: 0.4,
duration: 2000
}
});
}
// Create a new leaf at a random position
function createLeaf() {
var leaf = new Leaf();
leaf.x = Math.random() * GAME_WIDTH;
leaf.y = Math.random() * GAME_HEIGHT;
leaf.vx = (Math.random() - 0.5) * 2;
leaf.vy = (Math.random() - 0.5) * 2;
leaves.push(leaf);
game.addChild(leaf);
}
// Create a new cloud
function createCloud() {
var cloud = new Cloud();
var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
var type = Math.random() < threatChance ? "threat" : "normal";
switch (side) {
case 0:
// top
cloud.init(Math.random() * GAME_WIDTH, -100, type);
cloud.vy = Math.random() * 1 + 0.5;
break;
case 1:
// right
cloud.init(GAME_WIDTH + 100, Math.random() * GAME_HEIGHT, type);
cloud.vx = -(Math.random() * 1 + 0.5);
break;
case 2:
// bottom
cloud.init(Math.random() * GAME_WIDTH, GAME_HEIGHT + 100, type);
cloud.vy = -(Math.random() * 1 + 0.5);
break;
case 3:
// left
cloud.init(-100, Math.random() * GAME_HEIGHT, type);
cloud.vx = Math.random() * 1 + 0.5;
break;
}
clouds.push(cloud);
game.addChild(cloud);
}
// Create air particles
function createAirParticles(x, y, dirX, dirY, count, speed) {
for (var i = 0; i < count; i++) {
var particle = new AirParticle();
var angle = Math.atan2(dirY, dirX) + (Math.random() - 0.5) * 1;
var particleSpeed = speed * (0.5 + Math.random() * 0.5);
particle.init(x + (Math.random() - 0.5) * 40, y + (Math.random() - 0.5) * 40, Math.cos(angle) * particleSpeed, Math.sin(angle) * particleSpeed, 50 + Math.random() * 50);
airParticles.push(particle);
game.addChild(particle);
}
}
// Create a tornado
function createTornado(x, y) {
var tornado = new Tornado();
tornado.init(x, y);
tornados.push(tornado);
game.addChild(tornado);
}
// Create an enemy
function createEnemy() {
if (remainingEnemies <= 0) return; // Don't create enemies if level quota reached
var enemy = new Enemy();
var angle = Math.random() * Math.PI * 2;
var distance = 1200; // Spawn outside the player's immediate view
var x = airShrine.x + Math.cos(angle) * distance;
var y = airShrine.y + Math.sin(angle) * distance;
// Ensure enemy is spawned within game bounds + margin
x = Math.max(-100, Math.min(GAME_WIDTH + 100, x));
y = Math.max(-100, Math.min(GAME_HEIGHT + 100, y));
enemy.init(x, y, levelManager.enemyHealth, levelManager.enemySpeed);
enemies.push(enemy);
game.addChild(enemy);
remainingEnemies--;
}
// Handle pointer down event
game.down = function (x, y, obj) {
var hand = new PlayerHand();
hand.init(x, y);
playerHands.push(hand);
game.addChild(hand);
// Play wind sound
LK.getSound('wind').play();
// Create initial air particles
createAirParticles(x, y, 0, 0, 5, 1);
};
// Handle pointer move event
game.move = function (x, y, obj) {
// Update the most recent hand position
if (playerHands.length > 0) {
var hand = playerHands[playerHands.length - 1];
// Calculate direction and speed
var dirX = x - hand.x;
var dirY = y - hand.y;
var speed = Math.sqrt(dirX * dirX + dirY * dirY);
// Only update if the hand has moved enough
if (speed > 1) {
hand.x = x;
hand.y = y;
// Create air particles based on movement speed
if (speed > 10) {
var normalizedDirX = dirX / speed;
var normalizedDirY = dirY / speed;
createAirParticles(x, y, normalizedDirX, normalizedDirY, Math.min(5, speed / 5), speed / 10);
// Create wind effect
if (speed > 20 && LK.ticks % 5 === 0) {
var windEffect = new WindEffect();
windEffect.init(x, y, normalizedDirX, normalizedDirY, speed / 20);
windEffects.push(windEffect);
game.addChild(windEffect);
}
// Apply wind force to nearby leaves and clouds
var windRadius = 200 + speed * 2;
var windStrength = speed / 30;
for (var i = 0; i < leaves.length; i++) {
var leaf = leaves[i];
var dx = leaf.x - x;
var dy = leaf.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < windRadius) {
leaf.applyWind(normalizedDirX, normalizedDirY, windStrength * (1 - distance / windRadius));
}
}
for (var i = 0; i < clouds.length; i++) {
var cloud = clouds[i];
var dx = cloud.x - x;
var dy = cloud.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < windRadius * 1.5) {
cloud.applyWind(normalizedDirX, normalizedDirY, windStrength * 0.5 * (1 - distance / (windRadius * 1.5)));
}
}
}
// Check for circular motion (tornado creation)
if (hand.isCircularMotion()) {
var center = hand.getCircleCenter();
createTornado(center.x, center.y);
hand.trailPoints = []; // Reset trail after creating tornado
}
}
}
};
// Handle pointer up event
game.up = function (x, y, obj) {
if (playerHands.length > 0) {
var hand = playerHands[playerHands.length - 1];
hand.deactivate();
}
};
// Main game update loop
game.update = function () {
// Update all game objects
// Update air particles
for (var i = airParticles.length - 1; i >= 0; i--) {
if (!airParticles[i].update()) {
airParticles[i].destroy();
airParticles.splice(i, 1);
}
}
// Update player hands
for (var i = playerHands.length - 1; i >= 0; i--) {
var hand = playerHands[i];
hand.update();
if (!hand.active && hand.alpha <= 0) {
hand.destroy();
playerHands.splice(i, 1);
}
}
// Update leaves
for (var i = 0; i < leaves.length; i++) {
leaves[i].update();
}
// Update clouds and check for collisions with shrine
for (var i = clouds.length - 1; i >= 0; i--) {
var cloud = clouds[i];
cloud.update();
// Check if cloud is off screen by a large margin
if (cloud.x < -300 || cloud.x > GAME_WIDTH + 300 || cloud.y < -300 || cloud.y > GAME_HEIGHT + 300) {
cloud.destroy();
clouds.splice(i, 1);
continue;
}
// Check for threat clouds intersecting with shrine
if (cloud.type === "threat") {
cloud.lastIntersecting = cloud.intersects(airShrine);
if (cloud.lastIntersecting) {
airShrine.damage(0.1);
// Visual feedback
createAirParticles(cloud.x, cloud.y, 0, 0, 5, 2);
}
}
}
// Update tornados and apply forces
for (var i = tornados.length - 1; i >= 0; i--) {
var tornado = tornados[i];
if (!tornado.update()) {
tornado.destroy();
tornados.splice(i, 1);
continue;
}
// Apply tornado forces to leaves and clouds
for (var j = 0; j < leaves.length; j++) {
tornado.applyForce(leaves[j]);
}
for (var j = 0; j < clouds.length; j++) {
if (tornado.applyForce(clouds[j]) && clouds[j].type === "threat") {
// Destroy threat clouds caught in tornados
score += 5;
scoreText.setText("Score: " + score);
// Create particle effect
createAirParticles(clouds[j].x, clouds[j].y, 0, 0, 20, 3);
// Play success sound
LK.getSound('success').play();
// Remove the cloud
clouds[j].destroy();
clouds.splice(j, 1);
j--;
}
}
}
// Update air shrine
airShrine.update();
// Check for game over condition
if (airShrine.health <= 0 && airShrine.lastHealth > 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
// Update wind effects
for (var i = windEffects.length - 1; i >= 0; i--) {
if (!windEffects[i].update()) {
windEffects[i].destroy();
windEffects.splice(i, 1);
}
}
// Check for level completion (all enemies defeated)
if (remainingEnemies <= 0 && enemies.length === 0) {
levelManager.startLevel(levelManager.currentLevel + 1);
levelText.setText("Level: " + levelManager.currentLevel);
remainingEnemies = levelManager.enemyCount;
// Update game parameters
threatChance = levelManager.threatChance;
cloudInterval = levelManager.cloudInterval;
leafInterval = levelManager.leafInterval;
enemyInterval = levelManager.enemyInterval;
// Heal shrine a bit
airShrine.heal(20);
// Visual feedback
LK.effects.flashScreen(0x00ff00, 500);
}
// Update health bar
healthBarFill.scale.x = 40 * (airShrine.health / 100);
if (airShrine.health < 30) {
healthBarFill.tint = 0xff3030;
} else if (airShrine.health < 60) {
healthBarFill.tint = 0xffff30;
} else {
healthBarFill.tint = 0x42f5a7;
}
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check if enemy reached the shrine
if (enemy.intersects(airShrine)) {
if (!enemy.lastIntersecting) {
airShrine.damage(5);
createAirParticles(enemy.x, enemy.y, 0, 0, 15, 3);
LK.effects.flashObject(enemy, 0xff0000, 300);
}
enemy.lastIntersecting = true;
} else {
enemy.lastIntersecting = false;
}
// Check if enemy is hit by wind
for (var j = 0; j < playerHands.length; j++) {
var hand = playerHands[j];
if (hand.active && hand.vx * hand.vx + hand.vy * hand.vy > 25) {
var dx = enemy.x - hand.x;
var dy = enemy.y - hand.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
if (enemy.damage()) {
score += 10;
scoreText.setText("Score: " + score);
createAirParticles(enemy.x, enemy.y, hand.vx / 10, hand.vy / 10, 20, 2);
LK.getSound('success').play();
enemy.destroy();
enemies.splice(i, 1);
break;
} else {
// Knockback effect
enemy.x += hand.vx * 0.5;
enemy.y += hand.vy * 0.5;
createAirParticles(enemy.x, enemy.y, hand.vx / 20, hand.vy / 20, 5, 1);
}
}
}
}
// Check if enemy is caught in tornado
for (var j = 0; j < tornados.length; j++) {
if (tornados[j].applyForce(enemy)) {
if (enemy.damage()) {
score += 15;
scoreText.setText("Score: " + score);
createAirParticles(enemy.x, enemy.y, 0, 0, 25, 3);
LK.getSound('success').play();
enemy.destroy();
enemies.splice(i, 1);
break;
}
}
}
}
// Spawn new clouds, leaves and enemies at intervals
if (LK.ticks >= nextCloudTime) {
createCloud();
nextCloudTime = LK.ticks + cloudInterval;
}
if (LK.ticks >= nextLeafTime) {
createLeaf();
nextLeafTime = LK.ticks + leafInterval;
}
if (LK.ticks >= nextEnemyTime && remainingEnemies > 0) {
createEnemy();
nextEnemyTime = LK.ticks + enemyInterval;
}
// Set score for LK system
LK.setScore(score);
};
// Initialize the game
initializeGame();
Modern App Store icon, high definition, square with rounded corners, for a game titled "Air Weaver" and with the description "A mystical adventure where you control the element of air through touch gestures. Harness wind currents, create tornadoes, and manipulate your environment by moving your hands across the screen. Master your air powers to overcome obstacles and restore balance to a world disrupted by chaotic weather patterns.". No text on icon!
A boy controlling wind. In-Game asset. 2d. High contrast. No shadows