-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathboid.go
94 lines (80 loc) · 2.61 KB
/
boid.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package main
import (
"math"
"math/rand"
"time"
)
type Boid struct {
position Vector2d
velocity Vector2d
id int
}
func (b *Boid) start() {
for {
b.moveOne()
time.Sleep(4 * time.Millisecond)
}
}
func (b *Boid) calcAcceleration() Vector2d {
upper, lower := b.position.AddValue(viewRadius), b.position.AddValue(-viewRadius)
avgPosition, avgVelocity, separation := Vector2d{0, 0}, Vector2d{0, 0}, Vector2d{0, 0}
count := 0.0
rWlock.RLock()
for i := math.Max(lower.x, 0); i <= math.Min(upper.x, screenWidth); i++ {
for j := math.Max(lower.y, 0); j <= math.Min(upper.y, screenHeight); j++ {
if otherBoidId := boidMap[int(i)][int(j)]; otherBoidId != -1 && otherBoidId != b.id {
if dist := boids[otherBoidId].position.distance(b.position); dist < viewRadius {
count++
avgVelocity = avgVelocity.Add(boids[otherBoidId].velocity)
avgPosition = avgPosition.Add(boids[otherBoidId].position)
separation = separation.Add(b.position.Substract(boids[otherBoidId].position).DivideValue(dist))
}
}
}
}
rWlock.RUnlock()
acc := Vector2d{b.borderBounce(b.position.x, screenWidth), b.borderBounce(b.position.y, screenHeight)}
if count > 0 {
avgVelocity = avgVelocity.DivideValue(count).MultiplyValue(1.05)
avgPosition = avgPosition.DivideValue(count)
accCohesion := avgPosition.Substract(b.position).MultiplyValue(adjustmentRadius)
accSeparation := separation.MultiplyValue(adjustmentRadius)
accAlignement := avgVelocity.Substract(b.velocity).MultiplyValue(adjustmentRadius)
acc = acc.Add(accAlignement).Add(accCohesion).Add(accSeparation)
}
return acc
}
func (b *Boid) borderBounce(pos, maxBorder float64) float64 {
if pos < viewRadius {
return 1 / pos
} else if pos > maxBorder-viewRadius {
return 1 / (pos - maxBorder)
}
return 0
}
func (b *Boid) moveOne() {
acceleration := b.calcAcceleration()
rWlock.Lock()
b.velocity = b.velocity.Add(acceleration).limit(-1, 1)
boidMap[int(b.position.x)][int(b.position.y)] = -1
b.position = b.position.Add(b.velocity)
boidMap[int(b.position.x)][int(b.position.y)] = b.id
// next := b.position.Add(b.velocity)
// if next.x >= screenWidth || next.x < 0 {
// b.velocity = Vector2d{-b.velocity.x, b.velocity.y}
// }
// if next.y >= screenHeight || next.y < 0 {
// b.velocity = Vector2d{b.velocity.x, -b.velocity.y}
// }
rWlock.Unlock()
}
func createBoid(id int) {
b := Boid{
position: Vector2d{rand.Float64() * screenWidth, rand.Float64() * screenHeight},
velocity: Vector2d{1.5 * (rand.Float64()*2 - 1), 1.5 * (rand.Float64()*2 - 1)},
id: id,
}
boids[id] = &b
boidMap[int(b.position.x)][int(b.position.y)] = b.id
go b.start()
}