-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathray_tilemap_dda.go
More file actions
100 lines (85 loc) · 2.55 KB
/
ray_tilemap_dda.go
File metadata and controls
100 lines (85 loc) · 2.55 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
package coll
import (
"image"
"math"
"github.com/setanarut/v"
)
// RayTilemapDDA performs the DDA (Digital Differential Analysis) algorithm to find intersections with a tile map
//
// youtube.com/watch?v=NbSee-XM7WA
//
// Parameters:
// - pos: Starting position of the ray
// - dir: Direction unit vector of the ray (should be normalized)
// - mag: Maximum distance the ray can travel
// - tileMap: 2D grid of cells where any non-zero value represents a wall/obstacle
// - cellSize: Size of each tile in the grid
// - hit: Optional pointer to Hit struct (can be nil)
//
// Returns:
// - bool: True if a collision occurred
// - image.Point: The grid coordinates of the wall that was hit (0,0 if no hit)
func RayTilemapDDA(pos, dir v.Vec, mag float64, tileMap [][]uint8, cellSize float64, hit *Hit) (bool, image.Point) {
// Bitiş noktasını hesapla
end := pos.Add(dir.Scale(mag))
// DDA için delta değerlerini hesapla
delta := end.Sub(pos)
steps := int(max(math.Abs(delta.X), math.Abs(delta.Y)))
// Her adımdaki artış miktarı
var inc v.Vec
if steps != 0 {
inc = delta.Scale(1.0 / float64(steps))
}
// Başlangıç noktası
current := pos
// Her piksel için kontrol et
for i := 0; i <= steps; i++ {
// Grid hücresini bul
cell := image.Point{
X: int(current.X / cellSize),
Y: int(current.Y / cellSize),
}
// Sınırları kontrol et
if cell.X >= 0 && cell.X < len(tileMap[0]) && cell.Y >= 0 && cell.Y < len(tileMap) {
if tileMap[cell.Y][cell.X] != 0 {
// hit nil değilse bilgileri doldur
if hit != nil {
// Mesafe ve zaman (0..1) hesapla
distance := current.Sub(pos).Mag()
if mag > 0 {
hit.Data = distance / mag
} else {
hit.Data = 0
}
// Yüzey normalini hesapla
cellCenterX := float64(cell.X)*cellSize + cellSize/2
cellCenterY := float64(cell.Y)*cellSize + cellSize/2
diffX := math.Abs(current.X - cellCenterX)
diffY := math.Abs(current.Y - cellCenterY)
if diffX > diffY {
// X yüzeyine çarpış
hit.Normal = v.Vec{X: -math.Copysign(1, dir.X), Y: 0}
} else {
// Y yüzeyine çarpış
hit.Normal = v.Vec{X: 0, Y: -math.Copysign(1, dir.Y)}
}
}
// Return true and the cell coordinate
return true, cell
}
}
// Bir sonraki piksele geç
current = current.Add(inc)
}
// Çarpışma bulunamadı - hit nil değilse son durumu kaydet
if hit != nil {
hit.Normal = v.Vec{}
if mag > 0 {
hit.Data = 1.0
} else {
hit.Data = 0.0
}
}
// Return false and an empty point
return false, image.Point{}
}