I want to achieve movement in water like Blox Fruits
It looks like its walking the y position stays the same and
It still has the swimming animations and everything, how?
I want to achieve movement in water like Blox Fruits
It looks like its walking the y position stays the same and
It still has the swimming animations and everything, how?
Could you provide a video of how your expecting it to look to assist people who see this post.
try experimenting with it a little first
if you can somehow salvage this garbage script I made during ancient times, feel free to tweak it to suit your use case
local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local Terrain = game.Workspace.Terrain
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
local animator = humanoid:FindFirstChildWhichIsA("Animator")
humanoid:SetStateEnabled(Enum.HumanoidStateType.Swimming, false)
local position = character.PrimaryPart:FindFirstChildWhichIsA("BodyPosition") or Instance.new("BodyPosition")
position.Parent = character.PrimaryPart
position.Position = character.PrimaryPart.Position
position.MaxForce = Vector3.zero
local underwater = false
local entered = false
local rising = false
local height = character.PrimaryPart.Position.Y
local delta = 1/30 -- rate i guess idk lol
-- anims
local animations = character:WaitForChild("Animate", 5)
local current_anim: AnimationTrack = nil
local swim_idle: AnimationTrack = animator:LoadAnimation(animations:FindFirstChild("SwimIdle", true))
local swim_move: AnimationTrack = animator:LoadAnimation(animations:FindFirstChild("Swim", true))
local name = script.Name
local folder = player:FindFirstChild(name) or Instance.new("Folder", player)
folder.Name = name
-- clean folder on respawn
for _, thing in pairs(folder:GetChildren()) do
thing:Destroy()
end
local function GetBoundingBox(character: Model): (CFrame, Vector3)
character.Archivable = true
local clone = character:Clone()
clone.Parent = folder
for _, v in pairs(clone:GetChildren()) do
if not v:IsA("BasePart") then
v:Destroy()
end
end
local cframe, size = clone:GetBoundingBox()
clone:Destroy()
return cframe, size
end
-- for keyboard/controller players
local function rise(action: string, state: Enum.UserInputState)
if state == Enum.UserInputState.Begin and underwater then
rising = true
return Enum.ContextActionResult.Sink
end
rising = false
return Enum.ContextActionResult.Pass
end
ContextActionService:BindAction("rise", rise, false, Enum.PlayerActions.CharacterJump, Enum.KeyCode.ButtonA) -- not sure if characterjump will register on A presses
local function get_characters(): {}
local characters = {}
for _, plr in pairs(game:GetService("Players"):GetPlayers()) do
table.insert(characters, plr.Character)
end
return characters
end
local function raycast(origin: Vector3, direction: Vector3): RaycastResult
local params = RaycastParams.new()
params.RespectCanCollide = true
params.IgnoreWater = true
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = get_characters()
local ray = game.Workspace:Raycast(origin, direction*50, params)
return ray
end
local function lerp(a, b, alpha)
return a + (b - a) * alpha
end
local function clamp(number: number, min: number, max: number): number
if min > max then
return math.clamp(number, max, min)
else
return math.clamp(number, min, max)
end
end
-- for mobile players cuz playeractions dont work on mobile for some reason and there's no :IsKeyDown() equivalent for a button
local button: GuiButton
if UserInputService.TouchEnabled then
button = player.PlayerGui:WaitForChild("TouchGui"):WaitForChild("TouchControlFrame"):WaitForChild("JumpButton")
button.MouseButton1Down:Connect(function()
rising = true
end)
button.MouseButton1Up:Connect(function()
rising = false
end)
end
local other: BodyPosition
local check: BodyGyro
while task.wait() do
-- for admins
check = character.PrimaryPart:FindFirstChildWhichIsA("BodyGyro")
if check then
if check.MaxTorque.Magnitude > 0 then
underwater = false
entered = false
continue
end
end
local bounds, size = GetBoundingBox(character)
local region = Region3.new(bounds.Position, bounds.Position + (size/2)):ExpandToGrid(4)
local material = Terrain:ReadVoxels(region, 4)[1][1][1]
underwater = material == Enum.Material.Water
if underwater then
-- angular_velocity.Parent = character.PrimaryPart
local min = raycast(character.PrimaryPart.Position, -character.PrimaryPart.CFrame.UpVector)
local max = character.PrimaryPart.Position.Y + size.Y/2
min = (min and min.Position.Y + size.Y/2) or character.PrimaryPart.Position.Y
local increment = (rising and 1) or -1
height = lerp(height, clamp(height + increment, min, max), delta*3)
position.Position = Vector3.new(bounds.Position.X, height, bounds.Position.Z)
position.MaxForce = Vector3.new(0, math.huge, 0) -- Vector3.new(0, game.Workspace.Gravity, 0)
if not entered then
entered = true
height -= 1
end
if humanoid.MoveDirection.Magnitude > 0 and current_anim ~= swim_move then
current_anim = swim_move
swim_move:Play(0.5)
swim_idle:Stop(0.5)
humanoid.AutoRotate = true
elseif humanoid.MoveDirection.Magnitude == 0 and current_anim ~= swim_idle then
current_anim = swim_idle
swim_idle:Play(0.5)
swim_move:Stop(0.5)
end
else
-- angular_velocity.Parent = folder
if current_anim ~= nil then
current_anim = nil
swim_move:Stop()
swim_idle:Stop()
end
if entered then
entered = false
if rising then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
end
height = character.PrimaryPart.Position.Y
position.MaxForce = Vector3.zero
end
end
idk what the blox fruits water looks like but you could make realistic water with a mesh and then changing the height of the water using bones
then for the swimming it could be invisible terrain water or a custom swimming system