203 lines
6.0 KiB
Go
203 lines
6.0 KiB
Go
package entity
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
|
|
"edgaru089.ml/go/gl01/internal/util"
|
|
"edgaru089.ml/go/gl01/internal/util/itype"
|
|
"edgaru089.ml/go/gl01/internal/world"
|
|
)
|
|
|
|
// WorldHitbox returns the hitboxes of the entity, in world coordinates.
|
|
func (e *Entity) WorldHitbox() []itype.Boxd {
|
|
boxes := e.Hitbox()
|
|
for i := range boxes {
|
|
boxes[i] = boxes[i].Offset(e.pos)
|
|
}
|
|
return boxes
|
|
}
|
|
|
|
// MoveEps is a small value used to indicate a tiny amount more than zero.
|
|
const MoveEps = 1e-7
|
|
|
|
// move attempts to move the entity by delta in the world.
|
|
// It does not change anything in e.
|
|
func (e *Entity) move(delta itype.Vec3d, w *world.World) (finDelta itype.Vec3d, finVelocity itype.Vec3d, onGround bool) {
|
|
|
|
// Truncate the delta to [0, 1]
|
|
for i := 0; i < len(delta); i++ {
|
|
if math.Abs(delta[i]) > 1 {
|
|
delta[i] /= math.Abs(delta[i])
|
|
}
|
|
}
|
|
|
|
// Get the hitboxes and the blocks region covering it
|
|
hb := e.WorldHitbox()
|
|
hbmin, hbmax := itype.Vec3d{1000000000, 1000000000, 1000000000}, itype.Vec3d{-1000000000, -1000000000, -1000000000}
|
|
for _, b := range hb {
|
|
bmin, bmax := b.MinPoint(), b.MaxPoint()
|
|
hbmin[0] = util.Mind(hbmin[0], bmin[0])
|
|
hbmin[1] = util.Mind(hbmin[1], bmin[1])
|
|
hbmin[2] = util.Mind(hbmin[2], bmin[2])
|
|
hbmax[0] = util.Maxd(hbmax[0], bmax[0])
|
|
hbmax[1] = util.Maxd(hbmax[1], bmax[1])
|
|
hbmax[2] = util.Maxd(hbmax[2], bmax[2])
|
|
}
|
|
|
|
// So this is the region of blocks we should calculate
|
|
imin, imax := hbmin.Floor().Addv(-1, -1, -1), hbmax.Ceiling().Addv(1, 1, 1)
|
|
|
|
finDelta = delta
|
|
finVelocity = e.speed
|
|
for x := imin[0]; x <= imax[0]; x++ {
|
|
for y := imin[1]; y <= imax[1]; y++ {
|
|
for z := imin[2]; z <= imax[2]; z++ {
|
|
blockDelta, blockVelocity, blockOnGround := e.moveBlock(hb, delta, itype.Vec3i{x, y, z}, w)
|
|
finDelta[0] = util.AbsMind(finDelta[0], blockDelta[0])
|
|
finDelta[1] = util.AbsMind(finDelta[1], blockDelta[1])
|
|
finDelta[2] = util.AbsMind(finDelta[2], blockDelta[2])
|
|
finVelocity[0] = util.AbsMind(finVelocity[0], blockVelocity[0])
|
|
finVelocity[1] = util.AbsMind(finVelocity[1], blockVelocity[1])
|
|
finVelocity[2] = util.AbsMind(finVelocity[2], blockVelocity[2])
|
|
onGround = onGround || blockOnGround
|
|
}
|
|
}
|
|
}
|
|
|
|
// Y-
|
|
if delta[1] < 0 {
|
|
onGround = onGround || e.onGround
|
|
} else {
|
|
onGround = false
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// moveBlock simulates moving the entity by delta, and tests collision with the block hibbox.
|
|
func (e *Entity) moveBlock(worldHitbox []itype.Boxd, delta itype.Vec3d, blockCoord itype.Vec3i, w *world.World) (blockDelta itype.Vec3d, finVelocity itype.Vec3d, onGround bool) {
|
|
blockDelta = delta
|
|
finVelocity = e.speed
|
|
onGround = false
|
|
|
|
var blockHitbox []itype.Boxd
|
|
if block := w.Block(blockCoord); block.Id != 0 {
|
|
blocka := block.Appearance(blockCoord)
|
|
if !blocka.NotSolid {
|
|
blockHitbox = w.Block(blockCoord).Appearance(blockCoord).Hitbox
|
|
for i := range blockHitbox {
|
|
blockHitbox[i] = blockHitbox[i].Offset(blockCoord.ToFloat64())
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(blockHitbox) == 0 {
|
|
return
|
|
}
|
|
|
|
for _, eb := range worldHitbox {
|
|
for _, bb := range blockHitbox {
|
|
// Already intersecting: return
|
|
if ok, _ := eb.Intersect(bb); ok {
|
|
continue
|
|
}
|
|
|
|
// X
|
|
if ok, _ := eb.Offsetv(blockDelta[0], 0, 0).Intersect(bb); ok {
|
|
if blockDelta[0] > 0 {
|
|
blockDelta[0] = bb.OffX - (eb.OffX + eb.SizeX) - MoveEps
|
|
//log.Printf("Hit(X+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
} else {
|
|
blockDelta[0] = (bb.OffX + bb.SizeX) - eb.OffX + MoveEps
|
|
//log.Printf("Hit(X-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
}
|
|
finVelocity[0] = 0
|
|
}
|
|
|
|
// Y
|
|
if ok, _ := eb.Offsetv(0, blockDelta[1], 0).Intersect(bb); ok {
|
|
if blockDelta[1] > 0 {
|
|
blockDelta[1] = bb.OffY - (eb.OffY + eb.SizeY) - MoveEps
|
|
//log.Printf("Hit(Y+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
} else {
|
|
onGround = true
|
|
blockDelta[1] = (bb.OffY + bb.SizeY) - eb.OffY + MoveEps
|
|
//log.Printf("Hit(Y-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
}
|
|
finVelocity[1] = 0
|
|
}
|
|
|
|
// Z
|
|
if ok, _ := eb.Offsetv(0, 0, blockDelta[2]).Intersect(bb); ok {
|
|
if blockDelta[2] > 0 {
|
|
blockDelta[2] = bb.OffZ - (eb.OffZ + eb.SizeZ) - MoveEps
|
|
//log.Printf("Hit(Z+): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
} else {
|
|
blockDelta[2] = (bb.OffZ + bb.SizeZ) - eb.OffZ + MoveEps
|
|
//log.Printf("Hit(Z-): On (X%d,Y%d,Z%d), delta=%v\n", blockCoord[0], blockCoord[1], blockCoord[2], blockDelta)
|
|
}
|
|
finVelocity[2] = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
const gravity = 26
|
|
const deaclc = 28
|
|
const maxspeed = 8
|
|
|
|
func (e *Entity) Update(world *world.World, deltaTime time.Duration) {
|
|
|
|
/*
|
|
delta, vec, onGround := e.move(itype.Vec3d{e.speed[0] * deltaTime.Seconds()}, world)
|
|
e.pos = e.pos.Add(delta)
|
|
e.speed = vec
|
|
delta, vec, onGround = e.move(e.speed.Multiply(deltaTime.Seconds()), world)
|
|
e.pos = e.pos.Add(delta)
|
|
e.speed = vec
|
|
delta, vec, onGround = e.move(e.speed.Multiply(deltaTime.Seconds()), world)
|
|
e.pos = e.pos.Add(delta)
|
|
e.speed = vec
|
|
|
|
e.onGround = onGround
|
|
*/
|
|
|
|
var deltaSpeed itype.Vec3d
|
|
if e.onGround {
|
|
speed := math.Sqrt(e.speed[0]*e.speed[0] + e.speed[2]*e.speed[2])
|
|
if speed > MoveEps {
|
|
decrease := deaclc * deltaTime.Seconds()
|
|
factor := util.Maxd(util.Mind(speed-decrease, 6), 0) / speed
|
|
|
|
deltaSpeed[0] = -e.speed[0] * (1 - factor)
|
|
deltaSpeed[2] = -e.speed[2] * (1 - factor)
|
|
} else {
|
|
e.speed[0] = 0
|
|
e.speed[2] = 0
|
|
}
|
|
}
|
|
deltaSpeed[1] = -gravity * deltaTime.Seconds()
|
|
|
|
delta := e.speed.Multiply(deltaTime.Seconds()).Add(deltaSpeed.Multiply(deltaTime.Seconds() / 2))
|
|
e.speed = e.speed.Add(deltaSpeed)
|
|
|
|
findelta, vec, onGround := e.move(delta, world)
|
|
e.pos = e.pos.Add(findelta)
|
|
e.speed = vec
|
|
e.onGround = onGround
|
|
|
|
if !e.onGround {
|
|
vecXZ := itype.Vec2d{e.speed[0], e.speed[2]}
|
|
if vecXZ.Length() > maxspeed {
|
|
vecXZ = vecXZ.Normalize().Multiply(maxspeed)
|
|
}
|
|
e.speed[0] = vecXZ[0]
|
|
e.speed[2] = vecXZ[1]
|
|
}
|
|
|
|
e.b.Update(e.pos, e.ds, world, deltaTime)
|
|
}
|