#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace std::chrono; string init(string map){ map += "################"; map += "#..............#"; map += "#####......#####"; map += "#..............#"; map += "#..........#####"; map += "#..............#"; map += "#####......#####"; map += "#####......#####"; map += "#####......#####"; map += "#####......#####"; map += "#####......#####"; map += "#..............#"; map += "#..............#"; map += "#####......#####"; map += "#..............#"; map += "################"; return (map); } //#include char cInput[5]; string debugMsg; bool bGameLoop = true; int nScreenWidth; int nScreenHeight; string screen; float fPlayerX = 8.0f; float fPlayerY = 8.0f; float fPlayerA = 0.0f; float fElapsedTime; bool bMoveForward; bool bMoveBackwards; bool bTurnLeft; bool bTurnRight; void *keyListener(void *tid){ long id = (long) tid; initscr(); noecho(); //raw(); //cbreak(); //nodelay(stdscr, TRUE); //scrollok(stdscr, TRUE); //raw(); int c; while ((c = getch()) != ERR){ debugMsg = ""; debugMsg+=to_string(c); switch (c) { case 119: //w bMoveForward = true; break; case 97: //a bTurnLeft = true; break; case 115: //s bMoveBackwards = true; break; case 100: //d bTurnRight = true; break; default: break; } } endwin(); pthread_exit(NULL); } void writeStringToScreen(int x, int y, string text){ int s = (y*nScreenWidth)+x; for (int i = s; i < s+text.length(); i++){ screen[i] = text[i-s]; } } int main(){ ///I HAVE TO LOOK INTO THIS MORE struct termios ttystate; tcgetattr(STDIN_FILENO, &ttystate); ttystate.c_lflag &= (~ICANON & ~ECHO); //Not display character ttystate.c_cc[VMIN] = 1; tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); /// bool keyStates[1000] = {false}; int keyTimer[1000] = {0}; //cInput = {'a','b'}; //fputs("\e[?25h", stdout); //get cursor back /on signal abort ~ //setterm(1); pthread_t pThread[1]; pthread_create(&pThread[0], NULL, keyListener, 0); struct winsize size; ioctl(STDOUT_FILENO,TIOCGWINSZ,&size); nScreenWidth = size.ws_col; nScreenHeight = size.ws_row; int nFrameRate = 60; int nMapHeight = 16; int nMapWidth = 16; float fFOV = 3.14159 / 4.0; float fDepth = 16.0f; string map = init(map); system("kbdrate -d 250 -r 10"); using clock = steady_clock; auto tp1 = clock::now(); auto tp2 = clock::now(); fputs("\e[?25l", stdout); //remove cursor*/ float fSpeedFactor = 1.0f; /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// ////////BEGINDRAW///// /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// while(bGameLoop){ tp2 = clock::now(); duration elapsedTime = tp2 - tp1; tp1 = tp2; fElapsedTime = elapsedTime.count(); //dynamic terminal window size (on Window Resize) ioctl(STDOUT_FILENO,TIOCGWINSZ,&size); nScreenWidth = size.ws_col; nScreenHeight = size.ws_row; screen.clear(); screen.resize(nScreenWidth*nScreenHeight); cout << "\x1B[0;0H"; //reset cursor to 0,0 //fun part //this would be much better as class if(bMoveForward){ fPlayerX += fSpeedFactor*sinf(fPlayerA) * 5.0f * fElapsedTime; fPlayerY += fSpeedFactor*cosf(fPlayerA) * 5.0f * fElapsedTime; if(map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#') { fPlayerX -= fSpeedFactor*sinf(fPlayerA) * 5.0f * fElapsedTime; fPlayerY -= fSpeedFactor*cosf(fPlayerA) * 5.0f * fElapsedTime; } bMoveForward = false; } if(bMoveBackwards){ fPlayerX -= fSpeedFactor*sinf(fPlayerA) * 5.0f * fElapsedTime; fPlayerY -= fSpeedFactor*cosf(fPlayerA) * 5.0f * fElapsedTime; if(map[(int)fPlayerY * nMapWidth + (int)fPlayerX] == '#') { fPlayerX += fSpeedFactor*sinf(fPlayerA) * 5.0f * fElapsedTime; fPlayerY += fSpeedFactor*cosf(fPlayerA) * 5.0f * fElapsedTime; } bMoveBackwards = false; } if(bTurnLeft){ fPlayerA -= 0.15f; bTurnLeft = false; } if(bTurnRight){ fPlayerA += 0.15f; bTurnRight = false; } //shading part for (int x = 0; x < nScreenWidth; x++){ float fRayAngle = (fPlayerA - fFOV / 2.0f) + ((float)x / (float)nScreenWidth) * fFOV; float fDistanceToWall = 0; bool bHitWall = false; bool bBoundary = false; float fEyeX = sinf(fRayAngle); float fEyeY = cosf(fRayAngle); while(!bHitWall && fDistanceToWall < fDepth){ fDistanceToWall += 0.1f; int nTestX = (int)(fPlayerX + fEyeX * fDistanceToWall); int nTestY = (int)(fPlayerY + fEyeY * fDistanceToWall); if(nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight){ bHitWall = true; fDistanceToWall = fDepth; } else { if(map[nTestY * nMapWidth + nTestX] == '#') { bHitWall = true; vector> p; //distance, dot for (int tx = 0; tx < 2; tx++) for (int ty = 0; ty < 2; ty++) { float vy = (float)nTestY + ty - fPlayerY; float vx = (float)nTestX + tx - fPlayerX; float d = sqrt(vx*vx + vy*vy); float dot = (fEyeX * vx / d) + (fEyeY * vy / d); p.push_back(make_pair(d,dot)); } sort(p.begin(), p.end(), [](const pair &left, const pair &right) { return left.first < right.first; }); float fBound = 0.005; if (acos(p.at(0).second) < fBound) bBoundary = true; if (acos(p.at(1).second) < fBound) bBoundary = true; if (acos(p.at(2).second) < fBound) bBoundary = true; } } } int nCeiling = (float)(nScreenHeight / 2.0) - nScreenHeight / ((float)fDistanceToWall); int nFloor = nScreenHeight - nCeiling; short nShade = 32; for(int y = 0; y < nScreenHeight; y++){ if(y < nCeiling) screen[y*nScreenWidth+x] = ' '; if(y > nCeiling && y <= nFloor){ if (fDistanceToWall <= fDepth / 4.0f) nShade = 77; //very close else if (fDistanceToWall < fDepth / 3.5f) nShade = 72; else if (fDistanceToWall < fDepth / 3.0f) nShade = 84; else if (fDistanceToWall < fDepth / 2.5f) nShade = 73; else if (fDistanceToWall < fDepth / 2.0f) nShade = 105; else if (fDistanceToWall < fDepth / 1.5) nShade = 58; else if (fDistanceToWall < fDepth) nShade = 46; else nShade = 32; // too far if(bBoundary) nShade = '-'; screen[y*nScreenWidth+x] = nShade; } else { float b = 1.0f - (((float)y - nScreenHeight / 2.0f) / ((float)nScreenHeight / 2.0f)); if (b < 0.2) nShade = 32; //32 //very close else if (b < 0.4) nShade = 96; //96 else if (b < 0.7) nShade = 94; //94 else if (b < 0.75) nShade = 42; //42 else nShade = 32; //64 too far screen[y*nScreenWidth+x] = nShade; } } } //writeStringToScreen(0, 0, "Key pressed: " + to_string(123) + " Key code: " + to_string(cInput)); //writeStringToScreen(0, nScreenHeight-3, debugMsg); writeStringToScreen(0, nScreenHeight-2, "Frame rate: " + to_string(1.0f / fElapsedTime) + " "); writeStringToScreen(0, nScreenHeight-1, "Key pressed: " + debugMsg + " Angle: " + to_string(fPlayerA) + " X: " + to_string(fPlayerX) + " Y: " + to_string(fPlayerY) + " "); //string sInput(1, cInput[0]); cout << screen; //this is the renderer //cout << ; tp1 += milliseconds(1000 / nFrameRate); this_thread::sleep_until(tp1); } return 0; }