Author Topic: Another Raycaster [BB2D]  (Read 2210 times)

0 Members and 1 Guest are viewing this topic.

Offline mike_g

  • Amiga 1200
  • ****
  • Posts: 435
  • Karma: 34
    • View Profile
Another Raycaster [BB2D]
« on: August 12, 2007 »
Heres a raycaster I have been working on. It needs optimising and the clipping can be a bit dodgy at times. If its too slow you can comment out the DrawFire(), which should speed it up a bit. I seriously dont understand how people make these things in < 5K. Anyway:
Code: [Select]
Const GRAPHICS_W=640
Const GRAPHICS_H=480
Const DRAW_FROM=20
Const MAP_W=30
Const MAP_H=30
Const TEX_W=64
Const TEX_H=64

Graphics GRAPHICS_W, GRAPHICS_H, 32, 0
SetBuffer BackBuffer()
Dim screen(GRAPHICS_W, GRAPHICS_H)


Dim fire(GRAPHICS_W, GRAPHICS_H)
Dim palette(256)
FireInit()


;LOAD TEXTURES
tmp = LoadImage("tex.png");LoadAnimImage("textures.png", 64, 64, 0, 8)
Dim tex(ImageWidth(tmp), ImageHeight(tmp))
LockBuffer ImageBuffer(tmp)
For y=0 To ImageHeight(tmp)-1
For x=0 To ImageWidth(tmp)-1
tex(x, y)=ReadPixelFast(x, y, ImageBuffer(tmp))
Next
Next
UnlockBuffer ImageBuffer(tmp)
FreeImage(tmp)

;INIT MAP
Dim map(MAP_W, MAP_H)
For y=0 To MAP_H-1
For x=0 To MAP_W-1
Read map(x, y)
Next
Next

;PLAYER VARIABLES
Global pos_x#=10, pos_y#=5
Global dir_x#=-1, dir_y#=0
Global cam_x#=0,  cam_y#=0.66 ;camera plane
Global mov_spd#=0.3, rot_spd#=3

;FRAME RATE VARIABLES
Global old_time = MilliSecs()
Global frame_count, fps

;MAIN LOOP
While Not KeyHit(1)
Clear();can go when roof and floor are drawn
DrawFire()
Raycast()
Render()
PlayerMove()
FPS()
Flip
Wend

;---------------------------------------------------------------------------------------------------;
;*************************************** RAYCASTING ************************************************;
;---------------------------------------------------------------------------------------------------;

Function Raycast()
Local ray_x# = pos_x#
Local ray_y# = pos_y#

For x=0 To GRAPHICS_W-1
camera_x# = 2 * x / Float(GRAPHICS_W)-1
ray_dir_x# = dir_x# + cam_x# * camera_x#
ray_dir_y# = dir_y# + cam_y# * camera_x#
map_x = ray_x#
map_y = ray_y#

;DISTANCE TO NEXT SIDE
delta_dist_x# = Sqr(1+(ray_dir_y# * ray_dir_y#)/(ray_dir_x# * ray_dir_x#))
delta_dist_y# = Sqr(1+(ray_dir_x# * ray_dir_x#)/(ray_dir_y# * ray_dir_y#))

;CALCULATE STEP AND INITIAL DISTANCE TO NEAREST SIDE
If ray_dir_x# < 0
step_x = -1
side_dist_x# = (ray_x# - map_x) * delta_dist_x#
Else
step_x = 1
side_dist_x# = (map_x + 1.0 - ray_x#) * delta_dist_x#
EndIf
If ray_dir_y# < 0
step_y = -1
side_dist_y#= (ray_y# - map_y) * delta_dist_y#
Else
step_y = 1
side_dist_y# = (map_y + 1.0 - ray_y#) * delta_dist_y#
EndIf


;PERFORM DDA
hit=0
While hit = 0
;jump To next map square, or in x-direction, or in y-direction
If side_dist_x# < side_dist_y#
side_dist_x# = side_dist_x# + delta_dist_x#
map_x = map_x + step_x
side = 0
Else
side_dist_y# = side_dist_y# + delta_dist_y#
map_y = map_y + step_y
side = 1
EndIf
;Check If ray has hit a wall
If map(map_x, map_y) > 0 hit = 1
Wend


;CALCULATE DISTANCE PROJECTED ON CAMERA DIRECTION
If side = 0
perp_wall_dist# = Abs((map_x - ray_x# + (1-step_x) / 2) / ray_dir_x#)
Else
perp_wall_dist# = Abs((map_y - ray_y# + (1-step_y) / 2) / ray_dir_y#)
EndIf

Local line_height = Abs(Int(GRAPHICS_H / perp_wall_dist#))
Local line_start = (-line_height / 2) + (GRAPHICS_H / 2)
If line_start < 0 Then line_start = 0
Local line_end = (line_height / 2) + (GRAPHICS_H / 2)
If line_end >= GRAPHICS_H Then line_end = GRAPHICS_H-1

;TEXTURE WALLS
tex_num = map(map_x, map_y)-1 ;what texture to use

;GET VALUE OF WALL_X
If side = 1
wall_x# = ray_x# + ((map_y - ray_y# + (1 - step_y) / 2) / ray_dir_y#) * ray_dir_x#
Else
wall_x# = ray_y# + ((map_x - ray_x# + (1 - step_x) / 2) / ray_dir_x#) * ray_dir_y#
EndIf
wall_x# = wall_x# - Floor(wall_x#)

;GET X CO-ORD ON TEXTURE
tex_x = Int(wall_x# * Float(TEX_W))
If side = 0 And ray_dir_x# > 0 Then tex_x = TEX_W - tex_x - 1
If side = 1 And ray_dir_y# < 0 Then tex_x = TEX_W - tex_x - 1
If tex_x >= TEX_W Then tex_x = tex_x - TEX_W
If tex_x < 0 Then tex_x = TEX_W + tex_x


;For y=0 To line_start
; screen(x, y)=255
;Next

;DRAW TO WALLS TO BUFFER
For y=line_start+1 To line_end

d = (y * 256) - ((GRAPHICS_H * 128) + (line_height * 128))
If line_height > 0 ;stops divide by 0
tex_y = (((d * TEX_H) / line_height) / 256)
If tex_y >= TEX_H Then tex_y = tex_y - TEX_H
If tex_y < 0 Then tex_y = TEX_H + tex_y
Else
tex_y=0
EndIf

col = tex((tex_num*TEX_W)+tex_x, tex_y)
If side = 1 Then col = (col Shr 1) And 8355711
screen(x, y)=col
Next

;FLOOR CASTING
If side = 0 And ray_dir_x# >= 0
floor_wall_x# = map_x
floor_wall_y# = map_y + wall_x#
Else If side = 0 And ray_dir_x# < 0
floor_wall_x# = map_x + 1
floor_wall_y# = map_y + wall_x#
Else If side = 1 And ray_dir_y# > 0
floor_wall_x# = map_x + wall_x#
floor_wall_y# = map_y
Else
floor_wall_x# = map_x + wall_x#
floor_wall_y# = map_y + 1
EndIf

wall_dist# = perp_wall_dist#
player_dist# = 0
If line_end < 0 Then line_end =0


For y=line_end+1 To GRAPHICS_H-1
current_dist# = GRAPHICS_H / (2.0 * y-GRAPHICS_H);make a lookup table for this
weight# = (current_dist# - player_dist#) / (wall_dist# - player_dist#)
current_floor_x# = weight * floor_wall_x# +(1-weight) * pos_x#
current_floor_y# = weight * floor_wall_y# +(1-weight) * pos_y#

floor_tex_x = Int(current_floor_x# * TEX_W) Mod TEX_W
floor_tex_y = Int(current_floor_y# * TEX_H) Mod TEX_H
screen(x, y) = tex(floor_tex_x, floor_tex_y)
Next

Next

End Function

;---------------------------------------------------------------------------------------------------;
;************************************* SCREEN DRAWING **********************************************;
;---------------------------------------------------------------------------------------------------;

Function Clear()
For y=0 To GRAPHICS_H-1
For x=0 To GRAPHICS_W-1
screen(x, y)=0
Next
Next
End Function

Function Render()
LockBuffer BackBuffer()
For y=0 To GRAPHICS_H-1
For x=0 To GRAPHICS_W-1
WritePixelFast(x, y, screen(x, y))
Next
Next
UnlockBuffer BackBuffer()
End Function

;---------------------------------------------------------------------------------------------------;
;************************************* PLAYER MOVEMENT *********************************************;
;---------------------------------------------------------------------------------------------------;

Function PlayerMove()
;STRAFE MODE
If KeyDown(42)
If KeyDown(203);left
mov_x# = pos_x# + ((-dir_y#) * mov_spd# *0.5)
mov_y# = pos_y# - ((-dir_x#) * mov_spd# *0.5)
If map(mov_x#, pos_y#) = 0 Then pos_x# = mov_x#
If map(pos_x#, mov_y#) = 0 Then pos_y# = mov_y#
Else If KeyDown(205);right
mov_x# = pos_x# + ((dir_y#) * mov_spd# *0.5)
mov_y# = pos_y# - ((dir_x#) * mov_spd# *0.5)
If map(mov_x#, pos_y#) = 0 Then pos_x# = mov_x#
If map(pos_x#, mov_y#) = 0 Then pos_y# = mov_y#
EndIf
;TURN MODE
Else
;Rotate camera direction and plane
If KeyDown(203);left
old_dir_x# = dir_x#
dir_x# = (dir_x# * Cos(rot_spd#)) - (dir_y# * Sin(rot_spd#))
dir_y# = (old_dir_x# * Sin(rot_spd#)) + (dir_y# * Cos(rot_spd#))
old_cam_x# = cam_x#
cam_x# = (cam_x# * Cos(rot_spd#)) - (cam_y# * Sin(rot_spd#))
cam_y# = (old_cam_x# * Sin(rot_spd#)) + (cam_y# * Cos(rot_spd#))
Else If KeyDown(205);right
old_dir_x# = dir_x#
dir_x# = (dir_x# * Cos(-rot_spd#)) - (dir_y# * Sin(-rot_spd#))
dir_y# = (old_dir_x# * Sin(-rot_spd#)) + (dir_y# * Cos(-rot_spd#))
old_cam_x# = cam_x#
cam_x# = (cam_x# * Cos(-rot_spd#)) - (cam_y# * Sin(-rot_spd#))
cam_y# = (old_cam_x# * Sin(-rot_spd#)) + (cam_y# * Cos(-rot_spd#))
EndIf
EndIf

;MOVE FORWARDS AND BACKWARDS
If KeyDown(200)
mov_x#=pos_x# + (dir_x# * mov_spd#)
mov_y#=pos_y# + (dir_y# * mov_spd#)
If map(mov_x#, pos_y#) = 0 Then pos_x# = mov_x#
If map(pos_x#, mov_y#) = 0 Then pos_y# = mov_y#
Else If KeyDown(208)
mov_x#=pos_x# - (dir_x# * mov_spd# *0.7)
mov_y#=pos_y# - (dir_y# * mov_spd# *0.7)
If map(mov_x#, pos_y#) = 0 Then pos_x# = mov_x#
If map(pos_x#, mov_y#) = 0 Then pos_y# = mov_y#
EndIf
End Function


;---------------------------------------------------------------------------------------------------;
;************************************* EXTRA FUNCTIONS *********************************************;
;---------------------------------------------------------------------------------------------------;


Function FPS()
If MilliSecs() > old_time+1000
old_time = MilliSecs()
fps=frame_count
frame_count=0
EndIf
Color 255, 255, 255
Text 0, 0, "FPS: "+fps
frame_count=frame_count+1
End Function

Function FireInit()
For i = 0 To 255
If r > 255 Then r = 255
If g > 255 Then g = 255
If b > 255 Then b = 255
palette(i)=(r Shl 16)+(g Shl 8)+b
r=r+2: g=g+3: b=b+5
Next
End Function


Function DrawFire()
Local w=GRAPHICS_W-1
Local h=(GRAPHICS_H/2)-1

;CREATE A RANDOM BASE FOR THE FIRE
For x=0 To w
    fire(x, h) = Rand(0, 400)
Next

;DO FIRE
For y=DRAW_FROM To h-1
upper_y = y+1
If y < h-1
lower_y = y+2
Else
lower_y = upper_y
EndIf
left_pix = fire( 0, upper_y )
mid_pix =  fire( 0, upper_y )
right_pix =fire( 1, upper_y)
base_pix = fire( 0, lower_y)

For x=0 To w
left_pix = mid_pix
mid_pix = right_pix

If x < w
right_pix= fire( x+1, upper_y )
Else
right_pix= fire( x, upper_y )
EndIf
base_pix = fire( x, lower_y )

fire(x, y)=((left_pix+mid_pix+right_pix+base_pix)Shl 5)/129

;DRAW FIRE TO SCREEN BUFFER
screen(x, y)=palette( fire(x, y) )
Next
Next


End Function

;---------------------------------------------------------------------------------------------------;
;*************************************** LEVEL DATA ************************************************;
;---------------------------------------------------------------------------------------------------;

Data 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 3, 5, 5, 3, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
Data 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 5, 5, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 4, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 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, 1
Data 1, 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, 1
Data 1, 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, 1
Data 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 2, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 2, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 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, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 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, 1
Data 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 6, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1

And heres the textures for it:

One thing I wanted to do was draw variable height walls. I created this working from a tutorial that doesent explain how to do this, does anyone know how this could be done, or where I can find a tut that explains this? Cheers. 

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Another Raycaster [BB2D]
« Reply #1 on: August 12, 2007 »
Slight bugette in the fire code
Code: [Select]
Dim palette(256)
...
fire(x, h) = Rand(0, 400)
...
screen(x, y)=palette( fire(x, y) )
It just goes out of range sometimes, when rand>256.

Quote
I seriously dont understand how people make these things in < 5K.
Your code would compile to about 5Kb under Windows if you didn't have the 700Kb Blitz runtime library :)

Very nice demo :)  K+
Any plans for it?

Jim
Challenge Trophies Won:

Offline mike_g

  • Amiga 1200
  • ****
  • Posts: 435
  • Karma: 34
    • View Profile
Re: Another Raycaster [BB2D]
« Reply #2 on: August 12, 2007 »
Quote
Slight bugette in the fire code
Yeah, by turning the rand up the flames fill the sky more, but yeah I know its a bad way to do it ;)

Quote
Your code would compile to about 5Kb under Windows if you didn't have the 700Kb Blitz runtime library
I just had a look at tetras one, and thats quite a bit less code with no clipping problems, so I'll go over it a bit more.

At the end of the day I don't really deserve all that much credit for it, as I was basically converting it from C++, and trying to understand it as I went along. At least I'm starting to get what vectors are  tho.

As for plans, a little doom like shoot em up would be cool. I've already got the strafeing set up, just need to make it so you dont move faster on diagnals, but thats easy to fix :)

Offline Devils Child

  • C= 64
  • **
  • Posts: 66
  • Karma: 2
    • View Profile
Re: Another Raycaster [BB2D]
« Reply #3 on: August 12, 2007 »
thats cool. a raycaster with floor-casting. never knew how floorcasting works...
also it is pretty slow and there are some bugs.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17378
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: Another Raycaster [BB2D]
« Reply #4 on: August 12, 2007 »
Not a bad raycaster really :) Thanks for posting it!
Shockwave ^ Codigos
Challenge Trophies Won:

Offline mike_g

  • Amiga 1200
  • ****
  • Posts: 435
  • Karma: 34
    • View Profile
Re: Another Raycaster [BB2D]
« Reply #5 on: August 12, 2007 »
Cheers, I made a level editor and added lighting effects for indoors. I can't seem to fix that clipping problem tho and its really pissing me off  >:(

Basically it only seems to happen when the player x direction is around +-1 and y direction is 0 or the other way around. Then the ray seems to get hits when they arent there (to the left), and misses walls when they are (to the right). This only seems to happen when you are looking more or less at the edge of a wall facing it. Sorry if that sounds confusing, you should be able to see it by running the code above.

I'm thinking that the problem could be down to floating point inacuracy, as I converted from a C++ tutorial which used doubles. If anyone can find whats going wrong I would be very grateful :)

Offline mike_g

  • Amiga 1200
  • ****
  • Posts: 435
  • Karma: 34
    • View Profile
Re: Another Raycaster [BB2D]
« Reply #6 on: August 13, 2007 »
Ok I got this sorted now. It took fucking ages and I rewrote half the raytracer, in a way I found more understandable, but theres no more clipping problems :updance:

The ray positions are now checked at regular intervals, instead of moving from one grid square to the next, which slows it down even more, but I made quite a few tweaks to get the speed back elsewhere. Anyway I'll post what I got when in a few days. Hopefully it will be starting to resemble a game of some sort by then.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17378
  • Karma: 497
  • evil/good
    • View Profile
    • My Homepage
Re: Another Raycaster [BB2D]
« Reply #7 on: August 13, 2007 »
Cool and even better if it actually turns into a game at the end of it! Most raycasters end up gathering dust once they have been perfected, it seems to me that very few of them actually end up inside a game!
Shockwave ^ Codigos
Challenge Trophies Won: