-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcalculateScreen.c
More file actions
244 lines (218 loc) · 7.72 KB
/
calculateScreen.c
File metadata and controls
244 lines (218 loc) · 7.72 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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
* This file contains functions to calculate the screen.
* Using information from the game logic it will know where
* and how to draw the walls
*/
// display constants
#define DISPLAY_HEIGHT 32 // screen pixels
#define DISPLAY_WIDTH 128 // screen pixels
#define BYTE_SIZE 8
// math constants
#define PI 3.1415926535
#define P2 PI/2
#define P3 3*PI/2
#define DR 0.01745329251
#include <stdio.h>
//#include <string.h>
#include "screen.h"
#include "math.h"
/* Draw a vertical line with specified height and opacity
* @param display: the display on which the line will be drawn
* @param col: the column on which the line will be drawn
* @param distance: distance to the wall
* @param opacity: opacity of the line (0-1)
*/
void drawLine(char display[4][DISPLAY_WIDTH], int col, float distance, float opacity) {
int i;
// clear column
for (i = 0; i < 4; i++) {
display[i][col] = 0;
}
// calculate the height of the line
// map distance (can be 0-128) to 1-0
float height = 1 - distance/64;
if (height < 0) {
height = 0;
}
// map height to 0-30
height = (int)(height * 30);
int dither = 1/opacity;
int top = (DISPLAY_HEIGHT - height)/2;
int bot = (DISPLAY_HEIGHT + height)/2;
// writes from the top to the bottom
for (i = top; i < bot; i++) {
if (i % dither == 0) {
// calculate the index of the character in the display
// (4 characters per line, 128 lines)
// get the chunk index and bit index of that column
int char_index = i / BYTE_SIZE;
int bit_index = i % BYTE_SIZE;
// set the bit
display[char_index][col] |= 1 << bit_index;
}
}
}
/* Raytrace the walls based on the player position and orientation
* @param playerDirection: pointer to the player's direction
* @param playerPosX: pointer to the player's x position
* @param playerPosY: pointer to the player's y position
* @param map: pointer to the map
* @param mapSize: size of the map
*/
void castRay(float* playerDirection, int* playerPosX, int* playerPosY, int map[], int mapSize, char display[4][DISPLAY_WIDTH]) {
// Cast a ray from the player position to the edge of the screen
// Calculate the distance to the wall
// Calculate the opacity of the wall
// Draw the wall
int r, mx, my, mp, dof;
float rayX, rayY, rayDirection, xo, yo, disT;
rayDirection = *playerDirection - DR * DISPLAY_WIDTH/2;
if (rayDirection < 0) {
rayDirection += 2*PI;
}
if (rayDirection > 2*PI) {
rayDirection -= 2*PI;
}
for (r = 0; r < DISPLAY_WIDTH; r++) {
// Check horizontal lines
dof = 0;
float disH=1000000, hx=*playerPosX, hy=*playerPosY;
float aTan = -1/tan(rayDirection);
if (rayDirection > PI) {
rayY = (((int)*playerPosY >> 6) << 6) - 0.0001;
rayX = ((*playerPosY - rayY) * aTan) + *playerPosX;
yo = -64;
xo = -yo * aTan;
}
if (rayDirection < PI) {
rayY = (((int)*playerPosY >> 6) << 6) + 64;
rayX = ((*playerPosY - rayY) * aTan) + *playerPosX;
yo = 64;
xo = -yo * aTan;
}
if (rayDirection == 0 || rayDirection == PI) {
rayX = *playerPosX;
rayY = *playerPosY;
dof = 8;
}
// currently stuck in infinite loop, need to fix
while(dof < 8) {
mx = (int)(rayX) >> 6;
my = (int)(rayY) >> 6;
mp = (my * mapSize) + mx;
if (mp > 0 && mp < mapSize * mapSize && map[mp] != 0) {
// hit wall
// Calculate distance to wall
disH = sqrt(pow((rayX - *playerPosX), 2) + pow((rayY - *playerPosY), 2));
dof = 8;
} else {
// next line
rayX += xo;
rayY += yo;
dof += 1;
}
}
// Check vertical lines
dof = 0;
float disV=1000000, vx=*playerPosX, vy=*playerPosY;
float nTan = -tan(rayDirection);
if (rayDirection > P2 && rayDirection < P3) {
rayX = (((int)*playerPosX >> 6) << 6) - 0.0001;
rayY = ((*playerPosX - rayX) * nTan) + *playerPosY;
xo = -64;
yo = -xo * nTan;
}
if (rayDirection < P2 || rayDirection > P3) {
rayX = (((int)*playerPosX >> 6) << 6) + 64;
rayY = ((*playerPosX - rayX) * nTan) + *playerPosY;
xo = 64;
yo = -xo * nTan;
}
if (rayDirection == 0 || rayDirection == PI) {
rayX = *playerPosX;
rayY = *playerPosY;
dof = 8;
}
while (dof < 8) {
mx = (int)(rayX) >> 6;
my = (int)(rayY) >> 6;
mp = (my * mapSize) + mx;
if (mp > 0 && mp < mapSize * mapSize && map[mp] != 0) {
// hit wall
// Calculate distance to wall
disV = sqrt(pow((rayX - *playerPosX), 2) + pow((rayY - *playerPosY), 2));
dof = 8;
} else {
// next line
rayX += xo;
rayY += yo;
dof += 1;
}
}
if(disV < disH) {rayX=vx; rayY=vy; disT=disV;}//side=0;}
if(disH < disV) {rayX=hx; rayY=hy; disT=disH;}//side=1;}
float ca = *playerDirection - rayDirection;
if (ca < 0) {
ca += 2*PI;
}
if (ca > 2*PI) {
ca -= 2*PI;
}
//disT = disT * cos(ca); // fix fishbowl effect
// Draw one line of the wall
drawLine(display, r, disT, 1);
rayDirection += DR;
if (rayDirection < 0) {
rayDirection += 2*PI;
}
if (rayDirection > 2*PI) {
rayDirection -= 2*PI;
}
}
}
/* Move the player in the directino they are facing
* @param playerDirection: pointer to the player's direction
* @param playerPosX: pointer to the player's x position
* @param playerPosY: pointer to the player's y position
* @param map: pointer to the map
* @param mapSize: size of the map
*/
void movePlayer(float* playerDirection, int* playerPosX, int* playerPosY, int map[], int mapSize) {
// determine the player movement based on the direction
float moveX = cos(*playerDirection) + 0.5; // roundabout way of rounding to the nearest integer
float moveY = sin(*playerDirection) + 0.5;
// check for collisions
if (map[((int)(*playerPosY + moveY) * mapSize) + (int)(*playerPosX + moveX)] == 0) {
*playerPosX += moveX;
*playerPosY += moveY;
}
}
// used to test the code, final version will be in main.c
// int main() {
// char display[4][DISPLAY_WIDTH];
// memset(display, 0, sizeof(display));
// int map[] = {
// 1, 1, 1, 1, 1, 1, 1, 1,
// 1, 0, 1, 0, 0, 0, 0, 1,
// 1, 0, 1, 0, 1, 0, 0, 1,
// 1, 0, 1, 1, 1, 0, 0, 1,
// 1, 0, 0, 0, 0, 0, 0, 1,
// 1, 0, 0, 0, 0, 1, 0, 1,
// 1, 0, 0, 0, 0, 0, 0, 1,
// 1, 1, 1, 1, 1, 1, 1, 1
// };
// int playerPosX = 54, playerPosY = 54;
// float playerDirection = 0;
// // Test: distance can't be more than DISPLAY_HEIGHT
// // In the future, display will be a 2D array and only one column will be passed through
// castRay(&playerDirection, &playerPosX, &playerPosY, map, 8, display);
// // print the display
// // 4 characters per line, 128 lines
// for (int i = 0; i < DISPLAY_HEIGHT; i++) {
// for (int j = 0; j < 4; j++) {
// printf("%c", display[j][i]);
// }
// printf("\n");
// }
// return 0;
// }