diff --git a/Player.cpp b/Player.cpp index b6fa26c..b23f8c5 100644 --- a/Player.cpp +++ b/Player.cpp @@ -14,32 +14,15 @@ void Player::move(float dx, float dy) y += dy; } -void Player::rotate(float alpha) +void Player::rotate(int alpha) { - orientation += fmodf(alpha, 360); - if(orientation > 360) + orientation += alpha%360; + if(orientation >= 360) { orientation -= 360; } - else if(orientation < 0) + if(orientation <= 360) { orientation += 360; } - - /* - * Rotate the movement vector along the new angle, assumes that the only - * speed influencing the player is its own movement. - */ - float prevSpeedX = currentMoveSpeedX; - float prevSpeedY = currentMoveSpeedY; - currentMoveSpeedX = cosf(-alpha * deg_to_rad) * prevSpeedX - - sinf(-alpha * deg_to_rad) * prevSpeedY; - currentMoveSpeedY = sinf(-alpha * deg_to_rad) * prevSpeedX - + cosf(-alpha * deg_to_rad) * prevSpeedY; -} - -void Player::updateSpeed(float localX, float localY) { - // TODO: Support strafing. - currentMoveSpeedX = localX * sinf(orientation*deg_to_rad)*moveSpeed; - currentMoveSpeedY = localX * cosf(orientation*deg_to_rad)*moveSpeed; } diff --git a/Player.h b/Player.h index eab2795..05426c5 100644 --- a/Player.h +++ b/Player.h @@ -5,9 +5,6 @@ #ifndef RAYCASTING_PLAYER_H #define RAYCASTING_PLAYER_H -#include - -static constexpr float deg_to_rad = 3.14159265/180; class Player { public: @@ -17,22 +14,10 @@ public: float y; float orientation; - float moveSpeed = 5; - float rotationSpeed = 180; - - float currentMoveSpeedX = 0; - float currentMoveSpeedY = 0; - - float currentRotationSpeed = 0; - - /* View properties. */ float fov = 70; - float sensorSize = 0.035; /* 35mm, about equivalent to human eye ? */ - float focalLength = sensorSize / (2*tanf((fov*deg_to_rad)/2)); void move(float dx, float dy); - void rotate(float alpha); - void updateSpeed(float localX, float localY); + void rotate(int alpha); }; diff --git a/World.cpp b/World.cpp index f632b86..9c8ccb0 100644 --- a/World.cpp +++ b/World.cpp @@ -3,7 +3,6 @@ // #include "World.h" -#include World::World(int w, int h, sf::Color groundColor, sf::Color ceilingColor, std::vector worldMap) : w(w), h(h), @@ -93,119 +92,32 @@ void World::fillColumn(sf::RenderWindow& window, int column, float scale, sf::Co window.draw(pixelColumn); } -float World::castRay(float originX, float originY, float orientation) const +float World::castRay(float originX, float originY, float orientation) { /* * Reference used for ray intersection computations : * https://web.archive.org/web/20220628034315/https://yunes.informatique.univ-paris-diderot.fr/wp-content/uploads/cours/INFOGRAPHIE/08-Raycasting.pdf - * The logic is as follows : - * - This computes one set of point per edge crossings (horizontal/vertical) - * - The origin not being confined to the grid, offsets are computed to - * align the intersections properly - * - The intersections are at multiples of the tangent of the relevant - * angle for the axis of interest, and simply on successive edges of - * the grid for the other one - * - Depending on the orientation, signs must be taken into account - * to work 360° */ - /* Offsets to get back on the grid from the ray's origin. */ - float hOffsetX; - float hOffsetY; - float vOffsetX; - float vOffsetY; + float deltaX; + float deltaY; + if(orientation < 45 || orientation > 315) + { - /* Signs controlling the direction of travel. */ - float hDir; - float vDir; - /* Need offset for rounding in the right direction ? */ - float hRound; - float vRound; - - float rads = orientation * deg_to_rad; - /* Used for vertical intersections. */ - float rads_offset = (90 - orientation) * deg_to_rad; - - /* Tangents used for the different axes. */ - float hTan = tanf(rads); - float vTan = tanf(rads_offset); - - /* Check if cos > 0 for horizontal hits formulas. */ - if (orientation < 90 || orientation > 270) { - hOffsetX = ceilf(originY) - originY; - hOffsetY = ceilf(originY); - hDir = +1; - hRound = 0; - } else { - hOffsetX = originY - floorf(originY); - hOffsetY = floorf(originY); - hDir = -1; - hRound = -1; } - hTan *= hDir; - hOffsetX *= hTan; + else if(orientation < 135) + { - /* Check if sin > 0 for vertical hits formulas. */ - if (orientation < 180) { - vOffsetX = ceilf(originX); - vOffsetY = ceilf(originX) - originX; - vDir = +1; - vRound = 0; - } else { - vOffsetX = floorf(originX); - vOffsetY = originX - floorf(originX); - vDir = -1; - vRound = -1; } - vTan *= vDir; - vOffsetY *= vTan; + else if(orientation < 225) + { - /* - * Now we have all the constants and deltas to work with, cast the ray. - * Generated points follow the formulas : - * - h-intersect : (originX + hOffsetX + hTan*i, hOffsetY + hDir*i) - * - v-intersect : (vOffsetX + vDir*i, originY + vOffsetY + vTan*i) - */ - int i = 0; - float hCheckX = originX + hOffsetX; - float hCheckY = hOffsetY; - /* Bounds + sanity check. */ - while (hCheckX >= 0 && hCheckX <= w && hCheckY >= 0 && hCheckY <= h && i < h) { - if (getBlock(floorf(hCheckX), floorf(hCheckY) + hRound) == BlockType::WALL) { - break; - } + } + else + { - hCheckX += hTan; - hCheckY += hDir; - i++; } - i = 0; - float vCheckX = vOffsetX; - float vCheckY = originY + vOffsetY; - - /* Bounds + sanity check. */ - while (vCheckX >= 0 && vCheckX < w && vCheckY >= 0 && vCheckY < h && i < w) { - if (getBlock(floorf(vCheckX) + vRound, floorf(vCheckY)) == BlockType::WALL) { - break; - } - - vCheckX += vDir; - vCheckY += vTan; - i++; - } - - /* - * We may or may not have hit something. Check which coordinates are closest - * and use those for computing the apparent size on screen. - */ - float hDist = sqrtf((originX - hCheckX)*(originX - hCheckX) + - (originY - hCheckY)*(originY - hCheckY)); - float vDist = sqrtf((originX - vCheckX)*(originX - vCheckX) + - (originY - vCheckY)*(originY - vCheckY)); - float finalDist = hDist > vDist ? vDist : hDist; - - /* 2 Is wall height in meters. */ - return player.focalLength*2/finalDist; + return 0; } void World::render(sf::RenderWindow& window) const @@ -231,25 +143,7 @@ void World::render(sf::RenderWindow& window) const */ for(int i = 0;i 360) { - rayAngle -= 360; - } - float obstacleScale = castRay(player.x, player.y, rayAngle)/player.sensorSize; - fillColumn(window, i, obstacleScale); + fillColumn(window, i, 0.5); } -} -void World::step(const float& stepTime) { - player.move(player.currentMoveSpeedX*stepTime, - player.currentMoveSpeedY*stepTime); - /* Undo last move if the player would end up in a wall. */ - if (getBlock((int)player.x, (int)player.y) != BlockType::AIR) { - player.move(-player.currentMoveSpeedX*stepTime, - -player.currentMoveSpeedY*stepTime); - } - player.rotate(player.currentRotationSpeed*stepTime); } diff --git a/World.h b/World.h index c098e68..eeff8f5 100644 --- a/World.h +++ b/World.h @@ -23,24 +23,16 @@ class World { public: Player player; - World(int w, int h, - sf::Color groundColor = sf::Color{67, 137, 39}, - sf::Color ceilingColor = sf::Color{39, 69, 137}, - std::vector worldMap = {}); + World(int w, int h, sf::Color groundColor = sf::Color::Green, sf::Color ceilingColor = sf::Color::Blue, + std::vector worldMap = {}); int getW() const; int getH() const; - inline BlockType getBlock(float x, float y) const; + BlockType getBlock(float x, float y) const; void setBlock(BlockType block, int x, int y, int width = 1, int height = 1); void render(sf::RenderWindow&) const; - /** - * Move the world one step forward. - * @param stepTime delta time since last step, in seconds - */ - void step(const float& stepTime); - friend std::ostream& operator<<(std::ostream& ostream, World const & world); private: int w; @@ -50,16 +42,15 @@ private: sf::Color groundColor; sf::Color ceilingColor; - void fillColumn(sf::RenderWindow&, int column, float scale, - sf::Color wallColor = sf::Color(84,56,34)) const; + void fillColumn(sf::RenderWindow&, int column, float scale, sf::Color wallColor = sf::Color(127,127,127)) const; /** * Cast a ray from a given position and return the on-screen scale. - * @param originX Ray X origin, strictly positive - * @param originY Ray Y origin, strictly positive - * @param orientation Angle to cast to, in degrees between 0 and 360 + * @param originX Ray X origin + * @param originY Ray Y origin + * @param orientation Angle to cast to, in degrees * @return Scale on the screen of the hit wall. */ - float castRay(float originX, float originY, float orientation) const; + float castRay(float originX, float originY, float orientation); }; diff --git a/main.cpp b/main.cpp index 73c4dfc..7b883d3 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,22 @@ #include -#include +#include "SFML/Graphics.hpp" #include "World.h" +// TODO: Handle inputs to move player +// TODO: Raycast from player position +// TODO: Fix raycasts and use it correctly +// TODO: Render world in event loop +// TODO: Understand what the code was doing (looks like scale from fill column is the output of the raycast) +// Ref: https://lodev.org/cgtutor/raycasting.html +// Ref: http://yunes.informatique.univ-paris-diderot.fr/wp-content/uploads/cours/INFOGRAPHIE/08-Raycasting.pdf +// TODO: Update player for camera plane +// TODO: Camera plane represents screen, rays go through it proportional to the screen // TODO: Find a way to go to edges instead of just equally split (?) int main() { + std::cout << "Hello, World!" << std::endl; World world(10,10); world.setBlock(BlockType::AIR,1,1,8,8); world.setBlock(BlockType::WALL,4,4,2,2); @@ -17,55 +27,14 @@ int main() world.render(window); window.display(); - sf::Event event{}; - sf::Clock frameTime; while (window.isOpen()) { + sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); - else if (event.type == sf::Event::KeyPressed) { - switch (event.key.code) { - case sf::Keyboard::Key::Escape: - window.close(); - break; - case sf::Keyboard::Key::Left: - world.player.currentRotationSpeed = -world.player.rotationSpeed; - break; - case sf::Keyboard::Key::Right: - world.player.currentRotationSpeed = world.player.rotationSpeed; - break; - case sf::Keyboard::Key::Up: - world.player.updateSpeed(1, 0); - break; - case sf::Keyboard::Key::Down: - world.player.updateSpeed(-1, 0); - break; - default: - break; - } - } - else if (event.type == sf::Event::KeyReleased) { - switch (event.key.code) { - case sf::Keyboard::Key::Left: - case sf::Keyboard::Key::Right: - world.player.currentRotationSpeed = 0; - break; - case sf::Keyboard::Key::Up: - case sf::Keyboard::Key::Down: - world.player.updateSpeed(0, 0); - break; - default: - break; - } - } } - window.clear(); - - world.step(frameTime.restart().asSeconds()); - world.render(window); - window.display(); } return 0;