golang实现2D网格的射线投射、阴影投射和路径查找插件库grid的使用
Golang实现2D网格的射线投射、阴影投射和路径查找插件库grid的使用
功能特性
- DDA射线投射
- A-Star路径查找
- 基于射线的视线检测
- 递归阴影投射
- Dijkstra地图
- Bresenham直线算法
- 100%测试覆盖率
基本使用
值类型示例
import (
"image"
"github.com/s0rg/grid"
)
const mapW, mapH = 100, 100
func valueExample() {
// 使用值类型很简单
g := grid.New[int](image.Rect(0, 0, mapW, mapH))
// 现在网格填充了该类型的零值
// 你可以用其他值重新填充它:
g.Fill(func() int {
return 1
})
}
指针类型示例
func pointerExample() {
// 使用指针类型类似,但需要预先填充
type mycell struct {}
g := grid.New[*mycell](image.Rect(0, 0, mapW, mapH))
// 现在网格填充了nil,所以需要预先填充一些值
// 否则通过Get/MustGet方法访问的将是nil
g.Fill(func() *mycell {
return &mycell{}
})
}
使用示例
func usageExample() {
type mycell struct {
wall bool
}
g := grid.New[*mycell](image.Rect(0, 0, mapW, mapH))
g.Fill(func() *mycell {
return &mycell{}
})
pt := image.Pt(10, 10)
// 设置新值
g.Set(pt, &mycell{wall: true})
// 更新现有值
if v, ok := g.Get(pt); ok {
v.wall = false
}
// 简写形式,如果越界访问会panic
g.MustGet(pt).wall = true
// 遍历所有单元格
g.Iter(func(p image.Point, c *mycell) (next bool) {
if c.wall {
// 找到墙
}
return true
})
}
完整示例
package main
import (
"fmt"
"image"
"log"
"github.com/s0rg/grid"
)
type cell struct {
wall bool
}
func main() {
// 创建100x100的网格
g := grid.New[*cell](image.Rect(0, 0, 100, 100))
// 填充初始单元格
g.Fill(func() *cell {
return &cell{}
})
// 设置一些墙
for x := 20; x < 80; x++ {
g.Set(image.Pt(x, 20), &cell{wall: true})
g.Set(image.Pt(x, 80), &cell{wall: true})
}
for y := 20; y < 80; y++ {
g.Set(image.Pt(20, y), &cell{wall: true})
g.Set(image.Pt(80, y), &cell{wall: true})
}
// 起点和终点
start := image.Pt(10, 10)
end := image.Pt(90, 90)
// 使用A*算法查找路径
path, ok := g.Path(
start,
end,
func(p image.Point) bool {
// 检查点是否可通行
c, ok := g.Get(p)
return ok && !c.wall
},
grid.Diagonal,
)
if !ok {
log.Fatal("no path found")
}
// 打印路径
fmt.Println("Path from", start, "to", end)
for _, p := range path {
fmt.Println(p)
}
// 视线检测
visible := g.LineOfSight(
start,
end,
func(p image.Point) bool {
c, ok := g.Get(p)
return ok && !c.wall
},
)
fmt.Println("Is visible:", visible)
// 阴影投射
var visibleCells []image.Point
g.CastShadow(
start,
10, // 半径
func(p image.Point) bool {
c, ok := g.Get(p)
return ok && !c.wall
},
func(p image.Point) {
visibleCells = append(visibleCells, p)
},
)
fmt.Println("Visible cells count:", len(visibleCells))
}
性能基准
运行基准测试:
make bench
测试结果示例:
goos: linux
goarch: amd64
pkg: github.com/s0rg/grid
cpu: AMD Ryzen 5 5500U with Radeon Graphics
BenchmarkGrid/Set-12 1000000000 0.8108 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/Get-12 641611768 1.764 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/Neighbours-12 52243890 23.41 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/LineBresenham-12 4416172 269.0 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/CastRay-12 3829839 321.1 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/CastShadow-12 32648 36950 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/LineOfSight-12 9897 114576 ns/op 0 B/op 0 allocs/op
BenchmarkGrid/DijkstraMap-12 1029 1190195 ns/op 20656 B/op 3 allocs/op
BenchmarkGrid/Path-12 372 3225325 ns/op 997588 B/op 13643 allocs/op
PASS
ok github.com/s0rg/grid 12.098s
更多关于golang实现2D网格的射线投射、阴影投射和路径查找插件库grid的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现2D网格的射线投射、阴影投射和路径查找插件库grid的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 2D网格处理库 grid 使用指南
grid 是一个用于处理2D网格的Go语言库,提供了射线投射(ray casting)、阴影投射(shadow casting)和路径查找(path finding)等功能。下面我将详细介绍如何使用这个库。
安装
go get github.com/sidav/grid
基本概念
grid 库主要围绕 Grid
类型工作,它代表一个2D网格。网格中的每个单元格可以包含任意值。
初始化网格
package main
import (
"fmt"
"github.com/sidav/grid"
)
func main() {
// 创建一个10x10的网格,默认值为0
g := grid.NewGrid(10, 10)
// 设置单元格值
g.SetCell(3, 4, 1) // 将(3,4)位置的值设为1
// 获取单元格值
val := g.GetCell(3, 4)
fmt.Println("Value at (3,4):", val)
}
射线投射(Ray Casting)
射线投射用于检测从起点到终点之间的直线路径是否被阻挡。
func rayCastingExample(g *grid.Grid) {
// 定义障碍物检查函数
isObstacle := func(x, y int) bool {
return g.GetCell(x, y) == 1 // 假设1表示障碍物
}
// 从(1,1)到(8,8)投射射线
visible := grid.RayTrace(1, 1, 8, 8, isObstacle)
if visible {
fmt.Println("路径畅通")
} else {
fmt.Println("路径被阻挡")
}
// 获取射线经过的所有点
points := grid.GetRay(1, 1, 8, 8)
fmt.Println("射线经过的点:", points)
}
阴影投射(Shadow Casting)
阴影投射用于计算从某个点出发的视野范围。
func shadowCastingExample(g *grid.Grid) {
// 定义视野范围回调函数
visitFunc := func(x, y, dx, dy int) bool {
fmt.Printf("可见点: (%d,%d)\n", x, y)
// 返回true表示继续传播视野,false表示停止
return g.GetCell(x, y) != 1 // 遇到障碍物停止
}
// 从(5,5)点开始,半径7的视野
grid.ShadowCast(5, 5, 7, visitFunc)
}
路径查找(Path Finding)
grid 库提供了A*算法实现路径查找。
func pathFindingExample(g *grid.Grid) {
// 定义移动成本函数
costFunc := func(fromX, fromY, toX, toY int) int {
if g.GetCell(toX, toY) == 1 { // 障碍物
return -1 // 不可通过
}
return 1 // 普通移动成本
}
// 查找从(1,1)到(8,8)的路径
path := grid.FindPath(g, 1, 1, 8, 8, costFunc)
if path == nil {
fmt.Println("找不到路径")
} else {
fmt.Println("找到路径:", path)
}
}
完整示例
package main
import (
"fmt"
"github.com/sidav/grid"
)
func main() {
// 创建20x20的网格
g := grid.NewGrid(20, 20)
// 添加一些障碍物
for i := 5; i < 15; i++ {
g.SetCell(i, 10, 1)
}
// 射线投射测试
fmt.Println("--- 射线投射测试 ---")
rayCastingExample(g)
// 阴影投射测试
fmt.Println("\n--- 阴影投射测试 ---")
shadowCastingExample(g)
// 路径查找测试
fmt.Println("\n--- 路径查找测试 ---")
pathFindingExample(g)
}
func rayCastingExample(g *grid.Grid) {
isObstacle := func(x, y int) bool {
return g.GetCell(x, y) == 1
}
visible := grid.RayTrace(2, 2, 18, 18, isObstacle)
fmt.Println("从(2,2)到(18,18)是否可见:", visible)
}
func shadowCastingExample(g *grid.Grid) {
visitFunc := func(x, y, dx, dy int) bool {
fmt.Printf("(%d,%d) ", x, y)
return g.GetCell(x, y) != 1
}
fmt.Println("从(10,5)的视野范围:")
grid.ShadowCast(10, 5, 5, visitFunc)
fmt.Println()
}
func pathFindingExample(g *grid.Grid) {
costFunc := func(fromX, fromY, toX, toY int) int {
if g.GetCell(toX, toY) == 1 {
return -1
}
return 1
}
path := grid.FindPath(g, 2, 2, 18, 18, costFunc)
if path == nil {
fmt.Println("找不到从(2,2)到(18,18)的路径")
} else {
fmt.Println("找到路径:")
for _, p := range path {
fmt.Printf("(%d,%d) ", p.X, p.Y)
}
fmt.Println()
}
}
高级功能
- 自定义距离计算:
// 使用曼哈顿距离
distanceFunc := grid.ManhattanDistance
grid.SetDistanceFunction(distanceFunc)
- 网格操作:
// 复制网格
g2 := g.Clone()
// 调整网格大小
g.Resize(30, 30)
// 遍历所有单元格
g.ForEachCell(func(x, y int, value interface{}) {
fmt.Printf("(%d,%d)=%v ", x, y, value)
})
grid 库提供了强大的2D网格处理能力,适用于游戏开发、地图处理、AI寻路等多种场景。通过合理使用射线投射、阴影投射和路径查找功能,可以实现复杂的空间分析和移动逻辑。