Implement basic pathfinding
This commit is contained in:
49
bot/path/blocks.go
Normal file
49
bot/path/blocks.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
|
"github.com/Tnze/go-mc/data/block"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
safeStepBlocks = make(map[world.BlockStatus]struct{}, 1024)
|
||||||
|
blocks = []block.Block{
|
||||||
|
block.Stone,
|
||||||
|
block.Granite,
|
||||||
|
block.PolishedGranite,
|
||||||
|
block.Diorite,
|
||||||
|
block.PolishedDiorite,
|
||||||
|
block.Andesite,
|
||||||
|
block.PolishedAndesite,
|
||||||
|
block.GrassBlock,
|
||||||
|
block.Dirt,
|
||||||
|
block.CoarseDirt,
|
||||||
|
block.Cobblestone,
|
||||||
|
block.OakPlanks,
|
||||||
|
block.SprucePlanks,
|
||||||
|
block.BirchPlanks,
|
||||||
|
block.JunglePlanks,
|
||||||
|
block.AcaciaPlanks,
|
||||||
|
block.DarkOakPlanks,
|
||||||
|
block.Bedrock,
|
||||||
|
block.GoldOre,
|
||||||
|
block.IronOre,
|
||||||
|
block.CoalOre,
|
||||||
|
block.Glass,
|
||||||
|
block.LapisOre,
|
||||||
|
block.Sandstone,
|
||||||
|
block.RedstoneOre,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, b := range blocks {
|
||||||
|
if b.MinStateID == b.MaxStateID {
|
||||||
|
safeStepBlocks[world.BlockStatus(b.MinStateID)] = struct{}{}
|
||||||
|
} else {
|
||||||
|
for i := b.MinStateID; i <= b.MaxStateID; i++ {
|
||||||
|
safeStepBlocks[world.BlockStatus(i)] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
bot/path/path.go
Normal file
157
bot/path/path.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// Package path implements pathfinding.
|
||||||
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
|
"github.com/Tnze/go-mc/data/block"
|
||||||
|
"github.com/beefsack/go-astar"
|
||||||
|
)
|
||||||
|
|
||||||
|
type V3 struct {
|
||||||
|
X, Y, Z int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v V3) Cost(other V3) float64 {
|
||||||
|
x, y, z := v.X-other.X, v.Y-other.Y, v.Z-other.Z
|
||||||
|
return float64(x*x+z*z) + 1.2*float64(y*y)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nav represents a navigation to a position.
|
||||||
|
type Nav struct {
|
||||||
|
World *world.World
|
||||||
|
Start, Dest V3
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Nav) Path() (path []astar.Pather, distance float64, found bool) {
|
||||||
|
return astar.Path(
|
||||||
|
Tile{ // Start point
|
||||||
|
Nav: n,
|
||||||
|
Movement: Waypoint,
|
||||||
|
Pos: n.Start,
|
||||||
|
},
|
||||||
|
Tile{ // Destination point
|
||||||
|
Nav: n,
|
||||||
|
Movement: Waypoint,
|
||||||
|
Pos: n.Dest,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Movement represents a single type of movement in a path.
|
||||||
|
type Movement uint8
|
||||||
|
|
||||||
|
var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, TraverseWest}
|
||||||
|
|
||||||
|
// Valid movement values.
|
||||||
|
const (
|
||||||
|
Waypoint Movement = iota
|
||||||
|
TraverseNorth
|
||||||
|
TraverseSouth
|
||||||
|
TraverseEast
|
||||||
|
TraverseWest
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tile represents a point in a path. All tiles in a path are adjaceent their
|
||||||
|
// preceeding tiles.
|
||||||
|
type Tile struct {
|
||||||
|
Nav *Nav
|
||||||
|
|
||||||
|
Movement Movement
|
||||||
|
Pos V3
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Tile) PathNeighborCost(to astar.Pather) float64 {
|
||||||
|
other := to.(Tile)
|
||||||
|
return 1 + other.Movement.BaseCost()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Tile) PathEstimatedCost(to astar.Pather) float64 {
|
||||||
|
other := to.(Tile)
|
||||||
|
cost := t.Pos.Cost(other.Pos)
|
||||||
|
return cost + other.Movement.BaseCost()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Tile) PathNeighbors() []astar.Pather {
|
||||||
|
possibles := make([]astar.Pather, 0, 8)
|
||||||
|
|
||||||
|
if t.Pos == t.Nav.Dest && t.Movement != Waypoint {
|
||||||
|
dupe := t
|
||||||
|
dupe.Movement = Waypoint
|
||||||
|
return []astar.Pather{dupe}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range allMovements {
|
||||||
|
x, y, z := m.Offset()
|
||||||
|
pos := V3{X: t.Pos.X + x, Y: t.Pos.Y + y, Z: t.Pos.Z + z}
|
||||||
|
if m.Possible(t.Nav, pos.X, pos.Y, pos.Z) {
|
||||||
|
possibles = append(possibles, Tile{
|
||||||
|
Nav: t.Nav,
|
||||||
|
Movement: m,
|
||||||
|
Pos: pos,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fmt.Printf("%v.Neighbours(): %+v\n", t.Pos, possibles)
|
||||||
|
return possibles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Movement) Possible(nav *Nav, x, y, z int) bool {
|
||||||
|
// fmt.Printf("%s.Possible(%d,%d,%d)\n", m, x, y, z)
|
||||||
|
switch m {
|
||||||
|
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
||||||
|
b := nav.World.GetBlockStatus(x, y, z)
|
||||||
|
if _, safe := safeStepBlocks[b]; !safe {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
above1 := uint32(nav.World.GetBlockStatus(x, y+1, z))
|
||||||
|
above2 := uint32(nav.World.GetBlockStatus(x, y+2, z))
|
||||||
|
return above1 == block.Air.MinStateID && above2 == block.Air.MinStateID
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Movement) Offset() (x, y, z int) {
|
||||||
|
switch m {
|
||||||
|
case Waypoint:
|
||||||
|
return 0, 0, 0
|
||||||
|
case TraverseNorth:
|
||||||
|
return 0, 0, -1
|
||||||
|
case TraverseSouth:
|
||||||
|
return 0, 0, 1
|
||||||
|
case TraverseEast:
|
||||||
|
return 1, 0, 0
|
||||||
|
case TraverseWest:
|
||||||
|
return -1, 0, 0
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Movement) BaseCost() float64 {
|
||||||
|
switch m {
|
||||||
|
case Waypoint:
|
||||||
|
return 0
|
||||||
|
case TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
||||||
|
return 1
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Movement) String() string {
|
||||||
|
switch m {
|
||||||
|
case Waypoint:
|
||||||
|
return "waypoint"
|
||||||
|
case TraverseNorth:
|
||||||
|
return "traverse-north"
|
||||||
|
case TraverseSouth:
|
||||||
|
return "traverse-south"
|
||||||
|
case TraverseEast:
|
||||||
|
return "traverse-east"
|
||||||
|
case TraverseWest:
|
||||||
|
return "traverse-west"
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ const (
|
|||||||
resetVel = 0.003
|
resetVel = 0.003
|
||||||
|
|
||||||
maxYawChange = 33
|
maxYawChange = 33
|
||||||
maxPitchChange = 22
|
maxPitchChange = 11
|
||||||
|
|
||||||
gravity = 0.08
|
gravity = 0.08
|
||||||
drag = 0.98
|
drag = 0.98
|
||||||
@ -91,6 +91,8 @@ func (s *State) surroundings(query AABB, w World) Surrounds {
|
|||||||
func (s *State) applyLookInputs(input Inputs) {
|
func (s *State) applyLookInputs(input Inputs) {
|
||||||
errYaw := math.Min(math.Max(input.Yaw-s.Yaw, -maxYawChange), maxYawChange)
|
errYaw := math.Min(math.Max(input.Yaw-s.Yaw, -maxYawChange), maxYawChange)
|
||||||
s.Yaw += errYaw
|
s.Yaw += errYaw
|
||||||
|
errPitch := math.Min(math.Max(input.Pitch-s.Pitch, -maxPitchChange), maxPitchChange)
|
||||||
|
s.Pitch += errPitch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) applyPosInputs(input Inputs, acceleration, inertia float64) {
|
func (s *State) applyPosInputs(input Inputs, acceleration, inertia float64) {
|
||||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module github.com/Tnze/go-mc
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/beefsack/go-astar v0.0.0-20200827232313-4ecf9e304482
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/iancoleman/strcase v0.1.1 // indirect
|
github.com/iancoleman/strcase v0.1.1 // indirect
|
||||||
)
|
)
|
||||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
github.com/beefsack/go-astar v0.0.0-20200827232313-4ecf9e304482 h1:p4g4uok3+r6Tg6fxXEQUAcMAX/WdK6WhkQW9s0jaT7k=
|
||||||
|
github.com/beefsack/go-astar v0.0.0-20200827232313-4ecf9e304482/go.mod h1:Cu3t5VeqE8kXjUBeNXWQprfuaP5UCIc5ggGjgMx9KFc=
|
||||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/iancoleman/strcase v0.1.1 h1:2I+LRClyCYB7JgZb9U0k75VHUiQe9RfknRqDyUfzp7k=
|
github.com/iancoleman/strcase v0.1.1 h1:2I+LRClyCYB7JgZb9U0k75VHUiQe9RfknRqDyUfzp7k=
|
||||||
|
Reference in New Issue
Block a user