Page 1 of 14

Working Raycasting example! WolfenLöve 3D if you will...

Posted: Fri Jan 06, 2012 5:40 am
by Jasoco
Edit: Click this link to see where the actual progress begins:
viewtopic.php?f=4&t=6834&start=10#p45793

----Original post starts here----

I would really love to see a working Raycasting example that worked in Löve. I've tried converting numerous JavaScript versions with no luck at all. It's always just out of reach. Surely it can't be hard.

There was an example in the "What are you working on" thread a while ago but it was a bit buggy. I just tried the code now and it just looks and works wrong. I'm not talking about the fisheye, rather some other glitches. This is the code that was posted there:

Code: Select all

-------------------------------------------------------------------
--Raycasting sample code (written by Roland Yonaba)
-- Credits to :http://lodev.org/cgtutor/raycasting.html
-------------------------------------------------------------------
local map = {
  {1,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,0,1},
  {1,0,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,0,1},
  {1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
  {1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,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,0,1},
  {1,0,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,0,1},
  {1,0,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,0,1},
  {1,0,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,0,1},
  {1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
  {1,4,4,4,4,4,4,4,4,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,1}
}

local map_height,map_width = #map,#map[1]

local posX,posY = 22,12
local dirX,dirY = -1,0
local planeX,planeY = 0,0.66
local time,oldtime = 0,0
local w = love.graphics.getWidth()
local h = love.graphics.getHeight()

local moveSpeed, rotSpeed = 0,0

function love.update(dt)
   moveSpeed = dt*3
   rotSpeed = dt
   
   if love.keyboard.isDown('up') then
      if map[math.floor(posX+dirX*moveSpeed)][math.floor(posY)] == 0 then
      posX = posX + dirX*moveSpeed
      end
      if map[math.floor(posX)][math.floor(posY+dirY*moveSpeed)] == 0 then
      posY = posY + dirY*moveSpeed
      end
   end
   
   if love.keyboard.isDown('down') then
      if map[math.floor(posX-dirX*moveSpeed)][math.floor(posY)] == 0 then
      posX = posX - dirX*moveSpeed
      end
      if map[math.floor(posX)][math.floor(posY-dirY*moveSpeed)] == 0 then
      posY = posY - dirY*moveSpeed
      end
   end   
   
   if love.keyboard.isDown('left') then
   local oldDirX = dirX
   dirX = dirX * math.cos(rotSpeed)- dirY*math.sin(rotSpeed)
   dirY = oldDirX * math.sin(rotSpeed)+ dirY*math.cos(rotSpeed)
   local oldPlaneX = planeX
   planeX = planeX * math.cos(rotSpeed) - planeY*math.sin(rotSpeed)
   planeY = oldPlaneX * math.sin(rotSpeed) + planeY*math.cos(rotSpeed)
   end
   
   if love.keyboard.isDown('right') then
   local oldDirX = dirX
   dirX = dirX * math.cos(-rotSpeed)- dirY*math.sin(-rotSpeed)
   dirY = oldDirX * math.sin(-rotSpeed)+ dirY*math.cos(-rotSpeed)
   local oldPlaneX = planeX
   planeX = planeX * math.cos(-rotSpeed) - planeY*math.sin(-rotSpeed)
   planeY = oldPlaneX * math.sin(-rotSpeed) + planeY*math.cos(-rotSpeed)
   end   
   
end


function love.draw()
   love.graphics.clear({0,0,0})   
   for x = 0,w do
   local camX = 2*(x/w)-1
   local rayPosX = posX
   local rayPosY = posY
   local rayDirX = dirX + planeX*camX
   local rayDirY = dirY + planeY*camX
   local mapX = math.floor(rayPosX)
   local mapY = math.floor(rayPosY)
   local sideDistX,sideDistY
   
   local deltaDistX = math.sqrt(1+(rayDirY^2)/(rayDirX^2))
   local deltaDistY = math.sqrt(1+(rayDirX^2)/(rayDirY^2))
   local perpWallDist
   
   local stepX,stepY
   
   local hit = 0
   local side
   
      if rayDirX<0 then
      stepX = -1
      sideDistX = (rayPosX - mapX)*deltaDistX
      else
      stepX = 1
      sideDistX = (mapX+1-rayPosX)*deltaDistX
      end
      
      if rayDirY <0 then
      stepY = -1
      sideDistY = (rayPosY - mapY) * deltaDistY
      else
      stepY =  1
      sideDistY = (rayPosY +1-rayPosY)*deltaDistY
      end
      
      while (hit==0) do
         if (sideDistX < sideDistY) then
         sideDistX = sideDistX + deltaDistX
         mapX = mapX+stepX
         side = 0
         else
         sideDistY = sideDistY + deltaDistY
         mapY = mapY + stepY
         side = 1
         end
         
         if map[mapX][mapY] > 0 then hit = 1 end
      end
      
      if side==0 then
      perpWallDist = math.abs((mapX - rayPosX+(1-stepX)/2)/rayDirX)
      else
      perpWallDist = math.abs((mapY - rayPosY+(1-stepY)/2)/rayDirY)
      end
      
      local lineHeight = math.abs(math.floor(h/perpWallDist))
      local drawStart = -lineHeight/2 + h/2
         if drawStart < 0 then drawStart = 0 end
      local drawEnd = lineHeight/2 + h/2
         if drawEnd >= h then drawEnd = h-1 end
         
      local color = {}
      local square = map[mapX][mapY]
         if square == 1 then color = {255,0,0} 
         elseif square == 2 then color = {0,255,0}
         elseif square == 3 then color = {0,0,255}
         elseif square == 4 then color = {255,255,255}
         else color = {255,255,0}
         end
         
      if side == 1 then 
         for k,v in ipairs(color) do v = v/2 end 
      end
      love.graphics.setColor(color)
      love.graphics.line(x,drawStart,x,drawEnd)
   end

end
From Roland_Yonaba's post here: http://love2d.org/forums/viewtopic.php? ... ing#p33899

Surely if it could be done so perfectly in 1992, it can be done right now. I'm not even concerned about image textures yet. I just want the shapes. The textures would come later based on where along the wall tile a ray is touching and dividing the texture into a quad per horizontal pixel unit. Blah blah blah.

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 9:21 am
by Erniecz
Hello everybody,
I wrote a very simple (only 144 lines!) raycasting example (I used this toturial: http://www.permadi.com/tutorial/raycast/, it is really good). I just changed one thing - when finding walls, I used very simple and VERY slow algorithm. So if you want to use it, you have to rewrite it to the algorithm in tutorial.
Obviously, it should run in smaller window (320 x 200), it uses bigger window for map and some info.

Here it is:
http://dl.dropbox.com/u/6534785/simple3D.love
(i can't upload attachment, I click button and nothing happens).

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 10:29 am
by SimonLarsen
I did a quick test some time ago. Did the math myself so it's not very optimized.

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 3:02 pm
by T-Bone
SimonLarsen wrote:I did a quick test some time ago. Did the math myself so it's not very optimized.
Hey, that's awesome! And it runs well even on my netbook.

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 5:20 pm
by jfroco
Hi,

This is my first post!!!!

I took this: http://dev.opera.com/articles/view/crea ... l-5-can-1/

and implemented a texture-less Love2d version...

Image

http://dl.dropbox.com/u/4281970/love2d/raycast.love

Move using arrows...

Hope this helps.

JF

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 6:13 pm
by T-Bone
So when will we see the first FPS made in LÖVE?

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 6:26 pm
by MarekkPie
I really like jfroco's version. Much cleaner walls.

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 8:35 pm
by Jasoco
jfroco wrote:Hi,

This is my first post!!!!

I took this: http://dev.opera.com/articles/view/crea ... l-5-can-1/

and implemented a texture-less Love2d version...

http://dl.dropbox.com/u/4281970/love2d/raycast.png

http://dl.dropbox.com/u/4281970/love2d/raycast.love

Move using arrows...

Hope this helps.

JF
I am impressed. That's the exact same code I was trying to port myself all yesterday with no avail. I am going to have to compare your port to the original and my half-assed failure and see if I can learn more.

I want to try and get a real working Wolf-style game engine going. I even downloaded that Prelude of the Chambered (Notch's Ludum Dare game from the previous LD) and couldn't make heads nor tails of the code to figure out which stuff was the actual math calculations or if it was even raycasting or simply warping 2D images in 3D space like MineCraft does.

Thanks for this. It'll be a good testing ground to start with. You even accounted for the fisheye. Now if you could get texturing in, it would be even better. Then I'd have to figure out how to do sprites with clipping and z-indexing.

Everyone's examples are great. But jfroco somehow reached into my brain and figured out what I was trying to do all day yesterday. Don't know how.

I'd really like to up the resolution on how many lines of ray are drawn across the screen up to 320 so I can have a true 320x200 game.

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 8:45 pm
by bartbes
It's probably because your name are alike.. are you the same person? :P

Re: Working Raycasting example?

Posted: Fri Jan 06, 2012 10:58 pm
by Jasoco
Not unless jfroco's the me from the future come back in time to secretly help me become the master of the universe.