# Dynamic 2D water

Based on http://gamedevelopment.tutsplus.com/tutorials/creating-dynamic-2d-water-effects-in-unity--gamedev-14143 which I came across via @andymac3d’s blog I’ve implemented the first bit in Codea. Touch the screen to create a wave.

``````-- waves
--by West
--based on http://gamedevelopment.tutsplus.com/tutorials/creating-dynamic-2d-water-effects-in-unity--gamedev-14143

-- Use this function to perform your initial setup
function setup()
numwatersprings=150
water={}
border=10
for i=1,numwatersprings do
table.insert(water,{x=border+i*(WIDTH-2*border)/numwatersprings,y=HEIGHT/2,vel=0,acc=0})
end
parameter.number("springconstant",0.01,0.1,0.02)
parameter.number("damping",0.01,0.1,0.04)
parameter.integer("neighbours",5,20,9)

leftDeltas={}
rightDeltas={}
baseheight=HEIGHT/2
left=100
bottom=50
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(2)

if CurrentTouch.state==BEGAN then
local nearestspring=math.floor(numwatersprings*CurrentTouch.x/WIDTH)
if nearestspring==0 then nearestspring=1 end
water[nearestspring].y=(CurrentTouch.y)
end
--calculate the new position of each water spring element
for u,w in pairs(water) do
force = springconstant * (w.y - baseheight) + w.vel*damping
w.acc = -force
w.y = w.y + w.vel
w.vel = w.vel + w.acc
end
--let each spring affect its neighbours
for j=1,neighbours do
for i=1,numwatersprings do
if (i > 1) then
leftDeltas[i] = spread * (water[i].y - water[i-1].y);
water[i-1].vel = water[i-1].vel + leftDeltas[i];
end
if (i < numwatersprings - 1) then
rightDeltas[i] = spread * (water[i].y - water[i+1].y);
water[i+1].vel=water[i+1].vel + rightDeltas[i];
end
end
end

for i=1,numwatersprings do
if (i > 1) then
water[i-1].y =water[i-1].y+ leftDeltas[i];
end
if (i < numwatersprings- 1) then
water[i+1].y=water[i+1].y + rightDeltas[i];
end
end
--draw the water line
for i=1,numwatersprings-1 do
line(water[i].x,water[i].y,water[i+1].x,water[i+1].y)
end
end
``````

nice!
With a bit more effort…world of jelly:

Good work @West - lots of potential for this methinks!

P.s. Im a big fan of the tuts+ site - great resource for game-devs and nicely written as well!

Really nice! I made a small change to make it look more like water:

``````-- waves
--by West
--based on http://gamedevelopment.tutsplus.com/tutorials/creating-dynamic-2d-water-effects-in-unity--gamedev-14143

-- Use this function to perform your initial setup
function setup()
numwatersprings=150
water={}
border=10
for i=1,numwatersprings do
table.insert(water,{x=border+i*(WIDTH-2*border)/numwatersprings,y=HEIGHT/2,vel=0,acc=0})
end
parameter.watch("1/DeltaTime")
parameter.number("springconstant",0.01,0.1,0.02)
parameter.number("damping",0.01,0.1,0.04)
parameter.integer("neighbours",5,20,9)

leftDeltas={}
rightDeltas={}
baseheight=HEIGHT/2
left=100
bottom=50
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)
-- This sets the line thickness
strokeWidth(2)

if CurrentTouch.state==BEGAN then
local nearestspring=math.floor(numwatersprings*CurrentTouch.x/WIDTH)
if nearestspring==0 then nearestspring=1 end
water[nearestspring].y=(CurrentTouch.y)
end
--calculate the new position of each water spring element
for u,w in pairs(water) do
force = springconstant * (w.y - baseheight) + w.vel*damping
w.acc = -force
w.y = w.y + w.vel
w.vel = w.vel + w.acc
end
--let each spring affect its neighbours
for j=1,neighbours do
for i=1,numwatersprings do
if (i > 1) then
leftDeltas[i] = spread * (water[i].y - water[i-1].y);
water[i-1].vel = water[i-1].vel + leftDeltas[i];
end
if (i < numwatersprings - 1) then
rightDeltas[i] = spread * (water[i].y - water[i+1].y);
water[i+1].vel=water[i+1].vel + rightDeltas[i];
end
end
end

for i=1,numwatersprings do
if (i > 1) then
water[i-1].y =water[i-1].y+ leftDeltas[i];
end
if (i < numwatersprings- 1) then
water[i+1].y=water[i+1].y + rightDeltas[i];
end
end
--draw the water line
stroke(0, 150, 255, 255) strokeWidth(6)
for i = 1, numwatersprings do
local j = math.min(i + 1, numwatersprings)
line(water[i].x,water[i].y,water[j].x,water[j].y)
line(water[i].x, water[i].y, water[i].x, 0)
end
end
``````

@JakAttak nice - I went a step further and replaced the lines with meshes. I’ve also added rocks to drop into the water and droplets of water

``````-- waves
--by West
--based on http://gamedevelopment.tutsplus.com/tutorials/creating-dynamic-2d-water-effects-in-unity--gamedev-14143

-- Use this function to perform your initial setup
function setup()
-- displayMode(FULLSCREEN)
numwatersprings=60
water={}
wverts={}
droplets={}
rocks={}
border=0
for i=1,numwatersprings do
table.insert(water,{x=border+(i-1)*(WIDTH-2*border)/(numwatersprings-1),y=HEIGHT/2,vel=0,acc=0})
end
parameter.number("springconstant",0.01,0.1,0.02)
parameter.number("damping",0.01,0.1,0.06)
parameter.integer("neighbours",5,20,9)

leftDeltas={}
rightDeltas={}
baseheight=HEIGHT/2
bottom=0
watermesh=mesh()
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(110, 169, 224, 255)
-- This sets the line thickness
strokeWidth(3)

if CurrentTouch.state==BEGAN then
table.insert(rocks,{x=CurrentTouch.x,y=CurrentTouch.y,speed=0,splash=0})
end
--calculate the new position of each water spring element
for u,w in pairs(water) do
force = springconstant * (w.y - baseheight) + w.vel*damping
w.acc = -force
w.y = w.y + w.vel
w.vel = w.vel + w.acc
end
--let each spring affect its neighbours
for j=1,neighbours do
for i=1,numwatersprings do
if (i > 1) then
leftDeltas[i] = spread * (water[i].y - water[i-1].y);
water[i-1].vel = water[i-1].vel + leftDeltas[i];
end
if (i < numwatersprings - 1) then
rightDeltas[i] = spread * (water[i].y - water[i+1].y);
water[i+1].vel=water[i+1].vel + rightDeltas[i];
end
end
end

for i=1,numwatersprings do
if (i > 1) then
water[i-1].y =water[i-1].y+ leftDeltas[i];
end
if (i < numwatersprings- 1) then
water[i+1].y=water[i+1].y + rightDeltas[i];
end
end
--draw the water line
for i=1,numwatersprings-1 do
fill(50,70,190,255)
stroke(36, 32, 95, 255)
line(water[i].x,water[i].y,water[i+1].x,water[i+1].y)
--draw as a mesh
wverts[(i-1)*6+5]=vec2(water[i].x,water[i].y)
wverts[(i-1)*6+3]=vec2(water[i+1].x,water[i+1].y)
wverts[(i-1)*6+1]=vec2(water[i+1].x,bottom)
wverts[(i-1)*6+2]=vec2(water[i+1].x,bottom)
wverts[(i-1)*6+6]=vec2(water[i].x,bottom)
wverts[(i-1)*6+4]=vec2(water[i].x,water[i].y)
end

-- Draw the water droplets
for s,d in pairs(droplets) do
--add transparency to the droplets so they fades away
tint(77, 194, 231, d.fade)

d.x = d.x + d.xspeed*math.sin(math.rad(-d.dir))
d.y = d.y + d.yspeed
d.yspeed = d.yspeed -4

pushMatrix()
translate(d.x,d.y)
rotate(math.deg(angle)+90)
sprite("Small World:Raindrop Soft",0,0,15,20)
popMatrix()

table.remove(droplets,s)
end
end
tint(255)

watermesh.vertices=triangulate(wverts)
watermesh:setColors(40,60,180,255)
watermesh:draw()

for s,r in pairs(rocks) do
fall=4
tint(255)
if r.y<HEIGHT/2-50 then
fall=0.5
tint(40,60,180,100)
end
sprite("Tyrian Remastered:Rock 3",r.x,r.y)
r.speed = r.speed + fall
r.y = r.y -r.speed
local splashdepth=2
if r.splash<splashdepth and r.y<HEIGHT/2 then
r.splash = r.splash + 1
dfact=math.floor(r.speed)
local nearestspring=math.floor(numwatersprings*CurrentTouch.x/WIDTH)
if nearestspring==0 then nearestspring=1 end
water[nearestspring+1].y=(r.y)
water[nearestspring].y=(r.y)
if r.splash==splashdepth then
r.speed = r.speed /10
for i=1,dfact do
table.insert(droplets,
{x=r.x,y=HEIGHT/2-dfact,dir=340+math.random(40),
end
end
end

end
end
``````

Edit: typo changed WIDTH to HEIGHT in droplets
Edit: changed the order in which the vertices are processed to the proper order!

Wonderful… thanks a lot. Is it OK to reuse this code in a project?

Is “the floor is jelly” a project of yours developed on Codea alone, @piinthesky ?

@Rodolphe yes no probs from me - I just reimplemented someone else’s work so if giving attributions link back to them in the first instance. Also note that I’ve just edited the code to render the vertices in the correct order - the previous version caused some flickering

@rodolphe, no unfortunately floor of jelly is nothing to do with me. If i remember correctly it is a PC game and not made with codea.

Thanks @West!

Oh ok, @piinthesky, I should have looked further… I was quite impressed by little details like the flags. Is that, the flapping flags, for instance, something we could accomplish with methods similar to what’s used for the 2d water rendering?