2020-07-04 19:25:53 -04:00
package d2vector
2020-07-09 08:30:55 -04:00
import (
"fmt"
"math"
)
2020-07-04 19:25:53 -04:00
2020-07-09 08:30:55 -04:00
const subTilesPerTile float64 = 5
// Position is a vector in world space. The stored value is the one returned by Position.World()
2020-07-04 19:25:53 -04:00
type Position struct {
2020-07-09 08:30:55 -04:00
Vector
2020-07-04 19:25:53 -04:00
}
2020-07-09 08:30:55 -04:00
// NewPosition creates a new Position at the given float64 world position.
2020-07-11 18:11:26 -04:00
func NewPosition ( x , y float64 ) Position {
p := Position { NewVector ( x , y ) }
2020-07-09 08:30:55 -04:00
p . checkValues ( )
return p
}
2020-07-11 18:11:26 -04:00
// 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 )
}
2020-07-09 08:30:55 -04:00
// Set sets this position to the given x and y values.
func ( p * Position ) Set ( x , y float64 ) {
p . x , p . y = x , y
p . checkValues ( )
}
func ( p * Position ) checkValues ( ) {
if math . IsNaN ( p . x ) || math . IsNaN ( p . y ) {
panic ( fmt . Sprintf ( "float value is NaN: %s" , p . Vector ) )
}
if math . IsInf ( p . x , 0 ) || math . IsInf ( p . y , 0 ) {
panic ( fmt . Sprintf ( "float value is Inf: %s" , p . Vector ) )
}
2020-07-04 19:25:53 -04:00
}
2020-07-09 08:30:55 -04:00
// World is the position, where 1 = one map tile.
2020-07-11 18:11:26 -04:00
// unused
2020-07-09 08:30:55 -04:00
func ( p * Position ) World ( ) * Vector {
return & p . Vector
2020-07-04 19:25:53 -04:00
}
2020-07-11 18:11:26 -04:00
// Tile is the tile position, always a whole number. (tileX, tileY)
2020-07-09 08:30:55 -04:00
func ( p * Position ) Tile ( ) * Vector {
2020-07-04 19:25:53 -04:00
c := p . World ( ) . Clone ( )
return c . Floor ( )
}
2020-07-09 08:30:55 -04:00
// TileOffset is the offset from the tile position, always < 1.
2020-07-11 18:11:26 -04:00
// unused
2020-07-09 08:30:55 -04:00
func ( p * Position ) TileOffset ( ) * Vector {
2020-07-04 19:25:53 -04:00
c := p . World ( ) . Clone ( )
return c . Subtract ( p . Tile ( ) )
}
2020-07-11 18:11:26 -04:00
// SubWorld is the position, where 5 = one map tile. (locationX, locationY)
2020-07-09 08:30:55 -04:00
func ( p * Position ) SubWorld ( ) * Vector {
2020-07-04 19:25:53 -04:00
c := p . World ( ) . Clone ( )
2020-07-09 08:30:55 -04:00
return c . Scale ( subTilesPerTile )
2020-07-04 19:25:53 -04:00
}
2020-07-09 08:30:55 -04:00
// SubTile is the tile position in sub tiles, always a multiple of 5.
2020-07-11 18:11:26 -04:00
// unused
2020-07-09 08:30:55 -04:00
func ( p * Position ) SubTile ( ) * Vector {
2020-07-11 18:11:26 -04:00
return p . Tile ( ) . Scale ( subTilesPerTile )
2020-07-04 19:25:53 -04:00
}
2020-07-09 08:30:55 -04:00
// SubTileOffset is the offset from the sub tile position in sub tiles, always < 1.
2020-07-11 18:11:26 -04:00
// unused
2020-07-09 08:30:55 -04:00
func ( p * Position ) SubTileOffset ( ) * Vector {
2020-07-11 18:11:26 -04:00
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 )
2020-07-04 19:25:53 -04:00
}