1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-10-02 16:15:58 -04:00

Position struct for managing world coordinates (#540)

* Fixed nil pointer in Copy()

* Position added

Added Floor() and String() methods to Vector.

Also added Position which declares an embedded Vector2 and returns various forms of it.

* Position tests improved
This commit is contained in:
danhale-git 2020-07-05 00:25:53 +01:00 committed by GitHub
parent 853ad7ae64
commit 07d90e9681
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 176 additions and 7 deletions

View File

@ -40,4 +40,6 @@ type Vector interface {
Reflect(normal Vector) Vector
Mirror(axis Vector) Vector
Rotate(delta *big.Float) Vector
Floor() Vector
String() string
}

View File

@ -0,0 +1,56 @@
package d2vector
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
// Position is a vector in world space. The stored
// value is the one returned by Position.World()
type Position struct {
d2interface.Vector
}
// NewPosition creates a new Position at the given
// float64 world position.
func NewPosition(x, y float64) *Position {
return &Position{New(x, y)}
}
// World is the position, where 1 = one map
// tile.
func (p *Position) World() d2interface.Vector {
return p.Vector
}
// Tile is the tile position, always a whole
// number.
func (p *Position) Tile() d2interface.Vector {
c := p.World().Clone()
return c.Floor()
}
// TileOffset is the offset from the tile position,
// always < 1.
func (p *Position) TileOffset() d2interface.Vector {
c := p.World().Clone()
return c.Subtract(p.Tile())
}
// SubWorld is the position, where 5 = one map
// tile.
func (p *Position) SubWorld() d2interface.Vector {
c := p.World().Clone()
return c.Multiply(New(5, 5))
}
// SubTile is the tile position in sub tiles,
// always a multiple of 5.
func (p *Position) SubTile() d2interface.Vector {
c := p.Tile().Clone()
return c.Multiply(New(5, 5))
}
// SubTileOffset is the offset from the sub tile
// position in sub tiles, always < 1.
func (p *Position) SubTileOffset() d2interface.Vector {
c := p.SubWorld().Clone()
return c.Subtract(p.SubTile())
}

View File

@ -0,0 +1,62 @@
package d2vector
import (
"testing"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
func validate(t *testing.T, original, got, want, unchanged d2interface.Vector) {
if !got.FuzzyEquals(want) {
t.Errorf("want %s: got %s", want, got)
}
if !original.FuzzyEquals(unchanged) {
t.Errorf("Position value %s was incorrectly changed to %s when calling this method", unchanged, original)
}
}
func TestTile(t *testing.T) {
p := NewPosition(1.6, 1.6)
got := p.Tile()
want := New(1, 1)
unchanged := New(1.6, 1.6)
validate(t, p, got, want, unchanged)
}
func TestTileOffset(t *testing.T) {
p := NewPosition(1.6, 1.6)
got := p.TileOffset()
want := New(0.6, 0.6)
unchanged := New(1.6, 1.6)
validate(t, p, got, want, unchanged)
}
func TestSubWorld(t *testing.T) {
p := NewPosition(1, 1)
got := p.SubWorld()
want := New(5, 5)
unchanged := New(1, 1)
validate(t, p, got, want, unchanged)
}
func TestSubTile(t *testing.T) {
p := NewPosition(1, 1)
got := p.SubTile()
want := New(5, 5)
unchanged := New(1, 1)
validate(t, p, got, want, unchanged)
}
func TestSubTileOffset(t *testing.T) {
p := NewPosition(1.1, 1.1)
got := p.SubTileOffset()
want := New(0.5, 0.5)
unchanged := New(1.1, 1.1)
validate(t, p, got, want, unchanged)
}

View File

@ -2,6 +2,7 @@
package d2vector
import (
"fmt"
"math"
"math/big"
@ -64,7 +65,7 @@ func (v *Vector2) Unmarshal(buf []byte) error {
// Clone creates a copy of this Vector
func (v *Vector2) Clone() d2interface.Vector {
result := &Vector2{}
result := New(0, 0)
result.Copy(v)
return result
@ -359,32 +360,47 @@ func (v *Vector2) Rotate(angle *big.Float) d2interface.Vector {
return v
}
// Floor rounds the vector down to the nearest whole numbers.
func (v *Vector2) Floor() d2interface.Vector {
var xi, yi big.Int
v.x.Int(&xi)
v.y.Int(&yi)
v.X().SetInt(&xi)
v.Y().SetInt(&yi)
return v
}
func (v *Vector2) String() string {
return fmt.Sprintf("Vector2{%s, %s}", v.x.Text('f', 5), v.y.Text('f', 5))
}
// Up returns a new vector (0, 1)
func Up() *Vector2 {
func Up() d2interface.Vector {
return New(0, 1)
}
// Down returns a new vector (0, -1)
func Down() *Vector2 {
func Down() d2interface.Vector {
return New(0, -1)
}
// Right returns a new vector (1, 0)
func Right() *Vector2 {
func Right() d2interface.Vector {
return New(1, 0)
}
// Left returns a new vector (-1, 0)
func Left() *Vector2 {
func Left() d2interface.Vector {
return New(-1, 0)
}
// One returns a new vector (1, 1)
func One() *Vector2 {
func One() d2interface.Vector {
return New(1, 1)
}
// Zero returns a new vector (0, 0)
func Zero() *Vector2 {
func Zero() d2interface.Vector {
return New(0, 0)
}

View File

@ -0,0 +1,33 @@
package d2vector
import "testing"
func TestClone(t *testing.T) {
v := New(1, 1)
want := New(1, 1)
got := v.Clone()
if !got.Equals(want) {
t.Errorf("wanted %s: got %s", want, got)
}
}
func TestAbs(t *testing.T) {
v := New(-1, -1)
want := New(1, 1)
got := v.Abs()
if !got.Equals(want) {
t.Errorf("wanted %s: got %s", want, got)
}
}
func TestFloor(t *testing.T) {
v := New(1.6, 1.6)
want := New(1, 1)
if !v.Floor().Equals(want) {
t.Errorf("want %s: got %s", want, v)
}
}