mirror of
https://github.com/Relintai/programming_tutorials.git
synced 2025-04-25 21:55:03 +02:00
417 lines
8.2 KiB
C++
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(¤t_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;
|
|
}
|