1
\$\begingroup\$

I'm writing a raycasting engine in C++ and SFML.

I have the wall texturing done and I'm trying to get floor and ceiling texturing right.

I almost got it but the textures are "sliding" when the player moves, as illustrated here:

Display of 'sliding' effect

(Source)

I followed lodev tutorial agian and again but I can't get whats wrong. The code is available at https://github.com/Bazouz660/Raycaster-.git

Any help would be greatly appreciated.

Here is the raycasting algorythm :

Raycaster::Ray Raycaster::castRay(sf::Vector2f playerPosition, float angle, float refAngle, int x)
{
    Ray ray;
    sf::Vector2f rayStart = playerPosition / (float)m_grid.getTileSize();
    sf::Vector2f rayDir = normalize(sf::Vector2f(std::cos(angle), std::sin(angle)));
    sf::Vector2f unitStepSize = {std::sqrt(1 + (rayDir.y / rayDir.x) * (rayDir.y / rayDir.x)),
                                 std::sqrt(1 + (rayDir.x / rayDir.y) * (rayDir.x / rayDir.y))};
    sf::Vector2i mapCheck = {(int)rayStart.x, (int)rayStart.y};
    sf::Vector2f rayLength1D;
    sf::Vector2i step;
    sf::Vector2f intersection;
    sf::Texture *texture = ResourceManager::getInstance().getTexture("wall");
    sf::Image *image = ResourceManager::getInstance().getTextureImage("wall");
    bool tileFound = false;
    float distance = 0.0f;
    float perpWallDist = 0.0f;

    if (rayDir.x < 0)
    {
        step.x = -1;
        rayLength1D.x = (rayStart.x - float(mapCheck.x)) * unitStepSize.x;
    }
    else
    {
        step.x = 1;
        rayLength1D.x = (float(mapCheck.x + 1) - rayStart.x) * unitStepSize.x;
    }
    if (rayDir.y < 0)
    {
        step.y = -1;
        rayLength1D.y = (rayStart.y - float(mapCheck.y)) * unitStepSize.y;
    }
    else
    {
        step.y = 1;
        rayLength1D.y = (float(mapCheck.y + 1) - rayStart.y) * unitStepSize.y;
    }

    while (!tileFound && distance < RENDER_DISTANCE)
    {
        if (rayLength1D.x < rayLength1D.y)
        {
            mapCheck.x += step.x;
            distance = rayLength1D.x;
            rayLength1D.x += unitStepSize.x;
            ray.side = 0;
        }
        else
        {
            mapCheck.y += step.y;
            distance = rayLength1D.y;
            rayLength1D.y += unitStepSize.y;
            ray.side = 1;
        }

        if (mapCheck.x >= 0 && mapCheck.x < m_grid.getWidth() && mapCheck.y >= 0 && mapCheck.y < m_grid.getHeight())
        {
            if (m_grid.getTile(mapCheck.x, mapCheck.y).type != 0)
            {
                tileFound = true;
            }
        }
    }

    if (tileFound)
    {
        intersection = rayStart + rayDir * distance;
    }
    else
        intersection = rayStart;

    float angleFromRef = refAngle - angle;
    if (angleFromRef < 0)
        angleFromRef += 2 * PI;
    if (angleFromRef > 2 * PI)
        angleFromRef -= 2 * PI;

    ray.length = (distance * float(m_grid.getTileSize())) * std::cos(angleFromRef);

    // Calculate distance of perpendicular ray (Euclidean distance would give fisheye effect!)
    if (ray.side == 0)
        perpWallDist = (rayLength1D.x - unitStepSize.x);
    else
        perpWallDist = (rayLength1D.y - unitStepSize.y);

    // calculate value of wallX
    double wallX; // where exactly the wall was hit
    if (ray.side == 0)
        wallX = rayStart.y + perpWallDist * rayDir.y;
    else
        wallX = rayStart.x + perpWallDist * rayDir.x;
    wallX -= floor((wallX));

    // Floor and ceiling casting, bugged rn as the textures slides under the walls

    // Calculate height of line to draw on screen
    int lineHeight = (int)(RESY / (ray.length / m_grid.getTileSize()));

    // calculate lowest and highest pixel to fill in current stripe
    int drawStart = -lineHeight / 2 + RESY / 2;
    if (drawStart < 0)
        drawStart = 0;
    int drawEnd = lineHeight / 2 + RESY / 2;
    if (drawEnd >= RESY)
        drawEnd = RESY - 1;

    // FLOOR CASTING (vertical version, directly after drawing the vertical wall stripe for the current x)
    double floorXWall, floorYWall; // x, y position of the floor texel at the bottom of the wall

    // 4 different wall directions possible
    if (ray.side == 0 && rayDir.x > 0)
    {
        floorXWall = mapCheck.x;
        floorYWall = mapCheck.y + wallX;
    }
    else if (ray.side == 0 && rayDir.x < 0)
    {
        floorXWall = mapCheck.x + 1.0;
        floorYWall = mapCheck.y + wallX;
    }
    else if (ray.side == 1 && rayDir.y > 0)
    {
        floorXWall = mapCheck.x + wallX;
        floorYWall = mapCheck.y;
    }
    else
    {
        floorXWall = mapCheck.x + wallX;
        floorYWall = mapCheck.y + 1.0;
    }

    double distWall, currentDist;

    distWall = (ray.length / m_grid.getTileSize());

    if (drawEnd < 0)
        drawEnd = RESY; // becomes < 0 when the integer overflows

    // draw the floor from drawEnd to the bottom of the screen
    for (int y = drawEnd + 1; y < RESY; y++)
    {
        currentDist = RESY / (2.0 * y - RESY); // you could make a small lookup table for this instead

        double weight = (currentDist) / (distWall);

        double currentFloorX = weight * floorXWall + (1.0 - weight) * (rayStart.x);
        double currentFloorY = weight * floorYWall + (1.0 - weight) * (rayStart.y);

        int floorTexX, floorTexY;
        floorTexX = int(currentFloorX * texture->getSize().x * 1.25) % texture->getSize().x;
        floorTexY = int(currentFloorY * texture->getSize().y * 1.25) % texture->getSize().y;

        // floor
        m_floorGroundImage.setPixel(x, y, image->getPixel(floorTexX, floorTexY));
        // ceiling (symmetrical!)
        m_floorGroundImage.setPixel(x, RESY - y - 1, image->getPixel(floorTexX, floorTexY));
    }

    ray.wallX = wallX;
    ray.color = m_grid.getTile(mapCheck.x, mapCheck.y).color;
    ray.direction = rayDir;
    ray.origin = playerPosition;
    m_zBuffer[x] = ray.length;
    ray.vertices[0].position = ray.origin;
    ray.vertices[0].color = ray.color;
    ray.vertices[1].position = (intersection * float(m_grid.getTileSize()));
    ray.vertices[1].color = ray.color;
    return ray;
}
\$\endgroup\$
0

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.