I've been trying to get a swept collision detection up and running now for almost a week and I can't for the life of me get it working. I want to try a moving AABB against a line segment and find out if and when it collides.
There is a answer on this linked here below: https://gamedev.stackexchange.com/questions/29479/swept-aabb-vs-line-segment-2d/30220#30220?newreg=95e000808fe74acdbd7a6b7d1d4b3a05
I've translated this into Go which will be running the game server and needs this logic:
func SweepRectLine(rectX, rectY, rectW, rectH, rectHSpeed, rectVSpeed, lineX1, lineY1, lineX2, lineY2 float64) (bool, float64) {
outVel := [2]float64{}
// hitNormal := [2]float64{}
lineNX, lineNY := lineX2-lineX1, lineY2-lineY1
// lineMinX, lineMaxX, lineMinY, lineMaxY := math.Min(lineX1, lineX2), math.Max(lineX1, lineX2), math.Min(lineY1, lineY2), math.Max(lineY1, lineY2)
var lineMinX, lineMaxX, lineMinY, lineMaxY float64
if lineNX > 0 {
lineMinX, lineMaxX = lineX1, lineX2
} else {
lineMinX, lineMaxX = lineX2, lineX1
}
if lineNY > 0 {
lineMinY, lineMaxY = lineY1, lineY2
} else {
lineMinY, lineMaxY = lineY2, lineY1
}
r := (rectW/2)*math.Abs(lineNX) + (rectH/2)*math.Abs(lineNY) //radius to Line
boxProj := (lineX1-rectX)*lineNX + (lineY1-rectY)*lineNY
velProj := rectHSpeed*lineNX + rectVSpeed*lineNY
if velProj < 0 {
r *= -1
}
hitTime := math.Max((boxProj-r)/velProj, 0)
outTime := math.Min((boxProj+r)/velProj, 1)
// log.Println("start", hitTime, outTime)
rectXMax, rectXMin := rectX+rectW/2, rectX-rectW/2
if rectHSpeed < 0 { // left
if rectXMax < lineMinX {
return false, 0
}
hitTime = math.Max((lineMaxX-rectXMin)/rectHSpeed, hitTime)
outTime = math.Min((lineMinX-rectXMax)/rectHSpeed, outTime)
} else if rectHSpeed > 0 { // right
if rectXMin > lineMaxX {
return false, 0
}
hitTime = math.Max((lineMinX-rectXMax)/rectHSpeed, hitTime)
outTime = math.Min((lineMaxX-rectXMin)/rectHSpeed, outTime)
// log.Println("right", hitTime, outTime)
} else {
if lineMinX > rectXMax || lineMaxX < rectXMin {
return false, 0
}
}
if hitTime > outTime {
return false, 0
}
rectYMax, rectYMin := rectY+rectH/2, rectY-rectH/2
if rectVSpeed < 0 { // up
if rectYMax < lineMinY {
return false, 0
}
hitTime = math.Max((lineMaxY-rectYMin)/rectVSpeed, hitTime)
outTime = math.Min((lineMinY-rectYMax)/rectVSpeed, outTime)
} else if rectVSpeed > 0 { // down
if rectYMin > lineMaxY {
return false, 0
}
hitTime = math.Max((lineMinY-rectYMax)/rectVSpeed, hitTime)
outTime = math.Min((lineMaxY-rectYMin)/rectVSpeed, outTime)
} else {
if lineMinY > rectYMax || lineMaxY < rectYMin {
return false, 0
}
}
if hitTime > outTime {
return false, 0
}
outVel[0] = rectHSpeed * hitTime
outVel[1] = rectVSpeed * hitTime
return true, hitTime
}
I also put up a Gist with a executable UI here: https://gist.github.com/KidLinus/3f847c46b0e6dc1addac7252d9cb54ab
I can't for the life of me figure out what all class variables stand for. I think that some of them are native to Unity but that's just a guess. I've come so far as to figure out that the extent is half of the width/height in said direction. What the "line.n" stands for is anyones guess, I assume its the direction and have no idea if it's normalized or not. There are also a couple of dead variables just laying there.
I'd love some help in finishing an implementation in Go for this.