User prompt
Fix Bug: 'Uncaught ReferenceError: Decoration is not defined' in this line: 'var HealingPlant = Decoration.expand(function () {' Line Number: 375
User prompt
Fix Bug: 'Uncaught ReferenceError: Decoration is not defined' in this line: 'var DecorativeCastle = Decoration.expand(function () {' Line Number: 48
User prompt
Improve the entire code with two new functionality
User prompt
Fix Bug: 'Uncaught ReferenceError: Food is not defined' in this line: 'var SmartFood = Food.expand(function () {' Line Number: 442
User prompt
Fix Bug: 'ReferenceError: Bubble is not defined' in this line: 'var bubble = new Bubble();' Line Number: 1286
User prompt
Improve the entire code with two new functionality
User prompt
Improve the entire code with two new functionality
User prompt
Improve movement
User prompt
Improve the entire code with two new functionality
User prompt
Fix Bug: 'TypeError: self.getWaterBounds is not a function' in this line: 'var waterBounds = self.getWaterBounds();' Line Number: 794
User prompt
Fix Bug: 'TypeError: self.getNearbyFish is not a function' in this line: 'var nearbyPredators = self.getNearbyFish().filter(function (fish) {' Line Number: 949
User prompt
Fix Bug: 'TypeError: self.getNearbyFish is not a function' in this line: 'var nearbyPredators = self.getNearbyFish().filter(function (fish) {' Line Number: 949
User prompt
Fix Bug: 'TypeError: self.getNearbyFish is not a function' in this line: 'var nearbyPredators = self.getNearbyFish().filter(function (fish) {' Line Number: 949
User prompt
Fix Bug: 'TypeError: self.getNearbyFish is not a function' in this line: 'var nearbyPredators = self.getNearbyFish().filter(function (fish) {' Line Number: 949
User prompt
Improve
User prompt
Increase water size by 15 percent
User prompt
Decrease background size by 10 percent
User prompt
Increase background size by 20 percent
User prompt
Fix Bug: 'Uncaught ReferenceError: Bubble is not defined' in this line: 'var LiftingBubble = Bubble.expand(function () {' Line Number: 1443
User prompt
Fix Bug: 'Uncaught ReferenceError: Food is not defined' in this line: 'var SpeedFood = Food.expand(function () {' Line Number: 439
User prompt
Improve the entire code with 5 new functionality
User prompt
Improve the entire code with two new functionality
User prompt
Improve the entire code with two new functionality
User prompt
Fix Bug: 'Uncaught TypeError: Fish.extend is not a function' in this line: 'var SmartPredatorFish = Fish.extend(function () {' Line Number: 1505
User prompt
Fix Bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'expand')' in this line: 'var SmartPredatorFish = Fish.expand(function () {' Line Number: 31
var GrowingPlant = Container.expand(function () {
var self = Container.call(this) || this;
var plantGraphics = self.createAsset('growingPlant', 'Growing Plant Graphics', 0.5, 1);
self.growthRate = 0.005;
self.nutritionValue = 10;
self.on('tick', function () {
plantGraphics.scale.x += self.growthRate;
plantGraphics.scale.y += self.growthRate;
if (plantGraphics.scale.x > 5) {
self.destroy();
}
});
self.consume = function (fish) {
if (self.distanceTo(fish) < 100) {
fish.hunger = Math.min(fish.hunger + self.nutritionValue, 100);
self.destroy();
}
};
});
var HealingBubble = Container.expand(function () {
var self = Container.call(this);
self.healingRate = 1;
self.on('tick', function () {
var nearbyFish = self.getNearbyFishWithinRange(100);
nearbyFish.forEach(function (fish) {
fish.health = Math.min(fish.health + self.healingRate, 100);
});
Bubble.prototype.onTick.call(self);
});
});
var FishFeeder = Container.expand(function () {
var self = Container.call(this);
var feederGraphics = self.createAsset('fishFeeder', 'Fish Feeder Graphics', 0.5, 0.5);
self.foodReleaseRate = 5;
self.releaseFood = function () {
var food = new Food();
food.x = self.x;
food.y = self.y - feederGraphics.height;
LK.stageContainer.addChild(food);
var nearbyFish = self.getNearbyFishWithinRange(500);
nearbyFish.forEach(function (fish) {
fish.rushToFood(food);
});
};
LK.setInterval(self.releaseFood, 10000);
});
var InteractiveElement = Container.expand(function () {
var self = Container.call(this);
self.interact = function () {};
self.performInteraction = function () {
self.interact();
};
});
var Decoration = Container.expand(function () {
var self = Container.call(this);
self.decorate = function () {};
});
var DecorativeCastle = Decoration.expand(function () {
var self = Decoration.call(this) || this;
var castleGraphics = self.createAsset('decorativeCastle', 'Decorative Castle Graphics', 0.5, 1);
castleGraphics.width = 300;
castleGraphics.height = 400;
self.x = 1024;
self.y = 2732 - castleGraphics.height / 2;
});
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.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 AquariumLife = 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 AquariumCleaner = Cleaner.expand(function () {
var self = Cleaner.call(this) || this;
var cleanerGraphics = self.createAsset('aquariumCleaner', 'Aquarium Cleaner Graphics', 0.5, 0.5);
self.speed = 0.2;
self.cleaningRate = 1;
self.cleaningBehavior = new CleaningBehavior();
self.update = 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);
}
});
};
});
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 AquariumDecorator = 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;
});
var AquariumPlant = Decoration.expand(function () {
var self = Decoration.call(this) || this;
self.growthRate = 0.01;
self.nutritionValue = 5;
var plantGraphics = self.createAsset('aquariumPlant', 'Aquarium Plant Graphics', 0.5, 1);
self.on('tick', function () {
plantGraphics.scale.x += self.growthRate;
plantGraphics.scale.y += self.growthRate;
if (plantGraphics.scale.x > 3) {
plantGraphics.scale.x = 3;
plantGraphics.scale.y = 3;
}
});
self.consume = function (fish) {
if (self.distanceTo(fish) < 100) {
fish.hunger = Math.min(fish.hunger + self.nutritionValue, 100);
self.destroy();
}
};
});
var HealingPlant = Decoration.expand(function () {
var self = Decoration.call(this);
var plantGraphics = self.createAsset('healingPlant', 'Healing Plant Graphics', 0.5, 1);
self.healingRate = 0.1;
self.interactWithFish = function (fish) {
if (fish.size < self.size && self.distanceTo(fish) < 100) {
fish.health = Math.min(fish.health + self.healingRate, 100);
fish.isHidden = true;
fish.alpha = 0.5;
} else {
fish.isHidden = false;
fish.alpha = 1.0;
}
};
self.on('tick', function () {
var nearbyFish = self.getNearbyFishWithinRange(100);
nearbyFish.forEach(self.interactWithFish);
});
});
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.interact = function () {
self.isOpen = !self.isOpen;
chestGraphics.texture = LK.getAsset(self.isOpen ? 'chestOpen' : 'chestClosed', 'Chest Graphics', 0.5, 0.5).texture;
if (self.isOpen) {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
}
};
LK.setInterval(self.performInteraction, 10000);
});
var HealingAlgae = Container.expand(function () {
var self = Container.call(this);
var algaeGraphics = self.createAsset('healingAlgae', 'Healing Algae Graphics', 0.5, 0.5);
self.growthRate = 0.02;
self.nutrition = 10;
self.healingAmount = 2;
self.on('tick', function () {
algaeGraphics.scale.x += self.growthRate;
algaeGraphics.scale.y += self.growthRate;
self.nutrition += self.growthRate * 10;
if (algaeGraphics.scale.x > 5) {
self.destroy();
}
});
self.consume = function (fish) {
fish.health = Math.min(fish.health + self.healingAmount, 100);
self.destroy();
};
});
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 = InteractiveElement.expand(function () {
var self = InteractiveElement.call(this) || this;
self.nutrition = 10;
self.consume = function (fish) {
fish.hunger = Math.min(fish.hunger + self.nutrition, 100);
self.destroy();
};
});
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 BubbleStream = Container.expand(function () {
var self = Container.call(this);
self.bubbleRate = 1000;
self.createBubble = function () {
var bubble = new Bubble();
bubble.x = self.x;
bubble.y = self.y;
LK.stageContainer.addChild(bubble);
};
LK.setInterval(self.createBubble, self.bubbleRate);
});
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 FeedingArea = Container.expand(function () {
var self = Container.call(this);
var areaGraphics = self.createAsset('feedingArea', 'Feeding Area Graphics', 0.5, 0.5);
self.spawnFood = function () {
var food = new Food();
food.x = self.x + (Math.random() - 0.5) * areaGraphics.width;
food.y = self.y + (Math.random() - 0.5) * areaGraphics.height;
LK.stageContainer.addChild(food);
var nearbyFish = self.getNearbyFishWithinRange(500);
nearbyFish.forEach(function (fish) {
fish.rushToFood(food);
});
};
LK.setInterval(self.spawnFood, 5000);
});
var SmartFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.intelligenceLevel = 5;
self.avoidPredators = function (predators) {};
self.seekFood = function (foodSources) {};
self.move = function () {
var predators = self.getNearbyFish().filter(function (fish) {
return fish.size > self.size;
});
if (predators.length > 0) {
self.avoidPredators(predators);
} else {
var foodSources = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Food;
});
if (foodSources.length > 0) {
self.seekFood(foodSources);
}
}
var leaderFish = self.findLeaderFish(self.getNearbyFish());
if (leaderFish) {
self.followLeader(leaderFish);
} else {
self.schoolWith(self.getNearbyFish().filter(fish => fish.constructor === self.constructor));
}
self.interactWithDecorations(self.getNearbyObjects().filter(obj => obj instanceof InteractiveDecoration));
self.schoolWithOtherFish = function () {
var nearbyFish = self.getNearbyFish().filter(fish => fish.constructor === self.constructor);
if (nearbyFish.length > 1) {
var schoolCenterX = nearbyFish.reduce((sum, fish) => sum + fish.x, 0) / nearbyFish.length;
var schoolCenterY = nearbyFish.reduce((sum, fish) => sum + fish.y, 0) / nearbyFish.length;
self.targetRotation = Math.atan2(schoolCenterY - self.y, schoolCenterX - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
}
};
self.schoolWithOtherFish();
self.feedingFrenzy = function () {
var foodSources = self.getNearbyObjects().filter(obj => obj instanceof Food);
if (foodSources.length > 0) {
var closestFood = foodSources.reduce((closest, food) => self.distanceTo(food) < self.distanceTo(closest) ? food : closest, foodSources[0]);
self.targetRotation = Math.atan2(closestFood.y - self.y, closestFood.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 5;
}
};
self.feedingFrenzy();
Fish.prototype.move.call(self);
};
});
var AggressiveHunterFish = Fish.expand(function () {
var self = Fish.call(this) || this;
var hunterGraphics = self.createAsset('aggressiveHunterFish', 'Aggressive Hunter Fish Graphics', .5, .5);
self.speed = Math.random() * 0.5 + 1;
self.huntRange = 400;
self.hunt = function (prey) {
if (self.distanceTo(prey) < self.huntRange) {
self.targetRotation = Math.atan2(prey.y - self.y, prey.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 3;
prey.health -= 1;
if (prey.health <= 0) {
prey.die();
}
}
};
self.move = function () {
var nearbyPrey = self.getNearbyFish().filter(function (fish) {
return fish.size < self.size && fish.health > 0;
});
if (nearbyPrey.length > 0) {
self.hunt(nearbyPrey[0]);
}
Fish.prototype.move.call(self);
};
LK.setInterval(self.move, 500);
});
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;
}
};
});
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) {
var egg = new Egg();
egg.x = (fish.x + partner.x) / 2;
egg.y = (fish.y + partner.y) / 2;
LK.stageContainer.addChild(egg);
self.lastMateTime = LK.ticks;
partner.lastMateTime = LK.ticks;
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);
}
};
});
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;
};
});
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 = 0;
var schoolCenterY = 0;
similarFish.forEach(function (fish) {
schoolCenterX += fish.x;
schoolCenterY += fish.y;
});
schoolCenterX /= similarFish.length;
schoolCenterY /= similarFish.length;
fish.targetRotation = Math.atan2(schoolCenterY - fish.y, schoolCenterX - fish.x);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 30;
}
};
});
var EvasionBehavior = Container.expand(function () {
var self = Container.call(this);
self.evadePredators = function (fish, predators) {
var evadeAngle = 0;
predators.forEach(function (predator) {
var angleToPredator = Math.atan2(predator.y - fish.y, predator.x - fish.x);
evadeAngle += angleToPredator + Math.PI;
});
evadeAngle /= predators.length;
fish.targetRotation = evadeAngle + (Math.random() * Math.PI - Math.PI / 2);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 10;
};
});
var LeadershipBehavior = Container.expand(function () {
var self = Container.call(this);
self.followLeader = function (fish, leaderFish) {
var followDistance = 50;
var dx = leaderFish.x - fish.x;
var dy = leaderFish.y - fish.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > followDistance) {
fish.targetRotation = Math.atan2(dy, dx);
fish.directionChangeTime = LK.ticks;
fish.directionChangeInterval = 10;
}
};
});
var MortalityBehavior = Container.expand(function () {
var self = Container.call(this);
self.die = function (fish) {
fish.destroy();
};
});
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) * 18;
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) * 9;
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) * 9;
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 AquariumEnvironment = Container.expand(function () {
var self = Container.call(this);
var aquariumGraphics = self.createAsset('aquarium', 'Aquarium Background', 0, 0);
aquariumGraphics.width = 2048 * 1.3;
aquariumGraphics.height = 2732 * 1.3;
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;
waterGraphics.height = 2732 / 3 * 1.26;
waterGraphics.x = (2048 - waterGraphics.width) / 2;
waterGraphics.y = (2732 - waterGraphics.height) / 2 - 150;
waterGraphics.alpha = 0.7;
self.addChild(waterGraphics);
});
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) * 9;
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();
self.x += Math.cos(self.rotation) * self.speed;
self.y += Math.sin(self.rotation) * self.speed;
}
}
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) * 9;
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) * 9;
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) * 9;
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 BubbleGenerator = Container.expand(function () {
var self = Container.call(this);
self.bubbleRate = 500;
self.createBubble = function () {
var bubble = new Bubble();
bubble.x = Math.random() * 2048;
bubble.y = 2732;
self.addChild(bubble);
};
LK.setInterval(self.createBubble, self.bubbleRate);
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.createAsset('bubble', 'Bubble Graphics', 0.5, 0.5);
self.on('tick', function () {
self.y -= 2;
if (self.y < 0) self.destroy();
});
});
var HidingFish = Fish.expand(function () {
var self = Fish.call(this) || this;
self.hideInCastle = function (castle) {
if (self.size < 30 && self.distanceTo(castle) < 100 && self.isPredatorNearby()) {
self.targetRotation = Math.atan2(castle.y - self.y, castle.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 10;
self.isHidden = true;
} else {
self.isHidden = false;
}
};
self.isPredatorNearby = function () {
var nearbyPredators = self.getNearbyFish().filter(function (fish) {
return fish.size > self.size && self.distanceTo(fish) < 200;
});
return nearbyPredators.length > 0;
};
});
var FishSpawner = Container.expand(function () {
var self = Container.call(this);
var fishTypes = [Fish, KoiFish, Goldfish, GuppyFish, BettaFish, Angelfish, Clownfish, Pufferfish, Surgeonfish];
this.spawnFish = function (aquarium) {
var fishes = [];
for (var i = 0; i < fishTypes.length; i++) {
for (var j = 0; j < 1; j++) {
var fish = new fishTypes[i]();
if (typeof fish.move === 'function') {
var waterBounds = aquarium.getWaterBounds();
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);
fishes.push(fish);
self.addChild(fish);
}
}
}
return fishes;
};
});
var SmartPredatorFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.huntRange = 500;
self.huntSpeed = 3;
self.hunt = function (prey) {
if (self.distanceTo(prey) < self.huntRange) {
self.targetRotation = Math.atan2(prey.y - self.y, prey.x - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 3;
prey.health -= 2;
if (prey.health <= 0) {
prey.die();
}
}
};
self.move = function () {
var nearbyPrey = self.getNearbyFish().filter(function (fish) {
return fish.size < self.size && fish.health > 0;
});
if (nearbyPrey.length > 0) {
self.hunt(nearbyPrey[0]);
}
Fish.prototype.move.call(self);
};
LK.setInterval(self.move, 500);
});
var CastleHidingFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.hideInCastle = function (castle) {
if (self.size < 30 && self.distanceTo(castle) < 100 && self.isPredatorNearby()) {
self.isHidden = true;
self.alpha = 0.5;
} else {
self.isHidden = false;
self.alpha = 1.0;
}
};
});
var CleanerFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.cleaningRate = 0.5;
self.clean = function (algae) {
if (self.distanceTo(algae) < 50) {
algae.health -= self.cleaningRate;
if (algae.health <= 0) {
algae.destroy();
}
}
};
self.move = function () {
var dirtyObjects = self.getNearbyObjects().filter(function (obj) {
return obj instanceof Algae;
});
dirtyObjects.forEach(self.clean);
Fish.prototype.move.call(self);
};
});
var JumpingFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.jumpHeight = 100;
self.canJump = true;
self.jump = function () {
if (self.canJump && self.isPredatorNearby()) {
self.y -= self.jumpHeight;
self.canJump = false;
LK.setTimeout(function () {
self.canJump = true;
}, 5000);
}
};
self.move = function () {
self.jump();
Fish.prototype.move.call(self);
};
});
var CamouflageFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.camouflage = function () {
if (self.isPredatorNearby()) {
self.alpha = 0.1;
} else {
self.alpha = 1.0;
}
};
self.move = function () {
self.camouflage();
Fish.prototype.move.call(self);
};
});
var SchoolingFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.schoolWith = function (similarFish) {
if (similarFish.length > 1) {
var schoolCenterX = similarFish.reduce(function (sum, fish) {
return sum + fish.x;
}, 0) / similarFish.length;
var schoolCenterY = similarFish.reduce(function (sum, fish) {
return sum + fish.y;
}, 0) / similarFish.length;
self.targetRotation = Math.atan2(schoolCenterY - self.y, schoolCenterX - self.x);
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 30;
}
};
self.move = function () {
var similarFish = self.getNearbyFish().filter(function (fish) {
return fish.constructor === self.constructor;
});
self.schoolWith(similarFish);
Fish.prototype.move.call(self);
};
});
var PlayfulFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.playWithDecoration = function (decoration) {
if (self.distanceTo(decoration) < 100) {
self.targetRotation = Math.atan2(decoration.y - self.y, decoration.x - self.x) + Math.random() * Math.PI - Math.PI / 2;
self.directionChangeTime = LK.ticks;
self.directionChangeInterval = 5;
}
};
self.move = function () {
var decorations = self.getNearbyObjects().filter(function (obj) {
return obj instanceof InteractiveDecoration;
});
decorations.forEach(self.playWithDecoration);
Fish.prototype.move.call(self);
};
});
var BreedingFish = Fish.extend(function () {
var self = Fish.call(this) || this;
self.mateWith = function (partner) {
if (self.distanceTo(partner) < 100 && !self.isMating && !partner.isMating) {
self.isMating = true;
partner.isMating = true;
var egg = new Egg();
egg.x = (self.x + partner.x) / 2;
egg.y = (self.y + partner.y) / 2;
LK.stageContainer.addChild(egg);
LK.setTimeout(function () {
self.isMating = false;
partner.isMating = false;
}, 10000);
}
};
self.move = function () {
var potentialPartners = self.getNearbyFish().filter(function (fish) {
return fish.constructor === self.constructor && fish !== self;
});
potentialPartners.forEach(self.mateWith);
Fish.prototype.move.call(self);
};
});
var Game = Container.expand(function () {
var self = Container.call(this);
var aquarium = self.addChild(new Aquarium());
LK.stageContainer.setBackgroundColor(0x008080);
var fishSpawner = self.addChild(new FishSpawner());
var fishes = fishSpawner.spawnFish(aquarium);
LK.on('tick', function () {
for (var i = 0; i < fishes.length; i++) {
fishes[i].move();
}
});
});
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.