Skip to content

Commit 80f79b9

Browse files
committed
feat: animation: drain
1 parent e75cac1 commit 80f79b9

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

pkg/anim/fluid/anim.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Fluid struct {
1313
sim *Simulator
1414
start image.Image
1515
current image.Image
16+
options []Option
1617
}
1718

1819
var _ meta.Animation = (*Fluid)(nil)
@@ -21,6 +22,10 @@ const (
2122
POSITION_FACTOR = 10
2223
)
2324

25+
func NewAnimation(options ...Option) *Fluid {
26+
return &Fluid{options: options}
27+
}
28+
2429
func (f *Fluid) Init(start image.Image) {
2530
f.start = start
2631

@@ -45,6 +50,7 @@ func (f *Fluid) Init(start image.Image) {
4550
float64(size.C)*POSITION_FACTOR,
4651
float64(size.R)*POSITION_FACTOR,
4752
particles,
53+
f.options...,
4854
)
4955
}
5056

pkg/anim/fluid/module.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
11
package fluid
22

3+
import "math/rand"
4+
35
type number = float64
46

7+
// Option configures a Simulator.
8+
type Option func(*Simulator)
9+
10+
// WithDrain adds a hole in the bottom and top boundaries at random X
11+
// positions. Particles that fall through the bottom hole wrap to the top.
12+
func WithDrain() Option {
13+
return func(s *Simulator) {
14+
holeWidth := s.width / 4
15+
maxOffset := s.width - holeWidth
16+
bottomStart := rand.Float64() * maxOffset
17+
topStart := rand.Float64() * maxOffset
18+
s.drainEnabled = true
19+
s.bottomHoleMinX = bottomStart
20+
s.bottomHoleMaxX = bottomStart + holeWidth
21+
s.topHoleMinX = topStart
22+
s.topHoleMaxX = topStart + holeWidth
23+
}
24+
}
25+
526
type Simulator struct {
627
width number
728
height number
@@ -20,13 +41,24 @@ type Simulator struct {
2041
particleListNextIdx []int
2142

2243
material Material
44+
45+
// Drain mode: particles in the bottom hole wrap to the top hole
46+
drainEnabled bool
47+
bottomHoleMinX number
48+
bottomHoleMaxX number
49+
topHoleMinX number
50+
topHoleMaxX number
2351
}
2452

2553
func (s *Simulator) Particles() []Particle {
2654
return s.particles
2755
}
2856

29-
func New(width, height number, particles []Particle) *Simulator {
57+
func New(
58+
width, height number,
59+
particles []Particle,
60+
options ...Option,
61+
) *Simulator {
3062
s := &Simulator{
3163
width: width,
3264
height: height,
@@ -50,5 +82,10 @@ func New(width, height number, particles []Particle) *Simulator {
5082
s.particleListNextIdx = make([]int, len(particles))
5183

5284
s.material = NewMaterial("water", 4, 0.5, 0.5, 40)
85+
86+
for _, opt := range options {
87+
opt(s)
88+
}
89+
5390
return s
5491
}

pkg/anim/fluid/update.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,26 @@ func (s *Simulator) resolveCollisions(dt number) {
286286
s.particles[i].X += boundaryMul * (boundaryMaxX - p.X)
287287
}
288288

289-
if p.Y < boundaryMinY {
290-
s.particles[i].Y += boundaryMul * (boundaryMinY - p.Y)
291-
} else if p.Y > boundaryMaxY {
292-
s.particles[i].Y += boundaryMul * (boundaryMaxY - p.Y)
289+
inBottomHole := s.drainEnabled &&
290+
p.X >= s.bottomHoleMinX &&
291+
p.X <= s.bottomHoleMaxX
292+
293+
if inBottomHole && p.Y > boundaryMaxY {
294+
// Map X proportionally from bottom hole to top hole
295+
t := (p.X - s.bottomHoleMinX) /
296+
(s.bottomHoleMaxX - s.bottomHoleMinX)
297+
s.particles[i].X = s.topHoleMinX +
298+
t*(s.topHoleMaxX-s.topHoleMinX)
299+
s.particles[i].prevX = s.particles[i].X
300+
// Wrap to top
301+
s.particles[i].Y = boundaryMinY + FLUID_PADDING
302+
s.particles[i].prevY = s.particles[i].Y
303+
} else {
304+
if p.Y < boundaryMinY {
305+
s.particles[i].Y += boundaryMul * (boundaryMinY - p.Y)
306+
} else if p.Y > boundaryMaxY {
307+
s.particles[i].Y += boundaryMul * (boundaryMaxY - p.Y)
308+
}
293309
}
294310
}
295311
}

pkg/anim/module.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ func init() {
4040
registerAnimation("cy", func() Animation {
4141
return &cy.Cyform{}
4242
})
43+
registerAnimation("drain", func() Animation {
44+
return fluid.NewAnimation(fluid.WithDrain())
45+
})
4346
registerAnimation("fluid", func() Animation {
44-
return &fluid.Fluid{}
47+
return fluid.NewAnimation()
4548
})
4649
registerAnimation("perlin", func() Animation {
4750
return perlin.New()

0 commit comments

Comments
 (0)