Skip to content

Instantly share code, notes, and snippets.

@KidLinus

KidLinus/main.go Secret

Created May 4, 2021 07:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KidLinus/3f847c46b0e6dc1addac7252d9cb54ab to your computer and use it in GitHub Desktop.
Save KidLinus/3f847c46b0e6dc1addac7252d9cb54ab to your computer and use it in GitHub Desktop.
non-working aabb/line sweep
package main
import (
"image/color"
"log"
"math"
"sort"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
type Game struct {
lines [][4]float64
}
func (g *Game) Update() error {
return nil
}
func (g *Game) boxCollideSweep(x, y, w, h, dx, dy float64) (bool, float64) {
offsets := []float64{}
// log.Println(x, y, w, h, dx, dy)
for _, l := range g.lines {
coll, offset := SweepRectLine2(x, y, w, h, dx, dy, l[2], l[3], l[0], l[1])
if coll {
offsets = append(offsets, offset)
}
}
if len(offsets) == 0 {
return false, 0
}
sort.Float64s(offsets)
return true, offsets[0]
}
func (g *Game) Draw(screen *ebiten.Image) {
screen.Fill(color.RGBA{R: 255, G: 255, B: 255, A: 255})
for _, l := range g.lines {
ebitenutil.DrawLine(screen, l[0], l[1], l[2], l[3], color.RGBA{A: 255})
}
mx, my := ebiten.CursorPosition()
coll, offset := g.boxCollideSweep(400, 300, 10, 40, float64(mx)-400, float64(my)-300)
col := color.RGBA{G: 255, A: 255}
if coll {
col.G, col.R, col.B = 0, 255, uint8(offset)
}
ebitenutil.DrawRect(screen, 400-5, 300-20, 10, 40, color.RGBA{B: 255, A: 100})
ebitenutil.DrawLine(screen, 400, 300, float64(mx), float64(my), color.RGBA{B: 255, A: 100})
ebitenutil.DrawRect(screen, float64(mx)-5, float64(my)-20, 10, 40, col)
if offset > 0 {
// log.Println(offset)
ebitenutil.DrawRect(screen, 400-5+(float64(mx)-400)*offset, 300-20+(float64(my)-300)*offset, 10, 40, color.RGBA{B: 255, A: 100})
}
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
return outsideWidth, outsideHeight
}
func main() {
log.Println("start")
game := &Game{
lines: [][4]float64{
{10, 590, 790, 590},
{10, 590, 10, 300},
{790, 590, 790, 300},
{300, 400, 380, 400},
{300, 400, 200, 370},
{500, 300, 600, 370},
},
}
// Specify the window size as you like. Here, a doubled size is specified.
ebiten.SetWindowSize(800, 600)
ebiten.SetWindowTitle("Platformer")
// Call ebiten.RunGame to start your game loop.
if err := ebiten.RunGame(game); err != nil {
log.Fatal(err)
}
}
func SweepRectLine2(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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment