package entity import ( "math" "time" "edgaru089.ml/go/gl01/internal/util" "edgaru089.ml/go/gl01/internal/util/itype" "edgaru089.ml/go/gl01/internal/world" ) func (e *Entity) worldHitbox(hitbox itype.Vec3d) itype.Boxd { return itype.Boxd{ OffX: e.pos[0] - hitbox[0]/2, OffY: e.pos[1], OffZ: e.pos[2] - hitbox[2]/2, SizeX: hitbox[0], SizeY: hitbox[1], SizeZ: hitbox[2], } } // WorldHitbox returns the hitbox of the entity, in world coordinates. func (e *Entity) WorldHitbox() itype.Boxd { return e.worldHitbox(e.b.Hitbox(e.pos, e.ds)) } // the distance between hitpoints, in blocks const HitpointMeshLen = 0.4 func (e *Entity) boxHitpoints(points []itype.Vec3d, hitbox itype.Boxd) []itype.Vec3d { box := hitbox base := box.MinPoint() points = points[0:0] // add the bounding points first points = append(points, base, base.Add(itype.Vec3d{box.SizeX, 0, 0}), base.Add(itype.Vec3d{0, box.SizeY, 0}), base.Add(itype.Vec3d{0, 0, box.SizeZ}), base.Add(itype.Vec3d{box.SizeX, box.SizeY, 0}), base.Add(itype.Vec3d{0, box.SizeY, box.SizeZ}), base.Add(itype.Vec3d{box.SizeX, 0, box.SizeZ}), base.Add(itype.Vec3d{box.SizeX, box.SizeY, box.SizeZ}), ) /* // add the surface points // X+ and X- for y := base[1] + HitpointMeshLen; y < base[1]+hitbox[1]; y += HitpointMeshLen { for z := base[2] + HitpointMeshLen; z < base[2]+hitbox[2]; z += HitpointMeshLen { points = append(points, base.Addv(0, y, z), base.Addv(box.SizeX, y, z), ) } } // Y+ and Y- for x := base[0] + HitpointMeshLen; x < base[0]+hitbox[0]; x += HitpointMeshLen { for z := base[2] + HitpointMeshLen; z < base[2]+hitbox[2]; z += HitpointMeshLen { points = append(points, base.Addv(x, 0, z), base.Addv(x, box.SizeY, z), ) } } // Z+ and Z- for x := base[0] + HitpointMeshLen; x < base[0]+hitbox[0]; x += HitpointMeshLen { for y := base[1] + HitpointMeshLen; y < base[1]+hitbox[1]; y += HitpointMeshLen { points = append(points, base.Addv(x, y, 0), base.Addv(x, y, box.SizeZ), ) } }*/ return points } // MoveEps is a small value used to indicate a tiny amount more than zero. const MoveEps = 1e-7 // tells if the point is already stuck inside a block hitbox func pointStuck(point itype.Vec3d, w *world.World) bool { blockid := point.Floor() block := w.Block(blockid) return block.Id != 0 && block.Behaviour.Appearance( point.Floor(), block.Aux, block.Dataset, ).Hitbox.Offset(blockid.ToFloat64()).Contains(point) } // the move series functions should be called with e.hp already filled func (e *Entity) moveX(delta float64, hitbox itype.Boxd, w *world.World) { if math.Abs(delta) < MoveEps*10 { return } var hit bool = false var deltaMin float64 = 10000 if delta > 1-MoveEps { delta = 1 - MoveEps } if delta < -1+MoveEps { delta = -1 + MoveEps } // X+ / X- for _, p := range e.hp { if pointStuck(p, w) { continue } dest := p.Addv(delta, 0, 0) blockid := dest.Floor() block := w.Block(blockid) var deltaDone float64 if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true if delta > 0 { // moving X+, hit on the X- face deltaDone = blockBox.OffX - (e.pos[0] + hitbox.SizeX/2) - MoveEps //log.Print("Hit X+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) } else { // moving X-, hit on the X+ face deltaDone = blockBox.OffX + blockBox.SizeX - (e.pos[0] - hitbox.SizeX/2) + MoveEps //log.Print("Hit X-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) } } else { deltaDone = delta } } deltaMin = util.AbsMind(deltaMin, deltaDone) } if hit { e.speed[0] = 0 } e.pos[0] += deltaMin } func (e *Entity) moveY(delta float64, hitbox itype.Boxd, w *world.World) { if math.Abs(delta) < MoveEps*10 { return } var hit bool = false var deltaMin float64 = 10000 if delta > 1-MoveEps { delta = 1 - MoveEps } if delta < -1+MoveEps { delta = -1 + MoveEps } // Y+ / Y- for _, p := range e.hp { if pointStuck(p, w) { continue } dest := p.Addv(0, delta, 0) blockid := dest.Floor() block := w.Block(blockid) var deltaDone float64 if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true if delta > 0 { // moving Y+, hit on the Y- face deltaDone = blockBox.OffY - (e.pos[1] + hitbox.SizeY) - MoveEps //log.Print("Hit Y+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest,", deltaDone=",deltaDone) } else { // moving Y-, hit on the Y+ face (on the ground) deltaDone = blockBox.OffY + blockBox.SizeY - e.pos[1] + MoveEps //log.Print("Hit Y-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest,", deltaDone=",deltaDone) /*if !e.onGround { log.Print("onGround = true") }*/ e.onGround = true } } else { deltaDone = delta } } deltaMin = util.AbsMind(deltaMin, deltaDone) } if hit { e.speed[1] = 0 } if math.Abs(deltaMin) > MoveEps*10 { /*if e.onGround { log.Print("onGround = false") }*/ e.onGround = false } e.pos[1] += deltaMin } func (e *Entity) moveZ(delta float64, hitbox itype.Boxd, w *world.World) { if math.Abs(delta) < MoveEps*10 { return } var hit bool = false var deltaMin float64 = 10000 if delta > 1-MoveEps { delta = 1 - MoveEps } if delta < -1+MoveEps { delta = -1 + MoveEps } // Z+ / Z- for _, p := range e.hp { if pointStuck(p, w) { continue } dest := p.Addv(0, 0, delta) blockid := dest.Floor() block := w.Block(blockid) var deltaDone float64 if block.Id == 0 { deltaDone = delta } else { // block.Id!=0 app := world.GetBlockAppearance(blockid, block.Id, block.Aux, block.Dataset) blockBox := app.Hitbox.Offset(blockid.ToFloat64()) if !app.NotSolid && blockBox.Contains(dest) { // Hit! hit = true if delta > 0 { // moving Z+, hit on the Z- face deltaDone = util.Maxd(blockBox.OffZ-(e.pos[2]+hitbox.SizeZ/2)-MoveEps, 0) //log.Print("Hit Z+: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) } else { // moving Z-, hit on the Z+ face deltaDone = util.Mind(blockBox.OffZ+blockBox.SizeZ-(e.pos[2]-hitbox.SizeZ/2)+MoveEps, 0) //log.Print("Hit Z-: On Block ", blockid, ", delta=", delta, ", coord=", e.pos, ", p=", p, ", dest=", dest, ", deltaDone=", deltaDone) } } else { deltaDone = delta } } deltaMin = util.AbsMind(deltaMin, deltaDone) } if hit { e.speed[2] = 0 } e.pos[2] += deltaMin } const gravity float64 = 26 const deaclc float64 = 28 func (e *Entity) Update(world *world.World, deltaTime time.Duration) { hitbox := e.b.Hitbox(e.pos, e.ds) box := e.worldHitbox(hitbox) e.hp = e.hp[0:0] e.hp = e.boxHitpoints(e.hp, box) e.moveX(e.speed[0]*deltaTime.Seconds(), box, world) e.moveY(e.speed[1]*deltaTime.Seconds(), box, world) e.moveZ(e.speed[2]*deltaTime.Seconds(), box, world) speed := math.Sqrt(e.speed[0]*e.speed[0] + e.speed[2]*e.speed[2]) if speed > MoveEps { decrease := deaclc * deltaTime.Seconds() if !e.onGround { decrease /= 10 } factor := util.Maxd(util.Mind(speed-decrease, 9), 0) / speed e.speed[0] *= factor e.speed[2] *= factor } e.speed[1] -= gravity * deltaTime.Seconds() e.b.Update(e.pos, e.ds, world, deltaTime) }