mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-26 03:39:00 +00:00
Updated collider utility encapsulation for visualization subproject.
This commit is contained in:
parent
62f10e0877
commit
3baaf1d52c
@ -7,8 +7,6 @@ import (
|
|||||||
"github.com/solarlune/resolv"
|
"github.com/solarlune/resolv"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
"math"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorldColliderDisplay struct {
|
type WorldColliderDisplay struct {
|
||||||
@ -34,14 +32,11 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
spaceOffsetX := float64(spaceW) * 0.5
|
spaceOffsetX := float64(spaceW) * 0.5
|
||||||
spaceOffsetY := float64(spaceH) * 0.5
|
spaceOffsetY := float64(spaceH) * 0.5
|
||||||
|
|
||||||
// TODO: Move collider y-axis transformation to a "dnmshared"
|
|
||||||
playerColliderRadius := float64(32)
|
playerColliderRadius := float64(32)
|
||||||
playerColliders := make([]*resolv.Object, len(playerList))
|
playerColliders := make([]*resolv.Object, len(playerList))
|
||||||
space := resolv.NewSpace(int(spaceW), int(spaceH), 16, 16)
|
space := resolv.NewSpace(int(spaceW), int(spaceH), 16, 16)
|
||||||
for i, player := range playerList {
|
for i, player := range playerList {
|
||||||
playerCollider := resolv.NewObject(player.X-playerColliderRadius+spaceOffsetX, player.Y-playerColliderRadius+spaceOffsetY, playerColliderRadius*2, playerColliderRadius*2, "Player")
|
playerCollider := GenerateRectCollider(player.X, player.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
||||||
playerColliderShape := resolv.NewRectangle(0, 0, playerColliderRadius*2, playerColliderRadius*2) // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
|
||||||
playerCollider.SetShape(playerColliderShape)
|
|
||||||
Logger.Info(fmt.Sprintf("Player Collider#%d: player.X=%v, player.Y=%v, radius=%v, spaceOffsetX=%v, spaceOffsetY=%v, shape=%v; calibrationCheckX=player.X-radius+spaceOffsetX=%v", i, player.X, player.Y, playerColliderRadius, spaceOffsetX, spaceOffsetY, playerCollider.Shape, player.X-playerColliderRadius+spaceOffsetX))
|
Logger.Info(fmt.Sprintf("Player Collider#%d: player.X=%v, player.Y=%v, radius=%v, spaceOffsetX=%v, spaceOffsetY=%v, shape=%v; calibrationCheckX=player.X-radius+spaceOffsetX=%v", i, player.X, player.Y, playerColliderRadius, spaceOffsetX, spaceOffsetY, playerCollider.Shape, player.X-playerColliderRadius+spaceOffsetX))
|
||||||
playerColliders[i] = playerCollider
|
playerColliders[i] = playerCollider
|
||||||
space.Add(playerCollider)
|
space.Add(playerCollider)
|
||||||
@ -49,56 +44,43 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
|||||||
|
|
||||||
barrierLocalId := 0
|
barrierLocalId := 0
|
||||||
for _, barrierUnaligned := range barrierList {
|
for _, barrierUnaligned := range barrierList {
|
||||||
barrier := AlignPolygon2DToBoundingBox(barrierUnaligned)
|
barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
|
||||||
|
|
||||||
var w float64 = 0
|
|
||||||
var h float64 = 0
|
|
||||||
|
|
||||||
for i, pi := range barrier.Points {
|
|
||||||
for j, pj := range barrier.Points {
|
|
||||||
if i == j {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if math.Abs(pj.X-pi.X) > w {
|
|
||||||
w = math.Abs(pj.X - pi.X)
|
|
||||||
}
|
|
||||||
if math.Abs(pj.Y-pi.Y) > h {
|
|
||||||
h = math.Abs(pj.Y - pi.Y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
barrierColliderShape := resolv.NewConvexPolygon()
|
|
||||||
for i := 0; i < len(barrier.Points); i++ {
|
|
||||||
p := barrier.Points[i]
|
|
||||||
barrierColliderShape.AddPoints(p.X, p.Y)
|
|
||||||
}
|
|
||||||
|
|
||||||
barrierCollider := resolv.NewObject(barrier.Anchor.X+spaceOffsetX, barrier.Anchor.Y+spaceOffsetY, w, h, "Barrier")
|
|
||||||
barrierCollider.SetShape(barrierColliderShape)
|
|
||||||
|
|
||||||
space.Add(barrierCollider)
|
|
||||||
Logger.Info(fmt.Sprintf("Added barrier: shape=%v", barrierCollider.Shape))
|
Logger.Info(fmt.Sprintf("Added barrier: shape=%v", barrierCollider.Shape))
|
||||||
|
space.Add(barrierCollider)
|
||||||
barrierLocalId++
|
barrierLocalId++
|
||||||
}
|
}
|
||||||
|
|
||||||
world.Space = space
|
world.Space = space
|
||||||
|
|
||||||
toTestPlayerCollider := playerColliders[0]
|
moveToCollide := true
|
||||||
oldDx := 0.0
|
if moveToCollide {
|
||||||
oldDy := 180.0
|
toTestPlayerCollider := playerColliders[0]
|
||||||
if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
|
oldDx := 0.0
|
||||||
toCheckBarrier := collision.Objects[0].Shape
|
oldDy := 180.0
|
||||||
if intersection := toTestPlayerCollider.Shape.Intersection(oldDx, oldDy, toCheckBarrier); nil != intersection {
|
dx := oldDx
|
||||||
Logger.Info(fmt.Sprintf("Collided: shape=%v, oldDx=%v, oldDy=%v, intersection.MTV=%v", toTestPlayerCollider.Shape, oldDx, oldDy, intersection.MTV))
|
dy := oldDy
|
||||||
} else {
|
if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
|
||||||
Logger.Info(fmt.Sprintf("Collided: shape=%v, oldDx=%v, oldDy=%v, toCheckBarrier=%v, no intersecting points", toTestPlayerCollider.Shape, oldDx, oldDy, toCheckBarrier))
|
playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon)
|
||||||
}
|
barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon)
|
||||||
} else {
|
origX, origY := playerShape.Position()
|
||||||
Logger.Info(fmt.Sprintf("Collision Test: shape=%v, oldDx=%v, oldDy=%v, not colliding with any Barrier", toTestPlayerCollider.Shape, oldDx, oldDy))
|
playerShape.SetPosition(origX+oldDx, origY+oldDy)
|
||||||
}
|
if mtv := CalculateMTVForConvexPolygon(playerShape, barrierShape); mtv != nil {
|
||||||
|
Logger.Info(fmt.Sprintf("Collided: shape=%v, oldDx=%v, oldDy=%v, MTV=%v", toTestPlayerCollider.Shape, oldDx, oldDy, mtv))
|
||||||
|
//dx, dy = mtv[0], mtv[1]
|
||||||
|
} else {
|
||||||
|
Logger.Info(fmt.Sprintf("Collided: shape=%v, oldDx=%v, oldDy=%v, toCheckBarrier=%v, not intersecting", toTestPlayerCollider.Shape, oldDx, oldDy, barrierShape))
|
||||||
|
}
|
||||||
|
|
||||||
toTestPlayerCollider.Update()
|
playerShape.SetPosition(origX, origY)
|
||||||
|
|
||||||
|
toTestPlayerCollider.X += dx
|
||||||
|
toTestPlayerCollider.Y += dy
|
||||||
|
} else {
|
||||||
|
Logger.Info(fmt.Sprintf("Collision Test: shape=%v, oldDx=%v, oldDy=%v, not colliding with any Barrier", toTestPlayerCollider.Shape, oldDx, oldDy))
|
||||||
|
}
|
||||||
|
|
||||||
|
toTestPlayerCollider.Update()
|
||||||
|
}
|
||||||
|
|
||||||
return world
|
return world
|
||||||
}
|
}
|
||||||
|
82
dnmshared/resolv_helper.go
Normal file
82
dnmshared/resolv_helper.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package dnmshared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kvartborg/vector"
|
||||||
|
"github.com/solarlune/resolv"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||||
|
collider := resolv.NewObject(origX-w*0.5+spaceOffsetX, origY-h*0.5+spaceOffsetY, w, h, tag)
|
||||||
|
shape := resolv.NewRectangle(0, 0, w, h)
|
||||||
|
collider.SetShape(shape)
|
||||||
|
return collider
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||||
|
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
|
||||||
|
var w, h float64 = 0, 0
|
||||||
|
|
||||||
|
shape := resolv.NewConvexPolygon()
|
||||||
|
for i, pi := range aligned.Points {
|
||||||
|
for j, pj := range aligned.Points {
|
||||||
|
if i == j {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if math.Abs(pj.X-pi.X) > w {
|
||||||
|
w = math.Abs(pj.X - pi.X)
|
||||||
|
}
|
||||||
|
if math.Abs(pj.Y-pi.Y) > h {
|
||||||
|
h = math.Abs(pj.Y - pi.Y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(aligned.Points); i++ {
|
||||||
|
p := aligned.Points[i]
|
||||||
|
shape.AddPoints(p.X, p.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
|
||||||
|
collider.SetShape(shape)
|
||||||
|
|
||||||
|
return collider
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalculateMTVForConvexPolygon(cp *resolv.ConvexPolygon, other *resolv.ConvexPolygon) vector.Vector {
|
||||||
|
delta := vector.Vector{0, 0}
|
||||||
|
|
||||||
|
smallest := vector.Vector{math.MaxFloat64, 0}
|
||||||
|
|
||||||
|
for _, axis := range cp.SATAxes() {
|
||||||
|
if !cp.Project(axis).Overlapping(other.Project(axis)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
overlap := cp.Project(axis).Overlap(other.Project(axis))
|
||||||
|
|
||||||
|
if smallest.Magnitude() > overlap {
|
||||||
|
smallest = axis.Scale(overlap)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, axis := range other.SATAxes() {
|
||||||
|
|
||||||
|
if !cp.Project(axis).Overlapping(other.Project(axis)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
overlap := cp.Project(axis).Overlap(other.Project(axis))
|
||||||
|
|
||||||
|
if smallest.Magnitude() > overlap {
|
||||||
|
smallest = axis.Scale(overlap)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
delta[0] = smallest[0]
|
||||||
|
delta[1] = smallest[1]
|
||||||
|
|
||||||
|
return delta
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user