User prompt
Make enemies that try to come near you
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'tween.to(self, {' Line Number: 237 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
More code
Code edit (1 edits merged)
Please save this source code
User prompt
Air Weaver
Initial prompt
A person who controls air and with their hands
/**** * 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 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 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.to(self, { alpha: 1 }, 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.to(self, { alpha: 0, scale: 0.5 }, 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; }); /**** * 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 airShrine; var level = 1; var score = 0; var nextCloudTime = 0; var cloudInterval = 300; var nextLeafTime = 0; var leafInterval = 180; var threatChance = 0.2; // 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() { // 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); } // 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); // 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(); } // Check for level up condition if (score >= level * 50) { level++; levelText.setText("Level: " + level); // Increase difficulty threatChance = Math.min(0.5, 0.2 + level * 0.05); cloudInterval = Math.max(100, 300 - level * 20); leafInterval = Math.max(100, 180 - level * 5); // 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; } // Spawn new clouds and leaves at intervals if (LK.ticks >= nextCloudTime) { createCloud(); nextCloudTime = LK.ticks + cloudInterval; } if (LK.ticks >= nextLeafTime) { createLeaf(); nextLeafTime = LK.ticks + leafInterval; } // Set score for LK system LK.setScore(score); }; // Initialize the game initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -1,242 +1,353 @@
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
-var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
-var AirCurrent = Container.expand(function () {
+var AirParticle = Container.expand(function () {
var self = Container.call(this);
- var circle = self.attachAsset('airCircle', {
+ var particleGraphic = self.attachAsset('airParticle', {
anchorX: 0.5,
anchorY: 0.5,
- alpha: 0.4
+ alpha: 0.7
});
- self.force = 5;
- self.radius = 50;
- self.active = true;
- self.update = function () {
- if (!self.active) return;
- // Pulse effect
- if (!self.pulseDirection) self.pulseDirection = 1;
- circle.alpha += 0.01 * self.pulseDirection;
- if (circle.alpha >= 0.6) self.pulseDirection = -1;
- if (circle.alpha <= 0.2) self.pulseDirection = 1;
+ 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.applyForce = function (obj) {
- if (!self.active) return false;
- var dx = obj.x - self.x;
- var dy = obj.y - self.y;
- var distSq = dx * dx + dy * dy;
- var radiusSq = self.radius * self.radius;
- if (distSq <= radiusSq) {
- var dist = Math.sqrt(distSq);
- if (dist === 0) dist = 0.01;
- var forceFactor = (1 - dist / self.radius) * self.force;
- // Direction from air current to object
- var dirX = dx / dist;
- var dirY = dy / dist;
- obj.vx += dirX * forceFactor;
- obj.vy += dirY * forceFactor;
- return true;
+ 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 false;
+ return true;
};
return self;
});
-var AirParticle = Container.expand(function () {
+var AirShrine = Container.expand(function () {
var self = Container.call(this);
- var particle = self.attachAsset('airParticle', {
+ var shrineGraphic = self.attachAsset('airShrine', {
anchorX: 0.5,
+ anchorY: 0.5
+ });
+ var targetArea = self.attachAsset('targetArea', {
+ anchorX: 0.5,
anchorY: 0.5,
- alpha: 0.7
+ alpha: 0.3
});
- self.speed = {
- x: 0,
- y: 0
- };
- self.lifespan = 2000; // milliseconds
- self.born = Date.now();
- self.fadeSpeed = 0.01;
+ self.health = 100;
+ self.lastHealth = 100;
+ self.pulseDirection = 1;
+ self.pulseValue = 0;
self.update = function () {
- self.x += self.speed.x;
- self.y += self.speed.y;
- // Apply fade as particle ages
- var age = Date.now() - self.born;
- if (age > self.lifespan * 0.7) {
- particle.alpha -= self.fadeSpeed;
- if (particle.alpha <= 0) {
- self.destroy = true;
- }
+ 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;
}
- // Apply slight random movement
- self.speed.x += (Math.random() - 0.5) * 0.1;
- self.speed.y += (Math.random() - 0.5) * 0.1;
- // Slow down over time
- self.speed.x *= 0.99;
- self.speed.y *= 0.99;
+ 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 graphics = self.attachAsset('cloud', {
+ var cloudGraphic = self.attachAsset('cloud', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ alpha: 0.85
});
self.vx = 0;
self.vy = 0;
- self.friction = 0.98;
- self.interactable = true;
+ 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 () {
- if (self.interactable) {
- self.x += self.vx;
- self.y += self.vy;
- // Apply friction
- self.vx *= self.friction;
- self.vy *= self.friction;
- // Keep within bounds
- if (self.x < 0) {
- self.x = 0;
- self.vx *= -0.5;
- } else if (self.x > 2048) {
- self.x = 2048;
- self.vx *= -0.5;
- }
- if (self.y < 0) {
- self.y = 0;
- self.vy *= -0.5;
- } else if (self.y > 2732) {
- self.y = 2732;
- self.vy *= -0.5;
- }
+ 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 Flower = Container.expand(function () {
+var Leaf = Container.expand(function () {
var self = Container.call(this);
- var graphics = self.attachAsset('flower', {
+ var leafGraphic = self.attachAsset('leaf', {
anchorX: 0.5,
- anchorY: 0.5,
- scaleX: 0.5,
- scaleY: 0.5
+ anchorY: 0.5
});
- self.bloomed = false;
- self.bloom = function () {
- if (self.bloomed) return;
- self.bloomed = true;
- LK.getSound('flowerBloom').play();
- // Expand and brighten
- tween(graphics, {
- scaleX: 1.0,
- scaleY: 1.0
- }, {
- duration: 1000,
- easing: tween.elasticOut
- });
- // Increase score
- LK.setScore(LK.getScore() + 10);
+ 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 Obstacle = Container.expand(function () {
+var PlayerHand = Container.expand(function () {
var self = Container.call(this);
- var graphics = self.attachAsset('obstacle', {
+ var handGraphic = self.attachAsset('playerHand', {
anchorX: 0.5,
- anchorY: 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.friction = 0.95;
- self.health = 3;
- self.interactable = true;
+ 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.to(self, {
+ alpha: 1
+ }, 200);
+ };
self.update = function () {
- if (self.interactable) {
- self.x += self.vx;
- self.y += self.vy;
- // Apply friction
- self.vx *= self.friction;
- self.vy *= self.friction;
- // Keep within bounds
- if (self.x < 0) {
- self.x = 0;
- self.vx *= -0.2;
- } else if (self.x > 2048) {
- self.x = 2048;
- self.vx *= -0.2;
- }
- if (self.y < 0) {
- self.y = 0;
- self.vy *= -0.2;
- } else if (self.y > 2732) {
- self.y = 2732;
- self.vy *= -0.2;
- }
+ 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.damage = function () {
- if (!self.interactable) return;
- self.health--;
- // Flash effect
- LK.effects.flashObject(self, 0xff0000, 300);
- if (self.health <= 0) {
- self.interactable = false;
- LK.getSound('obstacleBreak').play();
- // Shrink and fade out
- tween(graphics, {
- alpha: 0,
- scaleX: 0.1,
- scaleY: 0.1
- }, {
- duration: 800,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- self.destroy = true;
- }
- });
+ self.deactivate = function () {
+ self.active = false;
+ // Fade out animation
+ tween.to(self, {
+ alpha: 0,
+ scale: 0.5
+ }, 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;
});
-var Whirlwind = Container.expand(function () {
+// Game size constants
+var Tornado = Container.expand(function () {
var self = Container.call(this);
- var graphics = self.attachAsset('whirlwind', {
+ var tornadoGraphic = self.attachAsset('tornadoBase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
- self.force = 8;
- self.radius = 100;
- self.active = true;
- self.rotationSpeed = 0.03;
- self.update = function () {
- if (!self.active) return;
- // Rotate continuously
- graphics.rotation += self.rotationSpeed;
- // Pulse effect
- if (!self.pulseDirection) self.pulseDirection = 1;
- graphics.alpha += 0.01 * self.pulseDirection;
- if (graphics.alpha >= 0.7) self.pulseDirection = -1;
- if (graphics.alpha <= 0.4) self.pulseDirection = 1;
+ 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.applyForce = function (obj) {
+ self.update = function () {
if (!self.active) return false;
- var dx = obj.x - self.x;
- var dy = obj.y - self.y;
- var distSq = dx * dx + dy * dy;
- var radiusSq = self.radius * self.radius;
- if (distSq <= radiusSq) {
- var dist = Math.sqrt(distSq);
- if (dist === 0) dist = 0.01;
- var angle = Math.atan2(dy, dx);
- var forceFactor = (1 - dist / self.radius) * self.force;
- // Orbital motion around the whirlwind center
- obj.vx += -Math.sin(angle) * forceFactor;
- obj.vy += Math.cos(angle) * forceFactor;
+ 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;
};
@@ -246,458 +357,329 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x87CEEB
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Define game parameters
-var airCurrents = [];
-var whirlwinds = [];
+// 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 obstacles = [];
-var flowers = [];
-var particles = [];
-var activeTouches = {};
-var gestureTrails = {};
+var tornados = [];
+var playerHands = [];
+var airShrine;
var level = 1;
-var maxLevels = 3;
-var windSound = null;
-// Create UI elements
-var scoreTxt = new Text2(LK.getScore().toString(), {
+var score = 0;
+var nextCloudTime = 0;
+var cloudInterval = 300;
+var nextLeafTime = 0;
+var leafInterval = 180;
+var threatChance = 0.2;
+// UI elements
+var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
-scoreTxt.anchor.set(0.5, 0);
-LK.gui.top.addChild(scoreTxt);
-var levelTxt = new Text2("Level " + level, {
- size: 60,
+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
});
-levelTxt.anchor.set(0, 0);
-levelTxt.x = 150;
-levelTxt.y = 20;
-LK.gui.topRight.addChild(levelTxt);
-var helpTxt = new Text2("Draw circles for whirlwinds\nSwipe for air currents", {
- size: 40,
- 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
});
-helpTxt.anchor.set(0.5, 0);
-helpTxt.y = 150;
-LK.gui.top.addChild(helpTxt);
-// Hide help text after 5 seconds
-LK.setTimeout(function () {
- tween(helpTxt, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeOut
+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() {
+ // 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
+ }
});
-}, 5000);
-// Setup game
-function setupLevel(levelNum) {
- // Clear previous level objects
- clearLevel();
- // Update level text
- levelTxt.setText("Level " + levelNum);
- // Common setup for all levels
- var cloudCount, obstacleCount, flowerCount;
- switch (levelNum) {
+}
+// 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:
- cloudCount = 3;
- obstacleCount = 2;
- flowerCount = 3;
+ // right
+ cloud.init(GAME_WIDTH + 100, Math.random() * GAME_HEIGHT, type);
+ cloud.vx = -(Math.random() * 1 + 0.5);
break;
case 2:
- cloudCount = 5;
- obstacleCount = 4;
- flowerCount = 5;
+ // bottom
+ cloud.init(Math.random() * GAME_WIDTH, GAME_HEIGHT + 100, type);
+ cloud.vy = -(Math.random() * 1 + 0.5);
break;
case 3:
- cloudCount = 7;
- obstacleCount = 6;
- flowerCount = 8;
+ // left
+ cloud.init(-100, Math.random() * GAME_HEIGHT, type);
+ cloud.vx = Math.random() * 1 + 0.5;
break;
- default:
- cloudCount = 3;
- obstacleCount = 2;
- flowerCount = 3;
}
- // Create clouds
- for (var i = 0; i < cloudCount; i++) {
- var cloud = new Cloud();
- cloud.x = Math.random() * 1848 + 100;
- cloud.y = Math.random() * 1000 + 300;
- clouds.push(cloud);
- game.addChild(cloud);
- }
- // Create obstacles
- for (var i = 0; i < obstacleCount; i++) {
- var obstacle = new Obstacle();
- obstacle.x = Math.random() * 1848 + 100;
- obstacle.y = Math.random() * 1500 + 600;
- obstacles.push(obstacle);
- game.addChild(obstacle);
- }
- // Create flowers that need to bloom
- for (var i = 0; i < flowerCount; i++) {
- var flower = new Flower();
- flower.x = Math.random() * 1848 + 100;
- flower.y = Math.random() * 2000 + 500;
- flowers.push(flower);
- game.addChild(flower);
- }
- // Play background music
- LK.playMusic('ambientMusic');
+ clouds.push(cloud);
+ game.addChild(cloud);
}
-function clearLevel() {
- // Remove all game elements
- for (var i = 0; i < airCurrents.length; i++) {
- if (airCurrents[i].parent) {
- airCurrents[i].parent.removeChild(airCurrents[i]);
- }
- }
- airCurrents = [];
- for (var i = 0; i < whirlwinds.length; i++) {
- if (whirlwinds[i].parent) {
- whirlwinds[i].parent.removeChild(whirlwinds[i]);
- }
- }
- whirlwinds = [];
- for (var i = 0; i < clouds.length; i++) {
- if (clouds[i].parent) {
- clouds[i].parent.removeChild(clouds[i]);
- }
- }
- clouds = [];
- for (var i = 0; i < obstacles.length; i++) {
- if (obstacles[i].parent) {
- obstacles[i].parent.removeChild(obstacles[i]);
- }
- }
- obstacles = [];
- for (var i = 0; i < flowers.length; i++) {
- if (flowers[i].parent) {
- flowers[i].parent.removeChild(flowers[i]);
- }
- }
- flowers = [];
- for (var i = 0; i < particles.length; i++) {
- if (particles[i].parent) {
- particles[i].parent.removeChild(particles[i]);
- }
- }
- particles = [];
-}
-// Check if level is complete
-function checkLevelComplete() {
- var allBloomed = true;
- for (var i = 0; i < flowers.length; i++) {
- if (!flowers[i].bloomed) {
- allBloomed = false;
- break;
- }
- }
- if (allBloomed && flowers.length > 0) {
- // Level complete!
- level++;
- if (level > maxLevels) {
- // Game complete!
- LK.showYouWin();
- } else {
- // Flash screen and move to next level
- LK.effects.flashScreen(0xffffff, 500);
- // Show level complete message
- var completeTxt = new Text2("Level Complete!", {
- size: 120,
- fill: 0xFFFFFF
- });
- completeTxt.anchor.set(0.5, 0.5);
- LK.gui.center.addChild(completeTxt);
- // Remove message and start next level after delay
- LK.setTimeout(function () {
- LK.gui.center.removeChild(completeTxt);
- setupLevel(level);
- }, 2000);
- }
- }
-}
-// Input handling
-function detectGesture(id) {
- var trail = gestureTrails[id];
- if (!trail || trail.length < 10) return null;
- // Check if it's a circle gesture
- var isCircle = detectCircleGesture(trail);
- if (isCircle) {
- return "circle";
- }
- // Check if it's a swipe gesture
- var isSwipe = detectSwipeGesture(trail);
- if (isSwipe) {
- return "swipe";
- }
- return null;
-}
-function detectCircleGesture(trail) {
- if (trail.length < 10) return false;
- // Calculate center of points
- var centerX = 0,
- centerY = 0;
- for (var i = 0; i < trail.length; i++) {
- centerX += trail[i].x;
- centerY += trail[i].y;
- }
- centerX /= trail.length;
- centerY /= trail.length;
- // Calculate average distance from center
- var avgDist = 0;
- for (var i = 0; i < trail.length; i++) {
- var dx = trail[i].x - centerX;
- var dy = trail[i].y - centerY;
- avgDist += Math.sqrt(dx * dx + dy * dy);
- }
- avgDist /= trail.length;
- // Check if points form a rough circle
- var isCircular = true;
- var threshold = 0.3; // Allow 30% deviation
- for (var i = 0; i < trail.length; i++) {
- var dx = trail[i].x - centerX;
- var dy = trail[i].y - centerY;
- var dist = Math.sqrt(dx * dx + dy * dy);
- if (Math.abs(dist - avgDist) / avgDist > threshold) {
- isCircular = false;
- break;
- }
- }
- // Check if first and last points are close enough
- var firstPoint = trail[0];
- var lastPoint = trail[trail.length - 1];
- var dx = firstPoint.x - lastPoint.x;
- var dy = firstPoint.y - lastPoint.y;
- var startEndDist = Math.sqrt(dx * dx + dy * dy);
- return isCircular && startEndDist < avgDist * 0.5;
-}
-function detectSwipeGesture(trail) {
- if (trail.length < 5) return false;
- var firstPoint = trail[0];
- var lastPoint = trail[trail.length - 1];
- var dx = lastPoint.x - firstPoint.x;
- var dy = lastPoint.y - firstPoint.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- // Check if the distance is significant enough to be a swipe
- return distance > 200;
-}
-function createWhirlwind(x, y) {
- var whirlwind = new Whirlwind();
- whirlwind.x = x;
- whirlwind.y = y;
- whirlwinds.push(whirlwind);
- game.addChild(whirlwind);
- // Play sound
- LK.getSound('whirlwindSound').play();
- // Automatically remove after some time
- LK.setTimeout(function () {
- tween(whirlwind, {
- alpha: 0
- }, {
- duration: 1000,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- if (whirlwind.parent) {
- whirlwind.parent.removeChild(whirlwind);
- }
- var index = whirlwinds.indexOf(whirlwind);
- if (index > -1) {
- whirlwinds.splice(index, 1);
- }
- }
- });
- }, 5000);
-}
-function createAirCurrent(fromX, fromY, toX, toY) {
- var dx = toX - fromX;
- var dy = toY - fromY;
- var length = Math.sqrt(dx * dx + dy * dy);
- var steps = Math.max(1, Math.floor(length / 100));
- for (var i = 0; i < steps; i++) {
- var t = i / steps;
- var x = fromX + dx * t;
- var y = fromY + dy * t;
- var airCurrent = new AirCurrent();
- airCurrent.x = x;
- airCurrent.y = y;
- airCurrents.push(airCurrent);
- game.addChild(airCurrent);
- // Create visual particles
- createAirParticles(x, y, dx / length, dy / length);
- }
- // Play sound
- if (!windSound) {
- windSound = LK.getSound('windSound');
- windSound.play();
- }
- // Automatically remove after some time
- LK.setTimeout(function () {
- for (var i = 0; i < airCurrents.length; i++) {
- var airCurrent = airCurrents[i];
- tween(airCurrent, {
- alpha: 0
- }, {
- duration: 800,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- if (airCurrent.parent) {
- airCurrent.parent.removeChild(airCurrent);
- }
- }
- });
- }
- airCurrents = [];
- if (windSound) {
- windSound = null;
- }
- }, 2000);
-}
-function createAirParticles(x, y, dirX, dirY) {
- for (var i = 0; i < 3; i++) {
+// Create air particles
+function createAirParticles(x, y, dirX, dirY, count, speed) {
+ for (var i = 0; i < count; i++) {
var particle = new AirParticle();
- particle.x = x + (Math.random() - 0.5) * 40;
- particle.y = y + (Math.random() - 0.5) * 40;
- particle.speed.x = dirX * (2 + Math.random() * 3);
- particle.speed.y = dirY * (2 + Math.random() * 3);
- particles.push(particle);
+ 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);
}
}
-// Touch event handlers
+// Create a tornado
+function createTornado(x, y) {
+ var tornado = new Tornado();
+ tornado.init(x, y);
+ tornados.push(tornado);
+ game.addChild(tornado);
+}
+// Handle pointer down event
game.down = function (x, y, obj) {
- var touchId = Date.now().toString();
- activeTouches[touchId] = {
- x: x,
- y: y
- };
- gestureTrails[touchId] = [{
- x: x,
- y: y
- }];
+ 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 active touches
- for (var id in activeTouches) {
- activeTouches[id] = {
- x: x,
- y: y
- };
- // Add point to gesture trail
- if (gestureTrails[id]) {
- gestureTrails[id].push({
- x: x,
- y: y
- });
+ // 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);
+ // 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) {
- for (var id in activeTouches) {
- // Detect gesture
- var gesture = detectGesture(id);
- if (gesture === "circle") {
- // Create a whirlwind at the center of the gesture
- var trail = gestureTrails[id];
- var centerX = 0,
- centerY = 0;
- for (var i = 0; i < trail.length; i++) {
- centerX += trail[i].x;
- centerY += trail[i].y;
- }
- centerX /= trail.length;
- centerY /= trail.length;
- createWhirlwind(centerX, centerY);
- } else if (gesture === "swipe") {
- // Create air current along the swipe
- var trail = gestureTrails[id];
- var firstPoint = trail[0];
- var lastPoint = trail[trail.length - 1];
- createAirCurrent(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
- }
- // Clear this touch
- delete activeTouches[id];
- delete gestureTrails[id];
+ if (playerHands.length > 0) {
+ var hand = playerHands[playerHands.length - 1];
+ hand.deactivate();
}
};
-// Game update function
+// Main game update loop
game.update = function () {
- // Update score display
- scoreTxt.setText(LK.getScore().toString());
// Update all game objects
- // Update air currents
- for (var i = 0; i < airCurrents.length; i++) {
- airCurrents[i].update();
+ // Update air particles
+ for (var i = airParticles.length - 1; i >= 0; i--) {
+ if (!airParticles[i].update()) {
+ airParticles[i].destroy();
+ airParticles.splice(i, 1);
+ }
}
- // Update whirlwinds
- for (var i = 0; i < whirlwinds.length; i++) {
- whirlwinds[i].update();
- }
- // Update clouds
- for (var i = 0; i < clouds.length; i++) {
- // Apply forces from air elements
- for (var j = 0; j < airCurrents.length; j++) {
- airCurrents[j].applyForce(clouds[i]);
+ // 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);
}
- for (var j = 0; j < whirlwinds.length; j++) {
- whirlwinds[j].applyForce(clouds[i]);
- }
- clouds[i].update();
}
- // Update obstacles
- for (var i = obstacles.length - 1; i >= 0; i--) {
- var obstacle = obstacles[i];
- // Apply forces from air elements
- var forcesApplied = 0;
- for (var j = 0; j < airCurrents.length; j++) {
- if (airCurrents[j].applyForce(obstacle)) {
- forcesApplied++;
- }
+ // 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;
}
- for (var j = 0; j < whirlwinds.length; j++) {
- if (whirlwinds[j].applyForce(obstacle)) {
- forcesApplied++;
+ // 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);
}
}
- // If multiple forces are applied, damage the obstacle
- if (forcesApplied >= 2 && LK.ticks % 30 === 0) {
- obstacle.damage();
+ }
+ // 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;
}
- obstacle.update();
- // Remove destroyed obstacles
- if (obstacle.destroy) {
- game.removeChild(obstacle);
- obstacles.splice(i, 1);
+ // Apply tornado forces to leaves and clouds
+ for (var j = 0; j < leaves.length; j++) {
+ tornado.applyForce(leaves[j]);
}
- }
- // Update flowers
- for (var i = flowers.length - 1; i >= 0; i--) {
- var flower = flowers[i];
- // Check if a cloud is over the flower
for (var j = 0; j < clouds.length; j++) {
- if (clouds[j].intersects(flower)) {
- flower.bloom();
- break;
+ 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 particles
- for (var i = particles.length - 1; i >= 0; i--) {
- particles[i].update();
- if (particles[i].destroy) {
- game.removeChild(particles[i]);
- particles.splice(i, 1);
- }
+ // Update air shrine
+ airShrine.update();
+ // Check for game over condition
+ if (airShrine.health <= 0 && airShrine.lastHealth > 0) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
}
- // Check if level is complete
- checkLevelComplete();
+ // Check for level up condition
+ if (score >= level * 50) {
+ level++;
+ levelText.setText("Level: " + level);
+ // Increase difficulty
+ threatChance = Math.min(0.5, 0.2 + level * 0.05);
+ cloudInterval = Math.max(100, 300 - level * 20);
+ leafInterval = Math.max(100, 180 - level * 5);
+ // 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;
+ }
+ // Spawn new clouds and leaves at intervals
+ if (LK.ticks >= nextCloudTime) {
+ createCloud();
+ nextCloudTime = LK.ticks + cloudInterval;
+ }
+ if (LK.ticks >= nextLeafTime) {
+ createLeaf();
+ nextLeafTime = LK.ticks + leafInterval;
+ }
+ // Set score for LK system
+ LK.setScore(score);
};
-// Start the game
-setupLevel(level);
\ No newline at end of file
+// Initialize the game
+initializeGame();
\ No newline at end of file
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