User prompt
Spawn one object
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'createAsset')' in this line: 'var castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);' Line Number: 379
User prompt
Fix Bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'castleGraphics')' in this line: 'self.castleGraphics = LK.getAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);' Line Number: 379
User prompt
Fix Bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'castleGraphics')' in this line: 'self.castleGraphics = castleGraphics;' Line Number: 380
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'createAsset')' in this line: 'var castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);' Line Number: 379
User prompt
Fix Bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'castleGraphics')' in this line: 'self.castleGraphics = LK.getAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);' Line Number: 379
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'createAsset')' in this line: 'self.castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);' Line Number: 379
User prompt
Fix Bug: 'Uncaught TypeError: self.activate is not a function' in this line: 'self.activate();' Line Number: 41
User prompt
Fix Bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'feedingRate')' in this line: 'self.feedingRate = 5000;' Line Number: 26
User prompt
Spawn one of each object
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var MovingFood = Food.expand(function () {' Line Number: 603
User prompt
Improve the entire code with 4 new functionality
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var PredatorFish = Fish.expand(function () {' Line Number: 43
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var FishFeeder = InteractiveElement.expand(function () {' Line Number: 17
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var FishFeeder = InteractiveDecoration.expand(function () {' Line Number: 17
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var BubbleCurtain = DecorativePlant.expand(function () {' Line Number: 1
User prompt
Improve the entire code with 4 new functionality
User prompt
Fix Bug: 'Uncaught TypeError: Fish.extend is not a function' in this line: 'var CleanerFish = Fish.extend(function () {' Line Number: 1806
User prompt
Fix Bug: 'Uncaught TypeError: Fish.extend is not a function' in this line: 'var SchoolLeaderFish = Fish.extend(function () {' Line Number: 1790
User prompt
Fix Bug: 'Uncaught TypeError: Fish.extend is not a function' in this line: 'var StealthFish = Fish.extend(function () {' Line Number: 1779
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var BubbleShieldFish = Fish.expand(function () {' Line Number: 46
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var JumpingFish = Fish.expand(function () {' Line Number: 23
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var StealthFish = Fish.expand(function () {' Line Number: 23
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var SchoolLeaderFish = Fish.expand(function () {' Line Number: 23
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var CleanerFish = Fish.expand(function () {' Line Number: 23
var InflatableFish = Container.expand(function () { var self = Container.call(this); self.inflationSize = 2; self.inflationDuration = 3000; self.isInflated = false; self.inflate = function () { if (!self.isInflated) { self.isInflated = true; self.scale.x *= self.inflationSize; self.scale.y *= self.inflationSize; LK.setTimeout(function () { self.scale.x /= self.inflationSize; self.scale.y /= self.inflationSize; self.isInflated = false; }, self.inflationDuration); } }; self.on('tick', function () { self.inflate(); }); return self; }); var SchoolLeaderFish = Fish.expand(function () { var self = Fish.call(this) || this; self.schoolingRange = 300; self.attractFishToSchool = function () { var nearbyFish = self.getNearbyFishWithinRange(self.schoolingRange); nearbyFish.forEach(function (fish) { if (fish.constructor !== SchoolLeaderFish) { fish.targetRotation = Math.atan2(self.y - fish.y, self.x - fish.x); } }); }; self.on('tick', function () { self.attractFishToSchool(); }); return self; }); var StealthFish = Fish.expand(function () { var self = Fish.call(this) || this; self.stealthMode = false; self.stealthDuration = 5000; self.toggleStealthMode = function () { self.stealthMode = !self.stealthMode; self.alpha = self.stealthMode ? 0.1 : 1.0; }; LK.setInterval(self.toggleStealthMode, self.stealthDuration); return self; }); var JumpingFish = Fish.expand(function () { var self = Fish.call(this) || this; self.jumpHeight = 150; self.jumpFrequency = 10000; self.isJumping = false; self.jump = function () { if (!self.isJumping) { self.isJumping = true; var initialY = self.y; LK.setTimeout(function () { self.y = initialY - self.jumpHeight; LK.setTimeout(function () { self.y = initialY; self.isJumping = false; }, 1000); }, self.jumpFrequency); } }; self.on('tick', function () { self.jump(); }); return self; }); var BubbleShieldFish = Fish.expand(function () { var self = Fish.call(this) || this; self.shieldBubbleRate = 5000; self.shieldBubbleSize = 100; self.createShieldBubble = function () { var bubble = new Bubble(); bubble.x = self.x; bubble.y = self.y; bubble.width = self.shieldBubbleSize; bubble.height = self.shieldBubbleSize; LK.stageContainer.addChild(bubble); }; LK.setInterval(self.createShieldBubble, self.shieldBubbleRate); return self; }); var DecorativePlant = Container.expand(function () { var self = Container.call(this); return self; }); var InteractiveElement = Container.expand(function () { var self = Container.call(this); self.interact = function () {}; self.performInteraction = function () { self.interact(); }; }); var TreasureChest = InteractiveElement.expand(function () { var self = InteractiveElement.call(this) || this; var chestGraphics = self.createAsset('treasureChest', 'Treasure Chest Graphics', 0.5, 0.5); self.isOpen = false; self.coinReleaseRate = 3; self.releaseCoins = function () { if (self.isOpen) { for (var i = 0; i < self.coinReleaseRate; i++) { var coin = new Coin(); coin.x = self.x; coin.y = self.y; LK.stageContainer.addChild(coin); } } }; self.interact = function () { self.isOpen = !self.isOpen; chestGraphics.texture = LK.getAsset(self.isOpen ? 'chestOpen' : 'chestClosed', 'Chest Graphics', 0.5, 0.5).texture; self.releaseCoins(); }; LK.setInterval(self.performInteraction, 10000); return self; }); var IntelligentFish = Container.expand(function () { var self = Container.call(this); self.intelligenceLevel = 10; self.avoidPredators = function () { var predators = self.getNearbyFish().filter(function (otherFish) { return otherFish.size > self.size && self.distanceTo(otherFish) < 300; }); if (predators.length > 0) { var escapeVector = { x: 0, y: 0 }; predators.forEach(function (predator) { var angle = Math.atan2(self.y - predator.y, self.x - predator.x); escapeVector.x += Math.cos(angle); escapeVector.y += Math.sin(angle); }); self.targetRotation = Math.atan2(escapeVector.y, escapeVector.x); } }; self.seekFood = function () { var foodSources = self.getNearbyObjects().filter(function (obj) { return obj instanceof Food; }); if (foodSources.length > 0) { var closestFood = foodSources[0]; for (var i = 1; i < foodSources.length; i++) { if (self.distanceTo(foodSources[i]) < self.distanceTo(closestFood)) { closestFood = foodSources[i]; } } self.targetRotation = Math.atan2(closestFood.y - self.y, closestFood.x - self.x); } }; return self; }); var FoodSpawningFish = IntelligentFish.expand(function () { var self = IntelligentFish.call(this) || this; self.foodReleaseRate = 5; self.releaseFood = function () { var food = new Food(); food.x = self.x; food.y = self.y; LK.stageContainer.addChild(food); var nearbyFish = self.getNearbyFishWithinRange(500); nearbyFish.forEach(function (fish) { fish.rushToFood(food); }); }; LK.setInterval(self.releaseFood, 10000); return self; }); var Bubble = Container.expand(function () { var self = Container.call(this); return self; }); var CapturingBubble = Bubble.expand(function () { var self = Bubble.call(this) || this; self.captureFish = function (fish) { if (fish instanceof Fish && !fish.isCaptured && self.intersects(fish)) { fish.isCaptured = true; fish.x = self.x; fish.y = self.y - fish.height / 2; fish.alpha = 0.5; } }; self.releaseFish = function (fish) { if (fish.isCaptured) { fish.isCaptured = false; fish.y += fish.height / 2; fish.alpha = 1.0; } }; self.on('tick', function () { self.y -= self.liftSpeed; if (self.y < 0) { if (fish.isCaptured) { self.releaseFish(fish); } self.destroy(); } }); return self; }); var BubbleProducingFish = Container.expand(function () { var self = Container.call(this); self.bubbleReleaseRate = 5; self.releaseBubbles = function () { var bubble = new Bubble(); bubble.x = self.x; bubble.y = self.y; LK.stageContainer.addChild(bubble); var nearbyFish = self.getNearbyFishWithinRange(500); nearbyFish.forEach(function (fish) { if (!fish.isCaptured) { fish.isCaptured = true; fish.y -= 10; } }); }; LK.setInterval(self.releaseBubbles, 10000); return self; }); var AquariumDecorator = Container.expand(function () { var self = Container.call(this); self.decorate = function () {}; self.updateDecoration = function () {}; }); var HidingCastle = AquariumDecorator.expand(function () { var self = AquariumDecorator.call(this); self.castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1); self.castleGraphics.width = 300; self.castleGraphics.height = 400; self.x = 1024; self.y = 2732 - self.castleGraphics.height / 2; self.provideHiding = function (fish) { if (fish.size < 30 && self.distanceTo(fish) < 100) { fish.isHidden = true; fish.alpha = 0.5; } else { fish.isHidden = false; fish.alpha = 1.0; } }; return self; }); var HidingBehavior = Container.expand(function () { var self = Container.call(this); self.hide = function (fish, castle) { if (fish.size < 30 && fish.distanceTo(castle) < 100 && fish.isPredatorNearby()) { fish.isHidden = true; fish.alpha = 0.5; } else { fish.isHidden = false; fish.alpha = 1.0; } }; self.isPredatorNearby = function (fish) { var nearbyPredators = fish.getNearbyFish().filter(function (otherFish) { return otherFish.size > fish.size && fish.distanceTo(otherFish) < 200; }); return nearbyPredators.length > 0; }; }); var Fish = Container.expand(function () { var self = Container.call(this); self.speed = 2; self.direction = Math.random() * Math.PI * 2; self.move = function () { var newX = self.x + Math.cos(self.direction) * self.speed; var newY = self.y + Math.sin(self.direction) * self.speed; var bounds = self.getWaterBounds(); newX = Math.max(bounds.left, Math.min(newX, bounds.right)); newY = Math.max(bounds.top, Math.min(newY, bounds.bottom)); self.x = newX; self.y = newY; }; self.on('tick', function () { self.move(); }); self.rushToFood = function (food) { self.targetRotation = Math.atan2(food.y - self.y, food.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 5; }; self.hunger = 100; Fish.prototype.restingBehavior = new RestingBehavior(); Fish.prototype.reproductionBehavior = new ReproductionBehavior(); self.hungerDecayRate = 0.1; Fish.prototype.feedingBehavior = new FeedingBehavior(); self.updateHunger = function () { var closestFood = self.feedingBehavior.findClosestFood(); if (closestFood && self.distanceTo(closestFood) <= self.feedingBehavior.feedingRange) { self.feedingBehavior.eatFood(closestFood); self.hunger += closestFood.nutrition; } self.hunger -= self.hungerDecayRate; if (self.hunger <= 0) { self.health -= self.hungerDecayRate; if (self.health <= 0) { self.die(); } } self.hunger = Math.max(self.hunger, 0); self.hunger = Math.min(self.hunger, 100); }; self.greetFish = function (otherFish) { if (!self.memory.includes(otherFish)) { self.targetRotation = Math.atan2(otherFish.y - self.y, otherFish.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 5; self.rememberObject(otherFish); } }; Fish.prototype.playfulBehavior = new PlayfulBehavior(); self.memory = []; self.rememberObject = function (target) { if (!self.memory.includes(target)) { self.memory.push(target); } }; Fish.prototype.foragingBehavior = new ForagingBehavior(); self.forgetObject = function (target) { var index = self.memory.indexOf(target); if (index > -1) { self.memory.splice(index, 1); } }; self.getNearbyObjects = function () { var nearbyObjects = []; LK.stageContainer.children.forEach(function (child) { if (!(child instanceof Fish) && child !== self) { var dx = child.x - self.x; var dy = child.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { nearbyObjects.push(child); } } }); return nearbyObjects; }; self.findCuriosityTarget = function () { var possibleTargets = self.getNearbyObjects(); if (possibleTargets.length > 0) { self.curiosityTarget = possibleTargets[Math.floor(Math.random() * possibleTargets.length)]; } }; self.investigateCuriosity = function (target) { self.targetRotation = Math.atan2(target.y - self.y, target.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; }; self.distanceTo = function (target) { var dx = target.x - self.x; var dy = target.y - self.y; return Math.sqrt(dx * dx + dy * dy); }; Fish.prototype.evasionBehavior = new EvasionBehavior(); Fish.prototype.leadershipBehavior = new LeadershipBehavior(); self.findMate = function (nearbyFish) { var potentialMate = null; var minDistance = Infinity; nearbyFish.forEach(function (fish) { if (fish.constructor === self.constructor && fish !== self && !fish.isMating) { var distance = self.distanceTo(fish); if (distance < minDistance) { minDistance = distance; potentialMate = fish; } } }); if (potentialMate && minDistance < 100) { self.isMating = true; potentialMate.isMating = true; var egg = new Egg(); egg.x = (self.x + potentialMate.x) / 2; egg.y = (self.y + potentialMate.y) / 2; LK.stageContainer.addChild(egg); } }; self.evadeLargerFish = function (largerFish) {}; self.getNearbyFish = function () { var nearbyFish = []; LK.stageContainer.children.forEach(function (child) { if (child instanceof Fish && child !== self) { var dx = child.x - self.x; var dy = child.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { nearbyFish.push(child); } } }); return nearbyFish; }; self.avoidObstacles = function (obstacles) { if (obstacles.length > 0) { var sumAngles = 0; var count = 0; for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; var angleToObstacle = Math.atan2(obstacle.y - self.y, obstacle.x - self.x); sumAngles += angleToObstacle + Math.PI; count++; } if (count > 0) { var averageAvoidAngle = sumAngles / count; self.targetRotation = averageAvoidAngle; self.directionChangeTime = LK.ticks; self.directionChangeInterval = Math.random() * 50 + 30; } } }; self.isPathBlocked = function (newX, newY, obstacles) { for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; var dx = obstacle.x - newX; var dy = obstacle.y - newY; if (Math.sqrt(dx * dx + dy * dy) < obstacle.radius + self.radius) { return true; } } return false; }; Fish.prototype.mortalityBehavior = new MortalityBehavior(); self.getNearbyObstacles = function () { var nearbyObstacles = []; LK.stageContainer.children.forEach(function (child) { if (typeof Obstacle !== 'undefined' && child instanceof Obstacle) { var dx = child.x - self.x; var dy = child.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 300) { nearbyObstacles.push(child); } } }); return nearbyObstacles; }; this.getWaterBounds = function () { var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0); return { left: (2048 - waterGraphics.width) / 2, right: (2048 + waterGraphics.width) / 2, top: (2732 - waterGraphics.height) / 2 - 150, bottom: (2732 + waterGraphics.height) / 2 - 150 }; }; }); var Lighting = Container.expand(function () { var self = Container.call(this); self.light = function () {}; }); var AquariumLighting = Lighting.expand(function () { var self = Lighting.call(this) || this; var lightingGraphics = self.createAsset('aquariumLighting', 'Aquarium Lighting Graphics', 0.5, 0.5); self.dayDuration = 18000; self.nightDuration = 12000; self.isDaytime = true; self.lastChangeTime = LK.ticks; self.lightingBehavior = new LightingBehavior(); self.update = function () { self.lightingBehavior.updateLighting(self, lightingGraphics); }; }); var LightingBehavior = Container.expand(function () { var self = Container.call(this); self.updateLighting = function (lighting, graphics) { if (lighting.isDaytime && LK.ticks - lighting.lastChangeTime > lighting.dayDuration) { lighting.isDaytime = false; lighting.lastChangeTime = LK.ticks; graphics.alpha = 0.3; } else if (!lighting.isDaytime && LK.ticks - lighting.lastChangeTime > lighting.nightDuration) { lighting.isDaytime = true; lighting.lastChangeTime = LK.ticks; graphics.alpha = 1; } }; }); var AquariumLifeManager = Container.expand(function () { var self = Container.call(this); self.lifeForms = []; self.addLifeForm = function (lifeForm) { self.lifeForms.push(lifeForm); self.addChild(lifeForm); }; self.updateLifeForms = function () { for (var i = 0; i < self.lifeForms.length; i++) { if (typeof self.lifeForms[i].update === 'function') { self.lifeForms[i].update(); } } }; }); var Cleaner = Container.expand(function () { var self = Container.call(this); self.clean = function () {}; }); var CleaningRobot = Container.expand(function () { var self = Container.call(this); self.speed = 0.2; self.cleaningRate = 1; self.cleaningBehavior = new CleaningBehavior(); self.moveAndClean = function () { var dirtyObjects = self.cleaningBehavior.findDirtyObjects(); dirtyObjects.forEach(function (obj) { self.x += (obj.x - self.x) * self.speed; self.y += (obj.y - self.y) * self.speed; if (self.distanceTo(obj) < 50) { self.cleaningBehavior.cleanObject(obj, self.cleaningRate); } }); }; LK.setInterval(self.moveAndClean, 1000); return self; }); var CleaningBehavior = Container.expand(function () { var self = Container.call(this); self.findDirtyObjects = function () { var dirtyObjects = []; LK.stageContainer.children.forEach(function (child) { if (child.isDirty && child.clean) { dirtyObjects.push(child); } }); return dirtyObjects; }; self.cleanObject = function (obj, rate) { obj.clean(rate); }; }); var AquariumDecoratorManager = Container.expand(function () { var self = Container.call(this); self.decorators = []; self.addDecorator = function (decorator) { self.decorators.push(decorator); self.addChild(decorator); }; self.removeDecorator = function (decorator) { var index = self.decorators.indexOf(decorator); if (index !== -1) { self.decorators.splice(index, 1); decorator.destroy(); } }; self.updateDecorators = function () { for (var i = 0; i < self.decorators.length; i++) { if (typeof self.decorators[i].update === 'function') { self.decorators[i].update(); } } }; }); var InteractiveDecoration = InteractiveElement.expand(function () { var self = InteractiveElement.call(this) || this; self.isActive = false; self.activate = function () { self.isActive = true; }; self.deactivate = function () { self.isActive = false; }; self.interactWithFish = function (fish) { if (self.isActive) {} }; }); var GrowingPlant = DecorativePlant.expand(function () { var self = DecorativePlant.call(this) || this; self.growthRate = 0.01; self.maxScale = 5; self.on('tick', function () { if (self.scale.x < self.maxScale) { self.scale.x += self.growthRate; self.scale.y += self.growthRate; } }); self.consume = function (fish) { if (fish instanceof Fish && self.distanceTo(fish) < 100) { fish.health = Math.min(fish.health + self.healthValue, 100); self.destroy(); } }; return self; }); var HealingFish = Fish.expand(function () { var self = Fish.call(this) || this; self.healingRate = 0.05; self.healingRange = 150; self.healNearbyFish = function () { var nearbyFish = self.getNearbyFishWithinRange(self.healingRange); nearbyFish.forEach(function (fish) { if (fish.health < 100) { fish.health += self.healingRate; } }); }; self.on('tick', function () { self.healNearbyFish(); }); return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.createAsset('coin', 'Coin Graphics', 0.5, 0.5); self.value = 1; self.collect = function (fish) { if (self.intersects(fish)) { LK.setScore(LK.getScore() + self.value); self.destroy(); } }; self.on('tick', function () { self.collect(fish); }); return self; }); var Algae = Container.expand(function () { var self = Container.call(this); var algaeGraphics = self.createAsset('algae', 'Algae Graphics', 0.5, 1); self.growthRate = 0.01; self.nutritionValue = 5; self.healthValue = 2; self.on('tick', function () { algaeGraphics.scale.x += self.growthRate; algaeGraphics.scale.y += self.growthRate; if (algaeGraphics.scale.x > 3) { algaeGraphics.scale.x = 3; algaeGraphics.scale.y = 3; } }); self.consume = function (fish) { if (self.distanceTo(fish) < 50) { fish.hunger = Math.min(fish.hunger + self.nutritionValue, 100); fish.health = Math.min(fish.health + self.healthValue, 100); self.destroy(); } }; return self; }); var MovingFood = Container.expand(function () { var self = Container.call(this); self.speed = 1; self.move = function () { var waterBounds = self.getWaterBounds(); self.x += (Math.random() - 0.5) * self.speed; self.y += (Math.random() - 0.5) * self.speed; self.x = Math.max(waterBounds.left, Math.min(self.x, waterBounds.right)); self.y = Math.max(waterBounds.top, Math.min(self.y, waterBounds.bottom)); }; self.on('tick', function () { self.move(); }); }); var Food = Container.expand(function () { var self = Container.call(this); return self; }); var SpeedyFood = Food.expand(function () { var self = Food.call(this) || this; self.nutrition = 10; self.speedBoost = 1.5; self.boostDuration = 5000; self.consume = function (fish) { if (fish instanceof Fish) { fish.increaseSpeed(self.speedBoost, self.boostDuration); } Food.prototype.consume.call(this, fish); }; return self; }); var SmartFood = Food.expand(function () { var self = Food.call(this) || this; self.nutrition = 20; self.intelligenceBoost = 2; self.consume = function (fish) { if (fish instanceof IntelligentFish) { fish.intelligenceLevel += self.intelligenceBoost; } Food.prototype.consume.call(this, fish); }; }); var SpeedFood = Food.expand(function () { var self = Food.call(this) || this; self.nutrition = 15; self.speedIncrease = 1.5; self.effectDuration = 5000; self.consume = function (fish) { Fish.prototype.increaseSpeed.call(fish, self.speedIncrease, self.effectDuration); Food.prototype.consume.call(this, fish); }; }); var FastFood = Food.expand(function () { var self = Food.call(this) || this; self.nutrition = 30; self.speed = 2; self.moveRandomly = function () { var waterBounds = self.getWaterBounds(); self.x += (Math.random() - 0.5) * self.speed; self.y += (Math.random() - 0.5) * self.speed; self.x = Math.max(waterBounds.left, Math.min(self.x, waterBounds.right)); self.y = Math.max(waterBounds.top, Math.min(self.y, waterBounds.bottom)); }; self.on('tick', function () { self.moveRandomly(); }); }); var VariableBubbleStream = Container.expand(function () { var self = Container.call(this); self.minBubbleRate = 500; self.maxBubbleRate = 1500; self.createBubble = function () { var bubble = new Bubble(); bubble.x = self.x; bubble.y = self.y; LK.stageContainer.addChild(bubble); }; self.startBubbleStream = function () { var bubbleRate = self.minBubbleRate + Math.random() * (self.maxBubbleRate - self.minBubbleRate); LK.setInterval(self.createBubble, bubbleRate); }; self.startBubbleStream(); return self; }); var Egg = Container.expand(function () { var self = Container.call(this); var eggGraphics = self.createAsset('egg', 'Egg Graphics', 0.5, 0.5); self.hatchTime = LK.ticks + Math.random() * 3000 + 2000; self.on('tick', function () { if (LK.ticks > self.hatchTime) { var babyFish = new Fish(); babyFish.x = self.x; babyFish.y = self.y; LK.stageContainer.addChild(babyFish); self.destroy(); } }); }); var FishFeeder = InteractiveDecoration.expand(function () { var self = InteractiveDecoration.call(this) || this; self.feedingRate = 5000; self.feed = function () { if (self.isActive) { var food = new Food(); food.x = 1024; food.y = 1366; LK.stageContainer.addChild(food); var nearbyFish = self.getNearbyFishWithinRange(500); nearbyFish.forEach(function (fish) { fish.rushToFood(food); }); } }; LK.setInterval(self.feed, self.feedingRate); self.activate(); return self; }); var IntelligentFishBehavior = Container.expand(function () { var self = Container.call(this); self.intelligenceLevel = 5; self.avoidPredators = function (fish) { var predators = fish.getNearbyFish().filter(function (otherFish) { return otherFish.size > fish.size && fish.distanceTo(otherFish) < 200; }); if (predators.length > 0) { var escapeVector = { x: 0, y: 0 }; predators.forEach(function (predator) { var angle = Math.atan2(fish.y - predator.y, fish.x - predator.x); escapeVector.x += Math.cos(angle); escapeVector.y += Math.sin(angle); }); fish.targetRotation = Math.atan2(escapeVector.y, escapeVector.x); } }; self.seekFood = function (fish) { var foodSources = fish.getNearbyObjects().filter(function (obj) { return obj instanceof Food; }); if (foodSources.length > 0) { var closestFood = foodSources[0]; for (var i = 1; i < foodSources.length; i++) { if (fish.distanceTo(foodSources[i]) < fish.distanceTo(closestFood)) { closestFood = foodSources[i]; } } fish.targetRotation = Math.atan2(closestFood.y - fish.y, closestFood.x - fish.x); } }; return self; }); var PredatorFish = Fish.expand(function () { var self = Fish.call(this) || this; self.predatorGraphics = self.createAsset('predatorFish', 'Predator Fish Graphics', 0.5, 0.5); self.speed = 3; self.huntRange = 300; self.hunt = function () { var nearbyPrey = self.getNearbyFish().filter(function (fish) { return fish.size < self.size && fish.health > 0; }); if (nearbyPrey.length > 0) { var prey = nearbyPrey[0]; for (var i = 1; i < nearbyPrey.length; i++) { if (self.distanceTo(nearbyPrey[i]) < self.distanceTo(prey)) { prey = nearbyPrey[i]; } } if (self.distanceTo(prey) < self.huntRange) { self.targetRotation = Math.atan2(prey.y - self.y, prey.x - self.x); prey.health -= 2; if (prey.health <= 0) { prey.destroy(); } } } }; self.on('tick', self.hunt); return self; }); var RestingBehavior = Container.expand(function () { var self = Container.call(this); self.isResting = false; self.lastRestTime = LK.ticks; self.restInterval = Math.random() * 3000 + 2000; self.rest = function (fish) { if (!self.isResting && Math.random() < 0.05) { self.isResting = true; self.lastRestTime = LK.ticks; self.restInterval = Math.random() * 5000 + 10000; fish.targetRotation = Math.PI / 2; fish.y = fish.getWaterBounds().bottom - 50; } else if (self.isResting && LK.ticks - self.lastRestTime > self.restInterval) { self.isResting = false; } }; return self; }); var ReproductionBehavior = Container.expand(function () { var self = Container.call(this); self.isMating = false; self.lastMateTime = LK.ticks; self.mateInterval = Math.random() * 5000 + 3000; self.isLayingEggs = false; self.lastEggTime = LK.ticks; self.eggInterval = Math.random() * 3000 + 2000; self.mate = function (fish, partner) { if (!self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) { self.isMating = true; partner.isMating = true; self.lastMateTime = LK.ticks; partner.lastMateTime = LK.ticks; var egg = new Egg(); egg.x = (fish.x + partner.x) / 2; egg.y = (fish.y + partner.y) / 2; LK.stageContainer.addChild(egg); } else if (self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) { self.isMating = false; partner.isMating = false; } }; self.layEggs = function (fish) { if (!self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval) { self.isLayingEggs = true; self.lastEggTime = LK.ticks; var egg = new Egg(); egg.x = fish.x; egg.y = fish.y; LK.stageContainer.addChild(egg); } else if (self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval) { self.isLayingEggs = false; } }; return self; }); var FeedingBehavior = Container.expand(function () { var self = Container.call(this); self.hunger = 100; self.lastFoodTime = 0; self.feedingRange = 50; self.eatFood = function (food) { if (self.distanceTo(food) < self.feedingRange && (food instanceof Food || food instanceof Algae)) { self.hunger = Math.min(self.hunger + food.nutrition, 100); food.consume(); self.lastFoodLocation = { x: food.x, y: food.y }; self.lastFoodTime = LK.ticks; } }; self.updateHunger = function () { self.hunger -= self.hungerDecayRate; if (self.hunger <= 0) { self.die(); } }; self.findClosestFood = function () { var closestFood = null; var closestDistance = Infinity; LK.stageContainer.children.forEach(function (child) { if (child instanceof Food) { var distance = self.distanceTo(child); if (distance < closestDistance) { closestDistance = distance; closestFood = child; } } }); return closestFood; }; return self; }); var PlayfulBehavior = Container.expand(function () { var self = Container.call(this); PlayfulBehavior.prototype.playWithObject = function (fish, target) { fish.targetRotation = Math.atan2(target.y - fish.y, target.x - fish.x) + Math.random() * Math.PI - Math.PI / 2; fish.directionChangeTime = LK.ticks; fish.directionChangeInterval = 5; }; self.playWithObject = function (fish, target) { fish.targetRotation = Math.atan2(target.y - fish.y, target.x - fish.x) + Math.random() * Math.PI - Math.PI / 2; fish.directionChangeTime = LK.ticks; fish.directionChangeInterval = 5; }; }); var ForagingBehavior = Container.expand(function () { var self = Container.call(this); self.findClosestFood = function (fish) { var closestFood = null; var closestDistance = Infinity; LK.stageContainer.children.forEach(function (child) { if (child instanceof Food) { var distance = fish.distanceTo(child); if (distance < closestDistance) { closestDistance = distance; closestFood = child; } } }); return closestFood; }; }); var SchoolingBehavior = Container.expand(function () { var self = Container.call(this); self.schoolWith = function (fish, similarFish) { if (similarFish.length > 1) { var schoolCenterX = similarFish.reduce((sum, fish) => sum + fish.x, 0) / similarFish.length; var schoolCenterY = similarFish.reduce((sum, fish) => sum + fish.y, 0) / similarFish.length; fish.targetRotation = Math.atan2(schoolCenterY - fish.y, schoolCenterX - fish.x); fish.directionChangeTime = LK.ticks; fish.directionChangeInterval = 30; } }; return self; }); var EvasionBehavior = Container.expand(function () { var self = Container.call(this); self.evadePredators = function (fish, predators) { if (predators.length > 0) { var evadeAngle = predators.reduce(function (sum, predator) { var angleToPredator = Math.atan2(predator.y - fish.y, predator.x - fish.x); return sum + angleToPredator + Math.PI; }, 0) / predators.length; fish.targetRotation = evadeAngle + (Math.random() * Math.PI - Math.PI / 2); fish.directionChangeTime = LK.ticks; fish.directionChangeInterval = 10; } }; return self; }); var LeadershipBehavior = Container.expand(function () { var self = Container.call(this); self.followLeader = function (fish, leaderFish) { var followDistance = 50; var distance = fish.distanceTo(leaderFish); if (distance > followDistance) { fish.targetRotation = Math.atan2(leaderFish.y - fish.y, leaderFish.x - fish.x); fish.directionChangeTime = LK.ticks; fish.directionChangeInterval = 10; } }; return self; }); var MortalityBehavior = Container.expand(function () { var self = Container.call(this); self.die = function (fish) { if (fish.health <= 0) { fish.destroy(); } }; return self; }); var Surgeonfish = Fish.expand(function () { var self = Fish.call(this) || this; Surgeonfish.prototype.findNearestCleaner = function () { var nearestCleaner = null; var nearestDistance = Infinity; LK.stageContainer.children.forEach((function (child) { if (child instanceof AquariumCleaner) { var distance = this.distanceTo(child); if (distance < nearestDistance) { nearestDistance = distance; nearestCleaner = child; } } }).bind(this)); return nearestCleaner; }; var fishGraphics = self.createAsset('surgeonfish', 'Surgeonfish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.5) * 6; self.move = function () { if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) { self.directionChangeTime = LK.ticks; self.directionChangeInterval = Math.random() * 120 + 60; if (Math.random() < 0.1) { self.targetRotation = Math.random() * Math.PI * 2; } } var cleaner = self.findNearestCleaner(); if (cleaner && self.distanceTo(cleaner) < 200) { self.targetRotation = Math.atan2(self.y - cleaner.y, self.x - cleaner.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; } var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval; if (progress < 1) { var rotationSpeed = 0.05; var rotationDifference = self.targetRotation - self.rotation; if (rotationDifference > Math.PI) rotationDifference -= Math.PI * 2; if (rotationDifference < -Math.PI) rotationDifference += Math.PI * 2; self.rotation += Math.sign(rotationDifference) * Math.min(Math.abs(rotationDifference), rotationSpeed); } else { self.rotation = self.targetRotation; } var newX = self.x + Math.cos(self.rotation) * self.speed; var newY = self.y + Math.sin(self.rotation) * self.speed; var obstacles = self.getNearbyObstacles(); var nearbyFish = self.getNearbyFish(); var overcrowdingThreshold = 5; if (nearbyFish.length > overcrowdingThreshold) { var averageX = 0; var averageY = 0; nearbyFish.forEach(function (fish) { averageX += fish.x; averageY += fish.y; }); averageX /= nearbyFish.length; averageY /= nearbyFish.length; self.targetRotation = Math.atan2(self.y - averageY, self.x - averageX); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 30; } nearbyFish.forEach(function (otherFish) { if (self.distanceTo(otherFish) < self.radius + otherFish.radius) { var angleBetween = Math.atan2(otherFish.y - self.y, otherFish.x - self.x); self.targetRotation = angleBetween + Math.PI; self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; } }); if (self.isPathBlocked(newX, newY, obstacles)) { var leaderFish = self.findLeaderFish(nearbyFish); if (leaderFish) { self.followLeader(leaderFish); } else { self.avoidObstacles(obstacles); } } else if (nearbyFish.some(fish => fish.size > self.size)) { var predators = nearbyFish.filter(fish => fish.size > self.size); if (predators.length > 0) { self.isFleeing = true; predators.forEach(function (predator) { self.rememberObject(predator); }); self.evadePredators(predators); if (self.isFleeing) { var predators = self.getNearbyFish().filter(function (fish) { return fish.size > self.size; }); if (predators.length > 0) { var hidingSpots = self.getNearbyObjects().filter(function (obj) { return obj instanceof Plant; }); if (hidingSpots.length > 0) { var hidingSpot = hidingSpots[Math.floor(Math.random() * hidingSpots.length)]; self.targetRotation = Math.atan2(hidingSpot.y - self.y, hidingSpot.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 20; } } } } else { if (self.isFleeing && LK.ticks - self.directionChangeTime > 300) { self.isFleeing = false; self.memory = self.memory.filter(function (obj) { return !(obj instanceof Fish); }); } } } else if (nearbyFish.length > 0) { var similarFish = nearbyFish.filter(fish => fish.constructor === self.constructor); if (similarFish.length > 1) { var schoolCenterX = similarFish.reduce((sum, fish) => sum + fish.x, 0) / similarFish.length; var schoolCenterY = similarFish.reduce((sum, fish) => sum + fish.y, 0) / similarFish.length; self.targetRotation = Math.atan2(schoolCenterY - self.y, schoolCenterX - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 30; } var similarFish = nearbyFish.filter(fish => fish.constructor === self.constructor); self.schoolWith(similarFish); } else if (self.curiosityTarget && self.distanceTo(self.curiosityTarget) < 100) { self.rememberObject(self.curiosityTarget); } else { self.x = newX; self.y = newY; if (self.hunger > 70 && Math.random() < 0.05) { self.restingBehavior.rest(self); } else if (self.hunger < 30 || self.hunger > 70 && Math.random() < 0.1) { var food; if (self.lastFoodLocation && LK.ticks - self.lastFoodTime > 3000) { food = self.lastFoodLocation; } else { food = self.foragingBehavior.findClosestFood(self); } if (food) { self.targetRotation = Math.atan2(food.y - self.y, food.x - self.x); } else { if (Math.random() < 0.05) { var toys = self.getNearbyObjects().filter(function (obj) { return !(obj instanceof Food) && !(obj instanceof Fish); }); if (toys.length > 0) { var toy = toys[Math.floor(Math.random() * toys.length)]; self.playfulBehavior.playWithObject(self, toy); } } else { if (Math.random() < 0.1) { self.findCuriosityTarget(); if (self.curiosityTarget) { self.investigateCuriosity(self.curiosityTarget); } } } } } else { self.findCuriosityTarget(); } } var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } if (self.isMating) { fishGraphics.tint = 0xFF69B4; } else if (self.isResting) { fishGraphics.tint = 0xADD8E6; self.rest(); } else { fishGraphics.tint = 0xFFFFFF; } self.rest = function () { if (LK.ticks - self.lastRestTime > self.restInterval) { self.isResting = false; } else if (!self.isResting && Math.random() < 0.05) { self.isResting = true; self.lastRestTime = LK.ticks; self.restInterval = Math.random() * 5000 + 10000; self.targetRotation = Math.PI / 2; self.y = self.getWaterBounds().bottom - 50; } }; fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1; fishGraphics.rotation = self.rotation; }; }); var Pufferfish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('pufferfish', 'Pufferfish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.4) * 9; self.move = function () { if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) { self.directionChangeTime = LK.ticks; self.directionChangeInterval = Math.random() * 140 + 80; self.targetRotation = Math.random() * Math.PI * 2; } var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval; if (progress < 1) { self.rotation += (self.targetRotation - self.rotation) * progress; } else { self.rotation = self.targetRotation; } var tentativeX = self.x + Math.cos(self.rotation) * self.speed; var tentativeY = self.y + Math.sin(self.rotation) * self.speed; var waterBounds = self.getWaterBounds(); tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right)); tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom)); var waterBounds = self.getWaterBounds(); tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right)); tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom)); self.x = tentativeX; self.y = tentativeY; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1; fishGraphics.rotation = self.rotation; }; }); var Clownfish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('clownfish', 'Clownfish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.4) * 3; self.move = function () { if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) { self.directionChangeTime = LK.ticks; self.directionChangeInterval = Math.random() * 110 + 70; self.targetRotation = Math.random() * Math.PI * 2; } var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval; if (progress < 1) { self.rotation += (self.targetRotation - self.rotation) * progress; } else { self.rotation = self.targetRotation; } var tentativeX = self.x + Math.cos(self.rotation) * self.speed * 2; var tentativeY = self.y + Math.sin(self.rotation) * self.speed * 2; var waterBounds = self.getWaterBounds(); tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right)); tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom)); self.x = tentativeX; self.y = tentativeY; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1; fishGraphics.rotation = self.rotation; }; }); var Angelfish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('angelfish', 'Angelfish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.45) * 3; self.move = function () { if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) { self.directionChangeTime = LK.ticks; self.directionChangeInterval = Math.random() * 130 + 90; self.targetRotation = Math.random() * Math.PI * 2; } var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval; if (progress < 1) { self.rotation += (self.targetRotation - self.rotation) * progress; } else { self.rotation = self.targetRotation; } if (!self.velocity) { self.velocity = { x: 0, y: 0 }; self.acceleration = Math.random() * 0.05 + 0.025; } var targetVelocityX = Math.cos(self.rotation) * self.speed; var targetVelocityY = Math.sin(self.rotation) * self.speed; self.velocity.x += (targetVelocityX - self.velocity.x) * self.acceleration; self.velocity.y += (targetVelocityY - self.velocity.y) * self.acceleration; self.x += self.velocity.x; self.y += self.velocity.y; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1; fishGraphics.rotation = self.rotation; }; }); var AquariumEnvironmentManager = Container.expand(function () { var self = Container.call(this); self.createEnvironment = function () { var aquariumGraphics = self.createAsset('aquarium', 'Aquarium Background', 0, 0); aquariumGraphics.width = 2048 * 1.3 * 1.08; aquariumGraphics.height = 2732 * 1.3 * 1.08; aquariumGraphics.x = (2048 - aquariumGraphics.width) / 2; aquariumGraphics.y = (2732 - aquariumGraphics.height) / 2; self.addChild(aquariumGraphics); var waterGraphics = self.createAsset('water', 'Water Graphics', 0, 0); waterGraphics.width = 2048 / 3 * 2 * 1.08 * 1.15; waterGraphics.height = 2732 / 3 * 1.26 * 1.15; waterGraphics.x = (2048 - waterGraphics.width) / 2; waterGraphics.y = (2732 - waterGraphics.height) / 2 - 150; waterGraphics.alpha = 0.7; self.addChild(waterGraphics); }; return self; }); var Aquarium = Container.expand(function () { var self = Container.call(this); self.getWaterBounds = function () { var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0); return { left: (2048 - waterGraphics.width) / 2, right: (2048 + waterGraphics.width) / 2, top: (2732 - waterGraphics.height) / 2 - 150, bottom: (2732 + waterGraphics.height) / 2 - 150 }; }; var aquariumEnvironment = self.addChild(new AquariumEnvironment()); }); var KoiFish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('koiFish', 'Koi Fish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.48) * 3; self.move = function () { if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) { self.targetRotation = Math.random() * Math.PI * 2; self.rotationStartTime = LK.ticks; self.rotationDuration = Math.random() * 130 + 70; } var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration; if (progress < 1) { var deltaRotation = (self.targetRotation - self.rotation) * progress; self.rotation += deltaRotation; } else { self.rotation = self.targetRotation; } if (!self.isResting) { if (!self.isSleeping) { if (!self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval && self.hunger > 70) { self.isLayingEggs = true; self.lastEggTime = LK.ticks; self.eggInterval = Math.random() * 3000 + 2000; var egg = new Egg(); egg.x = self.x; egg.y = self.y; LK.stageContainer.addChild(egg); } else if (self.isLayingEggs && LK.ticks - self.lastEggTime > 200) { self.isLayingEggs = false; } var nearbyPredators = self.getNearbyFish().filter(function (fish) { return fish.size > self.size && self.distanceTo(fish) < 200; }); if (nearbyPredators.length > 0) { var hidingSpots = self.getNearbyObjects().filter(function (obj) { return obj instanceof Plant; }); if (hidingSpots.length > 0) { var hidingSpot = hidingSpots[Math.floor(Math.random() * hidingSpots.length)]; self.targetRotation = Math.atan2(hidingSpot.y - self.y, hidingSpot.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 20; } } var similarFish = self.getNearbyFish().filter(function (fish) { return fish.constructor === self.constructor; }); if (similarFish.length > 1) { var averageX = similarFish.reduce(function (sum, fish) { return sum + fish.x; }, 0) / similarFish.length; var averageY = similarFish.reduce(function (sum, fish) { return sum + fish.y; }, 0) / similarFish.length; self.targetRotation = Math.atan2(averageY - self.y, averageX - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 30; } if (self.hunger < 20) { var food = self.feedingBehavior.findClosestFood(); if (food) { self.feedingBehavior.eatFood(food); } } if (self.hunger > 50 && !self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) { var potentialMates = self.getNearbyFish().filter(function (fish) { return fish.constructor === self.constructor && fish !== self && fish.hunger > 50; }); if (potentialMates.length > 0) { var mate = potentialMates[Math.floor(Math.random() * potentialMates.length)]; self.matingDance(mate); self.isMating = true; mate.isMating = true; self.lastMateTime = LK.ticks; mate.lastMateTime = LK.ticks; self.mateInterval = Math.random() * 5000 + 3000; mate.mateInterval = Math.random() * 5000 + 3000; } } else if (self.isMating && LK.ticks - self.lastMateTime > 200) { self.isMating = false; } if (!self.isResting && LK.ticks - self.lastRestTime > self.restInterval) { self.isResting = true; self.lastRestTime = LK.ticks; self.restInterval = Math.random() * 3000 + 2000; self.restPosition = { x: self.x, y: self.getWaterBounds().bottom - 50 }; self.targetRotation = Math.atan2(self.restPosition.y - self.y, self.restPosition.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 20; } else if (self.isResting && LK.ticks - self.lastRestTime > 200) { self.isResting = false; self.restAtBottom = function () { if (LK.ticks - self.lastRestTime > self.restInterval) { self.isResting = true; self.lastRestTime = LK.ticks; self.restInterval = Math.random() * 3000 + 2000; self.targetRotation = Math.PI / 2; self.directionChangeTime = LK.ticks; self.directionChangeInterval = 20; } }; self.formSchool = function (similarFish) { var averageX = 0; var averageY = 0; similarFish.forEach(function (fish) { averageX += fish.x; averageY += fish.y; }); averageX /= similarFish.length; averageY /= similarFish.length; self.targetRotation = Math.atan2(averageY - self.y, averageX - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 30; }; self.investigateObject = function (object) { self.targetRotation = Math.atan2(object.y - self.y, object.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; }; self.playWithObject = function (object) { self.targetRotation = Math.atan2(object.y - self.y, object.x - self.x) + Math.random() * Math.PI - Math.PI / 2; self.directionChangeTime = LK.ticks; self.directionChangeInterval = 5; }; self.findLeader = function () { var nearbyFish = self.getNearbyFish(); var leader = nearbyFish.reduce(function (leader, fish) { if (fish !== self && fish.size > self.size && fish.speed > self.speed) { return fish; } return leader; }, null); if (leader) { self.followLeader(leader); } }; self.followLeader = function (leader) { var distanceToLeader = self.distanceTo(leader); if (distanceToLeader > 50) { self.targetRotation = Math.atan2(leader.y - self.y, leader.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; } }; self.evadePredator = function (predator) { var angleToPredator = Math.atan2(predator.y - self.y, predator.x - self.x); self.targetRotation = angleToPredator + Math.PI; self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; }; self.matingDance = function (partner) { if (LK.ticks - self.lastMateTime > self.mateInterval) { self.targetRotation = Math.atan2(partner.y - self.y, partner.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; if (self.distanceTo(partner) < 10) { var egg = new Egg(); egg.x = (self.x + partner.x) / 2; egg.y = (self.y + partner.y) / 2; LK.stageContainer.addChild(egg); self.lastMateTime = LK.ticks; partner.lastMateTime = LK.ticks; self.isMating = false; partner.isMating = false; } } }; self.seekShelter = function () { if (self.health < 30) { var shelters = self.getNearbyObjects().filter(function (obj) { return obj instanceof Plant; }); if (shelters.length > 0) { var closestShelter = shelters.reduce(function (closest, shelter) { var distanceToShelter = self.distanceTo(shelter); return distanceToShelter < self.distanceTo(closest) ? shelter : closest; }, shelters[0]); self.targetRotation = Math.atan2(closestShelter.y - self.y, closestShelter.x - self.x); self.directionChangeTime = LK.ticks; self.directionChangeInterval = 10; } } }; } if (Math.random() < 0.01 && self.canJump) { self.isJumping = true; self.jumpStartTime = LK.ticks; self.jumpDuration = 60; self.jumpHeight = Math.random() * 100 + 50; self.canJump = false; } else if (self.isJumping) { var jumpProgress = (LK.ticks - self.jumpStartTime) / self.jumpDuration; if (jumpProgress < 1) { self.y -= self.jumpHeight * (1 - Math.cos(Math.PI * jumpProgress)); } else { self.isJumping = false; self.canJump = true; } } else { self.bubbleTrail = function () { if (Math.random() < 0.1) { var bubble = new Bubble(); bubble.x = self.x; bubble.y = self.y; LK.stageContainer.addChild(bubble); } }; self.bubbleTrail(); if (!self.velocity) { self.velocity = { x: 0, y: 0 }; self.acceleration = 0.05; } var targetVelocityX = Math.cos(self.rotation) * self.speed; var targetVelocityY = Math.sin(self.rotation) * self.speed; self.velocity.x += (targetVelocityX - self.velocity.x) * self.acceleration; self.velocity.y += (targetVelocityY - self.velocity.y) * self.acceleration; self.x += self.velocity.x; self.y += self.velocity.y; } } if (LK.ticks % 1800 === 0) { self.isSleeping = !self.isSleeping; self.directionChangeTime = LK.ticks; self.directionChangeInterval = self.isSleeping ? 300 : Math.random() * 120 + 60; } } if (LK.ticks % 300 === 0) { self.isResting = !self.isResting; self.directionChangeTime = LK.ticks; self.directionChangeInterval = self.isResting ? 120 : Math.random() * 120 + 60; } var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } self.rotation = self.rotation % (Math.PI * 2); if (Math.cos(self.rotation) < 0) { fishGraphics.scale.x = -1; } else { fishGraphics.scale.x = 1; } fishGraphics.rotation = self.rotation; }; }); var Goldfish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('goldfish', 'Goldfish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.4) * 3; self.move = function () { if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) { self.targetRotation = Math.random() * Math.PI * 2; self.rotationStartTime = LK.ticks; self.rotationDuration = Math.random() * 140 + 80; } var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration; if (progress < 1) { var deltaRotation = (self.targetRotation - self.rotation) * progress; self.rotation += deltaRotation; } else { self.rotation = self.targetRotation; } self.x += Math.cos(self.rotation) * self.speed; self.y += Math.sin(self.rotation) * self.speed; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } self.rotation = self.rotation % (Math.PI * 2); if (Math.cos(self.rotation) < 0) { fishGraphics.scale.x = -1; } else { fishGraphics.scale.x = 1; } fishGraphics.rotation = self.rotation; }; }); var GuppyFish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('guppyFish', 'Guppy Fish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.35) * 3; self.move = function () { if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) { self.targetRotation = Math.random() * Math.PI * 2; self.rotationStartTime = LK.ticks; self.rotationDuration = Math.random() * 100 + 50; } var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration; if (progress < 1) { var deltaRotation = (self.targetRotation - self.rotation) * progress; self.rotation += deltaRotation; } else { self.rotation = self.targetRotation; } self.x += Math.cos(self.rotation) * self.speed; self.y += Math.sin(self.rotation) * self.speed; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } self.rotation = self.rotation % (Math.PI * 2); if (Math.cos(self.rotation) < 0) { fishGraphics.scale.x = -1; } else { fishGraphics.scale.x = 1; } fishGraphics.rotation = self.rotation; }; }); var BettaFish = Fish.expand(function () { var self = Fish.call(this) || this; var fishGraphics = self.createAsset('bettaFish', 'Betta Fish Graphics', .5, .5); fishGraphics.scale.set(1, 1); self.speed = (Math.random() * 0.2 + 0.5) * 3; self.move = function () { if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) { self.targetRotation = Math.random() * Math.PI * 2; self.rotationStartTime = LK.ticks; self.rotationDuration = Math.random() * 150 + 100; } var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration; if (progress < 1) { var deltaRotation = (self.targetRotation - self.rotation) * progress; self.rotation += deltaRotation; } else { self.rotation = self.targetRotation; } self.x += Math.cos(self.rotation) * self.speed; self.y += Math.sin(self.rotation) * self.speed; var waterBounds = self.getWaterBounds(); if (self.x < waterBounds.left || self.x > waterBounds.right) { self.rotation = Math.PI - self.rotation; } if (self.y < waterBounds.top || self.y > waterBounds.bottom) { self.rotation = -self.rotation; } self.rotation = self.rotation % (Math.PI * 2); if (Math.cos(self.rotation) < 0) { fishGraphics.scale.x = -1; } else { fishGraphics.scale.x = 1; } fishGraphics.rotation = self.rotation; }; }); var BubbleCurtain = DecorativePlant.expand(function () { var self = DecorativePlant.call(this) || this; self.bubbleRate = 1000; self.createBubble = function () { var bubble = new RisingBubble(); bubble.x = self.x; bubble.y = self.y; LK.stageContainer.addChild(bubble); }; LK.setInterval(self.createBubble, self.bubbleRate); return self; }); var RisingBubble = Container.expand(function () { var self = Container.call(this); self.liftSpeed = 3; self.on('tick', function () { self.y -= self.liftSpeed; if (self.y < 0) { self.destroy(); } }); self.captureFish = function (fish) { if (!fish.isCaptured && self.intersects(fish)) { fish.isCaptured = true; fish.x = self.x; fish.y = self.y - fish.height / 2; } }; self.releaseFish = function (fish) { if (fish.isCaptured) { fish.isCaptured = false; fish.y += fish.height / 2; } }; }); var CamouflageFish = Fish.expand(function () { var self = Fish.call(this) || this; self.colorChangeRate = 0.1; self.colorChangeThreshold = 200; self.currentEnvironmentColor = 0xFFFFFF; self.changeColorBasedOnEnvironment = function () { var environmentObjects = self.getNearbyObjects().filter(function (obj) { return obj instanceof DecorativePlant || obj instanceof Algae; }); if (environmentObjects.length > 0) { var closestEnvironmentObject = environmentObjects[0]; for (var i = 1; i < environmentObjects.length; i++) { if (self.distanceTo(environmentObjects[i]) < self.distanceTo(closestEnvironmentObject)) { closestEnvironmentObject = environmentObjects[i]; } } if (self.distanceTo(closestEnvironmentObject) < self.colorChangeThreshold) { self.currentEnvironmentColor = closestEnvironmentObject.color; } } self.tint = self.currentEnvironmentColor; }; self.on('tick', function () { self.changeColorBasedOnEnvironment(); }); return self; }); var FishManager = Container.expand(function () { var self = Container.call(this); self.fishTypes = [Fish, KoiFish, Goldfish, GuppyFish, BettaFish, Angelfish, Clownfish, Pufferfish, Surgeonfish]; self.fishes = []; self.spawnFish = function (aquarium) { for (var i = 0; i < self.fishTypes.length; i++) { for (var j = 0; j < 1; j++) { var fish = new self.fishTypes[i](); if (typeof fish.move === 'function') { var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0); var waterBounds = { left: (2048 - waterGraphics.width) / 2, right: (2048 + waterGraphics.width) / 2, top: (2732 - waterGraphics.height) / 2 - 150, bottom: (2732 + waterGraphics.height) / 2 - 150 }; var waterWidth = waterBounds.right - waterBounds.left; var waterHeight = waterBounds.bottom - waterBounds.top; var waterCenterX = waterBounds.left + waterWidth / 2; var waterCenterY = waterBounds.top + waterHeight / 2; var maxDistanceX = waterWidth / 2 * 0.8; var maxDistanceY = waterHeight / 2 * 0.8; var angle = Math.random() * Math.PI * 2; var distanceX = Math.random() * maxDistanceX; var distanceY = Math.random() * maxDistanceY; fish.x = waterCenterX + distanceX * Math.cos(angle); fish.y = waterCenterY + distanceY * Math.sin(angle); self.fishes.push(fish); self.addChild(fish); } } } }; self.manageFish = function () {}; return self; }); var MentorFish = Fish.expand(function () { var self = Fish.call(this) || this; self.intelligenceBoostRate = 0.5; self.boostRange = 250; self.boostIntelligence = function () { var nearbyFish = self.getNearbyFishWithinRange(self.boostRange); nearbyFish.forEach(function (fish) { if (!(fish instanceof MentorFish)) { fish.intelligenceLevel += self.intelligenceBoostRate; } }); }; self.on('tick', function () { self.boostIntelligence(); }); return self; }); var CleanerFish = Fish.extend(function () { var self = Fish.call(this) || this; self.cleaningRate = 0.2; self.eatAlgae = function () { var algae = self.getNearbyObjects().filter(function (obj) { return obj instanceof Algae; }); algae.forEach(function (algae) { if (self.distanceTo(algae) < 50) { algae.consume(self); } }); }; self.on('tick', function () { self.eatAlgae(); }); return self; }); var DistractingFish = Fish.extend(function () { var self = Fish.call(this) || this; self.distractRange = 200; self.distractPredators = function () { var predators = self.getNearbyFish().filter(function (fish) { return fish.size > self.size; }); predators.forEach(function (predator) { if (self.distanceTo(predator) < self.distractRange) { predator.targetRotation = Math.atan2(self.y - predator.y, self.x - predator.x); } }); }; self.on('tick', function () { self.distractPredators(); }); return self; }); Fish.prototype.updateColorBasedOnHealth = function () { if (this.health < 30) { this.tint = 0xFF6347; } else if (this.health < 70) { this.tint = 0xFFFF00; } else { this.tint = 0x32CD32; } }; Fish.prototype.increaseSpeed = function (speedMultiplier, duration) { var originalSpeed = this.speed; this.speed *= speedMultiplier; var self = this; LK.setTimeout(function () { self.speed = originalSpeed; }, duration); }; Fish.prototype.getNearbyFishWithinRange = function (range) { var nearbyFish = []; LK.stageContainer.children.forEach(function (child) { if (child instanceof Fish && child !== this) { var distance = this.distanceTo(child); if (distance < range) { nearbyFish.push(child); } } }, this); return nearbyFish; }; var Game = Container.expand(function () { var self = Container.call(this); var aquariumEnvironmentManager = self.addChild(new AquariumEnvironmentManager()); aquariumEnvironmentManager.createEnvironment(); var fishManager = self.addChild(new FishManager()); fishManager.spawnFish(aquariumEnvironmentManager); LK.stageContainer.setBackgroundColor(0x008080); LK.on('tick', function () { fishManager.manageFish(); }); });
var InflatableFish = Container.expand(function () {
var self = Container.call(this);
self.inflationSize = 2;
self.inflationDuration = 3000;
self.isInflated = false;
self.inflate = function () {
if (!self.isInflated) {
self.isInflated = true;
self.scale.x *= self.inflationSize;
self.scale.y *= self.inflationSize;
LK.setTimeout(function () {
self.scale.x /= self.inflationSize;
self.scale.y /= self.inflationSize;
self.isInflated = false;
}, self.inflationDuration);
}
};
self.on('tick', function () {
self.inflate();
});
return self;
});
var SchoolLeaderFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.schoolingRange = 300;
self.attractFishToSchool = function () {
var nearbyFish = self.getNearbyFishWithinRange(self.schoolingRange);
nearbyFish.forEach(function (fish) {
if (fish.constructor !== SchoolLeaderFish) {
fish.targetRotation = Math.atan2(self.y - fish.y, self.x - fish.x);
}
});
};
self.on('tick', function () {
self.attractFishToSchool();
});
return self;
});
var StealthFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.stealthMode = false;
self.stealthDuration = 5000;
self.toggleStealthMode = function () {
self.stealthMode = !self.stealthMode;
self.alpha = self.stealthMode ? 0.1 : 1.0;
};
LK.setInterval(self.toggleStealthMode, self.stealthDuration);
return self;
});
var JumpingFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.jumpHeight = 150;
self.jumpFrequency = 10000;
self.isJumping = false;
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
var initialY = self.y;
LK.setTimeout(function () {
self.y = initialY - self.jumpHeight;
LK.setTimeout(function () {
self.y = initialY;
self.isJumping = false;
}, 1000);
}, self.jumpFrequency);
}
};
self.on('tick', function () {
self.jump();
});
return self;
});
var BubbleShieldFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.shieldBubbleRate = 5000;
self.shieldBubbleSize = 100;
self.createShieldBubble = function () {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
bubble.width = self.shieldBubbleSize;
bubble.height = self.shieldBubbleSize;
LK.stageContainer.addChild(bubble);
};
LK.setInterval(self.createShieldBubble, self.shieldBubbleRate);
return self;
});
var DecorativePlant = Container.expand(function () {
var self = Container.call(this);
return self;
});
var InteractiveElement = Container.expand(function () {
var self = Container.call(this);
self.interact = function () {};
self.performInteraction = function () {
self.interact();
};
});
var TreasureChest = InteractiveElement.expand(function () {
var self = InteractiveElement.call(this) || this;
var chestGraphics = self.createAsset('treasureChest', 'Treasure Chest Graphics', 0.5, 0.5);
self.isOpen = false;
self.coinReleaseRate = 3;
self.releaseCoins = function () {
if (self.isOpen) {
for (var i = 0; i < self.coinReleaseRate; i++) {
var coin = new Coin();
coin.x = self.x;
coin.y = self.y;
LK.stageContainer.addChild(coin);
}
}
};
self.interact = function () {
self.isOpen = !self.isOpen;
chestGraphics.texture = LK.getAsset(self.isOpen ? 'chestOpen' : 'chestClosed', 'Chest Graphics', 0.5, 0.5).texture;
self.releaseCoins();
};
LK.setInterval(self.performInteraction, 10000);
return self;
});
var IntelligentFish = Container.expand(function () {
var self = Container.call(this);
self.intelligenceLevel = 10;
self.avoidPredators = function () {
var predators = self.getNearbyFish().filter(function (otherFish) {
return otherFish.size > self.size && self.distanceTo(otherFish) < 300;
});
if (predators.length > 0) {
var escapeVector = {
x: 0,
y: 0
};
predators.forEach(function (predator) {
var angle = Math.atan2(self.y - predator.y, self.x - predator.x);
escapeVector.x += Math.cos(angle);
escapeVector.y += Math.sin(angle);
});
self.targetRotation = Math.atan2(escapeVector.y, escapeVector.x);
}
};
self.seekFood = function () {
var foodSources = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Food;
});
if (foodSources.length > 0) {
var closestFood = foodSources[0];
for (var i = 1; i < foodSources.length; i++) {
if (self.distanceTo(foodSources[i]) < self.distanceTo(closestFood)) {
closestFood = foodSources[i];
}
}
self.targetRotation = Math.atan2(closestFood.y - self.y, closestFood.x - self.x);
}
};
return self;
});
var FoodSpawningFish = IntelligentFish.expand(function () {
var self = IntelligentFish.call(this) || this;
self.foodReleaseRate = 5;
self.releaseFood = function () {
var food = new Food();
food.x = self.x;
food.y = self.y;
LK.stageContainer.addChild(food);
var nearbyFish = self.getNearbyFishWithinRange(500);
nearbyFish.forEach(function (fish) {
fish.rushToFood(food);
});
};
LK.setInterval(self.releaseFood, 10000);
return self;
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
return self;
});
var CapturingBubble = Bubble.expand(function () {
var self = Bubble.call(this) || this;
self.captureFish = function (fish) {
if (fish instanceof Fish && !fish.isCaptured && self.intersects(fish)) {
fish.isCaptured = true;
fish.x = self.x;
fish.y = self.y - fish.height / 2;
fish.alpha = 0.5;
}
};
self.releaseFish = function (fish) {
if (fish.isCaptured) {
fish.isCaptured = false;
fish.y += fish.height / 2;
fish.alpha = 1.0;
}
};
self.on('tick', function () {
self.y -= self.liftSpeed;
if (self.y < 0) {
if (fish.isCaptured) {
self.releaseFish(fish);
}
self.destroy();
}
});
return self;
});
var BubbleProducingFish = Container.expand(function () {
var self = Container.call(this);
self.bubbleReleaseRate = 5;
self.releaseBubbles = function () {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
var nearbyFish = self.getNearbyFishWithinRange(500);
nearbyFish.forEach(function (fish) {
if (!fish.isCaptured) {
fish.isCaptured = true;
fish.y -= 10;
}
});
};
LK.setInterval(self.releaseBubbles, 10000);
return self;
});
var AquariumDecorator = Container.expand(function () {
var self = Container.call(this);
self.decorate = function () {};
self.updateDecoration = function () {};
});
var HidingCastle = AquariumDecorator.expand(function () {
var self = AquariumDecorator.call(this);
self.castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);
self.castleGraphics.width = 300;
self.castleGraphics.height = 400;
self.x = 1024;
self.y = 2732 - self.castleGraphics.height / 2;
self.provideHiding = function (fish) {
if (fish.size < 30 && self.distanceTo(fish) < 100) {
fish.isHidden = true;
fish.alpha = 0.5;
} else {
fish.isHidden = false;
fish.alpha = 1.0;
}
};
return self;
});
var HidingBehavior = Container.expand(function () {
var self = Container.call(this);
self.hide = function (fish, castle) {
if (fish.size < 30 && fish.distanceTo(castle) < 100 && fish.isPredatorNearby()) {
fish.isHidden = true;
fish.alpha = 0.5;
} else {
fish.isHidden = false;
fish.alpha = 1.0;
}
};
self.isPredatorNearby = function (fish) {
var nearbyPredators = fish.getNearbyFish().filter(function (otherFish) {
return otherFish.size > fish.size && fish.distanceTo(otherFish) < 200;
});
return nearbyPredators.length > 0;
};
});
var Fish = Container.expand(function () {
var self = Container.call(this);
self.speed = 2;
self.direction = Math.random() * Math.PI * 2;
self.move = function () {
var newX = self.x + Math.cos(self.direction) * self.speed;
var newY = self.y + Math.sin(self.direction) * self.speed;
var bounds = self.getWaterBounds();
newX = Math.max(bounds.left, Math.min(newX, bounds.right));
newY = Math.max(bounds.top, Math.min(newY, bounds.bottom));
self.x = newX;
self.y = newY;
};
self.on('tick', function () {
self.move();
});
self.rushToFood = function (food) {
self.targetRotation = Math.atan2(food.y - self.y, food.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 5;
};
self.hunger = 100;
Fish.prototype.restingBehavior = new RestingBehavior();
Fish.prototype.reproductionBehavior = new ReproductionBehavior();
self.hungerDecayRate = 0.1;
Fish.prototype.feedingBehavior = new FeedingBehavior();
self.updateHunger = function () {
var closestFood = self.feedingBehavior.findClosestFood();
if (closestFood && self.distanceTo(closestFood) <= self.feedingBehavior.feedingRange) {
self.feedingBehavior.eatFood(closestFood);
self.hunger += closestFood.nutrition;
}
self.hunger -= self.hungerDecayRate;
if (self.hunger <= 0) {
self.health -= self.hungerDecayRate;
if (self.health <= 0) {
self.die();
}
}
self.hunger = Math.max(self.hunger, 0);
self.hunger = Math.min(self.hunger, 100);
};
self.greetFish = function (otherFish) {
if (!self.memory.includes(otherFish)) {
self.targetRotation = Math.atan2(otherFish.y - self.y, otherFish.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 5;
self.rememberObject(otherFish);
}
};
Fish.prototype.playfulBehavior = new PlayfulBehavior();
self.memory = [];
self.rememberObject = function (target) {
if (!self.memory.includes(target)) {
self.memory.push(target);
}
};
Fish.prototype.foragingBehavior = new ForagingBehavior();
self.forgetObject = function (target) {
var index = self.memory.indexOf(target);
if (index > -1) {
self.memory.splice(index, 1);
}
};
self.getNearbyObjects = function () {
var nearbyObjects = [];
LK.stageContainer.children.forEach(function (child) {
if (!(child instanceof Fish) && child !== self) {
var dx = child.x - self.x;
var dy = child.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
nearbyObjects.push(child);
}
}
});
return nearbyObjects;
};
self.findCuriosityTarget = function () {
var possibleTargets = self.getNearbyObjects();
if (possibleTargets.length > 0) {
self.curiosityTarget = possibleTargets[Math.floor(Math.random() * possibleTargets.length)];
}
};
self.investigateCuriosity = function (target) {
self.targetRotation = Math.atan2(target.y - self.y, target.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
};
self.distanceTo = function (target) {
var dx = target.x - self.x;
var dy = target.y - self.y;
return Math.sqrt(dx * dx + dy * dy);
};
Fish.prototype.evasionBehavior = new EvasionBehavior();
Fish.prototype.leadershipBehavior = new LeadershipBehavior();
self.findMate = function (nearbyFish) {
var potentialMate = null;
var minDistance = Infinity;
nearbyFish.forEach(function (fish) {
if (fish.constructor === self.constructor && fish !== self && !fish.isMating) {
var distance = self.distanceTo(fish);
if (distance < minDistance) {
minDistance = distance;
potentialMate = fish;
}
}
});
if (potentialMate && minDistance < 100) {
self.isMating = true;
potentialMate.isMating = true;
var egg = new Egg();
egg.x = (self.x + potentialMate.x) / 2;
egg.y = (self.y + potentialMate.y) / 2;
LK.stageContainer.addChild(egg);
}
};
self.evadeLargerFish = function (largerFish) {};
self.getNearbyFish = function () {
var nearbyFish = [];
LK.stageContainer.children.forEach(function (child) {
if (child instanceof Fish && child !== self) {
var dx = child.x - self.x;
var dy = child.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
nearbyFish.push(child);
}
}
});
return nearbyFish;
};
self.avoidObstacles = function (obstacles) {
if (obstacles.length > 0) {
var sumAngles = 0;
var count = 0;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var angleToObstacle = Math.atan2(obstacle.y - self.y, obstacle.x - self.x);
sumAngles += angleToObstacle + Math.PI;
count++;
}
if (count > 0) {
var averageAvoidAngle = sumAngles / count;
self.targetRotation = averageAvoidAngle;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = Math.random() * 50 + 30;
}
}
};
self.isPathBlocked = function (newX, newY, obstacles) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var dx = obstacle.x - newX;
var dy = obstacle.y - newY;
if (Math.sqrt(dx * dx + dy * dy) < obstacle.radius + self.radius) {
return true;
}
}
return false;
};
Fish.prototype.mortalityBehavior = new MortalityBehavior();
self.getNearbyObstacles = function () {
var nearbyObstacles = [];
LK.stageContainer.children.forEach(function (child) {
if (typeof Obstacle !== 'undefined' && child instanceof Obstacle) {
var dx = child.x - self.x;
var dy = child.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 300) {
nearbyObstacles.push(child);
}
}
});
return nearbyObstacles;
};
this.getWaterBounds = function () {
var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0);
return {
left: (2048 - waterGraphics.width) / 2,
right: (2048 + waterGraphics.width) / 2,
top: (2732 - waterGraphics.height) / 2 - 150,
bottom: (2732 + waterGraphics.height) / 2 - 150
};
};
});
var Lighting = Container.expand(function () {
var self = Container.call(this);
self.light = function () {};
});
var AquariumLighting = Lighting.expand(function () {
var self = Lighting.call(this) || this;
var lightingGraphics = self.createAsset('aquariumLighting', 'Aquarium Lighting Graphics', 0.5, 0.5);
self.dayDuration = 18000;
self.nightDuration = 12000;
self.isDaytime = true;
self.lastChangeTime = LK.ticks;
self.lightingBehavior = new LightingBehavior();
self.update = function () {
self.lightingBehavior.updateLighting(self, lightingGraphics);
};
});
var LightingBehavior = Container.expand(function () {
var self = Container.call(this);
self.updateLighting = function (lighting, graphics) {
if (lighting.isDaytime && LK.ticks - lighting.lastChangeTime > lighting.dayDuration) {
lighting.isDaytime = false;
lighting.lastChangeTime = LK.ticks;
graphics.alpha = 0.3;
} else if (!lighting.isDaytime && LK.ticks - lighting.lastChangeTime > lighting.nightDuration) {
lighting.isDaytime = true;
lighting.lastChangeTime = LK.ticks;
graphics.alpha = 1;
}
};
});
var AquariumLifeManager = Container.expand(function () {
var self = Container.call(this);
self.lifeForms = [];
self.addLifeForm = function (lifeForm) {
self.lifeForms.push(lifeForm);
self.addChild(lifeForm);
};
self.updateLifeForms = function () {
for (var i = 0; i < self.lifeForms.length; i++) {
if (typeof self.lifeForms[i].update === 'function') {
self.lifeForms[i].update();
}
}
};
});
var Cleaner = Container.expand(function () {
var self = Container.call(this);
self.clean = function () {};
});
var CleaningRobot = Container.expand(function () {
var self = Container.call(this);
self.speed = 0.2;
self.cleaningRate = 1;
self.cleaningBehavior = new CleaningBehavior();
self.moveAndClean = function () {
var dirtyObjects = self.cleaningBehavior.findDirtyObjects();
dirtyObjects.forEach(function (obj) {
self.x += (obj.x - self.x) * self.speed;
self.y += (obj.y - self.y) * self.speed;
if (self.distanceTo(obj) < 50) {
self.cleaningBehavior.cleanObject(obj, self.cleaningRate);
}
});
};
LK.setInterval(self.moveAndClean, 1000);
return self;
});
var CleaningBehavior = Container.expand(function () {
var self = Container.call(this);
self.findDirtyObjects = function () {
var dirtyObjects = [];
LK.stageContainer.children.forEach(function (child) {
if (child.isDirty && child.clean) {
dirtyObjects.push(child);
}
});
return dirtyObjects;
};
self.cleanObject = function (obj, rate) {
obj.clean(rate);
};
});
var AquariumDecoratorManager = Container.expand(function () {
var self = Container.call(this);
self.decorators = [];
self.addDecorator = function (decorator) {
self.decorators.push(decorator);
self.addChild(decorator);
};
self.removeDecorator = function (decorator) {
var index = self.decorators.indexOf(decorator);
if (index !== -1) {
self.decorators.splice(index, 1);
decorator.destroy();
}
};
self.updateDecorators = function () {
for (var i = 0; i < self.decorators.length; i++) {
if (typeof self.decorators[i].update === 'function') {
self.decorators[i].update();
}
}
};
});
var InteractiveDecoration = InteractiveElement.expand(function () {
var self = InteractiveElement.call(this) || this;
self.isActive = false;
self.activate = function () {
self.isActive = true;
};
self.deactivate = function () {
self.isActive = false;
};
self.interactWithFish = function (fish) {
if (self.isActive) {}
};
});
var GrowingPlant = DecorativePlant.expand(function () {
var self = DecorativePlant.call(this) || this;
self.growthRate = 0.01;
self.maxScale = 5;
self.on('tick', function () {
if (self.scale.x < self.maxScale) {
self.scale.x += self.growthRate;
self.scale.y += self.growthRate;
}
});
self.consume = function (fish) {
if (fish instanceof Fish && self.distanceTo(fish) < 100) {
fish.health = Math.min(fish.health + self.healthValue, 100);
self.destroy();
}
};
return self;
});
var HealingFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.healingRate = 0.05;
self.healingRange = 150;
self.healNearbyFish = function () {
var nearbyFish = self.getNearbyFishWithinRange(self.healingRange);
nearbyFish.forEach(function (fish) {
if (fish.health < 100) {
fish.health += self.healingRate;
}
});
};
self.on('tick', function () {
self.healNearbyFish();
});
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.createAsset('coin', 'Coin Graphics', 0.5, 0.5);
self.value = 1;
self.collect = function (fish) {
if (self.intersects(fish)) {
LK.setScore(LK.getScore() + self.value);
self.destroy();
}
};
self.on('tick', function () {
self.collect(fish);
});
return self;
});
var Algae = Container.expand(function () {
var self = Container.call(this);
var algaeGraphics = self.createAsset('algae', 'Algae Graphics', 0.5, 1);
self.growthRate = 0.01;
self.nutritionValue = 5;
self.healthValue = 2;
self.on('tick', function () {
algaeGraphics.scale.x += self.growthRate;
algaeGraphics.scale.y += self.growthRate;
if (algaeGraphics.scale.x > 3) {
algaeGraphics.scale.x = 3;
algaeGraphics.scale.y = 3;
}
});
self.consume = function (fish) {
if (self.distanceTo(fish) < 50) {
fish.hunger = Math.min(fish.hunger + self.nutritionValue, 100);
fish.health = Math.min(fish.health + self.healthValue, 100);
self.destroy();
}
};
return self;
});
var MovingFood = Container.expand(function () {
var self = Container.call(this);
self.speed = 1;
self.move = function () {
var waterBounds = self.getWaterBounds();
self.x += (Math.random() - 0.5) * self.speed;
self.y += (Math.random() - 0.5) * self.speed;
self.x = Math.max(waterBounds.left, Math.min(self.x, waterBounds.right));
self.y = Math.max(waterBounds.top, Math.min(self.y, waterBounds.bottom));
};
self.on('tick', function () {
self.move();
});
});
var Food = Container.expand(function () {
var self = Container.call(this);
return self;
});
var SpeedyFood = Food.expand(function () {
var self = Food.call(this) || this;
self.nutrition = 10;
self.speedBoost = 1.5;
self.boostDuration = 5000;
self.consume = function (fish) {
if (fish instanceof Fish) {
fish.increaseSpeed(self.speedBoost, self.boostDuration);
}
Food.prototype.consume.call(this, fish);
};
return self;
});
var SmartFood = Food.expand(function () {
var self = Food.call(this) || this;
self.nutrition = 20;
self.intelligenceBoost = 2;
self.consume = function (fish) {
if (fish instanceof IntelligentFish) {
fish.intelligenceLevel += self.intelligenceBoost;
}
Food.prototype.consume.call(this, fish);
};
});
var SpeedFood = Food.expand(function () {
var self = Food.call(this) || this;
self.nutrition = 15;
self.speedIncrease = 1.5;
self.effectDuration = 5000;
self.consume = function (fish) {
Fish.prototype.increaseSpeed.call(fish, self.speedIncrease, self.effectDuration);
Food.prototype.consume.call(this, fish);
};
});
var FastFood = Food.expand(function () {
var self = Food.call(this) || this;
self.nutrition = 30;
self.speed = 2;
self.moveRandomly = function () {
var waterBounds = self.getWaterBounds();
self.x += (Math.random() - 0.5) * self.speed;
self.y += (Math.random() - 0.5) * self.speed;
self.x = Math.max(waterBounds.left, Math.min(self.x, waterBounds.right));
self.y = Math.max(waterBounds.top, Math.min(self.y, waterBounds.bottom));
};
self.on('tick', function () {
self.moveRandomly();
});
});
var VariableBubbleStream = Container.expand(function () {
var self = Container.call(this);
self.minBubbleRate = 500;
self.maxBubbleRate = 1500;
self.createBubble = function () {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
};
self.startBubbleStream = function () {
var bubbleRate = self.minBubbleRate + Math.random() * (self.maxBubbleRate - self.minBubbleRate);
LK.setInterval(self.createBubble, bubbleRate);
};
self.startBubbleStream();
return self;
});
var Egg = Container.expand(function () {
var self = Container.call(this);
var eggGraphics = self.createAsset('egg', 'Egg Graphics', 0.5, 0.5);
self.hatchTime = LK.ticks + Math.random() * 3000 + 2000;
self.on('tick', function () {
if (LK.ticks > self.hatchTime) {
var babyFish = new Fish();
babyFish.x = self.x;
babyFish.y = self.y;
LK.stageContainer.addChild(babyFish);
self.destroy();
}
});
});
var FishFeeder = InteractiveDecoration.expand(function () {
var self = InteractiveDecoration.call(this) || this;
self.feedingRate = 5000;
self.feed = function () {
if (self.isActive) {
var food = new Food();
food.x = 1024;
food.y = 1366;
LK.stageContainer.addChild(food);
var nearbyFish = self.getNearbyFishWithinRange(500);
nearbyFish.forEach(function (fish) {
fish.rushToFood(food);
});
}
};
LK.setInterval(self.feed, self.feedingRate);
self.activate();
return self;
});
var IntelligentFishBehavior = Container.expand(function () {
var self = Container.call(this);
self.intelligenceLevel = 5;
self.avoidPredators = function (fish) {
var predators = fish.getNearbyFish().filter(function (otherFish) {
return otherFish.size > fish.size && fish.distanceTo(otherFish) < 200;
});
if (predators.length > 0) {
var escapeVector = {
x: 0,
y: 0
};
predators.forEach(function (predator) {
var angle = Math.atan2(fish.y - predator.y, fish.x - predator.x);
escapeVector.x += Math.cos(angle);
escapeVector.y += Math.sin(angle);
});
fish.targetRotation = Math.atan2(escapeVector.y, escapeVector.x);
}
};
self.seekFood = function (fish) {
var foodSources = fish.getNearbyObjects().filter(function (obj) {
return obj instanceof Food;
});
if (foodSources.length > 0) {
var closestFood = foodSources[0];
for (var i = 1; i < foodSources.length; i++) {
if (fish.distanceTo(foodSources[i]) < fish.distanceTo(closestFood)) {
closestFood = foodSources[i];
}
}
fish.targetRotation = Math.atan2(closestFood.y - fish.y, closestFood.x - fish.x);
}
};
return self;
});
var PredatorFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.predatorGraphics = self.createAsset('predatorFish', 'Predator Fish Graphics', 0.5, 0.5);
self.speed = 3;
self.huntRange = 300;
self.hunt = function () {
var nearbyPrey = self.getNearbyFish().filter(function (fish) {
return fish.size < self.size && fish.health > 0;
});
if (nearbyPrey.length > 0) {
var prey = nearbyPrey[0];
for (var i = 1; i < nearbyPrey.length; i++) {
if (self.distanceTo(nearbyPrey[i]) < self.distanceTo(prey)) {
prey = nearbyPrey[i];
}
}
if (self.distanceTo(prey) < self.huntRange) {
self.targetRotation = Math.atan2(prey.y - self.y, prey.x - self.x);
prey.health -= 2;
if (prey.health <= 0) {
prey.destroy();
}
}
}
};
self.on('tick', self.hunt);
return self;
});
var RestingBehavior = Container.expand(function () {
var self = Container.call(this);
self.isResting = false;
self.lastRestTime = LK.ticks;
self.restInterval = Math.random() * 3000 + 2000;
self.rest = function (fish) {
if (!self.isResting && Math.random() < 0.05) {
self.isResting = true;
self.lastRestTime = LK.ticks;
self.restInterval = Math.random() * 5000 + 10000;
fish.targetRotation = Math.PI / 2;
fish.y = fish.getWaterBounds().bottom - 50;
} else if (self.isResting && LK.ticks - self.lastRestTime > self.restInterval) {
self.isResting = false;
}
};
return self;
});
var ReproductionBehavior = Container.expand(function () {
var self = Container.call(this);
self.isMating = false;
self.lastMateTime = LK.ticks;
self.mateInterval = Math.random() * 5000 + 3000;
self.isLayingEggs = false;
self.lastEggTime = LK.ticks;
self.eggInterval = Math.random() * 3000 + 2000;
self.mate = function (fish, partner) {
if (!self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) {
self.isMating = true;
partner.isMating = true;
self.lastMateTime = LK.ticks;
partner.lastMateTime = LK.ticks;
var egg = new Egg();
egg.x = (fish.x + partner.x) / 2;
egg.y = (fish.y + partner.y) / 2;
LK.stageContainer.addChild(egg);
} else if (self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) {
self.isMating = false;
partner.isMating = false;
}
};
self.layEggs = function (fish) {
if (!self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval) {
self.isLayingEggs = true;
self.lastEggTime = LK.ticks;
var egg = new Egg();
egg.x = fish.x;
egg.y = fish.y;
LK.stageContainer.addChild(egg);
} else if (self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval) {
self.isLayingEggs = false;
}
};
return self;
});
var FeedingBehavior = Container.expand(function () {
var self = Container.call(this);
self.hunger = 100;
self.lastFoodTime = 0;
self.feedingRange = 50;
self.eatFood = function (food) {
if (self.distanceTo(food) < self.feedingRange && (food instanceof Food || food instanceof Algae)) {
self.hunger = Math.min(self.hunger + food.nutrition, 100);
food.consume();
self.lastFoodLocation = {
x: food.x,
y: food.y
};
self.lastFoodTime = LK.ticks;
}
};
self.updateHunger = function () {
self.hunger -= self.hungerDecayRate;
if (self.hunger <= 0) {
self.die();
}
};
self.findClosestFood = function () {
var closestFood = null;
var closestDistance = Infinity;
LK.stageContainer.children.forEach(function (child) {
if (child instanceof Food) {
var distance = self.distanceTo(child);
if (distance < closestDistance) {
closestDistance = distance;
closestFood = child;
}
}
});
return closestFood;
};
return self;
});
var PlayfulBehavior = Container.expand(function () {
var self = Container.call(this);
PlayfulBehavior.prototype.playWithObject = function (fish, target) {
fish.targetRotation = Math.atan2(target.y - fish.y, target.x - fish.x) + Math.random() * Math.PI - Math.PI / 2;
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 5;
};
self.playWithObject = function (fish, target) {
fish.targetRotation = Math.atan2(target.y - fish.y, target.x - fish.x) + Math.random() * Math.PI - Math.PI / 2;
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 5;
};
});
var ForagingBehavior = Container.expand(function () {
var self = Container.call(this);
self.findClosestFood = function (fish) {
var closestFood = null;
var closestDistance = Infinity;
LK.stageContainer.children.forEach(function (child) {
if (child instanceof Food) {
var distance = fish.distanceTo(child);
if (distance < closestDistance) {
closestDistance = distance;
closestFood = child;
}
}
});
return closestFood;
};
});
var SchoolingBehavior = Container.expand(function () {
var self = Container.call(this);
self.schoolWith = function (fish, similarFish) {
if (similarFish.length > 1) {
var schoolCenterX = similarFish.reduce((sum, fish) => sum + fish.x, 0) / similarFish.length;
var schoolCenterY = similarFish.reduce((sum, fish) => sum + fish.y, 0) / similarFish.length;
fish.targetRotation = Math.atan2(schoolCenterY - fish.y, schoolCenterX - fish.x);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 30;
}
};
return self;
});
var EvasionBehavior = Container.expand(function () {
var self = Container.call(this);
self.evadePredators = function (fish, predators) {
if (predators.length > 0) {
var evadeAngle = predators.reduce(function (sum, predator) {
var angleToPredator = Math.atan2(predator.y - fish.y, predator.x - fish.x);
return sum + angleToPredator + Math.PI;
}, 0) / predators.length;
fish.targetRotation = evadeAngle + (Math.random() * Math.PI - Math.PI / 2);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 10;
}
};
return self;
});
var LeadershipBehavior = Container.expand(function () {
var self = Container.call(this);
self.followLeader = function (fish, leaderFish) {
var followDistance = 50;
var distance = fish.distanceTo(leaderFish);
if (distance > followDistance) {
fish.targetRotation = Math.atan2(leaderFish.y - fish.y, leaderFish.x - fish.x);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 10;
}
};
return self;
});
var MortalityBehavior = Container.expand(function () {
var self = Container.call(this);
self.die = function (fish) {
if (fish.health <= 0) {
fish.destroy();
}
};
return self;
});
var Surgeonfish = Fish.expand(function () {
var self = Fish.call(this) || this;
Surgeonfish.prototype.findNearestCleaner = function () {
var nearestCleaner = null;
var nearestDistance = Infinity;
LK.stageContainer.children.forEach((function (child) {
if (child instanceof AquariumCleaner) {
var distance = this.distanceTo(child);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestCleaner = child;
}
}
}).bind(this));
return nearestCleaner;
};
var fishGraphics = self.createAsset('surgeonfish', 'Surgeonfish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.5) * 6;
self.move = function () {
if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) {
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = Math.random() * 120 + 60;
if (Math.random() < 0.1) {
self.targetRotation = Math.random() * Math.PI * 2;
}
}
var cleaner = self.findNearestCleaner();
if (cleaner && self.distanceTo(cleaner) < 200) {
self.targetRotation = Math.atan2(self.y - cleaner.y, self.x - cleaner.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
}
var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval;
if (progress < 1) {
var rotationSpeed = 0.05;
var rotationDifference = self.targetRotation - self.rotation;
if (rotationDifference > Math.PI) rotationDifference -= Math.PI * 2;
if (rotationDifference < -Math.PI) rotationDifference += Math.PI * 2;
self.rotation += Math.sign(rotationDifference) * Math.min(Math.abs(rotationDifference), rotationSpeed);
} else {
self.rotation = self.targetRotation;
}
var newX = self.x + Math.cos(self.rotation) * self.speed;
var newY = self.y + Math.sin(self.rotation) * self.speed;
var obstacles = self.getNearbyObstacles();
var nearbyFish = self.getNearbyFish();
var overcrowdingThreshold = 5;
if (nearbyFish.length > overcrowdingThreshold) {
var averageX = 0;
var averageY = 0;
nearbyFish.forEach(function (fish) {
averageX += fish.x;
averageY += fish.y;
});
averageX /= nearbyFish.length;
averageY /= nearbyFish.length;
self.targetRotation = Math.atan2(self.y - averageY, self.x - averageX);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
}
nearbyFish.forEach(function (otherFish) {
if (self.distanceTo(otherFish) < self.radius + otherFish.radius) {
var angleBetween = Math.atan2(otherFish.y - self.y, otherFish.x - self.x);
self.targetRotation = angleBetween + Math.PI;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
}
});
if (self.isPathBlocked(newX, newY, obstacles)) {
var leaderFish = self.findLeaderFish(nearbyFish);
if (leaderFish) {
self.followLeader(leaderFish);
} else {
self.avoidObstacles(obstacles);
}
} else if (nearbyFish.some(fish => fish.size > self.size)) {
var predators = nearbyFish.filter(fish => fish.size > self.size);
if (predators.length > 0) {
self.isFleeing = true;
predators.forEach(function (predator) {
self.rememberObject(predator);
});
self.evadePredators(predators);
if (self.isFleeing) {
var predators = self.getNearbyFish().filter(function (fish) {
return fish.size > self.size;
});
if (predators.length > 0) {
var hidingSpots = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Plant;
});
if (hidingSpots.length > 0) {
var hidingSpot = hidingSpots[Math.floor(Math.random() * hidingSpots.length)];
self.targetRotation = Math.atan2(hidingSpot.y - self.y, hidingSpot.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 20;
}
}
}
} else {
if (self.isFleeing && LK.ticks - self.directionChangeTime > 300) {
self.isFleeing = false;
self.memory = self.memory.filter(function (obj) {
return !(obj instanceof Fish);
});
}
}
} else if (nearbyFish.length > 0) {
var similarFish = nearbyFish.filter(fish => fish.constructor === self.constructor);
if (similarFish.length > 1) {
var schoolCenterX = similarFish.reduce((sum, fish) => sum + fish.x, 0) / similarFish.length;
var schoolCenterY = similarFish.reduce((sum, fish) => sum + fish.y, 0) / similarFish.length;
self.targetRotation = Math.atan2(schoolCenterY - self.y, schoolCenterX - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
}
var similarFish = nearbyFish.filter(fish => fish.constructor === self.constructor);
self.schoolWith(similarFish);
} else if (self.curiosityTarget && self.distanceTo(self.curiosityTarget) < 100) {
self.rememberObject(self.curiosityTarget);
} else {
self.x = newX;
self.y = newY;
if (self.hunger > 70 && Math.random() < 0.05) {
self.restingBehavior.rest(self);
} else if (self.hunger < 30 || self.hunger > 70 && Math.random() < 0.1) {
var food;
if (self.lastFoodLocation && LK.ticks - self.lastFoodTime > 3000) {
food = self.lastFoodLocation;
} else {
food = self.foragingBehavior.findClosestFood(self);
}
if (food) {
self.targetRotation = Math.atan2(food.y - self.y, food.x - self.x);
} else {
if (Math.random() < 0.05) {
var toys = self.getNearbyObjects().filter(function (obj) {
return !(obj instanceof Food) && !(obj instanceof Fish);
});
if (toys.length > 0) {
var toy = toys[Math.floor(Math.random() * toys.length)];
self.playfulBehavior.playWithObject(self, toy);
}
} else {
if (Math.random() < 0.1) {
self.findCuriosityTarget();
if (self.curiosityTarget) {
self.investigateCuriosity(self.curiosityTarget);
}
}
}
}
} else {
self.findCuriosityTarget();
}
}
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
if (self.isMating) {
fishGraphics.tint = 0xFF69B4;
} else if (self.isResting) {
fishGraphics.tint = 0xADD8E6;
self.rest();
} else {
fishGraphics.tint = 0xFFFFFF;
}
self.rest = function () {
if (LK.ticks - self.lastRestTime > self.restInterval) {
self.isResting = false;
} else if (!self.isResting && Math.random() < 0.05) {
self.isResting = true;
self.lastRestTime = LK.ticks;
self.restInterval = Math.random() * 5000 + 10000;
self.targetRotation = Math.PI / 2;
self.y = self.getWaterBounds().bottom - 50;
}
};
fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1;
fishGraphics.rotation = self.rotation;
};
});
var Pufferfish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('pufferfish', 'Pufferfish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.4) * 9;
self.move = function () {
if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) {
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = Math.random() * 140 + 80;
self.targetRotation = Math.random() * Math.PI * 2;
}
var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval;
if (progress < 1) {
self.rotation += (self.targetRotation - self.rotation) * progress;
} else {
self.rotation = self.targetRotation;
}
var tentativeX = self.x + Math.cos(self.rotation) * self.speed;
var tentativeY = self.y + Math.sin(self.rotation) * self.speed;
var waterBounds = self.getWaterBounds();
tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right));
tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom));
var waterBounds = self.getWaterBounds();
tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right));
tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom));
self.x = tentativeX;
self.y = tentativeY;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1;
fishGraphics.rotation = self.rotation;
};
});
var Clownfish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('clownfish', 'Clownfish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.4) * 3;
self.move = function () {
if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) {
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = Math.random() * 110 + 70;
self.targetRotation = Math.random() * Math.PI * 2;
}
var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval;
if (progress < 1) {
self.rotation += (self.targetRotation - self.rotation) * progress;
} else {
self.rotation = self.targetRotation;
}
var tentativeX = self.x + Math.cos(self.rotation) * self.speed * 2;
var tentativeY = self.y + Math.sin(self.rotation) * self.speed * 2;
var waterBounds = self.getWaterBounds();
tentativeX = Math.max(waterBounds.left, Math.min(tentativeX, waterBounds.right));
tentativeY = Math.max(waterBounds.top, Math.min(tentativeY, waterBounds.bottom));
self.x = tentativeX;
self.y = tentativeY;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1;
fishGraphics.rotation = self.rotation;
};
});
var Angelfish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('angelfish', 'Angelfish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.45) * 3;
self.move = function () {
if (!self.directionChangeTime || LK.ticks - self.directionChangeTime > self.directionChangeInterval) {
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = Math.random() * 130 + 90;
self.targetRotation = Math.random() * Math.PI * 2;
}
var progress = (LK.ticks - self.directionChangeTime) / self.directionChangeInterval;
if (progress < 1) {
self.rotation += (self.targetRotation - self.rotation) * progress;
} else {
self.rotation = self.targetRotation;
}
if (!self.velocity) {
self.velocity = {
x: 0,
y: 0
};
self.acceleration = Math.random() * 0.05 + 0.025;
}
var targetVelocityX = Math.cos(self.rotation) * self.speed;
var targetVelocityY = Math.sin(self.rotation) * self.speed;
self.velocity.x += (targetVelocityX - self.velocity.x) * self.acceleration;
self.velocity.y += (targetVelocityY - self.velocity.y) * self.acceleration;
self.x += self.velocity.x;
self.y += self.velocity.y;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
fishGraphics.scale.x = Math.cos(self.rotation) < 0 ? -1 : 1;
fishGraphics.rotation = self.rotation;
};
});
var AquariumEnvironmentManager = Container.expand(function () {
var self = Container.call(this);
self.createEnvironment = function () {
var aquariumGraphics = self.createAsset('aquarium', 'Aquarium Background', 0, 0);
aquariumGraphics.width = 2048 * 1.3 * 1.08;
aquariumGraphics.height = 2732 * 1.3 * 1.08;
aquariumGraphics.x = (2048 - aquariumGraphics.width) / 2;
aquariumGraphics.y = (2732 - aquariumGraphics.height) / 2;
self.addChild(aquariumGraphics);
var waterGraphics = self.createAsset('water', 'Water Graphics', 0, 0);
waterGraphics.width = 2048 / 3 * 2 * 1.08 * 1.15;
waterGraphics.height = 2732 / 3 * 1.26 * 1.15;
waterGraphics.x = (2048 - waterGraphics.width) / 2;
waterGraphics.y = (2732 - waterGraphics.height) / 2 - 150;
waterGraphics.alpha = 0.7;
self.addChild(waterGraphics);
};
return self;
});
var Aquarium = Container.expand(function () {
var self = Container.call(this);
self.getWaterBounds = function () {
var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0);
return {
left: (2048 - waterGraphics.width) / 2,
right: (2048 + waterGraphics.width) / 2,
top: (2732 - waterGraphics.height) / 2 - 150,
bottom: (2732 + waterGraphics.height) / 2 - 150
};
};
var aquariumEnvironment = self.addChild(new AquariumEnvironment());
});
var KoiFish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('koiFish', 'Koi Fish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.48) * 3;
self.move = function () {
if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) {
self.targetRotation = Math.random() * Math.PI * 2;
self.rotationStartTime = LK.ticks;
self.rotationDuration = Math.random() * 130 + 70;
}
var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration;
if (progress < 1) {
var deltaRotation = (self.targetRotation - self.rotation) * progress;
self.rotation += deltaRotation;
} else {
self.rotation = self.targetRotation;
}
if (!self.isResting) {
if (!self.isSleeping) {
if (!self.isLayingEggs && LK.ticks - self.lastEggTime > self.eggInterval && self.hunger > 70) {
self.isLayingEggs = true;
self.lastEggTime = LK.ticks;
self.eggInterval = Math.random() * 3000 + 2000;
var egg = new Egg();
egg.x = self.x;
egg.y = self.y;
LK.stageContainer.addChild(egg);
} else if (self.isLayingEggs && LK.ticks - self.lastEggTime > 200) {
self.isLayingEggs = false;
}
var nearbyPredators = self.getNearbyFish().filter(function (fish) {
return fish.size > self.size && self.distanceTo(fish) < 200;
});
if (nearbyPredators.length > 0) {
var hidingSpots = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Plant;
});
if (hidingSpots.length > 0) {
var hidingSpot = hidingSpots[Math.floor(Math.random() * hidingSpots.length)];
self.targetRotation = Math.atan2(hidingSpot.y - self.y, hidingSpot.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 20;
}
}
var similarFish = self.getNearbyFish().filter(function (fish) {
return fish.constructor === self.constructor;
});
if (similarFish.length > 1) {
var averageX = similarFish.reduce(function (sum, fish) {
return sum + fish.x;
}, 0) / similarFish.length;
var averageY = similarFish.reduce(function (sum, fish) {
return sum + fish.y;
}, 0) / similarFish.length;
self.targetRotation = Math.atan2(averageY - self.y, averageX - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
}
if (self.hunger < 20) {
var food = self.feedingBehavior.findClosestFood();
if (food) {
self.feedingBehavior.eatFood(food);
}
}
if (self.hunger > 50 && !self.isMating && LK.ticks - self.lastMateTime > self.mateInterval) {
var potentialMates = self.getNearbyFish().filter(function (fish) {
return fish.constructor === self.constructor && fish !== self && fish.hunger > 50;
});
if (potentialMates.length > 0) {
var mate = potentialMates[Math.floor(Math.random() * potentialMates.length)];
self.matingDance(mate);
self.isMating = true;
mate.isMating = true;
self.lastMateTime = LK.ticks;
mate.lastMateTime = LK.ticks;
self.mateInterval = Math.random() * 5000 + 3000;
mate.mateInterval = Math.random() * 5000 + 3000;
}
} else if (self.isMating && LK.ticks - self.lastMateTime > 200) {
self.isMating = false;
}
if (!self.isResting && LK.ticks - self.lastRestTime > self.restInterval) {
self.isResting = true;
self.lastRestTime = LK.ticks;
self.restInterval = Math.random() * 3000 + 2000;
self.restPosition = {
x: self.x,
y: self.getWaterBounds().bottom - 50
};
self.targetRotation = Math.atan2(self.restPosition.y - self.y, self.restPosition.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 20;
} else if (self.isResting && LK.ticks - self.lastRestTime > 200) {
self.isResting = false;
self.restAtBottom = function () {
if (LK.ticks - self.lastRestTime > self.restInterval) {
self.isResting = true;
self.lastRestTime = LK.ticks;
self.restInterval = Math.random() * 3000 + 2000;
self.targetRotation = Math.PI / 2;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 20;
}
};
self.formSchool = function (similarFish) {
var averageX = 0;
var averageY = 0;
similarFish.forEach(function (fish) {
averageX += fish.x;
averageY += fish.y;
});
averageX /= similarFish.length;
averageY /= similarFish.length;
self.targetRotation = Math.atan2(averageY - self.y, averageX - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
};
self.investigateObject = function (object) {
self.targetRotation = Math.atan2(object.y - self.y, object.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
};
self.playWithObject = function (object) {
self.targetRotation = Math.atan2(object.y - self.y, object.x - self.x) + Math.random() * Math.PI - Math.PI / 2;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 5;
};
self.findLeader = function () {
var nearbyFish = self.getNearbyFish();
var leader = nearbyFish.reduce(function (leader, fish) {
if (fish !== self && fish.size > self.size && fish.speed > self.speed) {
return fish;
}
return leader;
}, null);
if (leader) {
self.followLeader(leader);
}
};
self.followLeader = function (leader) {
var distanceToLeader = self.distanceTo(leader);
if (distanceToLeader > 50) {
self.targetRotation = Math.atan2(leader.y - self.y, leader.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
}
};
self.evadePredator = function (predator) {
var angleToPredator = Math.atan2(predator.y - self.y, predator.x - self.x);
self.targetRotation = angleToPredator + Math.PI;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
};
self.matingDance = function (partner) {
if (LK.ticks - self.lastMateTime > self.mateInterval) {
self.targetRotation = Math.atan2(partner.y - self.y, partner.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
if (self.distanceTo(partner) < 10) {
var egg = new Egg();
egg.x = (self.x + partner.x) / 2;
egg.y = (self.y + partner.y) / 2;
LK.stageContainer.addChild(egg);
self.lastMateTime = LK.ticks;
partner.lastMateTime = LK.ticks;
self.isMating = false;
partner.isMating = false;
}
}
};
self.seekShelter = function () {
if (self.health < 30) {
var shelters = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Plant;
});
if (shelters.length > 0) {
var closestShelter = shelters.reduce(function (closest, shelter) {
var distanceToShelter = self.distanceTo(shelter);
return distanceToShelter < self.distanceTo(closest) ? shelter : closest;
}, shelters[0]);
self.targetRotation = Math.atan2(closestShelter.y - self.y, closestShelter.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
}
}
};
}
if (Math.random() < 0.01 && self.canJump) {
self.isJumping = true;
self.jumpStartTime = LK.ticks;
self.jumpDuration = 60;
self.jumpHeight = Math.random() * 100 + 50;
self.canJump = false;
} else if (self.isJumping) {
var jumpProgress = (LK.ticks - self.jumpStartTime) / self.jumpDuration;
if (jumpProgress < 1) {
self.y -= self.jumpHeight * (1 - Math.cos(Math.PI * jumpProgress));
} else {
self.isJumping = false;
self.canJump = true;
}
} else {
self.bubbleTrail = function () {
if (Math.random() < 0.1) {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
}
};
self.bubbleTrail();
if (!self.velocity) {
self.velocity = {
x: 0,
y: 0
};
self.acceleration = 0.05;
}
var targetVelocityX = Math.cos(self.rotation) * self.speed;
var targetVelocityY = Math.sin(self.rotation) * self.speed;
self.velocity.x += (targetVelocityX - self.velocity.x) * self.acceleration;
self.velocity.y += (targetVelocityY - self.velocity.y) * self.acceleration;
self.x += self.velocity.x;
self.y += self.velocity.y;
}
}
if (LK.ticks % 1800 === 0) {
self.isSleeping = !self.isSleeping;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = self.isSleeping ? 300 : Math.random() * 120 + 60;
}
}
if (LK.ticks % 300 === 0) {
self.isResting = !self.isResting;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = self.isResting ? 120 : Math.random() * 120 + 60;
}
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
self.rotation = self.rotation % (Math.PI * 2);
if (Math.cos(self.rotation) < 0) {
fishGraphics.scale.x = -1;
} else {
fishGraphics.scale.x = 1;
}
fishGraphics.rotation = self.rotation;
};
});
var Goldfish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('goldfish', 'Goldfish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.4) * 3;
self.move = function () {
if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) {
self.targetRotation = Math.random() * Math.PI * 2;
self.rotationStartTime = LK.ticks;
self.rotationDuration = Math.random() * 140 + 80;
}
var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration;
if (progress < 1) {
var deltaRotation = (self.targetRotation - self.rotation) * progress;
self.rotation += deltaRotation;
} else {
self.rotation = self.targetRotation;
}
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
self.rotation = self.rotation % (Math.PI * 2);
if (Math.cos(self.rotation) < 0) {
fishGraphics.scale.x = -1;
} else {
fishGraphics.scale.x = 1;
}
fishGraphics.rotation = self.rotation;
};
});
var GuppyFish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('guppyFish', 'Guppy Fish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.35) * 3;
self.move = function () {
if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) {
self.targetRotation = Math.random() * Math.PI * 2;
self.rotationStartTime = LK.ticks;
self.rotationDuration = Math.random() * 100 + 50;
}
var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration;
if (progress < 1) {
var deltaRotation = (self.targetRotation - self.rotation) * progress;
self.rotation += deltaRotation;
} else {
self.rotation = self.targetRotation;
}
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
self.rotation = self.rotation % (Math.PI * 2);
if (Math.cos(self.rotation) < 0) {
fishGraphics.scale.x = -1;
} else {
fishGraphics.scale.x = 1;
}
fishGraphics.rotation = self.rotation;
};
});
var BettaFish = Fish.expand(function () {
var self = Fish.call(this) || this;
var fishGraphics = self.createAsset('bettaFish', 'Betta Fish Graphics', .5, .5);
fishGraphics.scale.set(1, 1);
self.speed = (Math.random() * 0.2 + 0.5) * 3;
self.move = function () {
if (self.targetRotation === undefined || LK.ticks - self.rotationStartTime >= self.rotationDuration) {
self.targetRotation = Math.random() * Math.PI * 2;
self.rotationStartTime = LK.ticks;
self.rotationDuration = Math.random() * 150 + 100;
}
var progress = (LK.ticks - self.rotationStartTime) / self.rotationDuration;
if (progress < 1) {
var deltaRotation = (self.targetRotation - self.rotation) * progress;
self.rotation += deltaRotation;
} else {
self.rotation = self.targetRotation;
}
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
var waterBounds = self.getWaterBounds();
if (self.x < waterBounds.left || self.x > waterBounds.right) {
self.rotation = Math.PI - self.rotation;
}
if (self.y < waterBounds.top || self.y > waterBounds.bottom) {
self.rotation = -self.rotation;
}
self.rotation = self.rotation % (Math.PI * 2);
if (Math.cos(self.rotation) < 0) {
fishGraphics.scale.x = -1;
} else {
fishGraphics.scale.x = 1;
}
fishGraphics.rotation = self.rotation;
};
});
var BubbleCurtain = DecorativePlant.expand(function () {
var self = DecorativePlant.call(this) || this;
self.bubbleRate = 1000;
self.createBubble = function () {
var bubble = new RisingBubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
};
LK.setInterval(self.createBubble, self.bubbleRate);
return self;
});
var RisingBubble = Container.expand(function () {
var self = Container.call(this);
self.liftSpeed = 3;
self.on('tick', function () {
self.y -= self.liftSpeed;
if (self.y < 0) {
self.destroy();
}
});
self.captureFish = function (fish) {
if (!fish.isCaptured && self.intersects(fish)) {
fish.isCaptured = true;
fish.x = self.x;
fish.y = self.y - fish.height / 2;
}
};
self.releaseFish = function (fish) {
if (fish.isCaptured) {
fish.isCaptured = false;
fish.y += fish.height / 2;
}
};
});
var CamouflageFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.colorChangeRate = 0.1;
self.colorChangeThreshold = 200;
self.currentEnvironmentColor = 0xFFFFFF;
self.changeColorBasedOnEnvironment = function () {
var environmentObjects = self.getNearbyObjects().filter(function (obj) {
return obj instanceof DecorativePlant || obj instanceof Algae;
});
if (environmentObjects.length > 0) {
var closestEnvironmentObject = environmentObjects[0];
for (var i = 1; i < environmentObjects.length; i++) {
if (self.distanceTo(environmentObjects[i]) < self.distanceTo(closestEnvironmentObject)) {
closestEnvironmentObject = environmentObjects[i];
}
}
if (self.distanceTo(closestEnvironmentObject) < self.colorChangeThreshold) {
self.currentEnvironmentColor = closestEnvironmentObject.color;
}
}
self.tint = self.currentEnvironmentColor;
};
self.on('tick', function () {
self.changeColorBasedOnEnvironment();
});
return self;
});
var FishManager = Container.expand(function () {
var self = Container.call(this);
self.fishTypes = [Fish, KoiFish, Goldfish, GuppyFish, BettaFish, Angelfish, Clownfish, Pufferfish, Surgeonfish];
self.fishes = [];
self.spawnFish = function (aquarium) {
for (var i = 0; i < self.fishTypes.length; i++) {
for (var j = 0; j < 1; j++) {
var fish = new self.fishTypes[i]();
if (typeof fish.move === 'function') {
var waterGraphics = LK.getAsset('water', 'Water Graphics', 0, 0);
var waterBounds = {
left: (2048 - waterGraphics.width) / 2,
right: (2048 + waterGraphics.width) / 2,
top: (2732 - waterGraphics.height) / 2 - 150,
bottom: (2732 + waterGraphics.height) / 2 - 150
};
var waterWidth = waterBounds.right - waterBounds.left;
var waterHeight = waterBounds.bottom - waterBounds.top;
var waterCenterX = waterBounds.left + waterWidth / 2;
var waterCenterY = waterBounds.top + waterHeight / 2;
var maxDistanceX = waterWidth / 2 * 0.8;
var maxDistanceY = waterHeight / 2 * 0.8;
var angle = Math.random() * Math.PI * 2;
var distanceX = Math.random() * maxDistanceX;
var distanceY = Math.random() * maxDistanceY;
fish.x = waterCenterX + distanceX * Math.cos(angle);
fish.y = waterCenterY + distanceY * Math.sin(angle);
self.fishes.push(fish);
self.addChild(fish);
}
}
}
};
self.manageFish = function () {};
return self;
});
var MentorFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.intelligenceBoostRate = 0.5;
self.boostRange = 250;
self.boostIntelligence = function () {
var nearbyFish = self.getNearbyFishWithinRange(self.boostRange);
nearbyFish.forEach(function (fish) {
if (!(fish instanceof MentorFish)) {
fish.intelligenceLevel += self.intelligenceBoostRate;
}
});
};
self.on('tick', function () {
self.boostIntelligence();
});
return self;
});
var CleanerFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.cleaningRate = 0.2;
self.eatAlgae = function () {
var algae = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Algae;
});
algae.forEach(function (algae) {
if (self.distanceTo(algae) < 50) {
algae.consume(self);
}
});
};
self.on('tick', function () {
self.eatAlgae();
});
return self;
});
var DistractingFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.distractRange = 200;
self.distractPredators = function () {
var predators = self.getNearbyFish().filter(function (fish) {
return fish.size > self.size;
});
predators.forEach(function (predator) {
if (self.distanceTo(predator) < self.distractRange) {
predator.targetRotation = Math.atan2(self.y - predator.y, self.x - predator.x);
}
});
};
self.on('tick', function () {
self.distractPredators();
});
return self;
});
Fish.prototype.updateColorBasedOnHealth = function () {
if (this.health < 30) {
this.tint = 0xFF6347;
} else if (this.health < 70) {
this.tint = 0xFFFF00;
} else {
this.tint = 0x32CD32;
}
};
Fish.prototype.increaseSpeed = function (speedMultiplier, duration) {
var originalSpeed = this.speed;
this.speed *= speedMultiplier;
var self = this;
LK.setTimeout(function () {
self.speed = originalSpeed;
}, duration);
};
Fish.prototype.getNearbyFishWithinRange = function (range) {
var nearbyFish = [];
LK.stageContainer.children.forEach(function (child) {
if (child instanceof Fish && child !== this) {
var distance = this.distanceTo(child);
if (distance < range) {
nearbyFish.push(child);
}
}
}, this);
return nearbyFish;
};
var Game = Container.expand(function () {
var self = Container.call(this);
var aquariumEnvironmentManager = self.addChild(new AquariumEnvironmentManager());
aquariumEnvironmentManager.createEnvironment();
var fishManager = self.addChild(new FishManager());
fishManager.spawnFish(aquariumEnvironmentManager);
LK.stageContainer.setBackgroundColor(0x008080);
LK.on('tick', function () {
fishManager.manageFish();
});
});
An aquarium with no fish on a sheel in a photorealistic style. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic goldfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic Angelfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic koyfish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic gupyfish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic bettafish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic clownfish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic pufferfish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic surgeonfish swiming to the right. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic buble of water. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic fish egg. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic celestial pearl danio. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic Parrotfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic dartfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic moorishidol. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic tangfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic bannerfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic butterflyfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
A realistic mandarinfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic lionfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic emperorFish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic sunfish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic discusFish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic neonTetra. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a realistic oscarFish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a cardinal tetra. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a tang fish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a clown fish. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.