User prompt
simple swipe boat control
User prompt
fix swipe control boal
User prompt
make smooth control a boat
User prompt
smoot swipe control a boat no bounching
User prompt
smooth swipe control boat
User prompt
swipe to control boat
User prompt
increase lure speed fishing line
User prompt
fishingline speed movement
User prompt
increase speed fish
User prompt
increase speed legendary fish
User prompt
remove the interface depth feature
User prompt
delete text DEEP
User prompt
Move the distance between the boat and the fish on the screen so that they don't look close
User prompt
Keep the distance between the boat and the fish on the screen
User prompt
extend the fishing line to the bottom of the screen
User prompt
reduce the number of fish so it doesn't lag
User prompt
reduce the number of obstacles so there is no lag
User prompt
lengthen the fishing line
User prompt
boat explodes after hitting obstacle
User prompt
obstacles are sea mines
User prompt
reduce quantity of obstacle
User prompt
unlimited number of scores ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
infinite score
User prompt
extreme reduce obstacle
Code edit (1 edits merged)
Please save this source code
/****
* 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 = 20; // Further reduced maximum velocity for even more control
self.friction = 0.93; // Further increased friction for even smoother deceleration
self.targetX = null; // Target position to move toward
self.dampingRatio = 0.9; // Reduced damping ratio to eliminate bouncing completely
self.springConstant = 0.015; // Spring constant for smooth approach to target
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 with zero-bounce approach
if (self.targetX !== null) {
// Calculate distance to target
var distanceToTarget = self.targetX - self.x;
if (Math.abs(distanceToTarget) > 0.5) {
// Use a smooth approach with critically damped spring physics
// Calculate spring force with adaptive stiffness
var springForce = distanceToTarget * self.springConstant;
// Apply variable damping based on distance and velocity
var velocityDamping = self.velocityX * self.dampingRatio;
// Final acceleration combines spring force with damping
var acceleration = springForce - velocityDamping;
// Apply acceleration to velocity with distance-based modulation
self.velocityX += acceleration * (1 - Math.min(0.5, Math.abs(distanceToTarget) / 2000));
// Additional damping when approaching target
if (Math.abs(distanceToTarget) < 50) {
self.velocityX *= 0.85; // Stronger damping near target
}
// Limit maximum velocity with distance-based scaling
var scaledMaxVelocity = self.maxVelocity * (0.5 + 0.5 * Math.min(1, Math.abs(distanceToTarget) / 500));
if (self.velocityX > scaledMaxVelocity) self.velocityX = scaledMaxVelocity;
if (self.velocityX < -scaledMaxVelocity) self.velocityX = -scaledMaxVelocity;
} else {
// If very close to target, just snap to position and stop
self.x = self.targetX;
self.velocityX = 0;
self.targetX = null;
}
}
// Apply velocity with improved friction and no bouncing
if (Math.abs(self.velocityX) > 0.05) {
// Apply velocity first
self.x += self.velocityX;
// Use multi-stage adaptive friction for ultra-smooth movement
var adaptiveFriction;
// Higher velocity = less friction (but still significant)
if (Math.abs(self.velocityX) > 12) {
adaptiveFriction = self.friction * 0.97;
}
// Medium velocity = medium friction
else if (Math.abs(self.velocityX) > 5) {
adaptiveFriction = self.friction * 0.92;
}
// Lower velocity = higher friction for smooth stop
else {
adaptiveFriction = self.friction * 0.85;
}
// Apply friction with smooth transition
self.velocityX *= adaptiveFriction;
// Keep boat within bounds with gentle approach to boundaries
if (self.x < 100) {
// Gradual slowing as we approach boundary
var distanceToBoundary = 100 - self.x;
self.x = 100 - distanceToBoundary * 0.85; // Don't snap immediately
self.velocityX *= 0.8; // Reduce velocity more gradually
if (Math.abs(self.velocityX) < 0.2) self.velocityX = 0;
} else if (self.x > 2048 - 100) {
var distanceToBoundary = self.x - (2048 - 100);
self.x = 2048 - 100 + distanceToBoundary * 0.85; // Don't snap immediately
self.velocityX *= 0.8; // Reduce velocity more gradually
if (Math.abs(self.velocityX) < 0.2) 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.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 and time
var deltaX = x - gameSwipeStartX;
var deltaY = y - gameSwipeStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var swipeTime = Math.max(16, Date.now() - boat.swipeStartTime); // Ensure minimum time to prevent excessive velocity
if (swipeDistance < 15) {
// It's a tap, not a swipe - toggle fishing line
if (boat.isCasting) {
boat.reelIn();
} else {
boat.castLine();
}
} else {
// Calculate velocity from recent movement history for smoother behavior
var finalVelocity = 0;
if (moveHistory.length > 1) {
// Get last few positions for a smoother velocity curve
var recentPositions = moveHistory.slice(-3);
var oldestRecentPos = recentPositions[0];
var newestPos = recentPositions[recentPositions.length - 1];
var timeSpan = Math.max(16, newestPos.time - oldestRecentPos.time);
var distanceSpan = newestPos.x - oldestRecentPos.x;
// Calculate base velocity with non-linear scaling for more natural feel
finalVelocity = distanceSpan / timeSpan * 12;
// Apply non-linear curve to velocity for more natural deceleration
finalVelocity = finalVelocity * (0.6 + 0.4 * Math.min(1, Math.abs(finalVelocity) / 20));
// Limit velocity with adaptive cap based on swipe speed
var adaptiveMaxVelocity = boat.maxVelocity * 0.8;
if (finalVelocity > adaptiveMaxVelocity) finalVelocity = adaptiveMaxVelocity;
if (finalVelocity < -adaptiveMaxVelocity) finalVelocity = -adaptiveMaxVelocity;
// Blend with current velocity for smoother transition
boat.velocityX = boat.velocityX * 0.3 + finalVelocity * 0.7;
// Set target based on velocity and current position
// For quick small swipes, use a shorter target distance
var targetDistance = Math.min(400, Math.abs(boat.velocityX) * 10);
if (boat.velocityX > 0) {
boat.targetX = boat.x + targetDistance;
} else {
boat.targetX = boat.x - targetDistance;
}
// Keep target within game bounds with buffer
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
}
}
isSwipingInGame = false;
moveHistory = []; // Clear movement history
}
};
// Handle touch move for navigating the boat with swipe
var swipeStartX = 0;
var swipeStartY = 0;
var isDraggingBoat = false;
var lastMoveX = 0;
var lastMoveTime = 0;
var moveHistory = [];
game.move = function (x, y, obj) {
if (isDraggingBoat && !isGameOver) {
var currentTime = Date.now();
// Calculate horizontal distance moved since last position
var deltaX = x - swipeStartX;
// Use time-averaged velocity for more stable movement
moveHistory.push({
x: x,
time: currentTime
});
// Keep only the most recent positions for calculating velocity
if (moveHistory.length > 5) {
moveHistory.shift();
}
// Calculate smooth velocity using position history
var avgVelocity = 0;
if (moveHistory.length > 1) {
var oldestMove = moveHistory[0];
var timeSpan = Math.max(1, currentTime - oldestMove.time);
var distanceSpan = x - oldestMove.x;
avgVelocity = distanceSpan / timeSpan * 10; // Scale factor for reasonable velocity
}
// Apply strong position filtering (follow finger but very smoothly)
var followFactor = 0.3; // How quickly the boat follows the finger
boat.targetX = boat.x + deltaX * followFactor;
// Apply filtered velocity with adaptive dampening
var velocityFactor = Math.min(0.5, Math.abs(avgVelocity) / 20);
boat.velocityX = avgVelocity * velocityFactor;
// Keep boat within game bounds with gradual approach to edges
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
// Update swipe start position for next move calculation
swipeStartX = x;
lastMoveX = x;
lastMoveTime = currentTime;
}
};
// 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
boat.lastMoveTime = boat.swipeStartTime; // Initialize last move time
boat.initialX = boat.x; // Track starting position for swipe distance calculation
// Reset movement history for clean velocity calculation
moveHistory = [{
x: x,
time: boat.swipeStartTime
}];
// Immediately reduce current velocity to make drag responsive
boat.velocityX *= 0.5;
// Clear any existing target to ensure direct control
boat.targetX = null;
};
// 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
}
}); ===================================================================
--- original.js
+++ change.js
@@ -20,12 +20,13 @@
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 = 25; // Reduced maximum velocity for more control
- self.friction = 0.95; // Increased friction for smoother deceleration
+ self.maxVelocity = 20; // Further reduced maximum velocity for even more control
+ self.friction = 0.93; // Further increased friction for even smoother deceleration
self.targetX = null; // Target position to move toward
- self.dampingRatio = 1.2; // Critical damping ratio to prevent bouncing
+ self.dampingRatio = 0.9; // Reduced damping ratio to eliminate bouncing completely
+ self.springConstant = 0.015; // Spring constant for smooth approach to target
var fishingLine = self.attachAsset('fishingLine', {
anchorX: 0.5,
anchorY: 0,
x: 0,
@@ -65,50 +66,69 @@
fishingLine.visible = false;
fishHook.visible = false;
self.lineLength = 0;
}
- // Smooth boat movement physics with improved damping
+ // Smooth boat movement physics with zero-bounce approach
if (self.targetX !== null) {
// Calculate distance to target
var distanceToTarget = self.targetX - self.x;
- // Use critically damped approach to prevent bouncing
- var dampingFactor = 0.025; // Reduced from 0.04 for smoother movement
- // Apply force based on distance with dampening
- self.velocityX += distanceToTarget * dampingFactor;
- // Apply stronger damping when close to target to prevent overshooting
- if (Math.abs(distanceToTarget) < 100) {
- self.velocityX *= 0.9; // Additional damping when approaching target
- }
- // 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.3) {
+ if (Math.abs(distanceToTarget) > 0.5) {
+ // Use a smooth approach with critically damped spring physics
+ // Calculate spring force with adaptive stiffness
+ var springForce = distanceToTarget * self.springConstant;
+ // Apply variable damping based on distance and velocity
+ var velocityDamping = self.velocityX * self.dampingRatio;
+ // Final acceleration combines spring force with damping
+ var acceleration = springForce - velocityDamping;
+ // Apply acceleration to velocity with distance-based modulation
+ self.velocityX += acceleration * (1 - Math.min(0.5, Math.abs(distanceToTarget) / 2000));
+ // Additional damping when approaching target
+ if (Math.abs(distanceToTarget) < 50) {
+ self.velocityX *= 0.85; // Stronger damping near target
+ }
+ // Limit maximum velocity with distance-based scaling
+ var scaledMaxVelocity = self.maxVelocity * (0.5 + 0.5 * Math.min(1, Math.abs(distanceToTarget) / 500));
+ if (self.velocityX > scaledMaxVelocity) self.velocityX = scaledMaxVelocity;
+ if (self.velocityX < -scaledMaxVelocity) self.velocityX = -scaledMaxVelocity;
+ } else {
+ // If very close to target, just snap to position and stop
self.x = self.targetX;
self.velocityX = 0;
self.targetX = null;
}
}
- // Apply velocity with improved friction
+ // Apply velocity with improved friction and no bouncing
if (Math.abs(self.velocityX) > 0.05) {
- // Reduced threshold for smoother stopping
- // Apply velocity with gradual deceleration
+ // Apply velocity first
self.x += self.velocityX;
- // Use adaptive friction - more friction at higher speeds for stability
- var adaptiveFriction = self.friction;
- if (Math.abs(self.velocityX) > 15) {
- adaptiveFriction = self.friction * 0.98; // Less friction at high speed
- } else if (Math.abs(self.velocityX) < 5) {
- adaptiveFriction = self.friction * 0.95; // More friction at low speed
+ // Use multi-stage adaptive friction for ultra-smooth movement
+ var adaptiveFriction;
+ // Higher velocity = less friction (but still significant)
+ if (Math.abs(self.velocityX) > 12) {
+ adaptiveFriction = self.friction * 0.97;
}
+ // Medium velocity = medium friction
+ else if (Math.abs(self.velocityX) > 5) {
+ adaptiveFriction = self.friction * 0.92;
+ }
+ // Lower velocity = higher friction for smooth stop
+ else {
+ adaptiveFriction = self.friction * 0.85;
+ }
+ // Apply friction with smooth transition
self.velocityX *= adaptiveFriction;
- // Keep boat within bounds - gradual slowing at edges
+ // Keep boat within bounds with gentle approach to boundaries
if (self.x < 100) {
- self.x = 100;
- self.velocityX = 0;
+ // Gradual slowing as we approach boundary
+ var distanceToBoundary = 100 - self.x;
+ self.x = 100 - distanceToBoundary * 0.85; // Don't snap immediately
+ self.velocityX *= 0.8; // Reduce velocity more gradually
+ if (Math.abs(self.velocityX) < 0.2) self.velocityX = 0;
} else if (self.x > 2048 - 100) {
- self.x = 2048 - 100;
- self.velocityX = 0;
+ var distanceToBoundary = self.x - (2048 - 100);
+ self.x = 2048 - 100 + distanceToBoundary * 0.85; // Don't snap immediately
+ self.velocityX *= 0.8; // Reduce velocity more gradually
+ if (Math.abs(self.velocityX) < 0.2) self.velocityX = 0;
}
} else {
self.velocityX = 0;
}
@@ -318,65 +338,95 @@
// Calculate swipe distance and time
var deltaX = x - gameSwipeStartX;
var deltaY = y - gameSwipeStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- var swipeTime = Math.max(1, Date.now() - boat.swipeStartTime); // Prevent division by zero
- if (swipeDistance < 20) {
+ var swipeTime = Math.max(16, Date.now() - boat.swipeStartTime); // Ensure minimum time to prevent excessive velocity
+ if (swipeDistance < 15) {
// It's a tap, not a swipe - toggle fishing line
if (boat.isCasting) {
boat.reelIn();
} else {
boat.castLine();
}
} else {
- // It was a swipe - calculate inertia based on swipe characteristics
- // Use exponential decay for velocity based on swipe duration
- // Shorter swipes get more velocity (more flick-like)
- var timeScaleFactor = Math.min(1, 500 / swipeTime);
- // Calculate velocity with adaptive scaling
- var swipeVelocity = deltaX / swipeTime * 8 * timeScaleFactor;
- // Apply velocity with dampening to prevent jerky motion
- boat.velocityX = boat.velocityX * 0.3 + swipeVelocity * 0.7;
- // Limit initial velocity with gradual approach to max
- var velocityLimit = boat.maxVelocity * (0.7 + 0.3 * (Math.abs(swipeVelocity) / 20));
- if (boat.velocityX > velocityLimit) boat.velocityX = velocityLimit;
- if (boat.velocityX < -velocityLimit) boat.velocityX = -velocityLimit;
- // Calculate target position with adaptive distance based on swipe speed
- var targetDistanceFactor = Math.min(1, Math.abs(swipeVelocity) / 15) * 0.5;
- boat.targetX = boat.x + deltaX * targetDistanceFactor;
- // Keep target within game bounds with buffer
- boat.targetX = Math.max(boat.targetX, 100);
- boat.targetX = Math.min(boat.targetX, 2048 - 100);
+ // Calculate velocity from recent movement history for smoother behavior
+ var finalVelocity = 0;
+ if (moveHistory.length > 1) {
+ // Get last few positions for a smoother velocity curve
+ var recentPositions = moveHistory.slice(-3);
+ var oldestRecentPos = recentPositions[0];
+ var newestPos = recentPositions[recentPositions.length - 1];
+ var timeSpan = Math.max(16, newestPos.time - oldestRecentPos.time);
+ var distanceSpan = newestPos.x - oldestRecentPos.x;
+ // Calculate base velocity with non-linear scaling for more natural feel
+ finalVelocity = distanceSpan / timeSpan * 12;
+ // Apply non-linear curve to velocity for more natural deceleration
+ finalVelocity = finalVelocity * (0.6 + 0.4 * Math.min(1, Math.abs(finalVelocity) / 20));
+ // Limit velocity with adaptive cap based on swipe speed
+ var adaptiveMaxVelocity = boat.maxVelocity * 0.8;
+ if (finalVelocity > adaptiveMaxVelocity) finalVelocity = adaptiveMaxVelocity;
+ if (finalVelocity < -adaptiveMaxVelocity) finalVelocity = -adaptiveMaxVelocity;
+ // Blend with current velocity for smoother transition
+ boat.velocityX = boat.velocityX * 0.3 + finalVelocity * 0.7;
+ // Set target based on velocity and current position
+ // For quick small swipes, use a shorter target distance
+ var targetDistance = Math.min(400, Math.abs(boat.velocityX) * 10);
+ if (boat.velocityX > 0) {
+ boat.targetX = boat.x + targetDistance;
+ } else {
+ boat.targetX = boat.x - targetDistance;
+ }
+ // Keep target within game bounds with buffer
+ boat.targetX = Math.max(boat.targetX, 100);
+ boat.targetX = Math.min(boat.targetX, 2048 - 100);
+ }
}
isSwipingInGame = false;
+ moveHistory = []; // Clear movement history
}
};
// Handle touch move for navigating the boat with swipe
var swipeStartX = 0;
var swipeStartY = 0;
var isDraggingBoat = false;
+var lastMoveX = 0;
+var lastMoveTime = 0;
+var moveHistory = [];
game.move = function (x, y, obj) {
if (isDraggingBoat && !isGameOver) {
+ var currentTime = Date.now();
// Calculate horizontal distance moved since last position
var deltaX = x - swipeStartX;
- // Use time-based velocity calculation for more consistent movement
- var currentTime = Date.now();
- var timeDelta = Math.max(1, currentTime - (boat.lastMoveTime || currentTime));
- boat.lastMoveTime = currentTime;
- // Calculate velocity based on distance moved over time
- var timeScaleFactor = 16 / timeDelta; // Normalize to 60fps
- // Apply smoothing filter to finger movement
- var filteredDeltaX = deltaX * 0.5; // Reduce the immediate effect of finger movement
- // Set target position with slight lead for more responsive feel
- boat.targetX = boat.x + filteredDeltaX;
- // Apply velocity but dampen it to prevent jerky movement
- var moveSpeed = deltaX * timeScaleFactor;
- boat.velocityX = moveSpeed * 0.4; // Reduced multiplier for smoother movement
+ // Use time-averaged velocity for more stable movement
+ moveHistory.push({
+ x: x,
+ time: currentTime
+ });
+ // Keep only the most recent positions for calculating velocity
+ if (moveHistory.length > 5) {
+ moveHistory.shift();
+ }
+ // Calculate smooth velocity using position history
+ var avgVelocity = 0;
+ if (moveHistory.length > 1) {
+ var oldestMove = moveHistory[0];
+ var timeSpan = Math.max(1, currentTime - oldestMove.time);
+ var distanceSpan = x - oldestMove.x;
+ avgVelocity = distanceSpan / timeSpan * 10; // Scale factor for reasonable velocity
+ }
+ // Apply strong position filtering (follow finger but very smoothly)
+ var followFactor = 0.3; // How quickly the boat follows the finger
+ boat.targetX = boat.x + deltaX * followFactor;
+ // Apply filtered velocity with adaptive dampening
+ var velocityFactor = Math.min(0.5, Math.abs(avgVelocity) / 20);
+ boat.velocityX = avgVelocity * velocityFactor;
// Keep boat within game bounds with gradual approach to edges
boat.targetX = Math.max(boat.targetX, 100);
boat.targetX = Math.min(boat.targetX, 2048 - 100);
- // Update swipe start position for next move
+ // Update swipe start position for next move calculation
swipeStartX = x;
+ lastMoveX = x;
+ lastMoveTime = currentTime;
}
};
// Start tracking swipe
boat.down = function (x, y, obj) {
@@ -385,8 +435,17 @@
swipeStartY = y;
boat.swipeStartTime = Date.now(); // Track when swipe started for velocity calculation
boat.lastMoveTime = boat.swipeStartTime; // Initialize last move time
boat.initialX = boat.x; // Track starting position for swipe distance calculation
+ // Reset movement history for clean velocity calculation
+ moveHistory = [{
+ x: x,
+ time: boat.swipeStartTime
+ }];
+ // Immediately reduce current velocity to make drag responsive
+ boat.velocityX *= 0.5;
+ // Clear any existing target to ensure direct control
+ boat.targetX = null;
};
// End swipe and cast fishing line
boat.up = function (x, y, obj) {
isDraggingBoat = false;
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