Implement ladders

This commit is contained in:
Tom
2020-09-23 21:17:37 -07:00
parent 565b241f0e
commit 797ba13fdd
3 changed files with 130 additions and 22 deletions

View File

@ -1,5 +1,55 @@
package path
import (
"fmt"
"github.com/Tnze/go-mc/bot/world"
"github.com/Tnze/go-mc/data/block"
)
// Cardinal directions.
type Direction uint8
func (d Direction) Offset() (x, y, z int) {
switch d {
case North:
return 0, 0, -1
case South:
return 0, 0, 1
case East:
return 1, 0, 0
case West:
return -1, 0, 0
}
panic(fmt.Sprintf("unknown direction value: %v", d))
}
func (d Direction) String() string {
switch d {
case North:
return "north"
case South:
return "south"
case East:
return "east"
case West:
return "west"
}
return fmt.Sprintf("Direction?<%d>", int(d))
}
// Valid direction values.
const (
North Direction = iota
South
West
East
)
func LadderDirection(bStateID world.BlockStatus) Direction {
return Direction(((uint32(bStateID) - block.Ladder.MinStateID) & 0xE) >> 1)
}
// Movement represents a single type of movement in a path.
type Movement uint8
@ -7,6 +57,7 @@ var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, Traver
TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast,
DropNorth, DropSouth, DropEast, DropWest,
AscendNorth, AscendSouth, AscendEast, AscendWest,
DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest,
}
// Valid movement values.
@ -28,16 +79,23 @@ const (
AscendSouth
AscendEast
AscendWest
DescendLadder
DescendLadderNorth
DescendLadderSouth
DescendLadderEast
DescendLadderWest
)
func (m Movement) Possible(nav *Nav, x, y, z int, from V3) bool {
func (m Movement) Possible(nav *Nav, x, y, z int, from V3, previous Movement) bool {
// fmt.Printf("%s.Possible(%d,%d,%d)\n", m, x, y, z)
switch m {
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
return false
}
return AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) && AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z))
b1, b2 := nav.World.GetBlockStatus(x, y+1, z), nav.World.GetBlockStatus(x, y+2, z)
u1, u2 := AirLikeBlock(b1) || IsLadder(b1), AirLikeBlock(b2) || IsLadder(b2)
return u1 && u2
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
@ -67,6 +125,24 @@ func (m Movement) Possible(nav *Nav, x, y, z int, from V3) bool {
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+1, from.Z)) &&
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+2, from.Z))
case DescendLadder:
if bID := nav.World.GetBlockStatus(x, y+1, z); !AirLikeBlock(bID) && !IsLadder(bID) {
return false
}
bID := nav.World.GetBlockStatus(x, y, z)
fmt.Println(bID, IsLadder(bID))
return IsLadder(nav.World.GetBlockStatus(x, y, z))
case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest:
for amt := 0; amt < 2; amt++ {
if bID := nav.World.GetBlockStatus(x, y+amt+1, z); !AirLikeBlock(bID) && !IsLadder(bID) {
return false
}
}
bID := nav.World.GetBlockStatus(x, y, z)
fmt.Println(bID, IsLadder(bID))
return IsLadder(nav.World.GetBlockStatus(x, y, z))
default:
panic(m)
}
@ -77,21 +153,23 @@ func (m Movement) Offset() (x, y, z int) {
case Waypoint:
return 0, 0, 0
case TraverseNorth:
return 0, 0, -1
return North.Offset()
case TraverseSouth:
return 0, 0, 1
return South.Offset()
case TraverseEast:
return 1, 0, 0
return East.Offset()
case TraverseWest:
return -1, 0, 0
return West.Offset()
case DropNorth:
case DescendLadder:
return 0, -1, 0
case DropNorth, DescendLadderNorth:
return 0, -1, -1
case DropSouth:
case DropSouth, DescendLadderSouth:
return 0, -1, 1
case DropEast:
case DropEast, DescendLadderEast:
return 1, -1, 0
case DropWest:
case DropWest, DescendLadderWest:
return -1, -1, 0
case AscendNorth:
return 0, 1, -1
@ -129,6 +207,10 @@ func (m Movement) BaseCost() float64 {
return 2
case AscendNorth, AscendSouth, AscendEast, AscendWest:
return 2.25
case DescendLadderNorth, DescendLadderSouth, DescendLadderEast, DescendLadderWest:
return 1.5
case DescendLadder:
return 1.2
default:
panic(m)
}
@ -173,6 +255,17 @@ func (m Movement) String() string {
return "traverse-southwest"
case TraverseSouthEast:
return "traverse-southeast"
case DescendLadder:
return "descend-ladder"
case DescendLadderNorth:
return "descend-ladder-north"
case DescendLadderSouth:
return "descend-ladder-south"
case DescendLadderEast:
return "descend-ladder-east"
case DescendLadderWest:
return "descend-ladder-west"
default:
panic(m)
}

View File

@ -80,7 +80,9 @@ func (t Tile) PathNeighbors() []astar.Pather {
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, t.Pos) {
possible := m.Possible(t.Nav, pos.X, pos.Y, pos.Z, t.Pos, t.Movement)
// fmt.Printf("%v-%v: Trying (%v) %v: possible=%v\n", t.Movement, t.Pos, pos, m, possible)
if possible {
possibles = append(possibles, Tile{
Nav: t.Nav,
Movement: m,
@ -114,3 +116,12 @@ func (t Tile) Inputs(deltaPos, vel Point) Inputs {
}
return out
}
func (t Tile) IsComplete(d Point) bool {
switch t.Movement {
case DescendLadder, DescendLadderNorth, DescendLadderSouth, DescendLadderWest, DescendLadderEast, DropNorth, DropSouth, DropEast, DropWest:
return (d.X*d.X+d.Z*d.Z) < (0.1*0.1*0.13) && d.Y <= 0.05
}
return (d.X*d.X+d.Z*d.Z) < (0.18*0.18) && d.Y >= -0.01 && d.Y <= 0.08
}

View File

@ -23,6 +23,7 @@ const (
stepHeight = 0.6
minJumpTicks = 14
ladderMaxSpeed = 0.15
ladderClimbSpeed = 0.2
gravity = 0.08
drag = 0.98
@ -152,6 +153,10 @@ func (s *State) Tick(input path.Inputs, w World) error {
s.collision.vertical = newVel.Y != s.Vel.Y
s.onGround = s.collision.vertical && s.Vel.Y < 0
if path.IsLadder(w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))) && s.collision.horizontal {
newVel.Y = ladderClimbSpeed
}
s.Vel = newVel
return nil
}
@ -205,20 +210,19 @@ func (s *State) tickVelocity(input path.Inputs, w World) {
s.applyLookInputs(input)
s.applyPosInputs(input, acceleration, inertia)
lower := w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))
if path.IsLadder(lower) {
s.Vel.X = math.Min(math.Max(-ladderMaxSpeed, s.Vel.X), ladderMaxSpeed)
s.Vel.Z = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Z), ladderMaxSpeed)
s.Vel.Y = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Y), ladderMaxSpeed)
}
// Gravity
s.Vel.Y -= gravity
// Drag & friction.
s.Vel.Y *= drag
s.Vel.X *= inertia
s.Vel.Z *= inertia
lower := w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y)), int(math.Floor(s.Pos.Z)))
if path.IsLadder(lower) {
s.Vel.X = math.Min(math.Max(-ladderMaxSpeed, s.Vel.X), ladderMaxSpeed)
s.Vel.Z = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Z), ladderMaxSpeed)
s.Vel.Y = math.Min(math.Max(-ladderMaxSpeed, s.Vel.Y), ladderMaxSpeed)
fmt.Println(s.Vel)
}
}
func (s *State) computeCollision(bb, query AABB, w World) (outBB AABB, outVel path.Point) {