|
| 1 | +# Metaballs |
| 2 | + |
| 3 | +Metaballs are *blobby objects* that meld together when they come into close proximity, appearing organically shaped. It is also reminiscent of cellular mitosis. |
| 4 | + |
| 5 | +When running the example, try pressing the arrow keys right or left to change the threshold of cohesion, or up and down arrow keys to alter the amount of (invisible) balls that make up the metaballs. |
| 6 | + |
| 7 | +*Metaballs was contributed by Tomasz Stecko.* |
| 8 | + |
| 9 | + |
| 10 | + |
| 11 | +```lua |
| 12 | +require("L5") |
| 13 | + |
| 14 | +dmin=0 |
| 15 | +dmax=800 |
| 16 | + |
| 17 | +function setup() |
| 18 | + size(dmax, dmax) |
| 19 | + windowTitle("lava lamp") |
| 20 | +end |
| 21 | + |
| 22 | +-- invisible balls that bounce around (flat velocity) |
| 23 | +Ball={} |
| 24 | + function Ball:new() |
| 25 | + data={ |
| 26 | + vx=math.random(1,3)*-1^math.random(1,2), vy=math.random(1,3)*-1^math.random(1,2), |
| 27 | + x=math.random(dmin,dmax), y=math.random(dmin,dmax), |
| 28 | + r=math.random(60,120) |
| 29 | + } |
| 30 | + setmetatable(data, self) |
| 31 | + self.__index = self |
| 32 | + return data |
| 33 | + end |
| 34 | + |
| 35 | + -- screensaver style bouncing around the edges |
| 36 | + function Ball:move() |
| 37 | + self.x=self.x+self.vx |
| 38 | + self.y=self.y+self.vy |
| 39 | + if self.x<dmin then self.x=dmin self.vx=-1*self.vx end |
| 40 | + if self.x>dmax then self.x=dmax self.vx=-1*self.vx end |
| 41 | + if self.y<dmin then self.y=dmin self.vy=-1*self.vy end |
| 42 | + if self.y>dmax then self.y=dmax self.vy=-1*self.vy end |
| 43 | + end |
| 44 | + |
| 45 | +-- initialize some balls |
| 46 | +function get_balls(n_balls) |
| 47 | + local balls={} |
| 48 | + for i = 1, n_balls do |
| 49 | + balls[i] = Ball:new() |
| 50 | + end |
| 51 | + return balls |
| 52 | +end |
| 53 | + |
| 54 | +-- tweak the behavior of balls |
| 55 | +threshold=2.5 |
| 56 | +n_balls=10 |
| 57 | +balls=get_balls(n_balls) |
| 58 | + |
| 59 | +-- point grid to calculate balls contribution to effect |
| 60 | +grid={} |
| 61 | +n=1 |
| 62 | +g_size=10 |
| 63 | +g_steps=dmax/g_size |
| 64 | +for i=0,g_steps do |
| 65 | + for j=0,g_steps do |
| 66 | + grid[n]={x=i*g_size,y=j*g_size,v=0} |
| 67 | + n=n+1 |
| 68 | + end |
| 69 | +end |
| 70 | + |
| 71 | +function draw() |
| 72 | + -- draw background |
| 73 | + background(0,0,0) |
| 74 | + -- move invisible balls |
| 75 | + for i=1, #balls do balls[i]:move() end |
| 76 | + |
| 77 | + -- calculate value of every dot in the grid |
| 78 | + for i=1, #grid do |
| 79 | + v1=0 |
| 80 | + g=grid[i] |
| 81 | + |
| 82 | + -- every ball contributes |
| 83 | + for i=1,#balls do |
| 84 | + b=balls[i] |
| 85 | + v2=(b.r*b.r)/((g.x-b.x)*(g.x-b.x)+(g.y-b.y)*(g.y-b.y)) |
| 86 | + v1=v1+v2 |
| 87 | + end |
| 88 | + |
| 89 | + grid[i].v=v1 |
| 90 | + end |
| 91 | + |
| 92 | + -- draw dots when they reach threshold |
| 93 | + for i=1, #grid do |
| 94 | + if grid[i].v>=threshold then |
| 95 | + fill(color(114, 222, 194)) |
| 96 | + noStroke() |
| 97 | + circle(grid[i].x,grid[i].y,10) |
| 98 | + end |
| 99 | + end |
| 100 | +end |
| 101 | + |
| 102 | +-- press arrow keys to mess with metaball count and 'physics' |
| 103 | +function keyPressed() |
| 104 | + if key == 'left' and threshold-0.5>=0 then threshold=threshold-0.5 end |
| 105 | + if key == 'right' and threshold+0.5<=4 then threshold=threshold+0.5 end |
| 106 | + |
| 107 | + if key == 'down' and n_balls-1>=2 then |
| 108 | + n_balls = n_balls-1 |
| 109 | + balls=get_balls(n_balls) |
| 110 | + end |
| 111 | + |
| 112 | + if key == 'up' and n_balls+1<=20 then |
| 113 | + n_balls = n_balls+1 |
| 114 | + balls=get_balls(n_balls) |
| 115 | + end |
| 116 | +end |
| 117 | +``` |
| 118 | + |
| 119 | +## Related References |
| 120 | + |
| 121 | +* [if](/reference/if) |
| 122 | +* [line()](/reference/line) |
| 123 | +* [draw()](/reference/draw) |
| 124 | +* [frameRate()](/reference/frameRate) |
| 125 | +* [random()](/reference/random) |
| 126 | + |
| 127 | +## Related Examples |
| 128 | + |
| 129 | +* [10print](10print.md) - An implementation of the classic maze-drawing algorithm |
| 130 | +* [Animation with Events](animation-and-variables-animation-with-events.md) - Pause and resume animation. |
| 131 | +* [Basic Pong](basic-pong.md) - A simple program demonstrating a basic implementation of pong with enemy AI player |
| 132 | +* [Conditions](animation-and-variables-conditions.md) - Use if and else statements to make decisions while your sketch runs. |
| 133 | +* [Copy Image Data](imported-media-copy-image-data.md) - Paint from an image file onto the canvas. |
| 134 | +* [Conway's Game Of Life](conways-life.md) - An implementation of the zero-player game and simulation formulated by mathematician John Conway |
| 135 | +* [Minimum Spanning Tree](min-span-tree.md) - An example of implementing Prim's algorithm for finding the shortest lengths to connect all randomly placed dots |
| 136 | + |
0 commit comments