Page 1 of 1

Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 10:07 am
by NoreoAlles
Hi, i´ve been trying to make a Raycaster in Löve and i need help because (1) my rays are kindof cluttered and (2) my rays dont care if they´ve hit a wall sometimes and (3) the rays sometimes all go right when my player is facing left and near to a wall in the right direction.
I´ve tried to comment most of the stuff.
Any help would be appriciated :nyu:

Re: Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 12:01 pm
by Bigfoot71
There are a number of choices that I haven't really been able to understand in your code, so I took the liberty of completely rewriting the function to better understand the concept, here's what it might look like (I've part removed point storage in hits):

Code: Select all

function RayCast(ray_step_size, num_rays)

    num_rays = num_rays or screen_width
    ray_step_size = ray_step_size or 5

    local angle = P.a - fov / 2
    local step = fov / (num_rays - 1)

    love.graphics.setColor(1, 0, 0) -- We apply the line color only once

    for i = 1, num_rays do

        local sin_a = math.sin(angle)
        local cos_a = math.cos(angle)

        local x = P.x
        local y = P.y

        local distance_to_wall = 0
        local hit_wall = false

        while not hit_wall do

            local map_x = math.floor(x / tile_size) + 1 -- Round ray pos to map pos
            local map_y = math.floor(y / tile_size) + 1

            if map[map_y][map_x] == 1 then                                    -- If the step of the ray is in a wall
                distance_to_wall = math.sqrt((x - P.x) ^ 2 + (y - P.y) ^ 2)   -- We calculate the distance
                hit_wall = true  -- This value is used for understanding the code
                break            -- We could do without it since we break just after
            end

            x = x + cos_a * ray_step_size   -- Next raystep
            y = y + sin_a * ray_step_size

            if x < 0 or y < 0 or x > map_width * tile_size or y > map_height * tile_size then -- Security if you leave the map
                break
            end

        end

        -- Draw the red line to the nearest wall --

        local line_end_x = P.x + cos_a * distance_to_wall
        local line_end_y = P.y + sin_a * distance_to_wall
        love.graphics.line(P.x, P.y, line_end_x, line_end_y)

        -- We go to the next angle step (next ray) --

        angle = angle + step

    end

end
It's still a version that I also tweaked personally, there are many courses on raycasting that cover even more optimized techniques, but I think what I wrote is quite simple to understand, if you have any questions. don't hesitate.

Otherwise maybe someone more knowledgeable than me could say more because I don't want to lose you. When I'm gone I don't stop anymore :crazy:

Here is the result with ray_step_size = 0.1 (px) and ray_nums = 45:
Image

And the result with the default parameters, i.e. ray_step_size = 5 (px) and ray_nums = screen_width:
Image

(Don't pay attention to the FPS counter which varies a lot, I'm on an old machine and I was filming, without filming it remained rather stable for me)

Re: Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 3:08 pm
by NoreoAlles
Thank you so much, that is so much cleaner then what i tried. I tried to skip the "extend ray by this size" part and tried to just do it super optimized without really understanding what i was doing. I´ll tell you if i have any more problems, but this just looks great. (:

Re: Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 3:50 pm
by NoreoAlles
I quickly made it render in 3d, thought you might want to see. I´ll later fix the fisheye and maybe make a full game out of this and post it here on the forums. I for now have copied your code exactly but i will ofc change it later on, hope you dont mind

Re: Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 3:52 pm
by Bigfoot71
NoreoAlles wrote: Tue Mar 28, 2023 3:08 pm Thank you so much, that is so much cleaner then what i tried. I tried to skip the "extend ray by this size" part and tried to just do it super optimized without really understanding what i was doing. I´ll tell you if i have any more problems, but this just looks great. (:
This code that I proposed remains as an example to fully understand the principle, I have kept it as simple as possible so as not to confuse you so it is very largely optimizable.

Besides the values ​​that are recalculated on each call to the function, you could also use a spatialization technique to limit the number of collision tests performed in each iteration of the loop. Something that looks technical said like that so I redirect you to this course which will explain it so much better than me, hoping that you are a little comfortable with C++ but it is the best course on raycasting that I have never found personally: https://lodev.org/cgtutor/raycasting.html

You don't have to reproduce the code shown exactly, at least understand what it says and you should be able to write your own code on your own. :)

By the way, this site contains a lot of very useful resources for graphic programming ^^

Edit:
NoreoAlles wrote: Tue Mar 28, 2023 3:50 pm I quickly made it render in 3d, thought you might want to see. I´ll later fix the fisheye and maybe make a full game out of this and post it here on the forums. I for now have copied your code exactly but i will ofc change it later on, hope you dont mind
Sorry I didn't see your answer, well done it's super cool! And no, it doesn't bother me at all, it's made for it, and if you improve it it's even better ^^
If you make a real game out of it, I really advise you to see the link I gave you to optimize and reduce the number of iterations of the while loop, it will be very useful for you to do something really clean!

Re: Raycaster Issues (Horizontal Checking)

Posted: Tue Mar 28, 2023 4:27 pm
by darkfrei
Your code

Code: Select all

        if self.a > math.pi*2 then 
            self.a = 0
        end 
must be

Code: Select all

        if self.a > math.pi*2 then 
            self.a = self.a - math.pi*2
        end 
Maybe just this for both rotations (not tested):

Code: Select all

self.a = self.a%(math.pi*2)