/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Boat = Container.expand(function () { var self = Container.call(this); var boatGraphics = self.attachAsset('boat', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.isCasting = false; self.lineLength = 0; self.maxLineLength = 2400; // Increased to reach bottom of screen (screen height is 2732, boat is at y=300) self.lineSpeed = 10; // Increased from 6 to 10 for even faster fishing line movement self.isExploding = false; self.explodeScale = 1; self.velocityX = 0; // Current horizontal velocity for smooth movement self.maxVelocity = 30; // Maximum velocity self.friction = 0.92; // Friction applied to slow down movement self.targetX = null; // Target position to move toward self.swipeStartTime = 0; // Track when swipe started for velocity calculation var fishingLine = self.attachAsset('fishingLine', { anchorX: 0.5, anchorY: 0, x: 0, y: 50, visible: false, height: 0 }); var fishHook = self.attachAsset('fishHook', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 50, visible: false }); self.castLine = function () { if (!self.isCasting) { self.isCasting = true; fishingLine.visible = true; fishHook.visible = true; LK.getSound('cast').play(); } }; self.reelIn = function () { self.isCasting = false; }; self.update = function () { if (self.isCasting && self.lineLength < self.maxLineLength) { self.lineLength += self.lineSpeed; fishingLine.height = self.lineLength; fishHook.y = 50 + self.lineLength; } else if (!self.isCasting && self.lineLength > 0) { self.lineLength -= self.lineSpeed * 2; fishingLine.height = self.lineLength; fishHook.y = 50 + self.lineLength; } if (self.lineLength <= 0 && !self.isCasting) { fishingLine.visible = false; fishHook.visible = false; self.lineLength = 0; } // Smooth boat movement physics if (self.targetX !== null) { // Calculate distance to target var distanceToTarget = self.targetX - self.x; // Apply force based on distance self.velocityX += distanceToTarget * 0.04; // Limit maximum velocity if (self.velocityX > self.maxVelocity) self.velocityX = self.maxVelocity; if (self.velocityX < -self.maxVelocity) self.velocityX = -self.maxVelocity; // If very close to target and moving slowly, just snap to position if (Math.abs(distanceToTarget) < 1 && Math.abs(self.velocityX) < 0.5) { self.x = self.targetX; self.velocityX = 0; self.targetX = null; } } // Apply velocity with friction if (Math.abs(self.velocityX) > 0.1) { self.x += self.velocityX; self.velocityX *= self.friction; // Keep boat within bounds if (self.x < 100) { self.x = 100; self.velocityX = 0; } else if (self.x > 2048 - 100) { self.x = 2048 - 100; self.velocityX = 0; } } else { self.velocityX = 0; } }; self.getHookPosition = function () { return { x: self.x, y: self.y + 50 + self.lineLength }; }; self.lastHookPosition = self.getHookPosition(); self.explode = function () { if (self.isExploding) return; self.isExploding = true; boatGraphics.tint = 0xFF3300; // Fire color function animateExplosion() { self.explodeScale += 0.2; boatGraphics.scale.set(self.explodeScale); boatGraphics.alpha -= 0.1; if (boatGraphics.alpha > 0) { LK.setTimeout(animateExplosion, 30); } else { // Boat destroyed completely self.visible = false; isGameOver = true; LK.showGameOver(); } } animateExplosion(); }; self.down = function (x, y, obj) { self.swipeStartTime = Date.now(); // Track when swipe started self.castLine(); }; self.up = function (x, y, obj) { self.reelIn(); }; return self; }); var Fish = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'normal'; var assetId, points; switch (self.type) { case 'rare': assetId = 'rareFish'; points = 50; self.speed = 3; // Increased speed for rare fish break; case 'legendary': assetId = 'legendaryFish'; points = 100; self.speed = 6; // Further increased speed for legendary fish break; default: assetId = 'fish'; points = 10; self.speed = 2.5; // Increased speed for normal fish } self.points = points; var fishGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Randomly set the direction (left or right) self.direction = Math.random() > 0.5 ? 1 : -1; // If moving right, flip the fish if (self.direction > 0) { fishGraphics.scaleX = -1; } self.update = function () { // Only update position every other frame to reduce computational load if (LK.ticks % 2 === 0) { self.x += self.speed * self.direction; // If fish goes off screen, remove it if (self.direction > 0 && self.x > 2048 + fishGraphics.width || self.direction < 0 && self.x < -fishGraphics.width) { self.shouldRemove = true; } // If boat is casting and fish is far from hook, adjust its path toward visible area if (boat && boat.isCasting) { var hookPos = boat.getHookPosition(); var verticalDistance = Math.abs(self.y - hookPos.y); // If fish is too far from hook vertically, move it toward the hook if (verticalDistance > 1000) { // Move fish toward hook's vertical position if (self.y > hookPos.y) { self.y -= 1; } else { self.y += 1; } } } } }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); // Sea mine asset (round shape with spikes) var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, tint: 0x333333, // Dark gray color for sea mines scaleX: 0.7, // Smaller size to reduce impact scaleY: 0.7 // Smaller size to reduce impact }); // Create spikes around the mine (using rotation) - reduced number of spikes for (var i = 0; i < 4; i++) { // Reduced from 8 to 4 spikes var spike = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0, scaleX: 0.15, scaleY: 0.4, tint: 0x333333 }); spike.rotation = i * Math.PI / 2; // 4 spikes at 90 degree intervals spike.x = Math.cos(spike.rotation) * 15; // Reduced distance spike.y = Math.sin(spike.rotation) * 15; // Reduced distance } self.speed = 0.08; // Even more reduced obstacle speed // Add simplified pulsing animation effect self.pulsePhase = Math.random() * Math.PI * 2; // Random starting phase self.update = function () { // Pulsing animation for sea mine - update less frequently to save CPU if (LK.ticks % 3 === 0) { // Only update animation every 3 frames var pulseFactor = 0.08 * Math.sin(self.pulsePhase); obstacleGraphics.scaleX = 0.7 + pulseFactor; obstacleGraphics.scaleY = 0.7 + pulseFactor; self.pulsePhase += 0.03; // Slower animation } self.y -= self.speed; if (self.y < -obstacleGraphics.height) { self.shouldRemove = true; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var boat; var fishes = []; var obstacles = []; var score = 0; var isGameOver = false; var waterLevel = 0; // Used for difficulty progression only var fishSpawnRate = 0.02; var obstacleSpawnRate = 0.01; var backgroundSpeed = 1; var highScore = storage.highScore || 0; // Create water background var water = LK.getAsset('water', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(water); // Initialize boat boat = new Boat(); boat.x = 2048 / 2; boat.y = 300; game.addChild(boat); // Create score text var scoreTxt = new Text2('Score: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create high score text var highScoreTxt = new Text2('High Score: ' + highScore, { size: 50, fill: 0xFFD700 }); highScoreTxt.anchor.set(0.5, 0); highScoreTxt.y = 150; LK.gui.top.addChild(highScoreTxt); // Depth indicator removed // Handle touch/click events for the game area var gameSwipeStartX = 0; var gameSwipeStartY = 0; var isSwipingInGame = false; game.down = function (x, y, obj) { if (!isGameOver) { gameSwipeStartX = x; gameSwipeStartY = y; isSwipingInGame = true; boat.swipeStartTime = Date.now(); // Track when swipe started for velocity calculation } }; game.up = function (x, y, obj) { if (!isGameOver) { // Calculate swipe distance var deltaX = x - gameSwipeStartX; var deltaY = y - gameSwipeStartY; var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var swipeTime = Date.now() - boat.swipeStartTime; if (swipeDistance < 20) { // It's a tap, not a swipe - toggle fishing line if (boat.isCasting) { boat.reelIn(); } else { boat.castLine(); } } else { // It was a swipe - apply momentum to the boat based on swipe speed var swipeVelocity = deltaX / swipeTime * 10; boat.velocityX += swipeVelocity; // Limit initial velocity if (boat.velocityX > boat.maxVelocity) boat.velocityX = boat.maxVelocity; if (boat.velocityX < -boat.maxVelocity) boat.velocityX = -boat.maxVelocity; // Calculate target position based on swipe length boat.targetX = boat.x + deltaX * 0.6; // Keep target within game bounds boat.targetX = Math.max(boat.targetX, 100); boat.targetX = Math.min(boat.targetX, 2048 - 100); } isSwipingInGame = false; } }; // Handle touch move for navigating the boat with swipe var swipeStartX = 0; var swipeStartY = 0; var isDraggingBoat = false; game.move = function (x, y, obj) { if (isDraggingBoat) { // Calculate horizontal distance moved since last position var deltaX = x - swipeStartX; // Set target position directly for smooth following boat.targetX = boat.x + deltaX; // Add velocity based on motion speed var moveSpeed = deltaX; boat.velocityX = moveSpeed * 0.8; // Keep boat within game bounds boat.targetX = Math.max(boat.targetX, 100); boat.targetX = Math.min(boat.targetX, 2048 - 100); // Update swipe start position for next move swipeStartX = x; } // Handle swiping in general game area - adds another way to control the boat if (isSwipingInGame) { var dragDeltaX = x - gameSwipeStartX; // Only update if there's enough movement to be considered a swipe if (Math.abs(dragDeltaX) > 5) { boat.targetX = boat.x + dragDeltaX * 0.5; boat.targetX = Math.max(boat.targetX, 100); boat.targetX = Math.min(boat.targetX, 2048 - 100); // Update swipe start for next move gameSwipeStartX = x; } } }; // Start tracking swipe boat.down = function (x, y, obj) { isDraggingBoat = true; swipeStartX = x; swipeStartY = y; boat.swipeStartTime = Date.now(); // Track when swipe started for velocity calculation }; // End swipe and cast fishing line boat.up = function (x, y, obj) { isDraggingBoat = false; // Only cast line if it was a tap (not a long swipe) var deltaX = Math.abs(x - swipeStartX); var deltaY = Math.abs(y - swipeStartY); if (deltaX < 20 && deltaY < 20) { boat.castLine(); } }; // Function to spawn fish function spawnFish() { // Limit the maximum number of fish to prevent lag if (fishes.length >= 10) return; // Don't create more than 10 fish at a time // Significantly reduced spawn chance if (Math.random() < fishSpawnRate * 0.3) { var fishType; var random = Math.random(); if (random < 0.05) { fishType = 'legendary'; } else if (random < 0.2) { fishType = 'rare'; } else { fishType = 'normal'; } var fish = new Fish(fishType); // Random position on left or right side if (fish.direction > 0) { fish.x = -fish.width / 2; } else { fish.x = 2048 + fish.width / 2; } // Random depth within screen bounds var minDepth = 400; var maxDepth = 2732 - 100; // If the boat is casting, ensure fish spawn near the hook if (boat.isCasting) { var hookPos = boat.getHookPosition(); // Calculate a reasonable vertical area around the hook (ensuring fish are on screen) var maxDistance = 800; // Maximum distance from hook in pixels minDepth = Math.max(400, hookPos.y - maxDistance); maxDepth = Math.min(2732 - 100, hookPos.y + maxDistance); } fish.y = minDepth + Math.random() * (maxDepth - minDepth); fishes.push(fish); game.addChild(fish); } } // Function to spawn obstacles function spawnObstacle() { // Limit the maximum number of obstacles to prevent lag if (obstacles.length >= 5) return; // Don't create more than 5 obstacles at a time if (Math.random() < obstacleSpawnRate) { var obstacle = new Obstacle(); // Sea mines float at varying depths obstacle.x = 100 + Math.random() * (2048 - 200); obstacle.y = 2732 + obstacle.height; // Add simple floating movement to sea mines obstacle.floatDirection = Math.random() > 0.5 ? 1 : -1; obstacle.floatSpeed = 0.1 + Math.random() * 0.1; // Reduced speed variation obstacle.floatPhase = Math.random() * Math.PI * 2; obstacles.push(obstacle); game.addChild(obstacle); } } // Function to check if hook caught a fish function checkFishCatch() { if (!boat.isCasting) return; var hookPos = boat.getHookPosition(); for (var i = fishes.length - 1; i >= 0; i--) { var fish = fishes[i]; var distance = Math.sqrt(Math.pow(hookPos.x - fish.x, 2) + Math.pow(hookPos.y - fish.y, 2)); if (distance < 40) { // Hook caught a fish // Add points based on fish type score += fish.points; LK.setScore(score); scoreTxt.setText('Score: ' + score); // Update high score if needed if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('High Score: ' + highScore); // Flash high score text when broken LK.effects.flashObject(highScoreTxt, 0xFFD700, 1000); } // Play catch sound LK.getSound('catch').play(); // Flash effect LK.effects.flashObject(fish, 0xFFFFFF, 500); // Remove the fish fish.destroy(); fishes.splice(i, 1); // Reel in after catching boat.reelIn(); break; } } } // Function to check boat collision with obstacles function checkObstacleCollisions() { var _loop = function _loop() { obstacle = obstacles[i]; if (boat.intersects(obstacle)) { var _animateExplosion = function animateExplosion() { explosionSize += 0.2; obstacle.scale.set(explosionSize); obstacle.alpha -= 0.1; if (obstacle.alpha > 0) { LK.setTimeout(_animateExplosion, 30); } else { // Remove the sea mine after explosion completes obstacle.destroy(); obstacles.splice(i, 1); } }; // Hit a sea mine - create explosion effect LK.effects.flashScreen(0xFF0000, 800); LK.getSound('splash').play(); // Create explosion animation explosionSize = 1; obstacle.tint = 0xFF3300; // Explosion color _animateExplosion(); // Make boat explode boat.explode(); return 0; // break } // Also check if fishing line hits sea mine if (boat.isCasting) { hookPos = boat.getHookPosition(); distance = Math.sqrt(Math.pow(hookPos.x - obstacle.x, 2) + Math.pow(hookPos.y - obstacle.y, 2)); if (distance < 60) { // Hook hit a sea mine LK.effects.flashScreen(0xFF5500, 500); LK.getSound('splash').play(); // Trigger mine explosion obstacle.tint = 0xFF3300; obstacle.scale.set(1.5); LK.setTimeout(function () { obstacle.destroy(); obstacles.splice(i, 1); }, 300); // Reel in after hitting mine boat.reelIn(); return 0; // break } } }, obstacle, explosionSize, hookPos, distance, _ret; for (var i = obstacles.length - 1; i >= 0; i--) { _ret = _loop(); if (_ret === 0) break; } } // Update game loop game.update = function () { if (isGameOver || boat.isExploding) return; // Increase difficulty over time waterLevel += backgroundSpeed * 0.1; // Increase difficulty based on time fishSpawnRate = 0.005 + waterLevel / 20000; // Further reduced fish spawn rate obstacleSpawnRate = 0.0001 + waterLevel / 100000; // Extremely reduced sea mine spawn rate to prevent lag // Spawn game elements spawnFish(); spawnObstacle(); // Keep track of current hook position if (boat.isCasting) { boat.lastHookPosition = boat.getHookPosition(); } // Update all game objects // Update fishes - only process a subset each frame if there are many var fishesToProcess = Math.min(fishes.length, 5); // Process max 5 fish per frame for (var i = fishes.length - 1; i >= Math.max(0, fishes.length - fishesToProcess); i--) { var fish = fishes[i]; if (fish.shouldRemove) { fish.destroy(); fishes.splice(i, 1); } } // Update obstacles (sea mines) for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Add gentle floating motion to sea mines - less frequently if (obstacle.floatPhase !== undefined && LK.ticks % 4 === 0) { // Only update floating every 4 frames obstacle.floatPhase += 0.01; // Slower movement obstacle.x += Math.sin(obstacle.floatPhase) * obstacle.floatSpeed * obstacle.floatDirection * 0.5; // Reduced movement } if (obstacle.shouldRemove) { obstacle.destroy(); obstacles.splice(i, 1); } } // Check for fish catch checkFishCatch(); // Check for obstacle collisions checkObstacleCollisions(); // No winning condition - allow unlimited play // Game continues indefinitely so players can achieve the highest score possible }; // Play background music LK.playMusic('backgroundNature', { fade: { start: 0, end: 0.3, duration: 1000 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Boat = Container.expand(function () {
var self = Container.call(this);
var boatGraphics = self.attachAsset('boat', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.isCasting = false;
self.lineLength = 0;
self.maxLineLength = 2400; // Increased to reach bottom of screen (screen height is 2732, boat is at y=300)
self.lineSpeed = 10; // Increased from 6 to 10 for even faster fishing line movement
self.isExploding = false;
self.explodeScale = 1;
self.velocityX = 0; // Current horizontal velocity for smooth movement
self.maxVelocity = 30; // Maximum velocity
self.friction = 0.92; // Friction applied to slow down movement
self.targetX = null; // Target position to move toward
self.swipeStartTime = 0; // Track when swipe started for velocity calculation
var fishingLine = self.attachAsset('fishingLine', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: 50,
visible: false,
height: 0
});
var fishHook = self.attachAsset('fishHook', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 50,
visible: false
});
self.castLine = function () {
if (!self.isCasting) {
self.isCasting = true;
fishingLine.visible = true;
fishHook.visible = true;
LK.getSound('cast').play();
}
};
self.reelIn = function () {
self.isCasting = false;
};
self.update = function () {
if (self.isCasting && self.lineLength < self.maxLineLength) {
self.lineLength += self.lineSpeed;
fishingLine.height = self.lineLength;
fishHook.y = 50 + self.lineLength;
} else if (!self.isCasting && self.lineLength > 0) {
self.lineLength -= self.lineSpeed * 2;
fishingLine.height = self.lineLength;
fishHook.y = 50 + self.lineLength;
}
if (self.lineLength <= 0 && !self.isCasting) {
fishingLine.visible = false;
fishHook.visible = false;
self.lineLength = 0;
}
// Smooth boat movement physics
if (self.targetX !== null) {
// Calculate distance to target
var distanceToTarget = self.targetX - self.x;
// Apply force based on distance
self.velocityX += distanceToTarget * 0.04;
// Limit maximum velocity
if (self.velocityX > self.maxVelocity) self.velocityX = self.maxVelocity;
if (self.velocityX < -self.maxVelocity) self.velocityX = -self.maxVelocity;
// If very close to target and moving slowly, just snap to position
if (Math.abs(distanceToTarget) < 1 && Math.abs(self.velocityX) < 0.5) {
self.x = self.targetX;
self.velocityX = 0;
self.targetX = null;
}
}
// Apply velocity with friction
if (Math.abs(self.velocityX) > 0.1) {
self.x += self.velocityX;
self.velocityX *= self.friction;
// Keep boat within bounds
if (self.x < 100) {
self.x = 100;
self.velocityX = 0;
} else if (self.x > 2048 - 100) {
self.x = 2048 - 100;
self.velocityX = 0;
}
} else {
self.velocityX = 0;
}
};
self.getHookPosition = function () {
return {
x: self.x,
y: self.y + 50 + self.lineLength
};
};
self.lastHookPosition = self.getHookPosition();
self.explode = function () {
if (self.isExploding) return;
self.isExploding = true;
boatGraphics.tint = 0xFF3300; // Fire color
function animateExplosion() {
self.explodeScale += 0.2;
boatGraphics.scale.set(self.explodeScale);
boatGraphics.alpha -= 0.1;
if (boatGraphics.alpha > 0) {
LK.setTimeout(animateExplosion, 30);
} else {
// Boat destroyed completely
self.visible = false;
isGameOver = true;
LK.showGameOver();
}
}
animateExplosion();
};
self.down = function (x, y, obj) {
self.swipeStartTime = Date.now(); // Track when swipe started
self.castLine();
};
self.up = function (x, y, obj) {
self.reelIn();
};
return self;
});
var Fish = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'normal';
var assetId, points;
switch (self.type) {
case 'rare':
assetId = 'rareFish';
points = 50;
self.speed = 3; // Increased speed for rare fish
break;
case 'legendary':
assetId = 'legendaryFish';
points = 100;
self.speed = 6; // Further increased speed for legendary fish
break;
default:
assetId = 'fish';
points = 10;
self.speed = 2.5;
// Increased speed for normal fish
}
self.points = points;
var fishGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Randomly set the direction (left or right)
self.direction = Math.random() > 0.5 ? 1 : -1;
// If moving right, flip the fish
if (self.direction > 0) {
fishGraphics.scaleX = -1;
}
self.update = function () {
// Only update position every other frame to reduce computational load
if (LK.ticks % 2 === 0) {
self.x += self.speed * self.direction;
// If fish goes off screen, remove it
if (self.direction > 0 && self.x > 2048 + fishGraphics.width || self.direction < 0 && self.x < -fishGraphics.width) {
self.shouldRemove = true;
}
// If boat is casting and fish is far from hook, adjust its path toward visible area
if (boat && boat.isCasting) {
var hookPos = boat.getHookPosition();
var verticalDistance = Math.abs(self.y - hookPos.y);
// If fish is too far from hook vertically, move it toward the hook
if (verticalDistance > 1000) {
// Move fish toward hook's vertical position
if (self.y > hookPos.y) {
self.y -= 1;
} else {
self.y += 1;
}
}
}
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Sea mine asset (round shape with spikes)
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x333333,
// Dark gray color for sea mines
scaleX: 0.7,
// Smaller size to reduce impact
scaleY: 0.7 // Smaller size to reduce impact
});
// Create spikes around the mine (using rotation) - reduced number of spikes
for (var i = 0; i < 4; i++) {
// Reduced from 8 to 4 spikes
var spike = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.15,
scaleY: 0.4,
tint: 0x333333
});
spike.rotation = i * Math.PI / 2; // 4 spikes at 90 degree intervals
spike.x = Math.cos(spike.rotation) * 15; // Reduced distance
spike.y = Math.sin(spike.rotation) * 15; // Reduced distance
}
self.speed = 0.08; // Even more reduced obstacle speed
// Add simplified pulsing animation effect
self.pulsePhase = Math.random() * Math.PI * 2; // Random starting phase
self.update = function () {
// Pulsing animation for sea mine - update less frequently to save CPU
if (LK.ticks % 3 === 0) {
// Only update animation every 3 frames
var pulseFactor = 0.08 * Math.sin(self.pulsePhase);
obstacleGraphics.scaleX = 0.7 + pulseFactor;
obstacleGraphics.scaleY = 0.7 + pulseFactor;
self.pulsePhase += 0.03; // Slower animation
}
self.y -= self.speed;
if (self.y < -obstacleGraphics.height) {
self.shouldRemove = true;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var boat;
var fishes = [];
var obstacles = [];
var score = 0;
var isGameOver = false;
var waterLevel = 0; // Used for difficulty progression only
var fishSpawnRate = 0.02;
var obstacleSpawnRate = 0.01;
var backgroundSpeed = 1;
var highScore = storage.highScore || 0;
// Create water background
var water = LK.getAsset('water', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(water);
// Initialize boat
boat = new Boat();
boat.x = 2048 / 2;
boat.y = 300;
game.addChild(boat);
// Create score text
var scoreTxt = new Text2('Score: 0', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create high score text
var highScoreTxt = new Text2('High Score: ' + highScore, {
size: 50,
fill: 0xFFD700
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 150;
LK.gui.top.addChild(highScoreTxt);
// Depth indicator removed
// Handle touch/click events for the game area
var gameSwipeStartX = 0;
var gameSwipeStartY = 0;
var isSwipingInGame = false;
game.down = function (x, y, obj) {
if (!isGameOver) {
gameSwipeStartX = x;
gameSwipeStartY = y;
isSwipingInGame = true;
boat.swipeStartTime = Date.now(); // Track when swipe started for velocity calculation
}
};
game.up = function (x, y, obj) {
if (!isGameOver) {
// Calculate swipe distance
var deltaX = x - gameSwipeStartX;
var deltaY = y - gameSwipeStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var swipeTime = Date.now() - boat.swipeStartTime;
if (swipeDistance < 20) {
// It's a tap, not a swipe - toggle fishing line
if (boat.isCasting) {
boat.reelIn();
} else {
boat.castLine();
}
} else {
// It was a swipe - apply momentum to the boat based on swipe speed
var swipeVelocity = deltaX / swipeTime * 10;
boat.velocityX += swipeVelocity;
// Limit initial velocity
if (boat.velocityX > boat.maxVelocity) boat.velocityX = boat.maxVelocity;
if (boat.velocityX < -boat.maxVelocity) boat.velocityX = -boat.maxVelocity;
// Calculate target position based on swipe length
boat.targetX = boat.x + deltaX * 0.6;
// Keep target within game bounds
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
}
isSwipingInGame = false;
}
};
// Handle touch move for navigating the boat with swipe
var swipeStartX = 0;
var swipeStartY = 0;
var isDraggingBoat = false;
game.move = function (x, y, obj) {
if (isDraggingBoat) {
// Calculate horizontal distance moved since last position
var deltaX = x - swipeStartX;
// Set target position directly for smooth following
boat.targetX = boat.x + deltaX;
// Add velocity based on motion speed
var moveSpeed = deltaX;
boat.velocityX = moveSpeed * 0.8;
// Keep boat within game bounds
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
// Update swipe start position for next move
swipeStartX = x;
}
// Handle swiping in general game area - adds another way to control the boat
if (isSwipingInGame) {
var dragDeltaX = x - gameSwipeStartX;
// Only update if there's enough movement to be considered a swipe
if (Math.abs(dragDeltaX) > 5) {
boat.targetX = boat.x + dragDeltaX * 0.5;
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
// Update swipe start for next move
gameSwipeStartX = x;
}
}
};
// Start tracking swipe
boat.down = function (x, y, obj) {
isDraggingBoat = true;
swipeStartX = x;
swipeStartY = y;
boat.swipeStartTime = Date.now(); // Track when swipe started for velocity calculation
};
// End swipe and cast fishing line
boat.up = function (x, y, obj) {
isDraggingBoat = false;
// Only cast line if it was a tap (not a long swipe)
var deltaX = Math.abs(x - swipeStartX);
var deltaY = Math.abs(y - swipeStartY);
if (deltaX < 20 && deltaY < 20) {
boat.castLine();
}
};
// Function to spawn fish
function spawnFish() {
// Limit the maximum number of fish to prevent lag
if (fishes.length >= 10) return; // Don't create more than 10 fish at a time
// Significantly reduced spawn chance
if (Math.random() < fishSpawnRate * 0.3) {
var fishType;
var random = Math.random();
if (random < 0.05) {
fishType = 'legendary';
} else if (random < 0.2) {
fishType = 'rare';
} else {
fishType = 'normal';
}
var fish = new Fish(fishType);
// Random position on left or right side
if (fish.direction > 0) {
fish.x = -fish.width / 2;
} else {
fish.x = 2048 + fish.width / 2;
}
// Random depth within screen bounds
var minDepth = 400;
var maxDepth = 2732 - 100;
// If the boat is casting, ensure fish spawn near the hook
if (boat.isCasting) {
var hookPos = boat.getHookPosition();
// Calculate a reasonable vertical area around the hook (ensuring fish are on screen)
var maxDistance = 800; // Maximum distance from hook in pixels
minDepth = Math.max(400, hookPos.y - maxDistance);
maxDepth = Math.min(2732 - 100, hookPos.y + maxDistance);
}
fish.y = minDepth + Math.random() * (maxDepth - minDepth);
fishes.push(fish);
game.addChild(fish);
}
}
// Function to spawn obstacles
function spawnObstacle() {
// Limit the maximum number of obstacles to prevent lag
if (obstacles.length >= 5) return; // Don't create more than 5 obstacles at a time
if (Math.random() < obstacleSpawnRate) {
var obstacle = new Obstacle();
// Sea mines float at varying depths
obstacle.x = 100 + Math.random() * (2048 - 200);
obstacle.y = 2732 + obstacle.height;
// Add simple floating movement to sea mines
obstacle.floatDirection = Math.random() > 0.5 ? 1 : -1;
obstacle.floatSpeed = 0.1 + Math.random() * 0.1; // Reduced speed variation
obstacle.floatPhase = Math.random() * Math.PI * 2;
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
// Function to check if hook caught a fish
function checkFishCatch() {
if (!boat.isCasting) return;
var hookPos = boat.getHookPosition();
for (var i = fishes.length - 1; i >= 0; i--) {
var fish = fishes[i];
var distance = Math.sqrt(Math.pow(hookPos.x - fish.x, 2) + Math.pow(hookPos.y - fish.y, 2));
if (distance < 40) {
// Hook caught a fish
// Add points based on fish type
score += fish.points;
LK.setScore(score);
scoreTxt.setText('Score: ' + score);
// Update high score if needed
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('High Score: ' + highScore);
// Flash high score text when broken
LK.effects.flashObject(highScoreTxt, 0xFFD700, 1000);
}
// Play catch sound
LK.getSound('catch').play();
// Flash effect
LK.effects.flashObject(fish, 0xFFFFFF, 500);
// Remove the fish
fish.destroy();
fishes.splice(i, 1);
// Reel in after catching
boat.reelIn();
break;
}
}
}
// Function to check boat collision with obstacles
function checkObstacleCollisions() {
var _loop = function _loop() {
obstacle = obstacles[i];
if (boat.intersects(obstacle)) {
var _animateExplosion = function animateExplosion() {
explosionSize += 0.2;
obstacle.scale.set(explosionSize);
obstacle.alpha -= 0.1;
if (obstacle.alpha > 0) {
LK.setTimeout(_animateExplosion, 30);
} else {
// Remove the sea mine after explosion completes
obstacle.destroy();
obstacles.splice(i, 1);
}
};
// Hit a sea mine - create explosion effect
LK.effects.flashScreen(0xFF0000, 800);
LK.getSound('splash').play();
// Create explosion animation
explosionSize = 1;
obstacle.tint = 0xFF3300; // Explosion color
_animateExplosion();
// Make boat explode
boat.explode();
return 0; // break
}
// Also check if fishing line hits sea mine
if (boat.isCasting) {
hookPos = boat.getHookPosition();
distance = Math.sqrt(Math.pow(hookPos.x - obstacle.x, 2) + Math.pow(hookPos.y - obstacle.y, 2));
if (distance < 60) {
// Hook hit a sea mine
LK.effects.flashScreen(0xFF5500, 500);
LK.getSound('splash').play();
// Trigger mine explosion
obstacle.tint = 0xFF3300;
obstacle.scale.set(1.5);
LK.setTimeout(function () {
obstacle.destroy();
obstacles.splice(i, 1);
}, 300);
// Reel in after hitting mine
boat.reelIn();
return 0; // break
}
}
},
obstacle,
explosionSize,
hookPos,
distance,
_ret;
for (var i = obstacles.length - 1; i >= 0; i--) {
_ret = _loop();
if (_ret === 0) break;
}
}
// Update game loop
game.update = function () {
if (isGameOver || boat.isExploding) return;
// Increase difficulty over time
waterLevel += backgroundSpeed * 0.1;
// Increase difficulty based on time
fishSpawnRate = 0.005 + waterLevel / 20000; // Further reduced fish spawn rate
obstacleSpawnRate = 0.0001 + waterLevel / 100000; // Extremely reduced sea mine spawn rate to prevent lag
// Spawn game elements
spawnFish();
spawnObstacle();
// Keep track of current hook position
if (boat.isCasting) {
boat.lastHookPosition = boat.getHookPosition();
}
// Update all game objects
// Update fishes - only process a subset each frame if there are many
var fishesToProcess = Math.min(fishes.length, 5); // Process max 5 fish per frame
for (var i = fishes.length - 1; i >= Math.max(0, fishes.length - fishesToProcess); i--) {
var fish = fishes[i];
if (fish.shouldRemove) {
fish.destroy();
fishes.splice(i, 1);
}
}
// Update obstacles (sea mines)
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Add gentle floating motion to sea mines - less frequently
if (obstacle.floatPhase !== undefined && LK.ticks % 4 === 0) {
// Only update floating every 4 frames
obstacle.floatPhase += 0.01; // Slower movement
obstacle.x += Math.sin(obstacle.floatPhase) * obstacle.floatSpeed * obstacle.floatDirection * 0.5; // Reduced movement
}
if (obstacle.shouldRemove) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Check for fish catch
checkFishCatch();
// Check for obstacle collisions
checkObstacleCollisions();
// No winning condition - allow unlimited play
// Game continues indefinitely so players can achieve the highest score possible
};
// Play background music
LK.playMusic('backgroundNature', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
});
horizontal image sea tuna. In-Game asset. 2d. High contrast. No shadows
horizontal image Snapper fish. In-Game asset. 2d. High contrast. No shadows
horizontal image blue marlin fish. In-Game asset. 2d. High contrast. No shadows
sea mine. In-Game asset. 2d. High contrast. No shadows
quite blue under water of sea
horizontal top down image submarine. In-Game asset. 2d. High contrast. No shadows
vertical harpoon head. In-Game asset. 2d. High contrast. No shadows