User prompt
the colliders are too big could you make them more accurate
User prompt
Could you make the colliders visible
User prompt
Could you add the value of the fish on the fish, so the values are visible from the players perspective
User prompt
Could you make medium fish bigger and the big fish even bigger
Code edit (1 edits merged)
Please save this source code
User prompt
could you make that if the player collides with the edges the game ends
User prompt
could you make the game go on until the player gets eaten.
Code edit (1 edits merged)
Please save this source code
User prompt
Fish Feast: Ocean Survival
Initial prompt
I want to make a fish game. In the game the player will be a fish in the ocean. There will be other fish , some big some small. The player should be able to eat smaller fish but get eaten by bigger fish. After some point the player should get bigger and the surrounding fish should adapt to the player.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Enemy Fish Class var EnemyFish = Container.expand(function () { var self = Container.call(this); // Will be set on creation self.fishType = 'smallFish'; // 'smallFish', 'mediumFish', 'bigFish' self.sizeValue = 1; // Used for collision and logic self.speed = 2; // px per frame self.direction = 1; // 1: right, -1: left // Asset var fishAsset = null; // Value label var valueLabel = null; // Collider visual var colliderCircle = null; self.init = function (type, sizeValue, speed, direction) { self.fishType = type; self.sizeValue = sizeValue; self.speed = speed; self.direction = direction; // Remove previous asset if any if (fishAsset) { self.removeChild(fishAsset); } if (valueLabel) { self.removeChild(valueLabel); } if (colliderCircle) { self.removeChild(colliderCircle); } fishAsset = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); self.scale.x = direction; // Flip if moving left self.scale.y = 1; // Set scale based on sizeValue self.scale.x *= sizeValue; self.scale.y *= sizeValue; // Add value label (rounded to 2 decimals) valueLabel = new Text2(self.sizeValue.toFixed(2), { size: 60, fill: 0xffffff, align: "center" }); valueLabel.anchor.set(0.5, 0.5); // Place label at center of fish valueLabel.x = 0; valueLabel.y = 0; self.addChild(valueLabel); // Add collider visual (ellipse for more accurate fit) var colliderW = fishAsset.width * Math.abs(self.scale.x) * 0.45; var colliderH = fishAsset.height * Math.abs(self.scale.y) * 0.45; colliderCircle = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: colliderW / 50, scaleY: colliderH / 50, alpha: 0.25, tint: 0xff0000 }); self.addChild(colliderCircle); }; self.getRadius = function () { return fishAsset.width * Math.abs(self.scale.x) * 0.5; }; // Move fish self.update = function () { self.x += self.speed * self.direction; // Keep collider visual in sync with scale (ellipse) if (colliderCircle && fishAsset) { var colliderW = fishAsset.width * Math.abs(self.scale.x) * 0.45; var colliderH = fishAsset.height * Math.abs(self.scale.y) * 0.45; colliderCircle.scale.x = colliderW / 50; colliderCircle.scale.y = colliderH / 50; } }; return self; }); // Player Fish Class var PlayerFish = Container.expand(function () { var self = Container.call(this); var fish = self.attachAsset('playerFish', { anchorX: 0.5, anchorY: 0.5 }); var colliderCircle = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: fish.width * 0.45 / 50, scaleY: fish.height * 0.45 / 50, alpha: 0.25, tint: 0x00ff00 }); self.addChild(colliderCircle); self.size = 1; // Growth multiplier // Update size/scale self.setSize = function (scale) { self.size = scale; self.scale.x = scale; self.scale.y = scale; // Update collider visual (ellipse) if (colliderCircle && fish) { var colliderW = fish.width * self.size * 0.45; var colliderH = fish.height * self.size * 0.45; colliderCircle.scale.x = colliderW / 50; colliderCircle.scale.y = colliderH / 50; } }; // For collision, always use the container, not the asset self.getRadius = function () { return fish.width * self.size * 0.5; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a237e // Deep blue ocean }); /**** * Game Code ****/ // Game constants // Fish assets: player, small fish, medium fish, big fish var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var PLAYER_START_SIZE = 1; var PLAYER_GROWTH = 0.12; // Each fish eaten increases size by this factor var MAX_PLAYER_SIZE = 2.5; var ENEMY_SPAWN_INTERVAL = 60; // frames var ENEMY_MIN_SPEED = 4; var ENEMY_MAX_SPEED = 10; var ENEMY_SPAWN_MARGIN = 120; // px offscreen // State var player = null; var enemyFishes = []; var score = 0; var scoreTxt = null; var dragNode = null; var lastGameOver = false; var spawnTick = 0; // Helper: Get random between min and max function randBetween(min, max) { return min + Math.random() * (max - min); } // Helper: Clamp value function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Initialize player player = new PlayerFish(); player.setSize(PLAYER_START_SIZE); player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT * 0.7; game.addChild(player); // Score text scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Spawning enemy fish function spawnEnemyFish() { // Determine player size for dynamic difficulty var pSize = player.size; // Decide fish type and size var type, sizeValue, speed, direction; var r = Math.random(); // Probability: 50% small, 35% medium, 15% big if (r < 0.5) { type = 'smallFish'; // Always smaller than player sizeValue = clamp(randBetween(0.5, pSize * 0.85), 0.4, 1.2); } else if (r < 0.85) { type = 'mediumFish'; // Medium fish are now noticeably bigger sizeValue = clamp(randBetween(pSize * 1.1, pSize * 1.7), 1.2, 2.2); } else { type = 'bigFish'; // Big fish are now much bigger sizeValue = clamp(randBetween(pSize * 1.7, pSize * 2.7), 2.2, 3.2); } // Speed: smaller fish are faster speed = clamp(ENEMY_MAX_SPEED - sizeValue * 3, ENEMY_MIN_SPEED, ENEMY_MAX_SPEED); // Direction: left or right direction = Math.random() < 0.5 ? 1 : -1; var fish = new EnemyFish(); fish.init(type, sizeValue, speed, direction); // Y position: random, but not too close to top/bottom var minY = 200 + fish.getRadius(); var maxY = GAME_HEIGHT - 200 - fish.getRadius(); fish.y = randBetween(minY, maxY); // X position: offscreen left or right if (direction === 1) { fish.x = -ENEMY_SPAWN_MARGIN; } else { fish.x = GAME_WIDTH + ENEMY_SPAWN_MARGIN; } // Track enemyFishes.push(fish); game.addChild(fish); } // Move handler for dragging player function handleMove(x, y, obj) { if (dragNode) { // Clamp to game area var r = player.getRadius(); dragNode.x = clamp(x, r, GAME_WIDTH - r); dragNode.y = clamp(y, r, GAME_HEIGHT - r); } } // Touch/drag events game.down = function (x, y, obj) { // Only allow drag if touch is on player var dx = x - player.x; var dy = y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < player.getRadius() * 1.1) { dragNode = player; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; game.move = handleMove; // Game update loop game.update = function () { // Spawn enemy fish spawnTick++; if (spawnTick >= ENEMY_SPAWN_INTERVAL) { spawnTick = 0; spawnEnemyFish(); } // Check if player collides with any edge var pr = player.getRadius(); if (player.x - pr <= 0 || player.x + pr >= GAME_WIDTH || player.y - pr <= 0 || player.y + pr >= GAME_HEIGHT) { if (!lastGameOver) { lastGameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Update enemy fish for (var i = enemyFishes.length - 1; i >= 0; i--) { var fish = enemyFishes[i]; fish.update(); // Remove if offscreen if (fish.direction === 1 && fish.x - fish.getRadius() > GAME_WIDTH + ENEMY_SPAWN_MARGIN || fish.direction === -1 && fish.x + fish.getRadius() < -ENEMY_SPAWN_MARGIN) { fish.destroy(); enemyFishes.splice(i, 1); continue; } // Collision with player var dx = fish.x - player.x; var dy = fish.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); var minDist = fish.getRadius() + player.getRadius() * 0.85; if (dist < minDist) { // Compare sizes if (player.size > fish.sizeValue * 1.05) { // Eat fish // Animate fish fade out tween(fish, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { fish.destroy(); } }); enemyFishes.splice(i, 1); // Grow player var newSize = clamp(player.size + PLAYER_GROWTH * fish.sizeValue, PLAYER_START_SIZE, MAX_PLAYER_SIZE); player.setSize(newSize); // Update score score += Math.floor(10 * fish.sizeValue); scoreTxt.setText(score); // Win condition removed: game continues until player is eaten } else if (player.size < fish.sizeValue * 0.95) { // Player is eaten if (!lastGameOver) { lastGameOver = true; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // If similar size, nothing happens } } }; // Reset state on game restart LK.on('gameStart', function () { // Remove all enemy fish for (var i = 0; i < enemyFishes.length; i++) { enemyFishes[i].destroy(); } enemyFishes = []; // Reset player player.setSize(PLAYER_START_SIZE); player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT * 0.7; // Reset score score = 0; scoreTxt.setText(score); lastGameOver = false; spawnTick = 0; });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy Fish Class
var EnemyFish = Container.expand(function () {
var self = Container.call(this);
// Will be set on creation
self.fishType = 'smallFish'; // 'smallFish', 'mediumFish', 'bigFish'
self.sizeValue = 1; // Used for collision and logic
self.speed = 2; // px per frame
self.direction = 1; // 1: right, -1: left
// Asset
var fishAsset = null;
// Value label
var valueLabel = null;
// Collider visual
var colliderCircle = null;
self.init = function (type, sizeValue, speed, direction) {
self.fishType = type;
self.sizeValue = sizeValue;
self.speed = speed;
self.direction = direction;
// Remove previous asset if any
if (fishAsset) {
self.removeChild(fishAsset);
}
if (valueLabel) {
self.removeChild(valueLabel);
}
if (colliderCircle) {
self.removeChild(colliderCircle);
}
fishAsset = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
self.scale.x = direction; // Flip if moving left
self.scale.y = 1;
// Set scale based on sizeValue
self.scale.x *= sizeValue;
self.scale.y *= sizeValue;
// Add value label (rounded to 2 decimals)
valueLabel = new Text2(self.sizeValue.toFixed(2), {
size: 60,
fill: 0xffffff,
align: "center"
});
valueLabel.anchor.set(0.5, 0.5);
// Place label at center of fish
valueLabel.x = 0;
valueLabel.y = 0;
self.addChild(valueLabel);
// Add collider visual (ellipse for more accurate fit)
var colliderW = fishAsset.width * Math.abs(self.scale.x) * 0.45;
var colliderH = fishAsset.height * Math.abs(self.scale.y) * 0.45;
colliderCircle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: colliderW / 50,
scaleY: colliderH / 50,
alpha: 0.25,
tint: 0xff0000
});
self.addChild(colliderCircle);
};
self.getRadius = function () {
return fishAsset.width * Math.abs(self.scale.x) * 0.5;
};
// Move fish
self.update = function () {
self.x += self.speed * self.direction;
// Keep collider visual in sync with scale (ellipse)
if (colliderCircle && fishAsset) {
var colliderW = fishAsset.width * Math.abs(self.scale.x) * 0.45;
var colliderH = fishAsset.height * Math.abs(self.scale.y) * 0.45;
colliderCircle.scale.x = colliderW / 50;
colliderCircle.scale.y = colliderH / 50;
}
};
return self;
});
// Player Fish Class
var PlayerFish = Container.expand(function () {
var self = Container.call(this);
var fish = self.attachAsset('playerFish', {
anchorX: 0.5,
anchorY: 0.5
});
var colliderCircle = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: fish.width * 0.45 / 50,
scaleY: fish.height * 0.45 / 50,
alpha: 0.25,
tint: 0x00ff00
});
self.addChild(colliderCircle);
self.size = 1; // Growth multiplier
// Update size/scale
self.setSize = function (scale) {
self.size = scale;
self.scale.x = scale;
self.scale.y = scale;
// Update collider visual (ellipse)
if (colliderCircle && fish) {
var colliderW = fish.width * self.size * 0.45;
var colliderH = fish.height * self.size * 0.45;
colliderCircle.scale.x = colliderW / 50;
colliderCircle.scale.y = colliderH / 50;
}
};
// For collision, always use the container, not the asset
self.getRadius = function () {
return fish.width * self.size * 0.5;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a237e // Deep blue ocean
});
/****
* Game Code
****/
// Game constants
// Fish assets: player, small fish, medium fish, big fish
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAYER_START_SIZE = 1;
var PLAYER_GROWTH = 0.12; // Each fish eaten increases size by this factor
var MAX_PLAYER_SIZE = 2.5;
var ENEMY_SPAWN_INTERVAL = 60; // frames
var ENEMY_MIN_SPEED = 4;
var ENEMY_MAX_SPEED = 10;
var ENEMY_SPAWN_MARGIN = 120; // px offscreen
// State
var player = null;
var enemyFishes = [];
var score = 0;
var scoreTxt = null;
var dragNode = null;
var lastGameOver = false;
var spawnTick = 0;
// Helper: Get random between min and max
function randBetween(min, max) {
return min + Math.random() * (max - min);
}
// Helper: Clamp value
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Initialize player
player = new PlayerFish();
player.setSize(PLAYER_START_SIZE);
player.x = GAME_WIDTH / 2;
player.y = GAME_HEIGHT * 0.7;
game.addChild(player);
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Spawning enemy fish
function spawnEnemyFish() {
// Determine player size for dynamic difficulty
var pSize = player.size;
// Decide fish type and size
var type, sizeValue, speed, direction;
var r = Math.random();
// Probability: 50% small, 35% medium, 15% big
if (r < 0.5) {
type = 'smallFish';
// Always smaller than player
sizeValue = clamp(randBetween(0.5, pSize * 0.85), 0.4, 1.2);
} else if (r < 0.85) {
type = 'mediumFish';
// Medium fish are now noticeably bigger
sizeValue = clamp(randBetween(pSize * 1.1, pSize * 1.7), 1.2, 2.2);
} else {
type = 'bigFish';
// Big fish are now much bigger
sizeValue = clamp(randBetween(pSize * 1.7, pSize * 2.7), 2.2, 3.2);
}
// Speed: smaller fish are faster
speed = clamp(ENEMY_MAX_SPEED - sizeValue * 3, ENEMY_MIN_SPEED, ENEMY_MAX_SPEED);
// Direction: left or right
direction = Math.random() < 0.5 ? 1 : -1;
var fish = new EnemyFish();
fish.init(type, sizeValue, speed, direction);
// Y position: random, but not too close to top/bottom
var minY = 200 + fish.getRadius();
var maxY = GAME_HEIGHT - 200 - fish.getRadius();
fish.y = randBetween(minY, maxY);
// X position: offscreen left or right
if (direction === 1) {
fish.x = -ENEMY_SPAWN_MARGIN;
} else {
fish.x = GAME_WIDTH + ENEMY_SPAWN_MARGIN;
}
// Track
enemyFishes.push(fish);
game.addChild(fish);
}
// Move handler for dragging player
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp to game area
var r = player.getRadius();
dragNode.x = clamp(x, r, GAME_WIDTH - r);
dragNode.y = clamp(y, r, GAME_HEIGHT - r);
}
}
// Touch/drag events
game.down = function (x, y, obj) {
// Only allow drag if touch is on player
var dx = x - player.x;
var dy = y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < player.getRadius() * 1.1) {
dragNode = player;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
game.move = handleMove;
// Game update loop
game.update = function () {
// Spawn enemy fish
spawnTick++;
if (spawnTick >= ENEMY_SPAWN_INTERVAL) {
spawnTick = 0;
spawnEnemyFish();
}
// Check if player collides with any edge
var pr = player.getRadius();
if (player.x - pr <= 0 || player.x + pr >= GAME_WIDTH || player.y - pr <= 0 || player.y + pr >= GAME_HEIGHT) {
if (!lastGameOver) {
lastGameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Update enemy fish
for (var i = enemyFishes.length - 1; i >= 0; i--) {
var fish = enemyFishes[i];
fish.update();
// Remove if offscreen
if (fish.direction === 1 && fish.x - fish.getRadius() > GAME_WIDTH + ENEMY_SPAWN_MARGIN || fish.direction === -1 && fish.x + fish.getRadius() < -ENEMY_SPAWN_MARGIN) {
fish.destroy();
enemyFishes.splice(i, 1);
continue;
}
// Collision with player
var dx = fish.x - player.x;
var dy = fish.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var minDist = fish.getRadius() + player.getRadius() * 0.85;
if (dist < minDist) {
// Compare sizes
if (player.size > fish.sizeValue * 1.05) {
// Eat fish
// Animate fish fade out
tween(fish, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
fish.destroy();
}
});
enemyFishes.splice(i, 1);
// Grow player
var newSize = clamp(player.size + PLAYER_GROWTH * fish.sizeValue, PLAYER_START_SIZE, MAX_PLAYER_SIZE);
player.setSize(newSize);
// Update score
score += Math.floor(10 * fish.sizeValue);
scoreTxt.setText(score);
// Win condition removed: game continues until player is eaten
} else if (player.size < fish.sizeValue * 0.95) {
// Player is eaten
if (!lastGameOver) {
lastGameOver = true;
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// If similar size, nothing happens
}
}
};
// Reset state on game restart
LK.on('gameStart', function () {
// Remove all enemy fish
for (var i = 0; i < enemyFishes.length; i++) {
enemyFishes[i].destroy();
}
enemyFishes = [];
// Reset player
player.setSize(PLAYER_START_SIZE);
player.x = GAME_WIDTH / 2;
player.y = GAME_HEIGHT * 0.7;
// Reset score
score = 0;
scoreTxt.setText(score);
lastGameOver = false;
spawnTick = 0;
});
Fish. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A stingray fish . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A big Black and White Orca. In-Game asset. 2d. High contrast. No shadows
A blueish Anchovy. In-Game asset. 2d. High contrast. No shadows