-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDDA_Raycaster2D.cpp
More file actions
172 lines (133 loc) · 3.43 KB
/
DDA_Raycaster2D.cpp
File metadata and controls
172 lines (133 loc) · 3.43 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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include "../Include/defGameEngine.hpp"
class Raycasting : public def::GameEngine
{
public:
Raycasting()
{
GetWindow()->SetTitle("Raycasting");
}
virtual ~Raycasting()
{
delete[] map;
}
private:
def::Vector2i tileSize;
def::Vector2i tilesCount;
def::Vector2f start;
def::Vector2f end;
bool* map;
float pointSpeed = 100.0f;
protected:
void ControlPoint(def::Vector2f& point, const float deltaTime, const def::Key up, const def::Key down, const def::Key left, const def::Key right)
{
if (GetInput()->GetKeyState(up).held)
point.y -= pointSpeed * deltaTime;
if (GetInput()->GetKeyState(down).held)
point.y += pointSpeed * deltaTime;
if (GetInput()->GetKeyState(left).held)
point.x -= pointSpeed * deltaTime;
if (GetInput()->GetKeyState(right).held)
point.x += pointSpeed * deltaTime;
}
void SetTile(const def::Vector2i& pos, const bool value)
{
map[pos.y * tilesCount.x + pos.x] = value;
}
bool GetTile(const def::Vector2i& pos)
{
return map[pos.y * tilesCount.x + pos.x];
}
bool OnUserCreate() override
{
tileSize = { 8, 8 };
tilesCount = GetWindow()->GetScreenSize() / tileSize;
map = new bool[tilesCount.x * tilesCount.y] { false };
start = { 10, 10 };
end = { 20, 10 };
return true;
}
bool OnUserUpdate(float deltaTime) override
{
ControlPoint(start, deltaTime, def::Key::W, def::Key::S, def::Key::A, def::Key::D);
ControlPoint(end, deltaTime, def::Key::UP, def::Key::DOWN, def::Key::LEFT, def::Key::RIGHT);
if (GetInput()->GetButtonState(def::Button::RIGHT).pressed)
{
def::Vector2i tilePos = GetInput()->GetMousePosition() / tileSize;
SetTile(tilePos, !GetTile(tilePos));
}
// Perform DDA algorithm
// thank you, https://lodev.org/cgtutor/raycasting.html
def::Vector2f rayStart = start / tileSize;
def::Vector2f rayDirection = (end / tileSize - rayStart).Normalise();
def::Vector2f stepSize = (1.0f / rayDirection).Abs();
def::Vector2f side, step;
def::Vector2i mapPos = rayStart;
if (rayDirection.x < 0)
{
step.x = -1;
side.x = (rayStart.x - (float)mapPos.x) * stepSize.x;
}
else
{
step.x = 1;
side.x = (float(mapPos.x + 1) - rayStart.x) * stepSize.x;
}
if (rayDirection.y < 0)
{
step.y = -1;
side.y = (rayStart.y - (float)mapPos.y) * stepSize.y;
}
else
{
step.y = 1;
side.y = (float(mapPos.y + 1) - rayStart.y) * stepSize.y;
}
bool tileFound = false;
float distance = 0.0f;
float maxDistance = 64.0f;
while (!tileFound && distance < maxDistance)
{
if (side.x < side.y)
{
mapPos.x += step.x;
distance = side.x;
side.x += stepSize.x;
}
else
{
mapPos.y += step.y;
distance = side.y;
side.y += stepSize.y;
}
if (mapPos.x >= 0 && mapPos.y >= 0 && mapPos.x < tilesCount.x && mapPos.y < tilesCount.y)
{
if (GetTile(mapPos))
tileFound = true;
}
}
def::Vector2f intersectionPoint;
if (tileFound)
intersectionPoint = rayStart + rayDirection * distance;
Clear(def::BLACK);
def::Vector2i p;
for (; p.y < tilesCount.y; p.y++)
for (p.x = 0; p.x < tilesCount.x; p.x++)
{
if (GetTile(p))
FillRectangle(p * tileSize, tileSize, def::BLUE);
}
DrawLine(start, end, def::GREY);
if (tileFound)
DrawCircle(intersectionPoint * tileSize, 3, def::CYAN);
FillCircle(start, 3, def::RED);
FillCircle(end, 3, def::GREEN);
return true;
}
};
int main()
{
Raycasting demo;
if (demo.Construct(241, 241, 4, 4))
demo.Run();
return 0;
}