From f43d6b5351c7ad8efd4ca6a0816c5122c29b181a Mon Sep 17 00:00:00 2001 From: Syndamia Date: Mon, 25 Apr 2022 15:16:14 +0300 Subject: Added a 3d console game thingy I made today --- C++/3D-Console-Game.cpp | 198 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 C++/3D-Console-Game.cpp (limited to 'C++') diff --git a/C++/3D-Console-Game.cpp b/C++/3D-Console-Game.cpp new file mode 100644 index 0000000..d98cb32 --- /dev/null +++ b/C++/3D-Console-Game.cpp @@ -0,0 +1,198 @@ +#include +#include + +const int mapSize = 7; +const float wallHeight = 1; +char map[mapSize][mapSize] = { + { '0', '9', '8', '7', 'M', 'P', 'O' }, // 0 + { '-', ' ', ' ', ' ', ' ', ' ', '3' }, // 1 + { '=', ' ', ' ', ' ', 'o', ' ', '2' }, // 2 + { '|', ' ', ' ', ' ', ' ', ' ', '1' }, // 3 + { '=', ' ', ' ', ' ', ' ', ' ', '2' }, // 4 + { '-', ' ', ' ', '0', ' ', ' ', '3' }, // 5 + { '0', '9', '8', '7', '6', '5', '0' }, // 6 + // 0 1 2 3 4 5 6 +}; + +struct Coord { + float x; + float y; +}; + +float dist(Coord c1, Coord c2) { + float x1 = c2.x - c1.x, y1 = c2.y - c1.y; + return sqrt(x1 * x1 + y1*y1); +} + +bool isValidCoord(float coord) { + return 0 <= coord && coord <= mapSize; +} +bool isValidCoord(Coord c) { + return isValidCoord(c.x) && isValidCoord(c.y); +} + +const float focalLength = 3.4; + +class Player { + Coord loc; + float lookingAngle = 0.0; + float height = 0.6; + int fov = 90; + +public: + Player() : Player(0, 0) {} + Player(float x, float y) { + this->loc = { x, y }; + } + + float get_height() const { + return height; + } + + const Coord& get_loc() const { + return loc; + } + + int get_fov() const { + return fov; + } + + float get_lookingAngle() const { + return lookingAngle; + } + + + void walkForward() { + if (isValidCoord(loc.x + 0.25)) + loc.x += 0.25; + } + void walkBackward() { + if (isValidCoord(loc.x - 0.25)) + loc.x -= 0.25; + } + void walkLeft() { + if (isValidCoord(loc.y - 0.25)) + loc.y -= 0.25; + } + void walkRight() { + if (isValidCoord(loc.y + 0.25)) + loc.y += 0.25; + } + + void lookLeft() { + if (lookingAngle == -180) + lookingAngle = 180; + else + lookingAngle -= 2; + } + void lookRight() { + if (lookingAngle == 180) + lookingAngle = -180; + else + lookingAngle += 2; + } + + Coord castRayFromEyes() const { + return castRayFromEyes(0); + } + + Coord castRayFromEyes(float angle) const { + Coord rayLoc = loc; + angle += lookingAngle; + float xOffset = cos(angle * M_PI / 180.0), yOffset = sin(angle * M_PI / 180.0); + while (rayLoc.x < mapSize && rayLoc.y < mapSize && rayLoc.x > -1 && rayLoc.y > -1 && map[(int)rayLoc.y][(int)rayLoc.x] == ' ') { + rayLoc.x += 0.25 * xOffset; + rayLoc.y += 0.25 * yOffset; + } + std::cout << rayLoc.x << " " << rayLoc.y << std::endl; + return rayLoc; + } +}; + +const int scrH = 200, scrW = 800; +// const int scrH = 20, scrW = 80; + +struct VerticalSlice { + Coord collision; + float collisionDistance; + int aboveRay; + int belowRay; + + VerticalSlice() = default; + + VerticalSlice(float topScr, float botScr, float plHeight, float angle, Coord plLoc, Coord objLoc) { + collision = objLoc; + float aboveHeight = wallHeight - plHeight; + float belowHeight = plHeight; + + float properFL = focalLength; + this->collisionDistance = dist(plLoc, objLoc); + this->aboveRay = ((aboveHeight * properFL) / collisionDistance) * topScr; + this->belowRay = ((belowHeight * properFL) / collisionDistance) * botScr; + } +}; + +char getDepthChar(float distance) { + if (distance >= 6) return ' '; + else if (distance >= 5) return '.'; + else if (distance >= 4) return ';'; + else if (distance >= 3) return '+'; + else if (distance >= 2) return '*'; + else if (distance >= 1) return '#'; + else return 'O'; +} + +void draw(Player& pl) { + float topScr = scrH * (wallHeight - pl.get_height()), botScr = scrH - topScr; + VerticalSlice slices[pl.get_fov()]; + int halfFov = pl.get_fov() / 2; + for (int i = -halfFov; i <= halfFov; i++) { + slices[i + halfFov] = VerticalSlice(topScr, botScr, pl.get_height(), i, pl.get_loc(), pl.castRayFromEyes(i)); + } + // return; + + float angleStep = pl.get_fov() / (float)scrW; + for (int row = 0; row < scrH; row++) { + for (int dot = 0; dot < scrW; dot++) { + VerticalSlice sl = slices[(int)(dot * angleStep)]; + if (row < topScr && topScr - row <= sl.aboveRay) + std::cout << getDepthChar(sl.collisionDistance); + else if (row >= topScr && row - topScr < sl.belowRay) + std::cout << getDepthChar(sl.collisionDistance); + else + std::cout << ' '; + } + std::cout << std::endl; + } +} + +int main() { + Player pl(1, 3); + + char buffer; + bool play = true; + + system("stty -echo"); + system("stty cbreak"); + while (play) { + std::cout << u8"\033[2J\033[1;1H"; // clear + + draw(pl); + + buffer = getchar(); + + switch (buffer) { + case 'w': pl.walkForward(); break; + case 's': pl.walkBackward(); break; + case 'a': pl.walkLeft(); break; + case 'd': pl.walkRight(); break; + case ',': pl.lookLeft(); break; + case '.': pl.lookRight(); break; + case 'x': play = false; break; + } + + for (int i = 0; i < 1000;i++){} + } + system("stty echo"); + system("stty -cbreak"); +} -- cgit v1.2.3