prism collism
This commit is contained in:
parent
67a8f03cbf
commit
94915072f0
5 changed files with 143 additions and 4 deletions
|
@ -93,3 +93,11 @@ func (b Box) XY() image.Rectangle {
|
|||
Max: b.Max.XY(),
|
||||
}
|
||||
}
|
||||
|
||||
// XZ returns the image.Rectangle representing the box if we forgot about Y.
|
||||
func (b Box) XZ() image.Rectangle {
|
||||
return image.Rectangle{
|
||||
Min: b.Min.XZ(),
|
||||
Max: b.Max.XZ(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package engine
|
||||
|
||||
import "image"
|
||||
import (
|
||||
"image"
|
||||
)
|
||||
|
||||
// ID implements Identifier directly (as a string value).
|
||||
type ID string
|
||||
|
@ -65,3 +67,97 @@ func cfloat(p image.Point) (x, y float64) {
|
|||
func dot(p, q image.Point) int {
|
||||
return p.X*q.X + p.Y*q.Y
|
||||
}
|
||||
|
||||
// polygonContains reports if a polygon contains a point
|
||||
func polygonContains(polygon []image.Point, p image.Point) bool {
|
||||
for i, p1 := range polygon {
|
||||
p2 := polygon[(i+1)%len(polygon)]
|
||||
// ∆(p p1 p2) should have positive signed area
|
||||
p1, p2 = p1.Sub(p), p2.Sub(p)
|
||||
if p2.X*p1.Y-p1.X*p2.Y < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// polygonRectOverlap reports if a polygon overlaps a rectangle.
|
||||
func polygonRectOverlap(polygon []image.Point, rect image.Rectangle) bool {
|
||||
// There's a good chance a vertex from one thing is inside the other...
|
||||
|
||||
// Check if any vertex of the polygon is inside the rect.
|
||||
for _, p := range polygon {
|
||||
if p.In(rect) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce Max to the inclusive bound.
|
||||
rect.Max = rect.Max.Sub(image.Pt(1, 1))
|
||||
|
||||
// Check if any vertex of the rect is inside the polygon.
|
||||
if polygonContains(polygon, rect.Min) {
|
||||
return true
|
||||
}
|
||||
if polygonContains(polygon, rect.Max) {
|
||||
return true
|
||||
}
|
||||
if polygonContains(polygon, image.Pt(rect.Min.X, rect.Max.Y)) {
|
||||
return true
|
||||
}
|
||||
if polygonContains(polygon, image.Pt(rect.Max.X, rect.Min.Y)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Only remaining cases involve line intersection between the rect and poly.
|
||||
|
||||
// Since rect is an axis-aligned rectangle, we only need vertical and
|
||||
// horizontal line intersection tests.
|
||||
// Walk each edge of polygon. Only a point and the ∆x, ∆y are needed.
|
||||
for i, p := range polygon {
|
||||
q := polygon[(i+1)%len(polygon)]
|
||||
d := q.Sub(p)
|
||||
// If the polygon edge is not vertical, test left and right sides
|
||||
if d.X != 0 {
|
||||
if d.X < 0 {
|
||||
d = d.Mul(-1)
|
||||
}
|
||||
min := (rect.Min.Y - p.Y) * d.X
|
||||
max := (rect.Max.Y - p.Y) * d.X
|
||||
// Test left side of rect
|
||||
if (rect.Min.X >= p.X || rect.Min.X >= q.X) && (rect.Min.X <= p.X || rect.Min.X <= q.X) {
|
||||
if t := (rect.Min.X - p.X) * d.Y; min <= t && t <= max {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Test right side of rect
|
||||
if (rect.Max.X >= p.X || rect.Max.X >= q.X) && (rect.Max.X <= p.X || rect.Max.X <= q.X) {
|
||||
if t := (rect.Max.X - p.X) * d.Y; min <= t && t <= max {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the polygon edge is not horizontal, test the top and bottom sides
|
||||
if d.Y != 0 {
|
||||
if d.Y < 0 {
|
||||
d = d.Mul(-1)
|
||||
}
|
||||
min := (rect.Min.X - p.X) * d.Y
|
||||
max := (rect.Max.X - p.X) * d.Y
|
||||
// Test top side of rect
|
||||
if (rect.Min.Y >= p.Y && rect.Min.Y >= q.Y) && (rect.Min.Y <= p.Y && rect.Min.Y <= q.Y) {
|
||||
if t := (rect.Min.Y - p.Y) * d.X; min <= t && t <= max {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Test bottom side of rect
|
||||
if (rect.Max.Y >= p.Y && rect.Max.Y >= q.Y) && (rect.Max.Y <= p.Y && rect.Max.Y <= q.Y) {
|
||||
if t := (rect.Max.Y - p.Y) * d.X; min <= t && t <= max {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@ func (p Int3) String() string {
|
|||
|
||||
// XY applies the Z-forgetting projection. (It returns just X and Y.)
|
||||
func (p Int3) XY() image.Point {
|
||||
return image.Point{p.X, p.Y}
|
||||
return image.Point{X: p.X, Y: p.Y}
|
||||
}
|
||||
|
||||
// XZ applies the Y-forgetting projection. (It returns just X and Z (as Y).)
|
||||
func (p Int3) XZ() image.Point {
|
||||
return image.Point{X: p.X, Y: p.Z}
|
||||
}
|
||||
|
||||
// Add performs vector addition.
|
||||
|
|
|
@ -40,6 +40,7 @@ type PrismMap struct {
|
|||
DrawOffset image.Point // offset applies to whole map
|
||||
PosToWorld IntMatrix3x4 // p.pos -> world voxelspace
|
||||
PrismSize Int3 // in world voxelspace units
|
||||
PrismTop []image.Point // polygon vertices anticlockwise, Y means Z
|
||||
Sheet Sheet
|
||||
|
||||
game *Game
|
||||
|
@ -50,6 +51,7 @@ func (m *PrismMap) CollidesWith(b Box) bool {
|
|||
if m.Ersatz {
|
||||
return false
|
||||
}
|
||||
|
||||
// To find the prisms need to test, we need to invert PosToWorld.
|
||||
|
||||
// Step 1: subtract whatever the translation component of PosToWorld is,
|
||||
|
@ -80,11 +82,31 @@ func (m *PrismMap) CollidesWith(b Box) bool {
|
|||
if !b.Overlaps(cb) {
|
||||
continue
|
||||
}
|
||||
// TODO: take into account the prism shape
|
||||
return true
|
||||
// Take into account the prism shape
|
||||
r := b.XZ().Sub(wp.XZ())
|
||||
if polygonRectOverlap(m.PrismTop, r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Here's the test-every-prism approach
|
||||
for pos := range m.Map {
|
||||
// Map it back to worldspace to get a bounding box for the prism
|
||||
wp := m.PosToWorld.Apply(pos)
|
||||
cb := Box{Min: wp, Max: wp.Add(m.PrismSize)}
|
||||
if !b.Overlaps(cb) {
|
||||
continue
|
||||
}
|
||||
// Take into account the prism shape
|
||||
r := b.XZ().Sub(wp.XZ())
|
||||
if polygonRectOverlap(m.PrismTop, r) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
*/
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
8
main.go
8
main.go
|
@ -121,6 +121,14 @@ func level1() *engine.Scene {
|
|||
2: [4]int{8, 0, 16, 0},
|
||||
},
|
||||
PrismSize: engine.Int3{X: 32, Y: 16, Z: 16},
|
||||
PrismTop: []image.Point{
|
||||
{X: 8, Y: 0},
|
||||
{X: 0, Y: 8},
|
||||
{X: 8, Y: 16},
|
||||
{X: 23, Y: 16},
|
||||
{X: 31, Y: 8},
|
||||
{X: 23, Y: 0},
|
||||
},
|
||||
Sheet: engine.Sheet{
|
||||
CellSize: image.Pt(32, 32),
|
||||
Src: engine.ImageRef{Path: "assets/hexprism32.png"},
|
||||
|
|
Loading…
Reference in a new issue