Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --# Flowfield
- Flowfield = class()
- function Flowfield:init(sampleRate)
- self.rate = sampleRate or 50
- self.noiseXPos = vec2( math.random(1,100), math.random(1,100) )
- self.noiseYPos = vec2( math.random(1,100), math.random(1,100) )
- self.noiseXDir = vec2(0,1):rotate( math.rad( math.random(0,360) ) )
- self.noiseYDir = vec2(0,1):rotate( math.rad( math.random(0,360) ) )
- self.speed = 0.01
- self.scale = 1
- self.noiseScale = 1/5
- self.vels = {}
- self.sampX = WIDTH/self.rate
- self.sampY = HEIGHT/self.rate
- for x = 1,self.sampX do
- self.vels[x] = {}
- for y = 1,self.sampY do
- self.vels[x][y] = vec2(0,0)
- end
- end
- end
- -- Sample the field at x,y using bilinear interpolation
- function Flowfield:sample(x,y)
- -- f(x,y) = f(0,0)(1-x)(1-y) + f(1,0)x(1-y) +
- -- f(0,1)(1-x)y + f(1,1)xy
- x = math.max( self.rate, math.min( x, WIDTH - self.rate ) )
- y = math.max( self.rate, math.min( y, HEIGHT - self.rate ) )
- local vels = self.vels
- local x0 = math.floor( x/self.rate )
- local x1 = x0 + 1
- local y0 = math.floor( y/self.rate )
- local y1 = y0 + 1
- local xa = (x/self.rate - x0)
- local ya = (y/self.rate - y0)
- local invXa = 1 - xa
- local invYa = 1 - ya
- local f00 = vels[x0][y0]
- local f10 = vels[x1][y0]
- local f01 = vels[x0][y1]
- local f11 = vels[x1][y1]
- return (f00 * invXa * invYa) + (f10 * xa * invYa) +
- (f01 * invXa * ya) + (f11 * xa * ya)
- end
- function Flowfield:update()
- -- Move the noise
- self.noiseXPos = self.noiseXPos + (self.noiseXDir * self.speed)
- self.noiseYPos = self.noiseYPos + (self.noiseYDir * self.speed)
- -- Rotate the "wind"
- self.noiseXDir = self.noiseXDir:rotate( 0.001 )
- self.noiseYDir = self.noiseYDir:rotate( 0.001 )
- -- Compute values at all gridpoints
- local sX = self.sampX
- local sY = self.sampY
- local vX, vY
- local vels = self.vels
- local s = self.scale
- local noiseScale = self.noiseScale
- local nX = self.noiseXPos
- local nY = self.noiseYPos
- for x = 1,sX do
- for y = 1,sY do
- vX = noise( nX.x + x * noiseScale,
- nX.y + y * noiseScale )
- vY = noise( nY.x + y * noiseScale,
- nY.y + x * noiseScale )
- vels[x][y] = vec2(vX, vY)
- end
- end
- -- Should probably track one of the velocities
- -- If it exceeds a length of 2 then re-normalize the
- -- entire field
- end
- function Flowfield:draw()
- -- For debugging
- pushStyle()
- noSmooth()
- stroke(0,0,0,100)
- strokeWidth(2)
- fill(128)
- rectMode(CENTER)
- local rate = self.rate
- local sX = self.sampX
- local sY = self.sampY
- local vels = self.vels
- local s = 70
- for x = 1,sX do
- local pX = x * rate
- for y = 1,sY do
- local pY = y * rate
- local v = vels[x][y]
- -- local v = self:sample(pX+0.5,pY+0.5)
- line( pX, pY, pX + v.x * s, pY + v.y * s )
- --rect( pX, pY, 5, 5 )
- end
- end
- popStyle()
- end
- --# Main
- supportedOrientations(LANDSCAPE_ANY)
- -- Use this function to perform your initial setup
- function setup()
- displayMode(FULLSCREEN)
- iparameter("FlowVisible", 0, 1, 1)
- field = Flowfield(44)
- particles = {}
- for i = 1,153 do
- table.insert( particles,
- Particle( vec2( math.random( 30, WIDTH - 30 ),
- math.random( 30, HEIGHT - 30 ) ) ) )
- end
- end
- function resetParticle(p)
- p.opacity = 0
- p.pos = vec2( math.random( 30, WIDTH - 30 ),
- math.random( 30, HEIGHT - 30 ) )
- end
- function updateParticle(p)
- p.vel = p.vel * 0.8 + field:sample(p.pos.x,p.pos.y) * 0.8
- p:update()
- local pos = p.pos + p.offset
- if pos.x < 0 or pos.x > WIDTH or
- pos.y < 0 or pos.y > HEIGHT then
- resetParticle(p)
- end
- end
- function draw()
- -- This sets a dark background color
- background(129, 120, 162, 255)
- -- Do your drawing here
- field:update()
- if FlowVisible == 1 then
- field:draw()
- end
- noSmooth()
- fill(255)
- rectMode(CENTER)
- noStroke()
- local angle
- for _,v in pairs(particles) do
- updateParticle(v)
- v:draw()
- end
- --FPS
- textMode(CORNER)
- font("Futura-CondensedMedium")
- fill(0, 40, 55, 100)
- fontSize(34)
- local fps = math.floor(1/DeltaTime)
- text("FPS "..fps, 20,35)
- end
- --# Particle
- Particle = class()
- function Particle:init(pos)
- -- you can accept and set parameters here
- self.offset = vec2( 0,0 )
- self.orientation = math.random(0,360)
- self.twistSpeed = 0
- self.size = math.random(8, 14)
- self.pos = pos or vec2(0,0)
- self.vel = vec2(0,0)
- self.opacity = 0
- self.color = color(250,242,242)
- end
- function Particle:update()
- self.pos = self.pos + self.vel --+ self.fate
- self.orientation = self.orientation + self.twistSpeed
- if self.opacity < 1 then
- self.opacity = self.opacity + 0.07
- end
- end
- function Particle:draw()
- pushMatrix()
- local os = self.offset
- translate(self.pos.x + os.x, self.pos.y + os.y)
- local angle = vec2(0,1):angleBetween( self.vel:normalize() )
- rotate( math.deg(angle) )
- local c = self.color
- fill(c.r,c.g,c.b,
- math.max( math.min( c.a * self.opacity, 255 ), 0 ) )
- rect( 0, 0, self.size, self.size )
- popMatrix()
- end
Advertisement
Add Comment
Please, Sign In to add comment