[Solved] Why are my textures not displaying propely in my raycasting engine?

sparky11520 Asks: Why are my textures not displaying propely in my raycasting engine?
I have been working on a simple raycasting engine (like wolfenstein 3d) using the SFML Graphical Library. For the most part, my raycasting works fine, I based it off of Lodev’s example and made some minor changes.

The problems I am having include:

  1. The Final Column of a Texture being drawn multiple times
  2. Parts of textures not being drawn because they stretch past there tile

Thanks you for your time, and thanks in advance to anyone who can help!

Image Depicting the issues:
As you can see the blue bricks on the left stop drawing before the edge of the shape and just repeat the last line, and the second eagle simply draws around half of the texture.

Here is my Code:

Code:
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <stdlib.h> 
#include <math.h>

#include <iostream>
#include <sstream>

#define mapWidth 23
#define mapHeight 7
#define texWidth 64
#define texHeight 64


std::string ConvertToString(int number) {
    std::ostringstream buff;
    buff << number;
    return buff.str();
}

int worldMap[mapHeight][mapWidth] =
{
    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },
    { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 },
    { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 },
    { 1,0,1,0,0,2,0,0,3,0,0,4,0,0,3,0,0,2,0,0,1,0,1 },
    { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 },
    { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 },
    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
};

int hitCount[mapHeight][mapWidth] =
{
    { 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,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,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,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,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 },
};
int main()
{
//initialize textures
int column = 1;

sf::Texture bluestone;
bluestone.loadFromFile("bluestone.png");

sf::Texture eagle;
eagle.loadFromFile("eagle.png");

sf::Texture greystone;
greystone.loadFromFile("greystone.png");

sf::Texture redbrick;
redbrick.loadFromFile("redbrick.png");

sf::Texture mossystone;
mossystone.loadFromFile("mossy.png");

sf::Sprite WallTexture;

int LastMapX = -1, LastMapY = -1;
int LastSide = -1;
int Repeats = 0;


int w = 1024, h = 576;
float scaleY;
int scaleX;
float textureSectionX;

double posX = 2, posY = 2;  //x and y start position
double dirX = -1, dirY = 0; //initial direction vector
double planeX = 0, planeY = 0.66; //the 2d raycaster version of camera plane

double time = 0; //time of current frame
double oldTime = 0; //time of previous frame

                    // Create the main window
sf::RenderWindow window(sf::VideoMode(w, h), "SFML window");

window.setFramerateLimit(60);
sf::Clock clock = sf::Clock();
sf::Time fps;

// Start the game loop
while (window.isOpen()) {
    // Process events
    sf::Event event;
    while (window.pollEvent(event))
    {
        // Close window: exit
        if (event.type == sf::Event::Closed)
            window.close();

        // Escape key: exit
        if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
            window.close();
    }

    window.clear();
    //ceiling and floor
    sf::RectangleShape floor(sf::Vector2f(1024, 288));
    sf::RectangleShape ceiling(sf::Vector2f(1024, 288));
    floor.setPosition(0, 288);
    floor.setFillColor(sf::Color(96, 96, 96));
    ceiling.setPosition(0, 0);
    ceiling.setFillColor(sf::Color(50, 50, 50));

    window.draw(floor);
    window.draw(ceiling);
    ///////////////////////COUNTING HITS PER SECTOR//////////////////////////////////////////////////////////
    for (int i = 0; i < mapHeight; i++)
    {
        for (int j = 0; j < mapWidth; j++)
        {
            hitCount[i][j] = 0;
        }
    } 

    for (float x = 0; x < w; x++)
    {
        //calculate ray position and direction
        double cameraX = 2 * x / double(w) - 1; //x-coordinate in camera space
        double rayPosX = posX;
        double rayPosY = posY;
        double rayDirX = dirX + planeX * cameraX;
        double rayDirY = dirY + planeY * cameraX;

        //which box of the map we're in
        int mapX = int(rayPosX);
        int mapY = int(rayPosY);

        //length of ray from current position to next x or y-side
        double sideDistX;
        double sideDistY;

        //length of ray from one x or y-side to next x or y-side
        double deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
        double deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
        double perpWallDist;

        //what direction to step in x or y-direction (either +1 or -1)
        int stepX;
        int stepY;

        int hit = 0; //was there a wall hit?
        int side; //was a NS or a EW wall hit?

                  //calculate step and initial sideDist
        if (rayDirX < 0)
        {
            stepX = -1;
            sideDistX = (rayPosX - mapX) * deltaDistX;
        }
        else
        {
            stepX = 1;
            sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
        }
        if (rayDirY < 0)
        {
            stepY = -1;
            sideDistY = (rayPosY - mapY) * deltaDistY;
        }
        else
        {
            stepY = 1;
            sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
        }

        //perform DDA
        while (hit == 0)
        {
            //jump to next map square, OR in x-direction, OR in y-direction
            if (sideDistX < sideDistY)
            {
                sideDistX += deltaDistX;
                mapX += stepX;
                side = 0;
            }
            else
            {
                sideDistY += deltaDistY;
                mapY += stepY;
                side = 1;
            }
            //Check if ray has hit a wall
            if (worldMap[mapX][mapY] > 0)
            {
                hitCount[mapX][mapY]++;
                hit = 1;
            }

        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    ///////////////////////RAYCASTING FOR TEXTURES AND Y SCALE + DRAWING ////////////////////////////////////
    for (float x = 0; x < w; x++)
    {
        //calculate ray position and direction
        double cameraX = 2 * x / double(w) - 1; //x-coordinate in camera space
        double rayPosX = posX;
        double rayPosY = posY;
        double rayDirX = dirX + planeX * cameraX;
        double rayDirY = dirY + planeY * cameraX;

        //which box of the map we're in
        int mapX = int(rayPosX);
        int mapY = int(rayPosY);

        //length of ray from current position to next x or y-side
        double sideDistX;
        double sideDistY;

        //length of ray from one x or y-side to next x or y-side
        double deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
        double deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
        double perpWallDist;

        //what direction to step in x or y-direction (either +1 or -1)
        int stepX;
        int stepY;

        int hit = 0; //was there a wall hit?
        int side; //was a NS or a EW wall hit?

                  //calculate step and initial sideDist
        if (rayDirX < 0)
        {
            stepX = -1;
            sideDistX = (rayPosX - mapX) * deltaDistX;
        }
        else
        {
            stepX = 1;
            sideDistX = (mapX + 1.0 - rayPosX) * deltaDistX;
        }
        if (rayDirY < 0)
        {
            stepY = -1;
            sideDistY = (rayPosY - mapY) * deltaDistY;
        }
        else
        {
            stepY = 1;
            sideDistY = (mapY + 1.0 - rayPosY) * deltaDistY;
        }

        //perform DDA
        while (hit == 0)
        {
            //jump to next map square, OR in x-direction, OR in y-direction
            if (sideDistX < sideDistY)
            {
                sideDistX += deltaDistX;
                mapX += stepX;
                side = 0;
            }
            else
            {
                sideDistY += deltaDistY;
                mapY += stepY;
                side = 1;
            }
            //Check if ray has hit a wall
            if (worldMap[mapX][mapY] > 0)
            {
                hit = 1;
            }
            
        }
        
        //Calculate distance projected on camera direction (oblique distance will give fisheye effect!)
        if (side == 0)
        {
            perpWallDist = fabs((mapX - rayPosX + (1 - stepX) / 2) / rayDirX);
            while (rayPosY > 1)
            {
                rayPosY =- 1;
            }
            textureSectionX = rayPosY;
        }
        else
        {
            perpWallDist = fabs((mapY - rayPosY + (1 - stepY) / 2) / rayDirY);
            while (rayPosX > 1)
            {
                rayPosX =- 1;
            }
            textureSectionX = rayPosX;
        }

        if (textureSectionX < 0)
        {
            textureSectionX = fabs(textureSectionX);
        }

        if (textureSectionX > 64)
        {
            return 0;
        }

        //Calculate height of line to draw on screen
        float lineHeight = abs(int(h / perpWallDist));
        scaleY = lineHeight / 64;
        scaleX = hitCount[mapX][mapY] / 64;
        if (scaleX < 1)
        {
            scaleX = 1;
        }

        //choose wall texture

        switch (worldMap[mapX][mapY])
        {
        case 1:  WallTexture.setTexture(bluestone); break;
        case 2:  WallTexture.setTexture(eagle); break;
        case 3:  WallTexture.setTexture(greystone);break;
        case 4:  WallTexture.setTexture(redbrick); break;
        default: WallTexture.setTexture(mossystone);break;
        }

        if (LastMapY == mapY && LastMapX == mapX && side == LastSide)
        {
            Repeats++;
        }
        else
        {
            Repeats = 0;
        }

        textureSectionX = textureSectionX + Repeats;

        //give x and y sides different brightness
        if (side == 1) 
        {
            WallTexture.setColor(sf::Color(148,148,148,255));
            textureSectionX = 64 - textureSectionX;
        
        }

        float y = 288 - ((64 * scaleY) / 2);

        //Draw the walls
        WallTexture.setScale(1, scaleY);
        WallTexture.setTextureRect(sf::IntRect(textureSectionX,0,1,64));

        int drawTexture = 0;

        while (drawTexture < scaleX)
        {
            WallTexture.setPosition(x, y);
            window.draw(WallTexture);
            drawTexture++;
            x++;
        }
        x--;

        WallTexture.setColor(sf::Color(255, 255, 255, 255));

        LastMapY = mapY;
        LastMapX = mapX;
        LastSide = side;
    }


    fps = clock.getElapsedTime();
    float fpsValue = 1000000 / fps.asMicroseconds();
    clock.restart();

    double moveSpeed = fps.asSeconds() * 5.0; //the constant value is in squares/second
    double rotSpeed = fps.asSeconds() * 3.0; //the constant value is in radians/second

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
        //both camera direction and camera plane must be rotated
        double oldDirX = dirX;
        dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed);
        dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed);
        double oldPlaneX = planeX;
        planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed);
        planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed);
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
        //both camera direction and camera plane must be rotated
        double oldDirX = dirX;
        dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed);
        dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed);
        double oldPlaneX = planeX;
        planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed);
        planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed);
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
        if (worldMap[int(posX + dirX * moveSpeed)][int(posY)] == false) posX += dirX * moveSpeed;
        if (worldMap[int(posX)][int(posY + dirY * moveSpeed)] == false) posY += dirY * moveSpeed;
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
        if (worldMap[int(posX - dirX * moveSpeed)][int(posY)] == false) posX -= dirX * moveSpeed;
        if (worldMap[int(posX)][int(posY - dirY * moveSpeed)] == false) posY -= dirY * moveSpeed;
    }

    window.display();
    window.clear();
}

return EXIT_SUCCESS;
};

Ten-tools.com may not be responsible for the answers or solutions given to any question asked by the users. All Answers or responses are user generated answers and we do not have proof of its validity or correctness. Please vote for the answer that helped you in order to help others find out which is the most helpful answer. Questions labeled as solved may be solved or may not be solved depending on the type of question and the date posted for some posts may be scheduled to be deleted periodically. Do not hesitate to share your response here to help other visitors like you. Thank you, Ten-tools.