Choppy Ocean Animation [HELP]

I’ve been working on this all day and it’s been slowly improving but there’s still an issue. It’s meant to load a model and after .25 seconds have past destroy it and load another to make it look animated. However it’s very choppy. Anyone have any ideas on how to fix this?

Video:

Script:

-- Services --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")

-- Ocean Templates Folder --
local oceanFolder = ReplicatedStorage:WaitForChild("OceanTemplates")

-- Starter Part --
local starterPart = Workspace:WaitForChild("StarterPart")

-- Configuration --
local sizeX = 24
local sizeZ = 24
local oceanHeight = starterPart.Position.Y
local frameDuration = 0.25
local loadedPositions = {}

-- List of ocean models --
local oceanModels = {
	"Ocean1_1",
	"Ocean1_2",
	"Ocean1_3",
	"Ocean1_4",
	"Ocean1_5",
	"Ocean1_6"
}

-- Generate Ocean Model --
local function generateOceanModel(x, z)
	local position = Vector3.new(x * sizeX, oceanHeight, z * sizeZ)
	local currentModel = oceanFolder:WaitForChild(oceanModels[1]):Clone()
	currentModel:PivotTo(CFrame.new(position))
	currentModel.Parent = Workspace

	-- Animation loop to switch models
	task.spawn(function()
		local frame = 1
		while true do
			-- Get the next model name
			local oceanModelName = oceanModels[frame]
			local nextModel = oceanFolder:FindFirstChild(oceanModelName)

			if nextModel then
				-- Clone and position the new model
				local newModel = nextModel:Clone()
				newModel:PivotTo(currentModel:GetPivot()) -- Match position
				newModel.Parent = Workspace

				-- Delay briefly for rendering, then set the new model to be visible
				task.wait(0)  -- Small delay to allow rendering of the new model
				currentModel:Destroy() -- Destroy the old model
				currentModel = newModel -- Update reference to the new model
			else
				warn("Model " .. oceanModelName .. " not found in OceanTemplates.")
			end

			-- Increment and loop through the model list
			frame = (frame % #oceanModels) + 1

			-- Wait for the frame duration before switching again
			task.wait(frameDuration)
		end
	end)
end

-- Generate Ocean Grid --
local function generateOceanGrid()
	for z = -5, 5 do
		for x = -5, 5 do
			local key = tostring(x) .. "_" .. tostring(z)
			if not loadedPositions[key] then
				generateOceanModel(x, z)
				loadedPositions[key] = true
			end
		end
	end
end

-- Start Generating the Ocean --
generateOceanGrid()

Any Ideas? Thanks!

dont load a model, just load textures. if you really need to load models, just use transparency instead of constantly destroying and creating.

1 Like

I want it to be models and also I did transparency and it did work however it was super laggy and wasn’t good for performance. I find this way to be better on performance.

Replace task.wait(0) with RunService.RenderStepped:Wait(), or just animate your water in a RenderStepped connection. task.wait() will wait with Heartbeat, which runs at 60 Hz.

2 Likes

I replace task.wait(0) with RunService.RenderStepped:Wait() and it only loads the first model. It doesn’t do anything just that. The code is the exact same just RunService.RenderStepped:Wait() instead of task.wait(0)

Instead of while true, just use RunService.Heartbeat. that way it’ll also sync up with the framerate.

1 Like

I did this and it experience the same problem as in the video

loading and unloading a ton of models will do that. it doesn’t work like that. just move parts or something. unfortunately, the current way of doing this is very laggy and unoptimized.

If you show me what you want i can try to help

1 Like

I just reduced the number of models, and found it looked better anyway, and went with transparency instead of cloning and destroying. Script if you’re curious:

-- Services --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")

-- Ocean Templates Folder --
local oceanFolder = ReplicatedStorage:WaitForChild("OceanTemplates")

-- Starter Part --
local starterPart = Workspace:WaitForChild("StarterPart")

-- Configuration --
local sizeX = 24
local sizeZ = 24
local oceanHeight = starterPart.Position.Y
local frameDuration = 0.25
local loadedPositions = {}

-- List of ocean models (only Ocean1 and Ocean2) --
local oceanModels = {
	"Ocean1",
	"Ocean2"
}

-- Helper function to set transparency for all parts in a model
local function setModelTransparency(model, transparency)
	for _, descendant in ipairs(model:GetDescendants()) do
		if descendant:IsA("BasePart") then
			descendant.Transparency = transparency
		end
	end
end

-- Generate Ocean Model --
local function generateOceanModel(x, z)
	local position = Vector3.new(x * sizeX, oceanHeight, z * sizeZ)

	-- Preload Ocean1 and Ocean2 at the same position
	local preloadedModels = {}
	for _, modelName in ipairs(oceanModels) do
		local model = oceanFolder:WaitForChild(modelName):Clone()
		model:PivotTo(CFrame.new(position))
		model.Parent = Workspace
		setModelTransparency(model, 1) -- Start as invisible
		table.insert(preloadedModels, model)
	end

	-- Animation loop to switch transparency
	task.spawn(function()
		local frame = 1
		while true do
			-- Set all models to transparent
			for _, model in ipairs(preloadedModels) do
				setModelTransparency(model, 1)
			end

			-- Make the current frame's model visible with 0.3 transparency
			setModelTransparency(preloadedModels[frame], 0.3)

			-- Increment and loop through the model list
			frame = frame + 1
			if frame > #oceanModels then
				frame = 1 -- Reset to the first model
			end

			-- Wait for the frame duration before switching again
			task.wait(frameDuration)
		end
	end)
end

-- Generate Ocean Grid --
local function generateOceanGrid()
	for z = -25, 25 do
		for x = -25, 25 do
			local key = tostring(x) .. "_" .. tostring(z)
			if not loadedPositions[key] then
				generateOceanModel(x, z)
				loadedPositions[key] = true
			end
		end
	end
end

-- Start Generating the Ocean --
generateOceanGrid()

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.