-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrid_rect.go
More file actions
executable file
·105 lines (86 loc) · 3.24 KB
/
Copy pathgrid_rect.go
File metadata and controls
executable file
·105 lines (86 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package grid
import (
"math"
geom "github.com/gravitton/geometry"
"github.com/gravitton/geometry/types/floats"
"github.com/gravitton/geometry/types/ints"
)
// NewRectGrid constructs a new rectangular grid with 4-directional (cardinal) movement.
// Pass RectGridOpts.DiagonalMovement() to enable 8-directional movement.
func NewRectGrid[T any](grid ints.Size, size floats.Size, opts ...RectGridOption) *Grid[T] {
return newRectGrid[T](grid, size, SquareFlat, opts)
}
// NewIsometricRectGrid constructs a new isometric (diamond-projection) grid with 4-directional movement.
// Pass RectGridOpts.DiagonalMovement() to enable 8-directional movement.
func NewIsometricRectGrid[T any](grid ints.Size, size floats.Size, opts ...RectGridOption) *Grid[T] {
return newRectGrid[T](grid, size, SquareIsometric, opts)
}
// RectCellSize returns the cell size for NewRectGrid where each tile is exactly
// width pixels wide and width pixels tall (1:1 ratio).
func RectCellSize(width float64) floats.Size {
return geom.SzU(width)
}
// IsometricRectCellSize returns the cell size for NewIsometricRectGrid where each
// diamond tile is width pixels wide at a geometrically accurate 30° isometric angle
// (height = width·tan30° ≈ width·0.577).
// For a pixel-art-friendly 2:1 ratio use IsometricPixelPerfectRectCellSize.
func IsometricRectCellSize(width float64) floats.Size {
return floats.Sz(width, width*math.Tan(geom.ToRadians(30)))
}
// IsometricPixelPerfectRectCellSize returns the cell size for NewIsometricRectGrid
// where each diamond tile is width pixels wide and width/2 pixels tall (2:1 ratio).
// The 2:1 ratio is the classic pixel-art isometric convention — tile edges land on
// exact pixel boundaries for crisp rendering.
// For a geometrically accurate 30° angle use IsometricRectCellSize.
func IsometricPixelPerfectRectCellSize(width float64) floats.Size {
return floats.Sz(width, width*0.5)
}
func newRectGrid[T any](grid ints.Size, size floats.Size, transform *Transform, opts []RectGridOption) *Grid[T] {
o := applyRectGridOptions(opts)
system := o.movement
offsets := system.Offsets()
layout := NewLayout(transform,
LayoutOpts.Size(grid),
LayoutOpts.CellSize(size),
).AlignTopLeft()
return NewGrid[T](
layout,
func(from, to ints.Point) int {
return system.DistanceTo(from, to)
},
func(index ints.Point, n int, valid ValidIndexFunc) []ints.Point {
p := Pt(index.XY())
candidates := p.Range(n)
var blocking []ints.Point
for _, i := range candidates {
if !valid(i) {
blocking = append(blocking, i)
}
}
return p.FieldOfView(candidates, blocking)
},
func(index ints.Point) []ints.Vector {
return offsets
},
)
}
// RectGridOption configures a rectangular grid constructor.
type RectGridOption func(*rectGridOptions)
type rectGridOptions struct {
movement System
}
// RectGridOpts is the namespace for rectangular grid options.
var RectGridOpts rectGridOptions
// DiagonalMovement returns an option that enables 8-directional (Chebyshev) movement.
func (o rectGridOptions) DiagonalMovement() RectGridOption {
return func(o *rectGridOptions) {
o.movement = Diagonal
}
}
func applyRectGridOptions(opts []RectGridOption) *rectGridOptions {
o := &rectGridOptions{}
for _, opt := range opts {
opt(o)
}
return o
}