-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollision.go
109 lines (101 loc) · 2.82 KB
/
collision.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// molecular is a 3D physics engine written in Go
// Copyright (C) 2023 Kevin Z <zyxkad@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package molecular
import (
"sync"
)
func (e *Engine) appendObjsInsideRange(objs []*Object, pos Vec3, radius float64) []*Object {
radius2 := radius * radius
for _, o := range e.objects {
if o.AbsPos().Subbed(pos).SqLen() <= radius2 {
objs = append(objs, o)
}
}
return objs
}
func (e *Engine) appendObjsInsideRing(objs []*Object, pos Vec3, minR, maxR float64) []*Object {
minR2 := minR * minR
maxR2 := maxR * maxR
for _, o := range e.objects {
l := o.AbsPos().Subbed(pos).SqLen()
if minR2 <= l && l <= maxR2 {
objs = append(objs, o)
}
}
return objs
}
type blockCollisionRecord struct {
A, B Block
Area Cube
}
// blockCollision check the fine collision between two objects' blocks
// hitarea is the relative area from "a" to "o"
func (o *Object) checkBlockCollisions(a *Object, hitarea *Cube) (records []*blockCollisionRecord) {
obox := o.innerHitbox.Clone()
obox.P.Add(hitarea.P)
if !obox.Overlap(a.innerHitbox) {
return
}
var ablocks []Block
for _, d := range a.blocks {
if d.Outline().Overlap(hitarea) {
ablocks = append(ablocks, d)
}
}
for _, b := range o.blocks {
cubeB := b.Outline()
if !cubeB.Overlap(hitarea) {
continue
}
cubeB = cubeB.Clone()
cubeB.P.Add(hitarea.P)
for _, d := range ablocks {
var rec blockCollisionRecord
if cubeB.OverlapBox(d.Outline(), &rec.Area) {
rec.A = b
rec.B = d
records = append(records, &rec)
}
}
}
return
}
type objCollisionRecord struct {
A, B *Object
Blocks []*blockCollisionRecord
}
func (e *Engine) sendCollisionObjects(wg *sync.WaitGroup, ch chan<- *objCollisionRecord, a, b *Object, bpos Vec3) {
defer wg.Done()
for i, p := range a.children {
pbox := p.outerHitbox.Clone()
pbox.P.Add(bpos)
for _, q := range b.children[i+1:] {
var area Cube
if pbox.OverlapBox(q.outerHitbox, &area) {
wg.Add(1)
go e.sendCollisionObjects(wg, ch, p, q, pbox.P.Subbed(q.outerHitbox.P))
records := p.checkBlockCollisions(q, &area)
if len(records) > 0 {
ch <- &objCollisionRecord{
A: p,
B: q,
Blocks: records,
}
}
}
}
}
}