WIP getting jumping to work
This commit is contained in:
@ -4,6 +4,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Tnze/go-mc/bot/path"
|
||||||
"github.com/Tnze/go-mc/bot/phy"
|
"github.com/Tnze/go-mc/bot/phy"
|
||||||
"github.com/Tnze/go-mc/bot/world"
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
"github.com/Tnze/go-mc/bot/world/entity"
|
"github.com/Tnze/go-mc/bot/world/entity"
|
||||||
@ -24,7 +25,7 @@ type Client struct {
|
|||||||
settings Settings
|
settings Settings
|
||||||
|
|
||||||
Wd world.World //the map data
|
Wd world.World //the map data
|
||||||
Inputs phy.Inputs
|
Inputs path.Inputs
|
||||||
Physics phy.State
|
Physics phy.State
|
||||||
lastPosTx time.Time
|
lastPosTx time.Time
|
||||||
justTeleported bool
|
justTeleported bool
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
safeStepBlocks = make(map[world.BlockStatus]struct{}, 1024)
|
safeStepBlocks = make(map[world.BlockStatus]struct{}, 1024)
|
||||||
blocks = []block.Block{
|
stepBlocks = []block.Block{
|
||||||
block.Stone,
|
block.Stone,
|
||||||
block.Granite,
|
block.Granite,
|
||||||
block.PolishedGranite,
|
block.PolishedGranite,
|
||||||
@ -34,10 +34,35 @@ var (
|
|||||||
block.Sandstone,
|
block.Sandstone,
|
||||||
block.RedstoneOre,
|
block.RedstoneOre,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
safeWalkBlocks = make(map[world.BlockStatus]struct{}, 128)
|
||||||
|
walkBlocks = []block.Block{
|
||||||
|
block.Air,
|
||||||
|
block.Grass,
|
||||||
|
block.Torch,
|
||||||
|
block.OakSign,
|
||||||
|
block.SpruceSign,
|
||||||
|
block.BirchSign,
|
||||||
|
block.AcaciaSign,
|
||||||
|
block.JungleSign,
|
||||||
|
block.DarkOakSign,
|
||||||
|
block.OakWallSign,
|
||||||
|
block.SpruceWallSign,
|
||||||
|
block.BirchWallSign,
|
||||||
|
block.AcaciaWallSign,
|
||||||
|
block.JungleWallSign,
|
||||||
|
block.DarkOakWallSign,
|
||||||
|
block.Cornflower,
|
||||||
|
}
|
||||||
|
|
||||||
|
additionalCostBlocks = map[*block.Block]int{
|
||||||
|
&block.Rail: 120,
|
||||||
|
&block.PoweredRail: 200,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, b := range blocks {
|
for _, b := range stepBlocks {
|
||||||
if b.MinStateID == b.MaxStateID {
|
if b.MinStateID == b.MaxStateID {
|
||||||
safeStepBlocks[world.BlockStatus(b.MinStateID)] = struct{}{}
|
safeStepBlocks[world.BlockStatus(b.MinStateID)] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
@ -46,4 +71,24 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, b := range walkBlocks {
|
||||||
|
if b.MinStateID == b.MaxStateID {
|
||||||
|
safeWalkBlocks[world.BlockStatus(b.MinStateID)] = struct{}{}
|
||||||
|
} else {
|
||||||
|
for i := b.MinStateID; i <= b.MaxStateID; i++ {
|
||||||
|
safeWalkBlocks[world.BlockStatus(i)] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SteppableBlock(bID world.BlockStatus) bool {
|
||||||
|
_, ok := safeStepBlocks[bID]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func AirLikeBlock(bID world.BlockStatus) bool {
|
||||||
|
_, ok := safeWalkBlocks[bID]
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package phy
|
package path
|
||||||
|
|
||||||
// Inputs describes the desired movements of the player.
|
// Inputs describes the desired movements of the player.
|
||||||
type Inputs struct {
|
type Inputs struct {
|
||||||
Yaw, Pitch float64
|
Yaw, Pitch float64
|
||||||
|
|
||||||
ThrottleX, ThrottleZ float64
|
ThrottleX, ThrottleZ float64
|
||||||
|
|
||||||
|
Jump bool
|
||||||
}
|
}
|
179
bot/path/movement.go
Normal file
179
bot/path/movement.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package path
|
||||||
|
|
||||||
|
// Movement represents a single type of movement in a path.
|
||||||
|
type Movement uint8
|
||||||
|
|
||||||
|
var allMovements = []Movement{TraverseNorth, TraverseSouth, TraverseEast, TraverseWest,
|
||||||
|
TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast,
|
||||||
|
DropNorth, DropSouth, DropEast, DropWest,
|
||||||
|
AscendNorth, AscendSouth, AscendEast, AscendWest,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid movement values.
|
||||||
|
const (
|
||||||
|
Waypoint Movement = iota
|
||||||
|
TraverseNorth
|
||||||
|
TraverseSouth
|
||||||
|
TraverseEast
|
||||||
|
TraverseWest
|
||||||
|
TraverseNorthEast
|
||||||
|
TraverseNorthWest
|
||||||
|
TraverseSouthEast
|
||||||
|
TraverseSouthWest
|
||||||
|
DropNorth
|
||||||
|
DropSouth
|
||||||
|
DropEast
|
||||||
|
DropWest
|
||||||
|
AscendNorth
|
||||||
|
AscendSouth
|
||||||
|
AscendEast
|
||||||
|
AscendWest
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m Movement) Possible(nav *Nav, x, y, z int, from V3) 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))
|
||||||
|
|
||||||
|
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
|
||||||
|
if !SteppableBlock(nav.World.GetBlockStatus(x, y, z)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !AirLikeBlock(nav.World.GetBlockStatus(from.X, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(from.X, y+2, z)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return AirLikeBlock(nav.World.GetBlockStatus(x, y+1, from.Z)) && AirLikeBlock(nav.World.GetBlockStatus(x, y+2, from.Z))
|
||||||
|
|
||||||
|
case DropNorth, DropSouth, DropEast, DropWest:
|
||||||
|
for amt := 0; amt < 3; amt++ {
|
||||||
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+amt+1, z)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SteppableBlock(nav.World.GetBlockStatus(x, y, z))
|
||||||
|
|
||||||
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
||||||
|
if !AirLikeBlock(nav.World.GetBlockStatus(x, y+1, z)) || !AirLikeBlock(nav.World.GetBlockStatus(x, y+2, z)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return SteppableBlock(nav.World.GetBlockStatus(x, y, z)) &&
|
||||||
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+1, from.Z)) &&
|
||||||
|
AirLikeBlock(nav.World.GetBlockStatus(from.X, from.Y+2, from.Z))
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
case DropNorth:
|
||||||
|
return 0, -1, -1
|
||||||
|
case DropSouth:
|
||||||
|
return 0, -1, 1
|
||||||
|
case DropEast:
|
||||||
|
return 1, -1, 0
|
||||||
|
case DropWest:
|
||||||
|
return -1, -1, 0
|
||||||
|
case AscendNorth:
|
||||||
|
return 0, 1, -1
|
||||||
|
case AscendSouth:
|
||||||
|
return 0, 1, 1
|
||||||
|
case AscendEast:
|
||||||
|
return 1, 1, 0
|
||||||
|
case AscendWest:
|
||||||
|
return -1, 1, 0
|
||||||
|
|
||||||
|
case TraverseNorthWest:
|
||||||
|
return -1, 0, -1
|
||||||
|
case TraverseNorthEast:
|
||||||
|
return 1, 0, -1
|
||||||
|
case TraverseSouthWest:
|
||||||
|
return -1, 0, 1
|
||||||
|
case TraverseSouthEast:
|
||||||
|
return 1, 0, 1
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Movement) BaseCost() float64 {
|
||||||
|
switch m {
|
||||||
|
case Waypoint:
|
||||||
|
return 0
|
||||||
|
case TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
||||||
|
return 1
|
||||||
|
case TraverseNorthWest, TraverseNorthEast, TraverseSouthWest, TraverseSouthEast:
|
||||||
|
return 1.5
|
||||||
|
|
||||||
|
case DropNorth, DropSouth, DropEast, DropWest:
|
||||||
|
return 2
|
||||||
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
||||||
|
return 2.25
|
||||||
|
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"
|
||||||
|
|
||||||
|
case DropNorth:
|
||||||
|
return "drop-north"
|
||||||
|
case DropSouth:
|
||||||
|
return "drop-south"
|
||||||
|
case DropEast:
|
||||||
|
return "drop-east"
|
||||||
|
case DropWest:
|
||||||
|
return "drop-west"
|
||||||
|
|
||||||
|
case AscendNorth:
|
||||||
|
return "jump-north"
|
||||||
|
case AscendSouth:
|
||||||
|
return "jump-south"
|
||||||
|
case AscendEast:
|
||||||
|
return "jump-east"
|
||||||
|
case AscendWest:
|
||||||
|
return "jump-west"
|
||||||
|
|
||||||
|
case TraverseNorthWest:
|
||||||
|
return "traverse-northwest"
|
||||||
|
case TraverseNorthEast:
|
||||||
|
return "traverse-northeast"
|
||||||
|
case TraverseSouthWest:
|
||||||
|
return "traverse-southwest"
|
||||||
|
case TraverseSouthEast:
|
||||||
|
return "traverse-southeast"
|
||||||
|
default:
|
||||||
|
panic(m)
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
package path
|
package path
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
"github.com/Tnze/go-mc/bot/world"
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
"github.com/Tnze/go-mc/data/block"
|
|
||||||
"github.com/beefsack/go-astar"
|
"github.com/beefsack/go-astar"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,27 +37,14 @@ func (n *Nav) Path() (path []astar.Pather, distance float64, found bool) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Tile represents a point in a path. All tiles in a path are adjaceent their
|
||||||
// preceeding tiles.
|
// preceeding tiles.
|
||||||
type Tile struct {
|
type Tile struct {
|
||||||
Nav *Nav
|
Nav *Nav
|
||||||
|
|
||||||
Movement Movement
|
Movement Movement
|
||||||
Pos V3
|
Pos V3
|
||||||
|
ExtraCost int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tile) PathNeighborCost(to astar.Pather) float64 {
|
func (t Tile) PathNeighborCost(to astar.Pather) float64 {
|
||||||
@ -67,12 +55,17 @@ func (t Tile) PathNeighborCost(to astar.Pather) float64 {
|
|||||||
func (t Tile) PathEstimatedCost(to astar.Pather) float64 {
|
func (t Tile) PathEstimatedCost(to astar.Pather) float64 {
|
||||||
other := to.(Tile)
|
other := to.(Tile)
|
||||||
cost := t.Pos.Cost(other.Pos)
|
cost := t.Pos.Cost(other.Pos)
|
||||||
|
|
||||||
return cost + other.Movement.BaseCost()
|
return cost + other.Movement.BaseCost()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tile) PathNeighbors() []astar.Pather {
|
func (t Tile) PathNeighbors() []astar.Pather {
|
||||||
possibles := make([]astar.Pather, 0, 8)
|
possibles := make([]astar.Pather, 0, 8)
|
||||||
|
|
||||||
|
if t.PathEstimatedCost(Tile{Pos: t.Nav.Start}) > 1200 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if t.Pos == t.Nav.Dest && t.Movement != Waypoint {
|
if t.Pos == t.Nav.Dest && t.Movement != Waypoint {
|
||||||
dupe := t
|
dupe := t
|
||||||
dupe.Movement = Waypoint
|
dupe.Movement = Waypoint
|
||||||
@ -82,7 +75,7 @@ func (t Tile) PathNeighbors() []astar.Pather {
|
|||||||
for _, m := range allMovements {
|
for _, m := range allMovements {
|
||||||
x, y, z := m.Offset()
|
x, y, z := m.Offset()
|
||||||
pos := V3{X: t.Pos.X + x, Y: t.Pos.Y + y, Z: t.Pos.Z + z}
|
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) {
|
if m.Possible(t.Nav, pos.X, pos.Y, pos.Z, t.Pos) {
|
||||||
possibles = append(possibles, Tile{
|
possibles = append(possibles, Tile{
|
||||||
Nav: t.Nav,
|
Nav: t.Nav,
|
||||||
Movement: m,
|
Movement: m,
|
||||||
@ -95,63 +88,18 @@ func (t Tile) PathNeighbors() []astar.Pather {
|
|||||||
return possibles
|
return possibles
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Movement) Possible(nav *Nav, x, y, z int) bool {
|
func (t Tile) Inputs(dX, dY, dZ float64) Inputs {
|
||||||
// fmt.Printf("%s.Possible(%d,%d,%d)\n", m, x, y, z)
|
// Sufficient for simple movements.
|
||||||
switch m {
|
at := math.Atan2(-dX, -dZ)
|
||||||
case Waypoint, TraverseNorth, TraverseSouth, TraverseEast, TraverseWest:
|
out := Inputs{
|
||||||
b := nav.World.GetBlockStatus(x, y, z)
|
ThrottleX: math.Sin(at),
|
||||||
if _, safe := safeStepBlocks[b]; !safe {
|
ThrottleZ: math.Cos(at),
|
||||||
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 t.Movement {
|
||||||
switch m {
|
case AscendNorth, AscendSouth, AscendEast, AscendWest:
|
||||||
case Waypoint:
|
out.Jump = math.Sqrt(dX*dX+dZ*dZ) < 1.75
|
||||||
return 0, 0, 0
|
out.Yaw = 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)
|
|
||||||
}
|
}
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
204
bot/phy/phy.go
204
bot/phy/phy.go
@ -5,6 +5,7 @@ package phy
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/Tnze/go-mc/bot/path"
|
||||||
"github.com/Tnze/go-mc/bot/world"
|
"github.com/Tnze/go-mc/bot/world"
|
||||||
"github.com/Tnze/go-mc/bot/world/entity/player"
|
"github.com/Tnze/go-mc/bot/world/entity/player"
|
||||||
)
|
)
|
||||||
@ -17,6 +18,9 @@ const (
|
|||||||
maxYawChange = 33
|
maxYawChange = 33
|
||||||
maxPitchChange = 11
|
maxPitchChange = 11
|
||||||
|
|
||||||
|
stepHeight = 0.6
|
||||||
|
minJumpTicks = 14
|
||||||
|
|
||||||
gravity = 0.08
|
gravity = 0.08
|
||||||
drag = 0.98
|
drag = 0.98
|
||||||
acceleration = 0.02
|
acceleration = 0.02
|
||||||
@ -43,6 +47,7 @@ type State struct {
|
|||||||
Pos Point
|
Pos Point
|
||||||
Vel Point
|
Vel Point
|
||||||
Yaw, Pitch float64
|
Yaw, Pitch float64
|
||||||
|
lastJump uint32
|
||||||
|
|
||||||
// player state flags.
|
// player state flags.
|
||||||
onGround bool
|
onGround bool
|
||||||
@ -51,7 +56,8 @@ type State struct {
|
|||||||
horizontal bool
|
horizontal bool
|
||||||
}
|
}
|
||||||
|
|
||||||
Run bool
|
tick uint32
|
||||||
|
Run bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) ServerPositionUpdate(player player.Pos, w World) error {
|
func (s *State) ServerPositionUpdate(player player.Pos, w World) error {
|
||||||
@ -79,7 +85,7 @@ func (s *State) surroundings(query AABB, w World) Surrounds {
|
|||||||
for y := minY; y < maxY; y++ {
|
for y := minY; y < maxY; y++ {
|
||||||
for z := minZ; z < maxZ; z++ {
|
for z := minZ; z < maxZ; z++ {
|
||||||
for x := minX; x < maxX; x++ {
|
for x := minX; x < maxX; x++ {
|
||||||
if block := w.GetBlockStatus(x, y, z); block > 0 {
|
if block := w.GetBlockStatus(x, y, z); !path.AirLikeBlock(block) {
|
||||||
out = append(out, AABB{X: MinMax{Max: 1}, Y: MinMax{Max: 1}, Z: MinMax{Max: 1}, Block: block}.Offset(float64(x), float64(y), float64(z)))
|
out = append(out, AABB{X: MinMax{Max: 1}, Y: MinMax{Max: 1}, Z: MinMax{Max: 1}, Block: block}.Offset(float64(x), float64(y), float64(z)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,89 +94,6 @@ func (s *State) surroundings(query AABB, w World) Surrounds {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) applyLookInputs(input Inputs) {
|
|
||||||
errYaw := math.Min(math.Max(input.Yaw-s.Yaw, -maxYawChange), maxYawChange)
|
|
||||||
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) {
|
|
||||||
speed := math.Sqrt(input.ThrottleX*input.ThrottleX + input.ThrottleZ*input.ThrottleZ)
|
|
||||||
if speed < 0.01 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
speed = acceleration / math.Max(speed, 1)
|
|
||||||
|
|
||||||
input.ThrottleX *= speed
|
|
||||||
input.ThrottleZ *= speed
|
|
||||||
|
|
||||||
s.Vel.X += input.ThrottleX
|
|
||||||
s.Vel.Z += input.ThrottleZ
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) Tick(input Inputs, w World) error {
|
|
||||||
if !s.Run {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var inertia = inertia
|
|
||||||
var acceleration = acceleration
|
|
||||||
if s.onGround {
|
|
||||||
inertia *= slipperiness
|
|
||||||
acceleration = 0.1 * (0.1627714 / (inertia * inertia * inertia))
|
|
||||||
}
|
|
||||||
s.applyLookInputs(input)
|
|
||||||
s.applyPosInputs(input, acceleration, inertia)
|
|
||||||
|
|
||||||
// Deadzone velocities when they get too low.
|
|
||||||
if math.Abs(s.Vel.X) < resetVel {
|
|
||||||
s.Vel.X = 0
|
|
||||||
}
|
|
||||||
if math.Abs(s.Vel.Y) < resetVel {
|
|
||||||
s.Vel.Y = 0
|
|
||||||
}
|
|
||||||
if math.Abs(s.Vel.Z) < resetVel {
|
|
||||||
s.Vel.Z = 0
|
|
||||||
}
|
|
||||||
// Gravity
|
|
||||||
s.Vel.Y -= gravity
|
|
||||||
// Drag & friction.
|
|
||||||
s.Vel.Y *= drag
|
|
||||||
s.Vel.X *= inertia
|
|
||||||
s.Vel.Z *= inertia
|
|
||||||
|
|
||||||
// Apply collision.
|
|
||||||
var (
|
|
||||||
player = s.BB()
|
|
||||||
query = player.Extend(s.Vel.X, s.Vel.Y, s.Vel.Z)
|
|
||||||
surroundings = s.surroundings(query, w)
|
|
||||||
newVel = s.Vel
|
|
||||||
)
|
|
||||||
for _, b := range surroundings {
|
|
||||||
newVel.Y = b.YOffset(player, newVel.Y)
|
|
||||||
}
|
|
||||||
player = player.Offset(0, newVel.Y, 0)
|
|
||||||
for _, b := range surroundings {
|
|
||||||
newVel.X = b.XOffset(player, newVel.X)
|
|
||||||
}
|
|
||||||
player = player.Offset(newVel.X, 0, 0)
|
|
||||||
for _, b := range surroundings {
|
|
||||||
newVel.Z = b.ZOffset(player, newVel.Z)
|
|
||||||
}
|
|
||||||
player = player.Offset(0, 0, newVel.Z)
|
|
||||||
|
|
||||||
// Update flags.
|
|
||||||
s.Pos.X = player.X.Min + playerWidth/2
|
|
||||||
s.Pos.Y = player.Y.Min
|
|
||||||
s.Pos.Z = player.Z.Min + playerWidth/2
|
|
||||||
s.collision.horizontal = newVel.X != s.Vel.X || newVel.Z != s.Vel.Z
|
|
||||||
s.collision.vertical = newVel.Y != s.Vel.Y
|
|
||||||
s.onGround = s.collision.vertical && s.Vel.Y < 0
|
|
||||||
|
|
||||||
s.Vel = newVel
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) BB() AABB {
|
func (s *State) BB() AABB {
|
||||||
return AABB{
|
return AABB{
|
||||||
X: MinMax{Min: -playerWidth / 2, Max: playerWidth / 2},
|
X: MinMax{Min: -playerWidth / 2, Max: playerWidth / 2},
|
||||||
@ -186,3 +109,114 @@ func (s *State) Position() player.Pos {
|
|||||||
OnGround: s.onGround,
|
OnGround: s.onGround,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) Tick(input path.Inputs, w World) error {
|
||||||
|
s.tick++
|
||||||
|
if !s.Run {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.tickVelocity(input, w)
|
||||||
|
|
||||||
|
player, newVel := s.computeCollision(s.BB(), s.BB().Extend(s.Vel.X, s.Vel.Y, s.Vel.Z), w)
|
||||||
|
|
||||||
|
bb := player.Extend(s.Vel.X, stepHeight, s.Vel.Z)
|
||||||
|
surroundings := s.surroundings(bb, w)
|
||||||
|
y := float64(0)
|
||||||
|
for _, b := range surroundings {
|
||||||
|
if b.Intersects(bb) && bb.Y.Max > b.Y.Min {
|
||||||
|
y = math.Max(y, b.Y.Max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fmt.Printf("pY = %.2f, maxblockY = %.1f (delta = %.1f)\n", bb.Y.Min, y, bb.Y.Min-y)
|
||||||
|
if d := bb.Y.Min - y; d >= -stepHeight && d < stepHeight-1 {
|
||||||
|
bb := player.Offset(0, stepHeight, 0)
|
||||||
|
player, newVel = s.computeCollision(bb, bb.Extend(s.Vel.X, s.Vel.Y, s.Vel.Z), w)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update flags.
|
||||||
|
s.Pos.X = player.X.Min + playerWidth/2
|
||||||
|
s.Pos.Y = player.Y.Min
|
||||||
|
s.Pos.Z = player.Z.Min + playerWidth/2
|
||||||
|
s.collision.horizontal = newVel.X != s.Vel.X || newVel.Z != s.Vel.Z
|
||||||
|
s.collision.vertical = newVel.Y != s.Vel.Y
|
||||||
|
s.onGround = s.collision.vertical && s.Vel.Y < 0
|
||||||
|
|
||||||
|
s.Vel = newVel
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) applyLookInputs(input path.Inputs) {
|
||||||
|
errYaw := math.Min(math.Max(input.Yaw-s.Yaw, -maxYawChange), maxYawChange)
|
||||||
|
s.Yaw += errYaw
|
||||||
|
errPitch := math.Min(math.Max(input.Pitch-s.Pitch, -maxPitchChange), maxPitchChange)
|
||||||
|
s.Pitch += errPitch
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) applyPosInputs(input path.Inputs, acceleration, inertia float64) {
|
||||||
|
// fmt.Println(input.Jump, s.lastJump, s.onGround)
|
||||||
|
if input.Jump && s.lastJump+minJumpTicks < s.tick {
|
||||||
|
s.lastJump = s.tick
|
||||||
|
s.Vel.Y += 0.42
|
||||||
|
}
|
||||||
|
|
||||||
|
speed := math.Sqrt(input.ThrottleX*input.ThrottleX + input.ThrottleZ*input.ThrottleZ)
|
||||||
|
if speed < 0.01 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
speed = acceleration / math.Max(speed, 1)
|
||||||
|
|
||||||
|
input.ThrottleX *= speed
|
||||||
|
input.ThrottleZ *= speed
|
||||||
|
|
||||||
|
s.Vel.X += input.ThrottleX
|
||||||
|
s.Vel.Z += input.ThrottleZ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) tickVelocity(input path.Inputs, w World) {
|
||||||
|
var inertia = inertia
|
||||||
|
var acceleration = acceleration
|
||||||
|
if below := w.GetBlockStatus(int(math.Floor(s.Pos.X)), int(math.Floor(s.Pos.Y))-1, int(math.Floor(s.Pos.Z))); s.onGround && !path.AirLikeBlock(below) {
|
||||||
|
inertia *= slipperiness
|
||||||
|
acceleration = 0.1 * (0.1627714 / (inertia * inertia * inertia))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deadzone velocities when they get too low.
|
||||||
|
if math.Abs(s.Vel.X) < resetVel {
|
||||||
|
s.Vel.X = 0
|
||||||
|
}
|
||||||
|
if math.Abs(s.Vel.Y) < resetVel {
|
||||||
|
s.Vel.Y = 0
|
||||||
|
}
|
||||||
|
if math.Abs(s.Vel.Z) < resetVel {
|
||||||
|
s.Vel.Z = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
s.applyLookInputs(input)
|
||||||
|
s.applyPosInputs(input, acceleration, inertia)
|
||||||
|
|
||||||
|
// Gravity
|
||||||
|
s.Vel.Y -= gravity
|
||||||
|
// Drag & friction.
|
||||||
|
s.Vel.Y *= drag
|
||||||
|
s.Vel.X *= inertia
|
||||||
|
s.Vel.Z *= inertia
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *State) computeCollision(bb, query AABB, w World) (outBB AABB, outVel Point) {
|
||||||
|
surroundings := s.surroundings(query, w)
|
||||||
|
outVel = s.Vel
|
||||||
|
|
||||||
|
for _, b := range surroundings {
|
||||||
|
outVel.Y = b.YOffset(bb, outVel.Y)
|
||||||
|
}
|
||||||
|
bb = bb.Offset(0, outVel.Y, 0)
|
||||||
|
for _, b := range surroundings {
|
||||||
|
outVel.X = b.XOffset(bb, outVel.X)
|
||||||
|
}
|
||||||
|
bb = bb.Offset(outVel.X, 0, 0)
|
||||||
|
for _, b := range surroundings {
|
||||||
|
outVel.Z = b.ZOffset(bb, outVel.Z)
|
||||||
|
}
|
||||||
|
bb = bb.Offset(0, 0, outVel.Z)
|
||||||
|
return bb, outVel
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user