I’ve got a main loop running 10 times a second like so:
while task.wait(.1) do
local deltaTime = os.clock() - l_os; l_os = os.clock()
task.desynchronize() calculate_vectors(1)
task.synchronize() perform_velocity(1)
end
Functions perform_velocity and calculate_vectors each take a number as a modifier, usually it would be the deltaTime, which would be around 0.1, but for experimental purposes, it is set to one to speed up the proccess.
calculate_vectors calculate the height difference between a pixel on the map and its surrounding pixels and adds a value to the pixel’s velocity
perform_velocity adds the velocity to the water pixel, calculating how much water is lost in the pixel.
Although for whatever reasons, once I place a water pixel it doesn’t spread out like I intend.
Full source code:
local rootFloor = workspace.RootGround
local entities = workspace.MapInstances
local fol_land = entities.segments.land
local fol_water = entities.segments.water
type water_object =
{
['c']: number,
['m']: number,
['i']: number
}
type land_object =
{
['m']: number,
['d']: number,
['i']: number,
}
--[[
ca: cached
ld: land data
wd: water data
w_obj: water objects
l_obj: land objects
v2: Vector2
bw_preset: base water preset
bl_preset: base land preset
--]]
local ca_wd : {[number]:water_object} = {}
local ca_ld : {[number]:land_object} = {}
local cached_vectors : {[number]: Vector2}= {}
local w_obj : {[number]: Part} = {}
local l_obj : {[number]: Part} = {}
local assembly : {{w:water_object, n:number, wo: water_object}} = {}
local clamp = math.clamp
local v2new = Vector2.new
local v2unpack = function(v:Vector2) return v.X, v.Y end
local v2clamp = function(v:Vector2, min, max) return v2new(clamp(v.X, min, max), clamp(v.X, min, max)) end
local def_x, def_y = 100,100
local function to_cord(index:number): (number, number)
local x = index % def_x
local y = bit32.bor(index / def_x)
return x, y
end
local function to_int(x, y)
return y * def_x + x
end
local landcol, watercol = Color3.fromRGB(51, 65, 63), Color3.fromRGB(19, 39, 127)
local corres = function(x, y)
return
{
[Vector2.xAxis]=y * def_x + x + 1,
[-Vector2.xAxis]= y * def_x + math.min(x-1,0),
[Vector2.yAxis]=(y+1) * def_x + x,
[-Vector2.yAxis]=(math.min(y-1,0)) * def_x + x
}
end
local function construct_cache()
for x=0, def_x do
task.wait()
for y=0, def_y do
local i = y * def_x + x
cached_vectors[i] = Vector2.zero
ca_ld[i] =
{
['m'] = 1,
['d'] = 1,
['i'] = i
}
ca_wd[i] =
{
['m'] = 0,
['c'] = 0,
['i'] = i
}
end end end
local function construct_land(f:(number, number)-> number)
for x=0, def_x do
task.wait()
for y=0, def_y do
local h = f(x,y)
local i = y * def_x + x
local earth_pos = Vector3.new(
(x - def_x/2),
h/2,
(y - def_y/2))
local earthPart = Instance.new('Part')
earthPart.Anchored = true
earthPart.Parent = fol_land
earthPart.Position = earth_pos
earthPart.Size = Vector3.one + Vector3.yAxis * h
earthPart.CastShadow = false
earthPart.Color = Color3.new(.4,.4,.4)
l_obj[i] = earthPart
ca_ld[i].m = h
end
end
end
local function place_water(index:number, amount: number)
local waterPart = Instance.new('Part')
local sel_ld = ca_ld[index]
local x, y = to_cord(index)
waterPart.Anchored = true
waterPart.CastShadow = false
waterPart.Parent = fol_water
waterPart.Size = Vector3.new(1, amount, 1)
waterPart.Position =
Vector3.new(
x - def_x / 2,
sel_ld.m + amount / 2,
y - def_y / 2
)
waterPart.Color = Color3.new(.1,.1,1)
w_obj[index] = waterPart
ca_wd[index] = {m = amount, c = 0, i = index}
return waterPart
end
local function modify_w(i:number, n:number, l:boolean?)
local w_data = ca_wd[i] if not w_data then return end
local part = w_obj[i] if not part then place_water(i, n) return end
if l then
w_data.m += n
part.Position += Vector3.yAxis * n / 2
part.Size += Vector3.yAxis * n
else
local dif = n - w_data.m
part.Position += Vector3.yAxis * n / 2
part.Size += Vector3.yAxis * n
end
end
local function modify_l(i:number, n:number, l:boolean?)
local l_data = ca_wd[i] if not l_data then return end
local dif = n - l_data.m if l then dif = n end
local part = l_obj[i]
l_data.m += n
part.Position += Vector3.yAxis * dif/2
part.Size += Vector3.yAxis * dif
if w_obj[i] then modify_w(i, dif, true) end
end
local function calculate_vectors(mod)
for i, wd in ca_wd do
if not w_obj[i] then return end
local ld = ca_ld[i]
for dif, co in pairs(corres(to_cord(i))) do
if clamp(co, 0, def_x*def_y) ~= co then return end
local co_d = ca_wd[co]
local hdif = (wd.m + ld.m) - (co_d.m + ca_ld[co].m)
if hdif <= 0 then return end
cached_vectors[i] += dif * (hdif ^ .77) * mod
print("cached vector: "..wd.i.." to "..co)
table.insert(assembly, {wo=wd, w = co_d, n = hdif})
end
end
end
local function perform_velocity(mod)
for i, t in pairs(assembly) do
modify_w(t.wo.i, -t.n*mod, true)
modify_w(t.w, t.n*mod, true)
table.remove(assembly,1)
print(t.wo.i.." transferred "..t.n*mod.." to "..t.w.i)
end
end
local l_os = os.clock()
construct_cache()
construct_land(function(x,y)
return 90 - (clamp(math.noise(x/10+.5,y/10+.5), -1, 1) + 1) / 2 * 45 * (math.sin(x/12.5)+1)
end)
place_water(math.random(0,def_x*def_y), 55)
while task.wait(.1) do
local deltaTime = os.clock() - l_os; l_os = os.clock()
task.desynchronize() calculate_vectors(1)
task.synchronize() perform_velocity(1)
end

