Fix Atlas gen with simplification
Only track lower and upper bounds in world space, and speak in terms of world space and chunks
This commit is contained in:
parent
dbe944bb4e
commit
8b83672dcc
5 changed files with 240 additions and 121 deletions
|
@ -38,11 +38,11 @@ type Atlas struct {
|
||||||
// This is intentionally not a 2D array so it can be expanded in all directions
|
// This is intentionally not a 2D array so it can be expanded in all directions
|
||||||
Chunks []Chunk `json:"chunks"`
|
Chunks []Chunk `json:"chunks"`
|
||||||
|
|
||||||
// CurrentSize is the current width/height of the atlas in chunks
|
// LowerBound is the origin of the bottom left corner of the current chunks in world space (current chunks cover >= this value)
|
||||||
CurrentSize vector.Vector `json:"currentSize"`
|
LowerBound vector.Vector `json:"lowerBound"`
|
||||||
|
|
||||||
// WorldOrigin represents the location of the [0,0] world space point in terms of the allotted current chunks
|
// UpperBound is the top left corner of the current chunks (curent chunks cover < this value)
|
||||||
WorldOrigin vector.Vector `json:"worldOrigin"`
|
UpperBound vector.Vector `json:"upperBound"`
|
||||||
|
|
||||||
// ChunkSize is the x/y dimensions of each square chunk
|
// ChunkSize is the x/y dimensions of each square chunk
|
||||||
ChunkSize int `json:"chunksize"`
|
ChunkSize int `json:"chunksize"`
|
||||||
|
@ -52,10 +52,10 @@ type Atlas struct {
|
||||||
func NewAtlas(chunkSize int) Atlas {
|
func NewAtlas(chunkSize int) Atlas {
|
||||||
// Start up with one chunk
|
// Start up with one chunk
|
||||||
a := Atlas{
|
a := Atlas{
|
||||||
ChunkSize: chunkSize,
|
ChunkSize: chunkSize,
|
||||||
Chunks: make([]Chunk, 1),
|
Chunks: make([]Chunk, 1),
|
||||||
CurrentSize: vector.Vector{X: 1, Y: 1},
|
LowerBound: vector.Vector{X: 0, Y: 0},
|
||||||
WorldOrigin: vector.Vector{X: 0, Y: 0},
|
UpperBound: vector.Vector{X: chunkSize, Y: chunkSize},
|
||||||
}
|
}
|
||||||
// Initialise the first chunk
|
// Initialise the first chunk
|
||||||
a.Chunks[0].populate(chunkSize)
|
a.Chunks[0].populate(chunkSize)
|
||||||
|
@ -162,129 +162,88 @@ func (a *Atlas) worldSpaceToChunkLocal(v vector.Vector) vector.Vector {
|
||||||
return vector.Vector{X: maths.Pmod(v.X, a.ChunkSize), Y: maths.Pmod(v.Y, a.ChunkSize)}
|
return vector.Vector{X: maths.Pmod(v.X, a.ChunkSize), Y: maths.Pmod(v.Y, a.ChunkSize)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// worldSpaceToChunk gets the current chunk ID for a position in the world
|
// worldSpaceToChunkID gets the current chunk ID for a position in the world
|
||||||
func (a *Atlas) worldSpaceToChunk(v vector.Vector) int {
|
func (a *Atlas) worldSpaceToChunkIndex(v vector.Vector) int {
|
||||||
// First convert to chunk space
|
// Shift the vector by our current min
|
||||||
chunkSpace := a.worldSpaceToChunkSpace(v)
|
v = v.Added(a.LowerBound.Negated())
|
||||||
|
|
||||||
// Then return the ID
|
// Divide by the current size and floor, to get chunk-scaled vector from the lower bound
|
||||||
return a.chunkSpaceToChunk(chunkSpace)
|
v = v.DividedFloor(a.ChunkSize)
|
||||||
|
|
||||||
|
// Calculate the width
|
||||||
|
width := a.UpperBound.X - a.LowerBound.X
|
||||||
|
widthInChunks := width / a.ChunkSize
|
||||||
|
|
||||||
|
// Along the corridor and up the stairs
|
||||||
|
return (v.Y * widthInChunks) + v.X
|
||||||
}
|
}
|
||||||
|
|
||||||
// worldSpaceToChunkSpace converts from world space to chunk space
|
// chunkOriginInWorldSpace returns the origin of the chunk in world space
|
||||||
func (a *Atlas) worldSpaceToChunkSpace(v vector.Vector) vector.Vector {
|
|
||||||
// Remove the chunk local part
|
|
||||||
chunkOrigin := v.Added(a.worldSpaceToChunkLocal(v).Negated())
|
|
||||||
// Convert to chunk space coordinate
|
|
||||||
chunkSpaceOrigin := chunkOrigin.Divided(a.ChunkSize)
|
|
||||||
// Shift it by our current chunk origin
|
|
||||||
chunkIndexOrigin := chunkSpaceOrigin.Added(a.WorldOrigin)
|
|
||||||
|
|
||||||
return chunkIndexOrigin
|
|
||||||
}
|
|
||||||
|
|
||||||
// chunkSpaceToWorldSpace vonverts from chunk space to world space
|
|
||||||
func (a *Atlas) chunkSpaceToWorldSpace(v vector.Vector) vector.Vector {
|
|
||||||
|
|
||||||
// Shift it by the current chunk origin
|
|
||||||
shifted := v.Added(a.WorldOrigin.Negated())
|
|
||||||
|
|
||||||
// Multiply out by chunk size
|
|
||||||
return shifted.Multiplied(a.ChunkSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// chunkOriginInChunkSpace Gets the chunk origin in chunk space
|
|
||||||
func (a *Atlas) chunkOriginInChunkSpace(chunk int) vector.Vector {
|
|
||||||
// convert the chunk to chunk space
|
|
||||||
chunkOrigin := a.chunkToChunkSpace(chunk)
|
|
||||||
|
|
||||||
// Shift it by the current chunk origin
|
|
||||||
return chunkOrigin.Added(a.WorldOrigin.Negated())
|
|
||||||
}
|
|
||||||
|
|
||||||
// chunkOriginInWorldSpace gets the chunk origin for a given chunk index
|
|
||||||
func (a *Atlas) chunkOriginInWorldSpace(chunk int) vector.Vector {
|
func (a *Atlas) chunkOriginInWorldSpace(chunk int) vector.Vector {
|
||||||
// convert the chunk to chunk space
|
// Calculate the width
|
||||||
chunkSpace := a.chunkToChunkSpace(chunk)
|
width := a.UpperBound.X - a.LowerBound.X
|
||||||
|
widthInChunks := width / a.ChunkSize
|
||||||
|
|
||||||
// Convert to world space
|
// Reverse the along the corridor and up the stairs
|
||||||
return a.chunkSpaceToWorldSpace(chunkSpace)
|
v := vector.Vector{
|
||||||
}
|
X: chunk % widthInChunks,
|
||||||
|
Y: chunk / widthInChunks,
|
||||||
// chunkSpaceToChunk converts from chunk space to the chunk
|
|
||||||
func (a *Atlas) chunkSpaceToChunk(v vector.Vector) int {
|
|
||||||
// Along the coridor and up the stair
|
|
||||||
return (v.Y * a.CurrentSize.X) + v.X
|
|
||||||
}
|
|
||||||
|
|
||||||
// chunkToChunkSpace returns the chunk space coord for the chunk
|
|
||||||
func (a *Atlas) chunkToChunkSpace(chunk int) vector.Vector {
|
|
||||||
return vector.Vector{
|
|
||||||
X: maths.Pmod(chunk, a.CurrentSize.Y),
|
|
||||||
Y: (chunk / a.CurrentSize.X),
|
|
||||||
}
|
}
|
||||||
|
// Multiply up to world scale
|
||||||
|
v = v.Multiplied(a.ChunkSize)
|
||||||
|
// Shift by the lower bound
|
||||||
|
return v.Added(a.LowerBound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Atlas) getExtents() (min vector.Vector, max vector.Vector) {
|
// getNewBounds gets new lower and upper bounds for the world space given a vector
|
||||||
min = a.WorldOrigin.Negated()
|
func (a *Atlas) getNewBounds(v vector.Vector) (lower vector.Vector, upper vector.Vector) {
|
||||||
max = min.Added(a.CurrentSize)
|
lower = vector.Min(v, a.LowerBound)
|
||||||
|
upper = vector.Max(v.Added(vector.Vector{X: 1, Y: 1}), a.UpperBound)
|
||||||
|
|
||||||
|
lower = vector.Vector{
|
||||||
|
X: maths.RoundDown(lower.X, a.ChunkSize),
|
||||||
|
Y: maths.RoundDown(lower.Y, a.ChunkSize),
|
||||||
|
}
|
||||||
|
upper = vector.Vector{
|
||||||
|
X: maths.RoundUp(upper.X, a.ChunkSize),
|
||||||
|
Y: maths.RoundUp(upper.Y, a.ChunkSize),
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// worldSpaceToTrunkWithGrow will expand the current atlas for a given world space position if needed
|
// worldSpaceToTrunkWithGrow will expand the current atlas for a given world space position if needed
|
||||||
func (a *Atlas) worldSpaceToChunkWithGrow(v vector.Vector) int {
|
func (a *Atlas) worldSpaceToChunkWithGrow(v vector.Vector) int {
|
||||||
min, max := a.getExtents()
|
// If we're within bounds, just return the current chunk
|
||||||
|
if v.X >= a.LowerBound.X && v.Y >= a.LowerBound.Y && v.X < a.UpperBound.X && v.Y < a.UpperBound.Y {
|
||||||
// Divide by the chunk size to bring into chunk space
|
return a.worldSpaceToChunkIndex(v)
|
||||||
v = v.Divided(a.ChunkSize)
|
|
||||||
|
|
||||||
// Check we're within the current extents and bail early
|
|
||||||
if v.X >= min.X && v.Y >= min.Y && v.X < max.X && v.Y < max.Y {
|
|
||||||
return a.worldSpaceToChunk(v)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the new origin and the new size
|
// Calculate the new bounds
|
||||||
origin := min
|
lower, upper := a.getNewBounds(v)
|
||||||
size := a.CurrentSize
|
size := upper.Added(lower.Negated())
|
||||||
|
size = size.Divided(a.ChunkSize)
|
||||||
|
|
||||||
// If we need to shift the origin back
|
// Create the new empty atlas
|
||||||
originDiff := origin.Added(v.Negated())
|
|
||||||
if originDiff.X > 0 {
|
|
||||||
origin.X -= originDiff.X
|
|
||||||
size.X += originDiff.X
|
|
||||||
}
|
|
||||||
if originDiff.Y > 0 {
|
|
||||||
origin.Y -= originDiff.Y
|
|
||||||
size.Y += originDiff.Y
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we need to expand the size
|
|
||||||
maxDiff := v.Added(max.Negated())
|
|
||||||
if maxDiff.X > 0 {
|
|
||||||
size.X += maxDiff.X
|
|
||||||
}
|
|
||||||
if maxDiff.Y > 0 {
|
|
||||||
size.Y += maxDiff.Y
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up the new size and origin
|
|
||||||
newAtlas := Atlas{
|
newAtlas := Atlas{
|
||||||
ChunkSize: a.ChunkSize,
|
ChunkSize: a.ChunkSize,
|
||||||
WorldOrigin: origin.Negated(),
|
LowerBound: lower,
|
||||||
CurrentSize: size,
|
UpperBound: upper,
|
||||||
Chunks: make([]Chunk, size.X*size.Y),
|
Chunks: make([]Chunk, size.X*size.Y),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all old chunks into the new atlas
|
// Copy all old chunks into the new atlas
|
||||||
for chunk, chunkData := range a.Chunks {
|
for chunk, chunkData := range a.Chunks {
|
||||||
// Calculate the new chunk location and copy over the data
|
|
||||||
newChunk := newAtlas.worldSpaceToChunk(a.chunkOriginInWorldSpace(chunk))
|
// Calculate the chunk ID in the new atlas
|
||||||
|
origin := a.chunkOriginInWorldSpace(chunk)
|
||||||
|
newChunk := newAtlas.worldSpaceToChunkIndex(origin)
|
||||||
|
|
||||||
// Copy over the old chunk to the new atlas
|
// Copy over the old chunk to the new atlas
|
||||||
newAtlas.Chunks[newChunk] = chunkData
|
newAtlas.Chunks[newChunk] = chunkData
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the new atlas data into this one
|
// Overwrite the old atlas with this one
|
||||||
*a = newAtlas
|
*a = newAtlas
|
||||||
|
|
||||||
return a.worldSpaceToChunk(v)
|
return a.worldSpaceToChunkIndex(v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,43 +22,49 @@ func TestAtlas_toChunk(t *testing.T) {
|
||||||
// Get a tile to spawn the chunks
|
// Get a tile to spawn the chunks
|
||||||
a.QueryPosition(vector.Vector{X: -1, Y: -1})
|
a.QueryPosition(vector.Vector{X: -1, Y: -1})
|
||||||
a.QueryPosition(vector.Vector{X: 0, Y: 0})
|
a.QueryPosition(vector.Vector{X: 0, Y: 0})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
|
||||||
// Chunks should look like:
|
// Chunks should look like:
|
||||||
// 2 | 3
|
// 2 | 3
|
||||||
// -----
|
// -----
|
||||||
// 0 | 1
|
// 0 | 1
|
||||||
chunkID := a.worldSpaceToChunk(vector.Vector{X: 0, Y: 0})
|
chunkID := a.worldSpaceToChunkIndex(vector.Vector{X: 0, Y: 0})
|
||||||
assert.Equal(t, 3, chunkID)
|
assert.Equal(t, 3, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: 0, Y: -1})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 0, Y: -1})
|
||||||
assert.Equal(t, 1, chunkID)
|
assert.Equal(t, 1, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -1, Y: -1})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -1, Y: -1})
|
||||||
assert.Equal(t, 0, chunkID)
|
assert.Equal(t, 0, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -1, Y: 0})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -1, Y: 0})
|
||||||
assert.Equal(t, 2, chunkID)
|
assert.Equal(t, 2, chunkID)
|
||||||
|
|
||||||
a = NewAtlas(2)
|
a = NewAtlas(2)
|
||||||
assert.NotNil(t, a)
|
assert.NotNil(t, a)
|
||||||
// Get a tile to spawn the chunks
|
// Get a tile to spawn the chunks
|
||||||
a.QueryPosition(vector.Vector{X: -2, Y: -2})
|
a.QueryPosition(vector.Vector{X: -2, Y: -2})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
a.QueryPosition(vector.Vector{X: 1, Y: 1})
|
a.QueryPosition(vector.Vector{X: 1, Y: 1})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
// Chunks should look like:
|
// Chunks should look like:
|
||||||
// 2 | 3
|
// 2 | 3
|
||||||
// -----
|
// -----
|
||||||
// 0 | 1
|
// 0 | 1
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: 1, Y: 1})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: 1})
|
||||||
assert.Equal(t, 3, chunkID)
|
assert.Equal(t, 3, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: 1, Y: -2})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: -2})
|
||||||
assert.Equal(t, 1, chunkID)
|
assert.Equal(t, 1, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -2, Y: -2})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -2, Y: -2})
|
||||||
assert.Equal(t, 0, chunkID)
|
assert.Equal(t, 0, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -2, Y: 1})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -2, Y: 1})
|
||||||
assert.Equal(t, 2, chunkID)
|
assert.Equal(t, 2, chunkID)
|
||||||
|
|
||||||
a = NewAtlas(2)
|
a = NewAtlas(2)
|
||||||
assert.NotNil(t, a)
|
assert.NotNil(t, a)
|
||||||
// Get a tile to spawn the chunks
|
// Get a tile to spawn a 4x4 grid of chunks
|
||||||
a.QueryPosition(vector.Vector{X: 5, Y: 5})
|
a.QueryPosition(vector.Vector{X: 3, Y: 3})
|
||||||
a.QueryPosition(vector.Vector{X: -5, Y: -5})
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
a.QueryPosition(vector.Vector{X: -3, Y: -3})
|
||||||
|
assert.Equal(t, 4*4, len(a.Chunks))
|
||||||
|
|
||||||
// Chunks should look like:
|
// Chunks should look like:
|
||||||
// 12| 13|| 14| 15
|
// 12| 13|| 14| 15
|
||||||
// ----------------
|
// ----------------
|
||||||
|
@ -67,14 +73,96 @@ func TestAtlas_toChunk(t *testing.T) {
|
||||||
// 4 | 5 || 6 | 7
|
// 4 | 5 || 6 | 7
|
||||||
// ----------------
|
// ----------------
|
||||||
// 0 | 1 || 2 | 3
|
// 0 | 1 || 2 | 3
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: 1, Y: 3})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: 3})
|
||||||
assert.Equal(t, 14, chunkID)
|
assert.Equal(t, 14, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: 1, Y: -3})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: -3})
|
||||||
assert.Equal(t, 2, chunkID)
|
assert.Equal(t, 2, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -1, Y: -1})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -1, Y: -1})
|
||||||
assert.Equal(t, 5, chunkID)
|
assert.Equal(t, 5, chunkID)
|
||||||
chunkID = a.worldSpaceToChunk(vector.Vector{X: -2, Y: 2})
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: -2, Y: 2})
|
||||||
assert.Equal(t, 13, chunkID)
|
assert.Equal(t, 13, chunkID)
|
||||||
|
|
||||||
|
a = NewAtlas(3)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
// Get a tile to spawn a 4x4 grid of chunks
|
||||||
|
a.QueryPosition(vector.Vector{X: 3, Y: 3})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
|
||||||
|
// Chunks should look like:
|
||||||
|
// || 2| 3
|
||||||
|
// -------
|
||||||
|
// || 0| 1
|
||||||
|
// =======
|
||||||
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: 1})
|
||||||
|
assert.Equal(t, 0, chunkID)
|
||||||
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 3, Y: 1})
|
||||||
|
assert.Equal(t, 1, chunkID)
|
||||||
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 1, Y: 4})
|
||||||
|
assert.Equal(t, 2, chunkID)
|
||||||
|
chunkID = a.worldSpaceToChunkIndex(vector.Vector{X: 5, Y: 5})
|
||||||
|
assert.Equal(t, 3, chunkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAtlas_toWorld(t *testing.T) {
|
||||||
|
a := NewAtlas(1)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
|
||||||
|
// Get a tile to spawn some chunks
|
||||||
|
a.QueryPosition(vector.Vector{X: -1, Y: -1})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
|
||||||
|
// Chunks should look like:
|
||||||
|
// 2 | 3
|
||||||
|
// -----
|
||||||
|
// 0 | 1
|
||||||
|
assert.Equal(t, vector.Vector{X: -1, Y: -1}, a.chunkOriginInWorldSpace(0))
|
||||||
|
assert.Equal(t, vector.Vector{X: 0, Y: -1}, a.chunkOriginInWorldSpace(1))
|
||||||
|
|
||||||
|
a = NewAtlas(2)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
// Get a tile to spawn the chunks
|
||||||
|
a.QueryPosition(vector.Vector{X: -2, Y: -2})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
a.QueryPosition(vector.Vector{X: 1, Y: 1})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
// Chunks should look like:
|
||||||
|
// 2 | 3
|
||||||
|
// -----
|
||||||
|
// 0 | 1
|
||||||
|
assert.Equal(t, vector.Vector{X: -2, Y: -2}, a.chunkOriginInWorldSpace(0))
|
||||||
|
assert.Equal(t, vector.Vector{X: -2, Y: 0}, a.chunkOriginInWorldSpace(2))
|
||||||
|
|
||||||
|
a = NewAtlas(2)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
// Get a tile to spawn a 4x4 grid of chunks
|
||||||
|
a.QueryPosition(vector.Vector{X: 3, Y: 3})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
a.QueryPosition(vector.Vector{X: -3, Y: -3})
|
||||||
|
assert.Equal(t, 4*4, len(a.Chunks))
|
||||||
|
|
||||||
|
// Chunks should look like:
|
||||||
|
// 12| 13|| 14| 15
|
||||||
|
// ----------------
|
||||||
|
// 8 | 9 || 10| 11
|
||||||
|
// ================
|
||||||
|
// 4 | 5 || 6 | 7
|
||||||
|
// ----------------
|
||||||
|
// 0 | 1 || 2 | 3
|
||||||
|
assert.Equal(t, vector.Vector{X: -4, Y: -4}, a.chunkOriginInWorldSpace(0))
|
||||||
|
assert.Equal(t, vector.Vector{X: 2, Y: -2}, a.chunkOriginInWorldSpace(7))
|
||||||
|
|
||||||
|
a = NewAtlas(3)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
// Get a tile to spawn a 4x4 grid of chunks
|
||||||
|
a.QueryPosition(vector.Vector{X: 3, Y: 3})
|
||||||
|
assert.Equal(t, 2*2, len(a.Chunks))
|
||||||
|
|
||||||
|
// Chunks should look like:
|
||||||
|
// || 2| 3
|
||||||
|
// -------
|
||||||
|
// || 0| 1
|
||||||
|
// =======
|
||||||
|
assert.Equal(t, vector.Vector{X: 0, Y: 0}, a.chunkOriginInWorldSpace(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAtlas_GetSetTile(t *testing.T) {
|
func TestAtlas_GetSetTile(t *testing.T) {
|
||||||
|
@ -137,3 +225,26 @@ func TestAtlas_Grown(t *testing.T) {
|
||||||
tile, _ = a.QueryPosition(vector.Vector{X: 1, Y: -2})
|
tile, _ = a.QueryPosition(vector.Vector{X: 1, Y: -2})
|
||||||
assert.Equal(t, byte(3), tile)
|
assert.Equal(t, byte(3), tile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAtlas_GetSetCorrect(t *testing.T) {
|
||||||
|
// Big stress test to ensure we do actually properly expand for all reasonable values
|
||||||
|
for i := 1; i <= 4; i++ {
|
||||||
|
|
||||||
|
for x := -i * 2; x < i*2; x++ {
|
||||||
|
for y := -i * 2; y < i*2; y++ {
|
||||||
|
a := NewAtlas(i)
|
||||||
|
assert.NotNil(t, a)
|
||||||
|
assert.Equal(t, 1, len(a.Chunks))
|
||||||
|
|
||||||
|
pos := vector.Vector{X: x, Y: y}
|
||||||
|
a.SetTile(pos, TileRock)
|
||||||
|
a.SetObject(pos, objects.Object{Type: objects.LargeRock})
|
||||||
|
tile, obj := a.QueryPosition(pos)
|
||||||
|
|
||||||
|
assert.Equal(t, TileRock, Tile(tile))
|
||||||
|
assert.Equal(t, objects.Object{Type: objects.LargeRock}, obj)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -39,3 +39,19 @@ func Min(x, y int) int {
|
||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RoundUp rounds a value up to the nearest multiple
|
||||||
|
func RoundUp(toRound int, multiple int) int {
|
||||||
|
remainder := Pmod(toRound, multiple)
|
||||||
|
if remainder == 0 {
|
||||||
|
return toRound
|
||||||
|
}
|
||||||
|
|
||||||
|
return (multiple - remainder) + toRound
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundDown rounds a value down to the nearest multiple
|
||||||
|
func RoundDown(toRound int, multiple int) int {
|
||||||
|
remainder := Pmod(toRound, multiple)
|
||||||
|
return toRound - remainder
|
||||||
|
}
|
||||||
|
|
|
@ -29,5 +29,19 @@ func TestMin(t *testing.T) {
|
||||||
assert.Equal(t, 100, Min(100, 500))
|
assert.Equal(t, 100, Min(100, 500))
|
||||||
assert.Equal(t, -4, Min(-4, 1))
|
assert.Equal(t, -4, Min(-4, 1))
|
||||||
assert.Equal(t, -4, Min(-4, -2))
|
assert.Equal(t, -4, Min(-4, -2))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundUp(t *testing.T) {
|
||||||
|
assert.Equal(t, 10, RoundUp(10, 5))
|
||||||
|
assert.Equal(t, 12, RoundUp(10, 4))
|
||||||
|
assert.Equal(t, -8, RoundUp(-8, 4))
|
||||||
|
assert.Equal(t, -4, RoundUp(-7, 4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoundDown(t *testing.T) {
|
||||||
|
assert.Equal(t, 10, RoundDown(10, 5))
|
||||||
|
assert.Equal(t, 8, RoundDown(10, 4))
|
||||||
|
assert.Equal(t, -8, RoundDown(-8, 4))
|
||||||
|
assert.Equal(t, -8, RoundDown(-7, 4))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,25 @@ func (v Vector) Divided(val int) Vector {
|
||||||
return Vector{v.X / val, v.Y / val}
|
return Vector{v.X / val, v.Y / val}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DividedFloor returns the vector divided but floors the value regardless
|
||||||
|
func (v Vector) DividedFloor(val int) Vector {
|
||||||
|
x := float64(v.X) / float64(val)
|
||||||
|
|
||||||
|
if x < 0 {
|
||||||
|
x = math.Floor(x)
|
||||||
|
} else {
|
||||||
|
x = math.Floor(x)
|
||||||
|
}
|
||||||
|
y := float64(v.Y) / float64(val)
|
||||||
|
if y < 0 {
|
||||||
|
y = math.Floor(y)
|
||||||
|
} else {
|
||||||
|
y = math.Floor(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vector{X: int(x), Y: int(y)}
|
||||||
|
}
|
||||||
|
|
||||||
// Abs returns an absolute version of the vector
|
// Abs returns an absolute version of the vector
|
||||||
func (v Vector) Abs() Vector {
|
func (v Vector) Abs() Vector {
|
||||||
return Vector{maths.Abs(v.X), maths.Abs(v.Y)}
|
return Vector{maths.Abs(v.X), maths.Abs(v.Y)}
|
||||||
|
|
Loading…
Add table
Reference in a new issue