#include #include #include #include #include #include #include #include "textures/textures.ppm" #define SPEED 1.5 #define RADSPD 0.05 // #define DELAY 1 #define MAPX 16 #define MAPY 16 #define PI 3.1415926535 #define DEG 0.01745329 #define HEIGHT 512 #define WIDTH 960 #define TILESIZE 32 #define SQRTTILE 5 #define MAPSCALE 2 struct player { float x; float y; float dx; float dy; float th; }; float dist(float x1, float y1, float x2, float y2) { return ( sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)) ); } int processEvents(SDL_Window *window, struct player *P, int map[], int *mpbool, clock_t *prevframe) { // Вычисление FPS clock_t frame; float fps; frame = clock(); fps = CLOCKS_PER_SEC/(double)(frame - *prevframe); *prevframe = frame; printf("%d\r", (int)fps); int done = 0; SDL_Event event; int xoff = 0; if((P->dx)>0) {xoff = 20;} else {xoff = -20;} int yoff = 0; if((P->dy)>0) {yoff = 20;} else {yoff = -20;} int px64 = (int)(P->x) >> SQRTTILE; int py64 = (int)(P->y) >> SQRTTILE; int pxadd = (int)(P->x + xoff) >> SQRTTILE, pyadd = (int)(P->y + yoff) >> SQRTTILE; int pxsub = (int)(P->x - xoff) >> SQRTTILE, pysub = (int)(P->y - yoff) >> SQRTTILE; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_WINDOWEVENT_CLOSE: { if(window) { SDL_DestroyWindow(window); window = NULL; done = 1; } } break; case SDL_KEYDOWN: { switch(event.key.keysym.sym) { case SDLK_ESCAPE: done = 1; break; case SDLK_m: // карта *mpbool = !*mpbool; break; case SDLK_e: // взаимодействие if(map[pyadd*MAPX + pxadd] == 4) // дверь map[pyadd*MAPX + pxadd] = 0; } } break; case SDL_QUIT: done = 1; break; } } const Uint8 *state = SDL_GetKeyboardState(NULL); if(state[SDL_SCANCODE_A]) P->th -= RADSPD; if(state[SDL_SCANCODE_W]) { if(map[py64*MAPX + pxadd]==0) {P->x += P->dx;} if(map[pyadd*MAPX + px64]==0) {P->y += P->dy;} } if(state[SDL_SCANCODE_S]) { if(map[py64*MAPX + pxsub]==0) {P->x -= P->dx;} if(map[pysub*MAPX + px64]==0) {P->y -= P->dy;} } if(state[SDL_SCANCODE_D]) P->th += RADSPD; if(P->th < 0) P->th = 2*PI - 0.00001; if(P->th > 2*PI) P->th = 0.0; P->dx = cos(P->th)*(75/fps); P->dy = sin(P->th)*(75/fps); return done; } void drawLevel(SDL_Renderer *renderer, int map[], struct player P) { for(int y = 0; y 0) { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 128); } else { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 128); } SDL_Rect wall = {x*TILESIZE/MAPSCALE, y*TILESIZE/MAPSCALE, TILESIZE/MAPSCALE-2, TILESIZE/MAPSCALE-2}; SDL_RenderFillRect(renderer, &wall); } } void drawPlayer(SDL_Renderer *renderer, struct player P) { SDL_Vertex arrow[3]; arrow[0].position.x = (P.x+7*cos(P.th-PI/2))/MAPSCALE; arrow[0].position.y = (P.y+7*sin(P.th-PI/2))/MAPSCALE; arrow[0].color.r = 255; arrow[0].color.g = 220; arrow[0].color.b = 0; arrow[0].color.a = 128; arrow[1].position.x = (P.x+7*cos(P.th+PI/2))/MAPSCALE; arrow[1].position.y = (P.y+7*sin(P.th+PI/2))/MAPSCALE; arrow[1].color.r = 255; arrow[1].color.g = 220; arrow[1].color.b = 0; arrow[1].color.a = 128; arrow[2].position.x = (P.x+20*cos(P.th))/MAPSCALE; arrow[2].position.y = (P.y+20*sin(P.th))/MAPSCALE; arrow[2].color.r = 255; arrow[2].color.g = 220; arrow[2].color.b = 0; arrow[2].color.a = 128; SDL_RenderGeometry(renderer, NULL, arrow, 3, NULL, 0); } void drawRays(SDL_Renderer *renderer, struct player P, int map[], int mapF[], int mapC[]) { int mx, my, mp, dof, texture_iv, texture_ih, texture_i; float rx, ry, ra, xo, yo, px, py, hlen, vlen, sinra, hx, hy, vx, vy, rdist; ra=P.th-30*DEG; if(ra<0) ra += 2*PI; if(ra>2*PI) ra -= 2*PI; px = P.x; py = P.y; float antan; for(int r = 0; r<240; r++) { // ----- по горизонтальным ----- hlen = 100000; dof = 0; sinra = sin(ra); if(sinra<-0.001) // "вверх" { antan=-1.0/tan(ra); ry = (((int)py>>SQRTTILE)<0.001) { antan=-1.0/tan(ra); ry = (((int)py>>SQRTTILE)<>SQRTTILE; my = (int)(ry)>>SQRTTILE; mp = my*MAPX+mx; if(mp > 0 && mp < MAPX*MAPY && map[mp]>0){ hx = rx; hy = ry; hlen = dist(px, py, hx, hy); texture_ih = map[mp]-1; dof = 16; } else { rx += xo; ry += yo; dof++; } } // ----- по вертикальным ----- dof = 0; vlen = 100000; float cosra = cos(ra); if(cosra<-0.001) // "влево" { antan=-tan(ra); rx = (((int)px>>SQRTTILE)<0.001) { antan=-tan(ra); rx = (((int)px>>SQRTTILE)<>SQRTTILE; my = (int)(ry)>>SQRTTILE; mp = my*MAPX+mx; if(mp > 0 && mp < MAPX*MAPY && map[mp]>0){ vx = rx; vy = ry; vlen = dist(px, py, vx, vy); texture_iv = map[mp]-1; dof = 16; } else { rx += xo; ry += yo; dof++; } } float shade = 1; if(vlen < hlen) { rx = vx; ry = vy; rdist = vlen; texture_i = texture_iv; } else { rx = hx; ry = hy; rdist = hlen; shade = 0.6; texture_i = texture_ih; } // ----- Рисуем стены ----- float corran = P.th - ra; if(corran<0) corran += 2*PI; if(corran>2*PI) corran -= 2*PI; rdist *= cos(corran); // рыбий глаз float lineh = (TILESIZE*HEIGHT)/rdist; float ty_step = 32.0 / lineh; float ty_offset = 0; if(lineh>HEIGHT){ ty_offset = (lineh-HEIGHT)/2.0; lineh=HEIGHT; } float lineo = HEIGHT/2 - lineh/2; float ty = ty_offset*ty_step; // Текстурирование float tx; if(vlen > hlen) { tx = (int)(rx/(TILESIZE/32)) % 32; if(ra < 180*DEG) {tx = 31-tx;} } else { tx = (int)(ry/(TILESIZE/32)) % 32; if(ra>90*DEG && ra < 270*DEG) {tx = 31-tx;} } /*int y; for(y = 0; y2*PI) ra -= 2*PI; } } void Render(SDL_Renderer *renderer, int map[], int mapF[], int mapC[], struct player P, int *mpbool) { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // фон SDL_RenderClear(renderer); drawRays(renderer, P, map, mapF, mapC); if(*mpbool) { drawLevel(renderer, map, P); drawPlayer(renderer, P); } SDL_RenderPresent(renderer); // SDL_Delay(DELAY); } int main(void) { SDL_Window *window; SDL_Renderer *renderer; SDL_Init(SDL_INIT_VIDEO); window = SDL_CreateWindow("Raycast", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, 0); renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); struct player P = {50, 50, 0, 0, PI/2}; clock_t prevframe = clock(); clock_t *pnt_pframe = &prevframe; int layoutW[MAPX*MAPY] = { /* 10 12 14 */ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,//0 3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,3,//1 3,0,0,3,3,0,3,0,0,3,0,0,3,0,0,3,//2 3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,3,//3 3,0,0,3,3,0,3,0,0,3,0,0,3,0,0,3,//4 3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,3,//5 3,0,0,3,3,3,3,3,3,3,3,3,3,0,0,3,//6 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,//7 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,//8 3,3,4,3,3,0,2,0,2,0,2,0,2,0,0,3,//9 3,0,0,0,3,3,3,3,3,4,3,3,3,0,0,3,//10 3,3,0,3,3,0,0,0,0,0,0,3,3,0,0,3,//11 3,0,0,0,3,0,3,3,3,3,0,3,3,0,0,3,//12 3,3,0,3,3,0,3,3,3,3,3,3,3,0,0,3,//13 3,0,0,0,3,0,0,0,0,0,0,0,4,0,0,3,//14 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,//15 /*0,1,2,3,4,5,6,7,8,9, 11 13 15*/ }; int layoutF[MAPX*MAPY] = { /* 10 12 14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//0 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//1 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//2 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//3 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//4 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//5 0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,//6 1,1,1,0,0,0,0,0,0,0,0,0,0,2,2,2,//7 1,1,1,0,0,0,0,0,0,0,0,0,0,2,2,2,//8 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//9 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//10 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//11 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//12 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//13 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//14 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//15 /*0,1,2,3,4,5,6,7,8,9, 11 13 15*/ }; int layoutC[MAPX*MAPY] = { /* 10 12 14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//0 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//1 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//2 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//3 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//4 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//5 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//6 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//7 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//8 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//9 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//10 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//11 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//12 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//13 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//14 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,//15 /*0,1,2,3,4,5,6,7,8,9, 11 13 15*/ }; int done = 0; // bool завершения программы int mpbool = 0; // bool вкл/выкл карты while(!done) { // проверка событий if(processEvents(window, &P, layoutW, &mpbool, pnt_pframe) == 1) done = 1; //rendering Render(renderer, layoutW, layoutF, layoutC, P, &mpbool); } SDL_DestroyWindow(window); SDL_DestroyRenderer(renderer); SDL_Quit(); printf("!%d!", errno); return 0; }