Position supports current coordinate types. (#576)
This commit is contained in:
parent
3aab0515cf
commit
fa0814e0b1
|
@ -13,13 +13,21 @@ type Position struct {
|
|||
}
|
||||
|
||||
// NewPosition creates a new Position at the given float64 world position.
|
||||
func NewPosition(x, y float64) *Position {
|
||||
p := &Position{NewVector(x, y)}
|
||||
func NewPosition(x, y float64) Position {
|
||||
p := Position{NewVector(x, y)}
|
||||
p.checkValues()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// EntityPosition returns a Position struct based on the given entity spawn point.
|
||||
// The value given should be the one set in d2mapstamp.Stamp.Entities:
|
||||
// (tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y
|
||||
// TODO: This probably doesn't support positions in between sub tiles so will only be suitable for spawning entities from map generation, not for multiplayer syncing.
|
||||
func EntityPosition(x, y int) Position {
|
||||
return NewPosition(float64(x)/5, float64(y)/5)
|
||||
}
|
||||
|
||||
// Set sets this position to the given x and y values.
|
||||
func (p *Position) Set(x, y float64) {
|
||||
p.x, p.y = x, y
|
||||
|
@ -37,36 +45,47 @@ func (p *Position) checkValues() {
|
|||
}
|
||||
|
||||
// World is the position, where 1 = one map tile.
|
||||
// unused
|
||||
func (p *Position) World() *Vector {
|
||||
return &p.Vector
|
||||
}
|
||||
|
||||
// Tile is the tile position, always a whole number.
|
||||
// Tile is the tile position, always a whole number. (tileX, tileY)
|
||||
func (p *Position) Tile() *Vector {
|
||||
c := p.World().Clone()
|
||||
return c.Floor()
|
||||
}
|
||||
|
||||
// TileOffset is the offset from the tile position, always < 1.
|
||||
// unused
|
||||
func (p *Position) TileOffset() *Vector {
|
||||
c := p.World().Clone()
|
||||
return c.Subtract(p.Tile())
|
||||
}
|
||||
|
||||
// SubWorld is the position, where 5 = one map tile.
|
||||
// SubWorld is the position, where 5 = one map tile. (locationX, locationY)
|
||||
func (p *Position) SubWorld() *Vector {
|
||||
c := p.World().Clone()
|
||||
return c.Scale(subTilesPerTile)
|
||||
}
|
||||
|
||||
// SubTile is the tile position in sub tiles, always a multiple of 5.
|
||||
// unused
|
||||
func (p *Position) SubTile() *Vector {
|
||||
c := p.Tile().Clone()
|
||||
return c.Scale(subTilesPerTile)
|
||||
return p.Tile().Scale(subTilesPerTile)
|
||||
}
|
||||
|
||||
// SubTileOffset is the offset from the sub tile position in sub tiles, always < 1.
|
||||
// unused
|
||||
func (p *Position) SubTileOffset() *Vector {
|
||||
c := p.SubWorld().Clone()
|
||||
return c.Subtract(p.SubTile())
|
||||
return p.SubWorld().Subtract(p.SubTile())
|
||||
}
|
||||
|
||||
// TODO: understand this and maybe improve/remove it
|
||||
// SubTileOffset() + 1. It's used for rendering. It seems to always do this:
|
||||
// v.offsetX+int((v.subcellX-v.subcellY)*16),
|
||||
// v.offsetY+int(((v.subcellX+v.subcellY)*8)-5),
|
||||
// ^ Maybe similar to Viewport.OrthoToWorld? (subCellX, subCellY)
|
||||
func (p *Position) SubCell() *Vector {
|
||||
return p.SubTileOffset().AddScalar(1)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,49 @@
|
|||
package d2vector
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func validate(t *testing.T, original, got, want, unchanged Vector) {
|
||||
func TestEntityPosition(t *testing.T) {
|
||||
x, y := rand.Intn(1000), rand.Intn(1000)
|
||||
pos := EntityPosition(x, y)
|
||||
locX, locY := float64(x), float64(y)
|
||||
|
||||
// old coordinate values Position equivalent
|
||||
locationX := locX // .SubWord().X()
|
||||
locationY := locY // .SubWord().Y()
|
||||
tileX := float64(x / 5) // .Tile().X()
|
||||
tileY := float64(y / 5) // .Tile().Y()
|
||||
subcellX := 1 + math.Mod(locX, 5) // .SubCell().X()
|
||||
subcellY := 1 + math.Mod(locY, 5) // .SubCell().Y()
|
||||
|
||||
want := NewVector(tileX, tileY)
|
||||
got := pos.Tile()
|
||||
|
||||
if !got.Equals(want) {
|
||||
t.Errorf("world position should match old value: got %s: want %s", got, want)
|
||||
}
|
||||
|
||||
want = NewVector(subcellX, subcellY)
|
||||
got = pos.SubCell()
|
||||
|
||||
if !got.Equals(want) {
|
||||
t.Errorf("sub cell position should match old value: got %s: want %s", got, want)
|
||||
}
|
||||
|
||||
want = NewVector(locationX, locationY)
|
||||
got = pos.SubWorld()
|
||||
|
||||
if !got.Equals(want) {
|
||||
t.Errorf("sub tile position should match old value: got %s: want %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func validate(description string, t *testing.T, original, got, want, unchanged Vector) {
|
||||
if !got.EqualsApprox(want) {
|
||||
t.Errorf("want %s: got %s", want, got)
|
||||
t.Errorf("%s: want %s: got %s", description, want, got)
|
||||
}
|
||||
|
||||
if !original.EqualsApprox(unchanged) {
|
||||
|
@ -20,7 +57,7 @@ func TestTile(t *testing.T) {
|
|||
want := NewVector(1, 1)
|
||||
unchanged := NewVector(1.6, 1.6)
|
||||
|
||||
validate(t, p.Vector, *got, want, unchanged)
|
||||
validate("tile position", t, p.Vector, *got, want, unchanged)
|
||||
}
|
||||
|
||||
func TestTileOffset(t *testing.T) {
|
||||
|
@ -29,7 +66,7 @@ func TestTileOffset(t *testing.T) {
|
|||
want := NewVector(0.6, 0.6)
|
||||
unchanged := NewVector(1.6, 1.6)
|
||||
|
||||
validate(t, p.Vector, *got, want, unchanged)
|
||||
validate("tile offset", t, p.Vector, *got, want, unchanged)
|
||||
}
|
||||
|
||||
func TestSubWorld(t *testing.T) {
|
||||
|
@ -38,7 +75,7 @@ func TestSubWorld(t *testing.T) {
|
|||
want := NewVector(5, 5)
|
||||
unchanged := NewVector(1, 1)
|
||||
|
||||
validate(t, p.Vector, *got, want, unchanged)
|
||||
validate("sub tile world position", t, p.Vector, *got, want, unchanged)
|
||||
}
|
||||
|
||||
func TestSubTile(t *testing.T) {
|
||||
|
@ -47,7 +84,7 @@ func TestSubTile(t *testing.T) {
|
|||
want := NewVector(5, 5)
|
||||
unchanged := NewVector(1, 1)
|
||||
|
||||
validate(t, p.Vector, *got, want, unchanged)
|
||||
validate("sub tile with offset", t, p.Vector, *got, want, unchanged)
|
||||
}
|
||||
|
||||
func TestSubTileOffset(t *testing.T) {
|
||||
|
@ -56,5 +93,5 @@ func TestSubTileOffset(t *testing.T) {
|
|||
want := NewVector(0.5, 0.5)
|
||||
unchanged := NewVector(1.1, 1.1)
|
||||
|
||||
validate(t, p.Vector, *got, want, unchanged)
|
||||
validate("offset from sub tile", t, p.Vector, *got, want, unchanged)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,16 @@ func NewVector(x, y float64) Vector {
|
|||
return Vector{x, y}
|
||||
}
|
||||
|
||||
// X returns the x value of this vector.
|
||||
func (v *Vector) X() float64 {
|
||||
return v.x
|
||||
}
|
||||
|
||||
// Y returns the y value of this vector.
|
||||
func (v *Vector) Y() float64 {
|
||||
return v.y
|
||||
}
|
||||
|
||||
// Equals returns true if the float64 values of this vector are exactly equal to the given Vector.
|
||||
func (v *Vector) Equals(o Vector) bool {
|
||||
return v.x == o.x && v.y == o.y
|
||||
|
@ -85,6 +95,14 @@ func (v *Vector) Add(o *Vector) *Vector {
|
|||
return v
|
||||
}
|
||||
|
||||
// AddScalar the given vector to this vector.
|
||||
func (v *Vector) AddScalar(s float64) *Vector {
|
||||
v.x += s
|
||||
v.y += s
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Subtract the given vector from this vector.
|
||||
func (v *Vector) Subtract(o *Vector) *Vector {
|
||||
v.x -= o.x
|
||||
|
@ -117,6 +135,14 @@ func (v *Vector) Divide(o *Vector) *Vector {
|
|||
return v
|
||||
}
|
||||
|
||||
// DivideScalar divides this vector by the given float64 value.
|
||||
func (v *Vector) DivideScalar(s float64) *Vector {
|
||||
v.x /= s
|
||||
v.y /= s
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Abs sets the vector to it's absolute (positive) equivalent.
|
||||
func (v *Vector) Abs() *Vector {
|
||||
xm, ym := 1.0, 1.0
|
||||
|
|
|
@ -154,15 +154,25 @@ func TestClamp(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
v := NewVector(1, 1)
|
||||
add := NewVector(0.5, 0.5)
|
||||
want := NewVector(1.5, 1.5)
|
||||
v := NewVector(1, 2)
|
||||
add := NewVector(0.5, 3)
|
||||
want := NewVector(1.5, 5)
|
||||
got := v.Clone()
|
||||
got.Add(&add)
|
||||
|
||||
evaluateVector(fmt.Sprintf("add %s to %s", add, v), want, got, t)
|
||||
}
|
||||
|
||||
func TestAddScalar(t *testing.T) {
|
||||
v := NewVector(1, -1)
|
||||
add := 0.5
|
||||
want := NewVector(1.5, -0.5)
|
||||
got := v.Clone()
|
||||
got.AddScalar(add)
|
||||
|
||||
evaluateVector(fmt.Sprintf("add %.2f to %s", add, v), want, got, t)
|
||||
}
|
||||
|
||||
func TestSubtract(t *testing.T) {
|
||||
v := NewVector(1, 1)
|
||||
subtract := NewVector(0.6, 0.6)
|
||||
|
@ -184,15 +194,25 @@ func TestMultiply(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDivide(t *testing.T) {
|
||||
v := NewVector(1, 1)
|
||||
divide := NewVector(2, 2)
|
||||
want := NewVector(0.5, 0.5)
|
||||
v := NewVector(1, 8)
|
||||
divide := NewVector(2, 4)
|
||||
want := NewVector(0.5, 2)
|
||||
got := v.Clone()
|
||||
got.Divide(÷)
|
||||
|
||||
evaluateVector(fmt.Sprintf("divide %s by %s", v, divide), want, got, t)
|
||||
}
|
||||
|
||||
func TestDivideScalar(t *testing.T) {
|
||||
v := NewVector(1, 2)
|
||||
divide := 2.0
|
||||
want := NewVector(0.5, 1.0)
|
||||
got := v.Clone()
|
||||
got.DivideScalar(divide)
|
||||
|
||||
evaluateVector(fmt.Sprintf("divide %s by %.2f", v, divide), want, got, t)
|
||||
}
|
||||
|
||||
func TestScale(t *testing.T) {
|
||||
v := NewVector(2, 3)
|
||||
want := NewVector(4, 6)
|
||||
|
|
Loading…
Reference in New Issue