89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
package collision
|
|
|
|
type Point struct {
|
|
X float64
|
|
Y float64
|
|
}
|
|
|
|
type Polygon struct {
|
|
Points []Point
|
|
}
|
|
|
|
type ObjectType int
|
|
|
|
const (
|
|
Hero ObjectType = 1 << iota
|
|
Zombie
|
|
Bullet
|
|
)
|
|
|
|
type Collidable interface {
|
|
CollisionShape() Polygon
|
|
HandleCollisionEvent(other Collidable)
|
|
CollisionObjectType() ObjectType
|
|
}
|
|
|
|
// Helper function to calculate the dot product of two points
|
|
func dot(p1, p2 Point) float64 {
|
|
return p1.X*p2.X + p1.Y*p2.Y
|
|
}
|
|
|
|
// Helper function to get the normal of the edge between two points
|
|
func edgeNormal(p1, p2 Point) Point {
|
|
return Point{X: p2.Y - p1.Y, Y: p1.X - p2.X}
|
|
}
|
|
|
|
// Project a polygon onto an axis and return the min and max projections
|
|
func projectPolygon(axis Point, polygon Polygon) (float64, float64) {
|
|
min := dot(axis, polygon.Points[0])
|
|
max := min
|
|
for _, p := range polygon.Points[1:] {
|
|
projection := dot(axis, p)
|
|
if projection < min {
|
|
min = projection
|
|
}
|
|
if projection > max {
|
|
max = projection
|
|
}
|
|
}
|
|
return min, max
|
|
}
|
|
|
|
// Check if two projections on an axis overlap
|
|
func overlap(minA, maxA, minB, maxB float64) bool {
|
|
if minA > maxB || minB > maxA {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Overlaps checks if two polygons overlap using the Separating Axis Theorem
|
|
func (p Polygon) Overlaps(p2 Polygon) bool {
|
|
if len(p.Points) == 0 || len(p2.Points) == 0 {
|
|
return false
|
|
}
|
|
for i := 0; i < len(p.Points); i++ {
|
|
next := (i + 1) % len(p.Points)
|
|
axis := edgeNormal(p.Points[i], p.Points[next])
|
|
minA, maxA := projectPolygon(axis, p)
|
|
minB, maxB := projectPolygon(axis, p2)
|
|
|
|
if !overlap(minA, maxA, minB, maxB) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
for i := 0; i < len(p2.Points); i++ {
|
|
next := (i + 1) % len(p2.Points)
|
|
axis := edgeNormal(p2.Points[i], p2.Points[next])
|
|
minA, maxA := projectPolygon(axis, p)
|
|
minB, maxB := projectPolygon(axis, p2)
|
|
|
|
if !overlap(minA, maxA, minB, maxB) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|