diff --git a/OneLoneCoder_CommandLineFPS.cpp b/OneLoneCoder_CommandLineFPS.cpp new file mode 100644 index 0000000..e1a799b --- /dev/null +++ b/OneLoneCoder_CommandLineFPS.cpp @@ -0,0 +1,265 @@ +/* + OneLoneCoder.com - Command Line First Person Shooter (FPS) Engine + "Why were games not done like this is 1990?" - @Javidx9 + + Disclaimer + ~~~~~~~~~~ + I don't care what you use this for. It's intended to be educational, and perhaps + to the oddly minded - a little bit of fun. Please hack this, change it and use it + in any way you see fit. BUT, you acknowledge that I am not responsible for anything + bad that happens as a result of your actions. However, if good stuff happens, I + would appreciate a shout out, or at least give the blog some publicity for me. + Cheers! + + Background + ~~~~~~~~~~ + Whilst waiting for TheMexicanRunner to start the finale of his NesMania project, + his Twitch stream had a counter counting down for a couple of hours until it started. + With some time on my hands, I thought it might be fun to see what the graphical + capabilities of the console are. Turns out, not very much, but hey, it's nice to think + Wolfenstein could have existed a few years earlier, and in just ~200 lines of code. + + IMPORTANT!!!! + ~~~~~~~~~~~~~ + READ ME BEFORE RUNNING!!! This program expects the console dimensions to be set to + 120 Columns by 40 Rows. I recommend a small font "Consolas" at size 16. You can do this + by running the program, and right clicking on the console title bar, and specifying + the properties. You can also choose to default to them in the future. + + Future Modifications + ~~~~~~~~~~~~~~~~~~~~ + 1) Shade block segments based on angle from player, i.e. less light reflected off + walls at side of player. Walls straight on are brightest. + 2) Find an interesting and optimised ray-tracing method. I'm sure one must exist + to more optimally search the map space + 3) Add bullets! + 4) Add bad guys! + + Author + ~~~~~~ + Twitter: @javidx9 + Blog: www.onelonecoder.com + + Video: + ~~~~~~ + xxxxxxx + + Last Updated: 27/02/2017 +*/ + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include + +int nScreenWidth = 120; // Console Screen Size X (columns) +int nScreenHeight = 40; // Console Screen Size Y (rows) +int nMapWidth = 16; // World Dimensions +int nMapHeight = 16; + +float fPlayerX = 14.7f; // Player Start Position +float fPlayerY = 5.09f; +float fPlayerA = 0.0f; // Player Start Rotation +float fFOV = 3.14159f / 4.0f; // Field of View +float fDepth = 16.0f; // Maximum rendering distance +float fSpeed = 5.0f; // Walking Speed + +int main() +{ + // Create Screen Buffer + wchar_t *screen = new wchar_t[nScreenWidth*nScreenHeight]; + HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); + SetConsoleActiveScreenBuffer(hConsole); + DWORD dwBytesWritten = 0; + + // Create Map of world space # = wall block, . = space + wstring map; + map += L"#########......."; + map += L"#..............."; + map += L"#.......########"; + map += L"#..............#"; + map += L"#......##......#"; + map += L"#......##......#"; + map += L"#..............#"; + map += L"###............#"; + map += L"##.............#"; + map += L"#......####..###"; + map += L"#......#.......#"; + map += L"#......#.......#"; + map += L"#..............#"; + map += L"#......#########"; + map += L"#..............#"; + map += L"################"; + + auto tp1 = chrono::system_clock::now(); + auto tp2 = chrono::system_clock::now(); + + while (1) + { + // We'll need time differential per frame to calculate modification + // to movement speeds, to ensure consistant movement, as ray-tracing + // is non-deterministic + tp2 = chrono::system_clock::now(); + chrono::duration elapsedTime = tp2 - tp1; + tp1 = tp2; + float fElapsedTime = elapsedTime.count(); + + + // Handle CCW Rotation + if (GetAsyncKeyState((unsigned short)'A') & 0x8000) + fPlayerA -= (fSpeed * 0.75f) * fElapsedTime; + + // Handle CW Rotation + if (GetAsyncKeyState((unsigned short)'D') & 0x8000) + fPlayerA += (fSpeed * 0.75f) * fElapsedTime; + + // Handle Forwards movement & collision + if (GetAsyncKeyState((unsigned short)'W') & 0x8000) + { + fPlayerX += sinf(fPlayerA) * fSpeed * fElapsedTime;; + fPlayerY += cosf(fPlayerA) * fSpeed * fElapsedTime;; + if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') + { + fPlayerX -= sinf(fPlayerA) * fSpeed * fElapsedTime;; + fPlayerY -= cosf(fPlayerA) * fSpeed * fElapsedTime;; + } + } + + // Handle backwards movement & collision + if (GetAsyncKeyState((unsigned short)'S') & 0x8000) + { + fPlayerX -= sinf(fPlayerA) * fSpeed * fElapsedTime;; + fPlayerY -= cosf(fPlayerA) * fSpeed * fElapsedTime;; + if (map.c_str()[(int)fPlayerX * nMapWidth + (int)fPlayerY] == '#') + { + fPlayerX += sinf(fPlayerA) * fSpeed * fElapsedTime;; + fPlayerY += cosf(fPlayerA) * fSpeed * fElapsedTime;; + } + } + + for (int x = 0; x < nScreenWidth; x++) + { + // For each column, calculate the projected ray angle into world space + float fRayAngle = (fPlayerA - fFOV/2.0f) + ((float)x / (float)nScreenWidth) * fFOV; + + // Find distance to wall + float fStepSize = 0.1f; // Increment size for ray casting, decrease to increase + float fDistanceToWall = 0.0f; // resolution + + bool bHitWall = false; // Set when ray hits wall block + bool bBoundary = false; // Set when ray hits boundary between two wall blocks + + float fEyeX = sinf(fRayAngle); // Unit vector for ray in player space + float fEyeY = cosf(fRayAngle); + + // Incrementally cast ray from player, along ray angle, testing for + // intersection with a block + while (!bHitWall && fDistanceToWall < fDepth) + { + fDistanceToWall += fStepSize; + int nTestX = (int)(fPlayerX + fEyeX * fDistanceToWall); + int nTestY = (int)(fPlayerY + fEyeY * fDistanceToWall); + + // Test if ray is out of bounds + if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight) + { + bHitWall = true; // Just set distance to maximum depth + fDistanceToWall = fDepth; + } + else + { + // Ray is inbounds so test to see if the ray cell is a wall block + if (map.c_str()[nTestX * nMapWidth + nTestY] == '#') + { + // Ray has hit wall + bHitWall = true; + + // To highlight tile boundaries, cast a ray from each corner + // of the tile, to the player. The more coincident this ray + // is to the rendering ray, the closer we are to a tile + // boundary, which we'll shade to add detail to the walls + vector> p; + + // Test each corner of hit tile, storing the distance from + // the player, and the calculated dot product of the two rays + for (int tx = 0; tx < 2; tx++) + for (int ty = 0; ty < 2; ty++) + { + // Angle of corner to eye + 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 Pairs from closest to farthest + sort(p.begin(), p.end(), [](const pair &left, const pair &right) {return left.first < right.first; }); + + // First two/three are closest (we will never see all four) + float fBound = 0.01; + 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; + } + } + } + + // Calculate distance to ceiling and floor + int nCeiling = (float)(nScreenHeight/2.0) - nScreenHeight / ((float)fDistanceToWall); + int nFloor = nScreenHeight - nCeiling; + + // Shader walls based on distance + short nShade = ' '; + if (fDistanceToWall <= fDepth / 4.0f) nShade = 0x2588; // Very close + else if (fDistanceToWall < fDepth / 3.0f) nShade = 0x2593; + else if (fDistanceToWall < fDepth / 2.0f) nShade = 0x2592; + else if (fDistanceToWall < fDepth) nShade = 0x2591; + else nShade = ' '; // Too far away + + if (bBoundary) nShade = ' '; // Black it out + + for (int y = 0; y < nScreenHeight; y++) + { + // Each Row + if(y <= nCeiling) + screen[y*nScreenWidth + x] = ' '; + else if(y > nCeiling && y <= nFloor) + screen[y*nScreenWidth + x] = nShade; + else // Floor + { + // Shade floor based on distance + float b = 1.0f - (((float)y -nScreenHeight/2.0f) / ((float)nScreenHeight / 2.0f)); + if (b < 0.25) nShade = '#'; + else if (b < 0.5) nShade = 'x'; + else if (b < 0.75) nShade = '.'; + else if (b < 0.9) nShade = '-'; + else nShade = ' '; + screen[y*nScreenWidth + x] = nShade; + } + } + } + + // Display Stats + swprintf_s(screen, 40, L"X=%3.2f, Y=%3.2f, A=%3.2f FPS=%3.2f ", fPlayerX, fPlayerY, fPlayerA, 1.0f/fElapsedTime); + + // Display Map + for (int nx = 0; nx < nMapWidth; nx++) + for (int ny = 0; ny < nMapWidth; ny++) + { + screen[(ny+1)*nScreenWidth + nx] = map[ny * nMapWidth + nx]; + } + screen[((int)fPlayerX+1) * nScreenWidth + (int)fPlayerY] = 'P'; + + // Display Frame + screen[nScreenWidth * nScreenHeight - 1] = '\0'; + WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten); + } + + return 0; +} \ No newline at end of file diff --git a/OneLoneCoder_LogitechG13Twitch.cpp b/OneLoneCoder_LogitechG13Twitch.cpp new file mode 100644 index 0000000..27b2e41 --- /dev/null +++ b/OneLoneCoder_LogitechG13Twitch.cpp @@ -0,0 +1,137 @@ +/* + OneLoneCoder.com - Program a Logitech Keyboard To Display Twitch Chat + "Put Your Money Where Your Mouth Is" - @Javidx9 + + Disclaimer + ~~~~~~~~~~ + I don't care what you use this for. It's intended to be educational, and perhaps + to the oddly minded - a little bit of fun. Please hack this, change it and use it + in any way you see fit. BUT, you acknowledge that I am not responsible for anything + bad that happens as a result of your actions. However, if good stuff happens, I + would appreciate a shout out, or at least give the blog some publicity for me. + Cheers! + + Background + ~~~~~~~~~~ + A very minimal example of using the Logitech SDK to interface with a keyboard display, + then uses a really sloppy implementation of sockets, to connect to a twitch chat + session, displaying the chat on the keybaord screen. + + Future Modifications + ~~~~~~~~~~~~~~~~~~~~ + 1) Wrap around text display on screen + + Author + ~~~~~~ + Twitter: @javidx9 + Blog: www.onelonecoder.com + + Video: + ~~~~~~ + https://youtu.be/8UXCo-GhiF0 + + Last Updated: 23/05/2017 +*/ + +#include +#include +using namespace std; + +// Include Winsock +#include +#include + +// Include Logitech library +#include "LogitechLCDLib.h" + +int main() +{ + // Load the driver + LogiLcdInit(L"OneLoneCoder Test", LOGI_LCD_TYPE_MONO); + + // Check hardware is connected + if (!LogiLcdIsConnected(LOGI_LCD_TYPE_MONO)) + wcout << "Hardware not found" << endl; + + // Load WinSock + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + wcout << "Could not start WinSock" << endl; + + // Get address to twitch server + struct addrinfo *addr = nullptr; + if (getaddrinfo("irc.chat.twitch.tv", "6667", nullptr, &addr) != 0) + wcout << "Failed to get address info" << endl; + + // Create socket + SOCKET sock = INVALID_SOCKET; + sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + + // Connect to server via socket + int i = connect(sock, addr->ai_addr, (int)addr->ai_addrlen); + if (i != SOCKET_ERROR) + { + // Handshake with twitch + string s; + + // Authenticate + s = "PASS oauth:###INSERT YOUR OAUTH HERE###\r\n"; + send(sock, s.c_str(), s.length(), 0); + + // Register your twitch name + s = "NICK javidx9\r\n"; + send(sock, s.c_str(), s.length(), 0); + + // Join a twitch chat + s = "JOIN #javidx9\r\n"; + send(sock, s.c_str(), s.length(), 0); + } + + char buffer[100]; + string s; + list sLines = { "","","","" }; + + while (1) + { + // Get Twitch Server Message + int i = recv(sock, buffer, 100, 0); + for (int j = 0; j < i; j++) + { + s.append(1, buffer[j]); + if (buffer[j] == '\n') + { + // User name is between first ':' and '!'. + // User chat is after second ':' + size_t m = s.find('!'); + string sUserName = s.substr(1, m - 1); + size_t n = s.find(':', m); + if (n != string::npos) + { + string chat = s.substr(n + 1); + cout << sUserName.c_str() << ": " << chat.c_str() << endl; + + sLines.pop_front(); + sLines.push_back(sUserName + ": " + chat); + } + s.clear(); + } + } + + // Display 4 lines of text from list + int p = 0; + for (auto k : sLines) + { + wstring ws; + ws.assign(k.begin(), k.end()); + LogiLcdMonoSetText(p, (wchar_t*)ws.c_str()); // yuck... + p++; + + } + + // Update display + LogiLcdUpdate(); + } + + LogiLcdShutdown(); + return 0; +} \ No newline at end of file diff --git a/OneLoneCoder_Tetris.cpp b/OneLoneCoder_Tetris.cpp index 677d07f..6b357a6 100644 --- a/OneLoneCoder_Tetris.cpp +++ b/OneLoneCoder_Tetris.cpp @@ -1,39 +1,39 @@ /* -OneLoneCoder.com - Command Line Tetris -"Put Your Money Where Your Mouth Is" - @Javidx9 - -Disclaimer -~~~~~~~~~~ -I don't care what you use this for. It's intended to be educational, and perhaps -to the oddly minded - a little bit of fun. Please hack this, change it and use it -in any way you see fit. BUT, you acknowledge that I am not responsible for anything -bad that happens as a result of your actions. However, if good stuff happens, I -would appreciate a shout out, or at least give the blog some publicity for me. -Cheers! - -Background -~~~~~~~~~~ -I made a video "8-Bits of advice for new programmers" (https://youtu.be/vVRCJ52g5m4) -and suggested that building a tetris clone instead of Dark Sould IV might be a better -approach to learning to code. Tetris is nice as it makes you think about algorithms. - -Controls are Arrow keys Left, Right & Down. Use Z to rotate the piece. -You score 25pts per tetronimo, and 2^(number of lines)*100 when you get lines. - -Future Modifications -~~~~~~~~~~~~~~~~~~~~ -1) Show next block and line counter - -Author -~~~~~~ -Twitter: @javidx9 -Blog: www.onelonecoder.com - -Video: -~~~~~~ -xxxxxxx - -Last Updated: 30/03/2017 + OneLoneCoder.com - Command Line Tetris + "Put Your Money Where Your Mouth Is" - @Javidx9 + + Disclaimer + ~~~~~~~~~~ + I don't care what you use this for. It's intended to be educational, and perhaps + to the oddly minded - a little bit of fun. Please hack this, change it and use it + in any way you see fit. BUT, you acknowledge that I am not responsible for anything + bad that happens as a result of your actions. However, if good stuff happens, I + would appreciate a shout out, or at least give the blog some publicity for me. + Cheers! + + Background + ~~~~~~~~~~ + I made a video "8-Bits of advice for new programmers" (https://youtu.be/vVRCJ52g5m4) + and suggested that building a tetris clone instead of Dark Sould IV might be a better + approach to learning to code. Tetris is nice as it makes you think about algorithms. + + Controls are Arrow keys Left, Right & Down. Use Z to rotate the piece. + You score 25pts per tetronimo, and 2^(number of lines)*100 when you get lines. + + Future Modifications + ~~~~~~~~~~~~~~~~~~~~ + 1) Show next block and line counter + + Author + ~~~~~~ + Twitter: @javidx9 + Blog: www.onelonecoder.com + + Video: + ~~~~~~ + https://youtu.be/8OK8_tHeCIA + + Last Updated: 30/03/2017 */ #include