User prompt
add many fish to the scene but make them run for the bait and eat the bait thrown ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
wants to eat fish food.
User prompt
When I click anywhere with the mouse, drop a bait there and the fish eats that bait and then swims freely again. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Aqua Betta - Virtual Fish Tank
Initial prompt
I want to make a betta fish swim. Let the betta fish swim freely in the water. Let there be realistic movements. Let the fish be colorful and have realistic details.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BettaFish = Container.expand(function () {
var self = Container.call(this);
// Create fish body parts
var body = self.attachAsset('bettaBody', {
anchorX: 0.5,
anchorY: 0.5
});
var tail = self.attachAsset('bettaTail', {
anchorX: 0.8,
anchorY: 0.5,
x: -60,
scaleX: 1.2
});
var topFin = self.attachAsset('bettaFin', {
anchorX: 0.5,
anchorY: 0.8,
y: -30,
scaleX: 0.8,
scaleY: 0.6
});
var bottomFin = self.attachAsset('bettaFin', {
anchorX: 0.5,
anchorY: 0.2,
y: 25,
scaleX: 0.6,
scaleY: 0.5
});
// Randomize colors
var colors = [0xff4444, 0x4444ff, 0x44ff44, 0xff44ff, 0xffff44, 0x44ffff, 0xff8844];
var mainColor = colors[Math.floor(Math.random() * colors.length)];
var finColor = mainColor + 0x222222;
body.tint = mainColor;
tail.tint = finColor;
topFin.tint = finColor;
bottomFin.tint = finColor;
// Movement properties
self.targetX = 1024;
self.targetY = 1366;
self.speed = 2;
self.direction = 0;
self.isGliding = true;
self.glideDuration = 0;
self.maxGlideDuration = 180;
self.dartCooldown = 0;
// Animation properties
self.finAnimationOffset = Math.random() * Math.PI * 2;
function setNewTarget() {
self.targetX = Math.random() * 1400 + 324;
self.targetY = Math.random() * 800 + 466;
}
function startDart() {
self.isGliding = false;
self.speed = 8;
self.dartCooldown = 60;
setNewTarget();
}
self.update = function () {
// Calculate distance to target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Movement logic
if (distance > 20) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
self.x += moveX;
self.y += moveY;
// Update direction for visual orientation
self.direction = Math.atan2(dy, dx);
self.rotation = self.direction;
} else {
// Reached target, start gliding
if (!self.isGliding && self.dartCooldown <= 0) {
self.isGliding = true;
self.speed = 1;
self.glideDuration = 0;
setNewTarget();
}
}
// Gliding behavior
if (self.isGliding) {
self.glideDuration++;
if (self.glideDuration > self.maxGlideDuration && Math.random() < 0.02) {
startDart();
}
}
// Dart cooldown
if (self.dartCooldown > 0) {
self.dartCooldown--;
}
// Fin animations
var finWave = Math.sin((LK.ticks + self.finAnimationOffset) * 0.1) * 0.1;
tail.scaleY = 1.2 + finWave;
topFin.rotation = finWave * 0.5;
bottomFin.rotation = -finWave * 0.3;
// Body subtle movement
body.scaleY = 1 + Math.sin((LK.ticks + self.finAnimationOffset) * 0.05) * 0.05;
};
self.reactToTouch = function (touchX, touchY) {
var dx = touchX - self.x;
var dy = touchY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 200) {
// Fish swims away from touch
self.targetX = self.x - dx / distance * 300;
self.targetY = self.y - dy / distance * 300;
} else {
// Fish is curious and swims toward touch
self.targetX = touchX + (Math.random() - 0.5) * 100;
self.targetY = touchY + (Math.random() - 0.5) * 100;
}
// Clamp targets to tank boundaries
self.targetX = Math.max(324, Math.min(1724, self.targetX));
self.targetY = Math.max(466, Math.min(1666, self.targetY));
startDart();
};
return self;
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.speed = Math.random() * 2 + 1;
self.floatSpeed = Math.random() * 0.5 + 0.5;
self.update = function () {
self.y -= self.floatSpeed;
self.x += Math.sin(LK.ticks * 0.02 + self.speed) * 0.5;
if (self.y < -50) {
self.y = 2800;
self.x = Math.random() * 1800 + 124;
}
};
return self;
});
var FishFood = Container.expand(function () {
var self = Container.call(this);
var foodGraphics = self.attachAsset('fishFood', {
anchorX: 0.5,
anchorY: 0.5
});
self.fallSpeed = 1.5;
self.isEaten = false;
self.update = function () {
if (!self.isEaten) {
self.y += self.fallSpeed;
// Remove food if it falls out of tank
if (self.y > 1900) {
self.destroy();
for (var i = fishFoods.length - 1; i >= 0; i--) {
if (fishFoods[i] === self) {
fishFoods.splice(i, 1);
break;
}
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x001122
});
/****
* Game Code
****/
// Create tank background
var tankBackground = game.attachAsset('tank', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366,
alpha: 0.3
});
// Create multiple betta fish
var bettaFishes = [];
for (var i = 0; i < 6; i++) {
var bettaFish = new BettaFish();
bettaFish.x = Math.random() * 1400 + 324;
bettaFish.y = Math.random() * 800 + 466;
bettaFishes.push(bettaFish);
game.addChild(bettaFish);
}
// Create bubbles
var bubbles = [];
for (var i = 0; i < 8; i++) {
var bubble = new Bubble();
bubble.x = Math.random() * 1800 + 124;
bubble.y = Math.random() * 1200 + 466;
bubbles.push(bubble);
game.addChild(bubble);
}
// Create fish food array
var fishFoods = [];
// Touch interaction - drop fish food
game.down = function (x, y, obj) {
var newFood = new FishFood();
newFood.x = x;
newFood.y = y;
fishFoods.push(newFood);
game.addChild(newFood);
};
// Spawn new bubbles occasionally
var bubbleSpawnTimer = 0;
game.update = function () {
// Spawn new bubbles
bubbleSpawnTimer++;
if (bubbleSpawnTimer > 300 && Math.random() < 0.1) {
if (bubbles.length < 12) {
var newBubble = new Bubble();
newBubble.x = Math.random() * 1800 + 124;
newBubble.y = 2800;
bubbles.push(newBubble);
game.addChild(newBubble);
}
bubbleSpawnTimer = 0;
}
// Clean up bubbles that are too far off screen
for (var i = bubbles.length - 1; i >= 0; i--) {
if (bubbles[i].y < -100) {
bubbles[i].destroy();
bubbles.splice(i, 1);
}
}
// Check for fish food interactions with all fish
for (var i = fishFoods.length - 1; i >= 0; i--) {
var food = fishFoods[i];
if (!food.isEaten) {
var closestFish = null;
var closestDistance = Infinity;
var foodEaten = false;
// Check all fish for this food
for (var j = 0; j < bettaFishes.length; j++) {
var fish = bettaFishes[j];
var dx = food.x - fish.x;
var dy = food.y - fish.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Track closest fish to this food
if (distance < closestDistance) {
closestDistance = distance;
closestFish = fish;
}
// If fish is close to food, make fish swim to it
if (distance < 200 && distance > 25) {
fish.targetX = food.x;
fish.targetY = food.y;
if (fish.isGliding) {
fish.isGliding = false;
fish.speed = 5; // Slightly faster when chasing food
}
}
// If fish reaches food, eat it
if (distance < 25 && !foodEaten) {
food.isEaten = true;
foodEaten = true;
// Scale food down and fade out
tween(food, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 250,
easing: tween.easeOut,
onFinish: function onFinish() {
food.destroy();
}
});
fishFoods.splice(i, 1);
// Make fish swim freely again after eating
fish.isGliding = true;
fish.speed = 1;
fish.glideDuration = 0;
fish.targetX = Math.random() * 1400 + 324;
fish.targetY = Math.random() * 800 + 466;
break; // Food is eaten, exit fish loop
}
}
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -186,13 +186,17 @@
x: 1024,
y: 1366,
alpha: 0.3
});
-// Create betta fish
-var bettaFish = new BettaFish();
-bettaFish.x = 1024;
-bettaFish.y = 1366;
-game.addChild(bettaFish);
+// Create multiple betta fish
+var bettaFishes = [];
+for (var i = 0; i < 6; i++) {
+ var bettaFish = new BettaFish();
+ bettaFish.x = Math.random() * 1400 + 324;
+ bettaFish.y = Math.random() * 800 + 466;
+ bettaFishes.push(bettaFish);
+ game.addChild(bettaFish);
+}
// Create bubbles
var bubbles = [];
for (var i = 0; i < 8; i++) {
var bubble = new Bubble();
@@ -232,46 +236,60 @@
bubbles[i].destroy();
bubbles.splice(i, 1);
}
}
- // Check for fish food interactions
+ // Check for fish food interactions with all fish
for (var i = fishFoods.length - 1; i >= 0; i--) {
var food = fishFoods[i];
if (!food.isEaten) {
- var dx = food.x - bettaFish.x;
- var dy = food.y - bettaFish.y;
- var distance = Math.sqrt(dx * dx + dy * dy);
- // If fish is close to food, make fish swim to it
- if (distance < 150 && distance > 25) {
- bettaFish.targetX = food.x;
- bettaFish.targetY = food.y;
- if (bettaFish.isGliding) {
- bettaFish.isGliding = false;
- bettaFish.speed = 4;
+ var closestFish = null;
+ var closestDistance = Infinity;
+ var foodEaten = false;
+ // Check all fish for this food
+ for (var j = 0; j < bettaFishes.length; j++) {
+ var fish = bettaFishes[j];
+ var dx = food.x - fish.x;
+ var dy = food.y - fish.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ // Track closest fish to this food
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestFish = fish;
}
- }
- // If fish reaches food, eat it
- if (distance < 25) {
- food.isEaten = true;
- // Scale food down and fade out
- tween(food, {
- scaleX: 0,
- scaleY: 0,
- alpha: 0
- }, {
- duration: 250,
- easing: tween.easeOut,
- onFinish: function onFinish() {
- food.destroy();
+ // If fish is close to food, make fish swim to it
+ if (distance < 200 && distance > 25) {
+ fish.targetX = food.x;
+ fish.targetY = food.y;
+ if (fish.isGliding) {
+ fish.isGliding = false;
+ fish.speed = 5; // Slightly faster when chasing food
}
- });
- fishFoods.splice(i, 1);
- // Make fish swim freely again after eating
- bettaFish.isGliding = true;
- bettaFish.speed = 1;
- bettaFish.glideDuration = 0;
- bettaFish.targetX = Math.random() * 1400 + 324;
- bettaFish.targetY = Math.random() * 800 + 466;
+ }
+ // If fish reaches food, eat it
+ if (distance < 25 && !foodEaten) {
+ food.isEaten = true;
+ foodEaten = true;
+ // Scale food down and fade out
+ tween(food, {
+ scaleX: 0,
+ scaleY: 0,
+ alpha: 0
+ }, {
+ duration: 250,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ food.destroy();
+ }
+ });
+ fishFoods.splice(i, 1);
+ // Make fish swim freely again after eating
+ fish.isGliding = true;
+ fish.speed = 1;
+ fish.glideDuration = 0;
+ fish.targetX = Math.random() * 1400 + 324;
+ fish.targetY = Math.random() * 800 + 466;
+ break; // Food is eaten, exit fish loop
+ }
}
}
}
};
\ No newline at end of file