programming_tutorials/03_sdl_basics/wip/raycaster/main.cpp

417 lines
8.2 KiB
C++

#define SDL_MAIN_HANDLED
#ifdef _MSC_VER
#define SDL_MAIN_HANDLED
#include <SDL.h>
#else
#ifdef __ANDROID__
#include <SDL.h>
#else
#include <SDL2/SDL.h>
#endif
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include <math.h>
#include <chrono>
int target_fps = 60;
float target_fpsf = 1 / target_fps;
float _delta = 0;
bool running = true;
SDL_Window *window;
SDL_Renderer *renderer;
#define WINDOW_WIDTH 1200
#define WINDOW_HEIGHT 640
//----------------------MAP----------------------
#define mapX 8 // map width
#define mapY 8 // map height
#define mapS 64 // map cube size
int map[] = {
1, 1, 1, 1, 1, 1, 1, 1, //
1, 0, 0, 0, 0, 0, 0, 0, //
1, 0, 0, 0, 0, 1, 0, 1, //
1, 0, 0, 1, 0, 0, 1, 1, //
1, 0, 1, 0, 0, 0, 0, 1, //
1, 0, 0, 1, 0, 0, 0, 1, //
1, 0, 0, 0, 0, 0, 0, 1, //
1, 1, 1, 0, 1, 1, 1, 1, //
};
void drawMap2D() {
SDL_Rect colorBar;
colorBar.x = 0;
colorBar.y = 0;
colorBar.w = mapS;
colorBar.h = mapS;
int x, y;
for (y = 0; y < mapY; ++y) {
for (x = 0; x < mapX; ++x) {
if (map[y * mapX + x] == 1) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
} else {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
}
colorBar.x = x * mapS;
colorBar.y = y * mapS;
SDL_RenderFillRect(renderer, &colorBar);
}
}
}
//---------------------------------------------------------------------------
#define KEY_FORWARD SDL_SCANCODE_W
#define KEY_LEFT SDL_SCANCODE_A
#define KEY_RIGHT SDL_SCANCODE_D
#define KEY_BACK SDL_SCANCODE_S
#define KEY_INDEX_FORWARD 0
#define KEY_INDEX_LEFT 1
#define KEY_INDEX_RIGHT 2
#define KEY_INDEX_BACK 3
#define KEYS_MAX 4
bool keys[KEYS_MAX] = { false, false, false, false };
bool is_key_down(int index) {
return keys[index];
}
void handle_keydown(SDL_Scancode scancode) {
switch (scancode) {
case KEY_FORWARD:
keys[KEY_INDEX_FORWARD] = true;
break;
case KEY_LEFT:
keys[KEY_INDEX_LEFT] = true;
break;
case KEY_RIGHT:
keys[KEY_INDEX_RIGHT] = true;
break;
case KEY_BACK:
keys[KEY_INDEX_BACK] = true;
break;
}
}
void handle_keyup(SDL_Scancode scancode) {
switch (scancode) {
case KEY_FORWARD:
keys[KEY_INDEX_FORWARD] = false;
break;
case KEY_LEFT:
keys[KEY_INDEX_LEFT] = false;
break;
case KEY_RIGHT:
keys[KEY_INDEX_RIGHT] = false;
break;
case KEY_BACK:
keys[KEY_INDEX_BACK] = false;
break;
}
}
void handle_input(float delta) {
// handle input
SDL_Event current_event;
while (SDL_PollEvent(&current_event)) {
switch (current_event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
//if (current_event.key.repeat > 0)
// break;
handle_keydown(current_event.key.keysym.scancode);
break;
case SDL_KEYUP:
handle_keyup(current_event.key.keysym.scancode);
break;
}
}
}
//------------------------PLAYER------------------------------------------------
#define PLAYER_SPEED 100.0
#define PLAYER_TURNING_SPEED 180.0
float degToRad(int a) {
return a * M_PI / 180.0;
}
float FixAng(float a) {
if (a >= 360) {
a -= 360;
}
if (a < 0) {
a += 360;
}
return a;
}
float px = 150;
float py = 150;
float pa = 90;
float pdx = cos(degToRad(pa));
float pdy = -sin(degToRad(pa));
void drawPlayer2D() {
SDL_Rect colorBar;
colorBar.x = 0;
colorBar.y = 0;
colorBar.w = 10;
colorBar.h = 10;
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
colorBar.x = px - 5;
colorBar.y = py - 5;
SDL_RenderFillRect(renderer, &colorBar);
SDL_RenderDrawLine(renderer, px, py, px + pdx * 20, py + pdy * 20);
}
void update_player(float delta) {
if (is_key_down(KEY_INDEX_LEFT)) {
pa += PLAYER_TURNING_SPEED * delta;
pa = FixAng(pa);
pdx = cos(degToRad(pa));
pdy = -sin(degToRad(pa));
}
if (is_key_down(KEY_INDEX_RIGHT)) {
pa -= PLAYER_TURNING_SPEED * delta;
pa = FixAng(pa);
pdx = cos(degToRad(pa));
pdy = -sin(degToRad(pa));
}
if (is_key_down(KEY_INDEX_FORWARD)) {
px += pdx * PLAYER_SPEED * delta;
py += pdy * PLAYER_SPEED * delta;
}
if (is_key_down(KEY_INDEX_BACK)) {
px -= pdx * PLAYER_SPEED * delta;
py -= pdy * PLAYER_SPEED * delta;
}
} //-----------------------------------------------------------------------------
//---------------------------Draw Rays and Walls--------------------------------
float distance(float ax, float ay, float bx, float by, float ang) {
return cos(degToRad(ang)) * (bx - ax) - sin(degToRad(ang)) * (by - ay);
}
void drawRays2D() {
int r, mx, my, mp, dof, side;
float vx, vy, rx, ry, ra, xo, yo, disV, disH;
ra = FixAng(pa + 30); //ray set back 30 degrees
for (r = 0; r < 60; r++) {
//---Vertical---
dof = 0;
side = 0;
disV = 100000;
float Tan = tan(degToRad(ra));
if (cos(degToRad(ra)) > 0.001) {
rx = (((int)px >> 6) << 6) + 64;
ry = (px - rx) * Tan + py;
xo = 64;
yo = -xo * Tan;
} //looking left
else if (cos(degToRad(ra)) < -0.001) {
rx = (((int)px >> 6) << 6) - 0.0001;
ry = (px - rx) * Tan + py;
xo = -64;
yo = -xo * Tan;
} //looking right
else {
rx = px;
ry = py;
dof = 8;
} //looking up or down. no hit
while (dof < 8) {
mx = (int)(rx) >> 6;
my = (int)(ry) >> 6;
mp = my * mapX + mx;
if (mp > 0 && mp < mapX * mapY && map[mp] == 1) {
dof = 8;
disV = cos(degToRad(ra)) * (rx - px) - sin(degToRad(ra)) * (ry - py);
} //hit
else {
rx += xo;
ry += yo;
dof += 1;
} //check next horizontal
}
vx = rx;
vy = ry;
//---Horizontal---
dof = 0;
disH = 100000;
Tan = 1.0 / Tan;
if (sin(degToRad(ra)) > 0.001) {
ry = (((int)py >> 6) << 6) - 0.0001;
rx = (py - ry) * Tan + px;
yo = -64;
xo = -yo * Tan;
} //looking up
else if (sin(degToRad(ra)) < -0.001) {
ry = (((int)py >> 6) << 6) + 64;
rx = (py - ry) * Tan + px;
yo = 64;
xo = -yo * Tan;
} //looking down
else {
rx = px;
ry = py;
dof = 8;
} //looking straight left or right
while (dof < 8) {
mx = (int)(rx) >> 6;
my = (int)(ry) >> 6;
mp = my * mapX + mx;
if (mp > 0 && mp < mapX * mapY && map[mp] == 1) {
dof = 8;
disH = cos(degToRad(ra)) * (rx - px) - sin(degToRad(ra)) * (ry - py);
} //hit
else {
rx += xo;
ry += yo;
dof += 1;
} //check next horizontal
}
SDL_SetRenderDrawColor(renderer, 255, 200, 255, 255);
if (disV < disH) {
rx = vx;
ry = vy;
disH = disV;
SDL_SetRenderDrawColor(renderer, 255, 160, 255, 255);
} //horizontal hit first
SDL_RenderDrawLine(renderer, px, py, rx, ry);
int ca = FixAng(pa - ra);
disH = disH * cos(degToRad(ca)); //fix fisheye
int lineH = (mapS * 320) / (disH);
if (lineH > 320) {
lineH = 320;
} //line height and limit
int lineOff = 160 - (lineH >> 1); //line offset
SDL_RenderDrawLine(renderer,r * 8 + 530,lineOff, r * 8 + 530, lineOff + lineH);
ra = FixAng(ra - 1); //go to next ray
}
} //-----------------------------------------------------------------------------
void update(float delta) {
update_player(delta);
}
void render() {
// Clear the window with a black background
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
drawMap2D();
drawPlayer2D();
drawRays2D();
SDL_RenderPresent(renderer);
}
void iterate() {
std::chrono::high_resolution_clock::time_point start =
std::chrono::high_resolution_clock::now();
handle_input(_delta);
update(_delta);
render();
std::chrono::high_resolution_clock::time_point end =
std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
double t = elapsed_seconds.count();
double remaining = target_fpsf - t;
if (remaining > 0) {
Uint32 fms = static_cast<Uint32>(remaining * 1000.0);
_delta = target_fpsf;
SDL_Delay(fms);
} else {
_delta = t;
}
}
int main(int argc, char *argv[]) {
SDL_SetMainReady();
int error = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
if (error) {
SDL_Log("SDL_Init Error!: %s", SDL_GetError());
return 1;
}
error = SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT,
SDL_WINDOW_SHOWN, &window, &renderer);
if (error) {
SDL_Log("SDL_Init Error!: %s", SDL_GetError());
return 1;
}
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(iterate, 0, 1);
#else
while (running) {
iterate();
}
#endif
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
window = nullptr;
renderer = nullptr;
SDL_Quit();
return 0;
}