1990's 3D Doom-Like Walls Example - SierraKen - 01-06-2025
This is a Public Domain post from the old newsgroup comp.lang.basic.misc that I remember from back in the 1990's. It's NOT my code, but many people have modified it, etc. I will post the URL I got it from below. The original programmer (Peter Cooper) says in the comments that is is public domain for anyone to modify, which is why I wanted to show you guys. The incredible thing is that it's so short and does so much. Maybe some of you can learn from it or add-on to it, or whatever. I might do the same someday.
To turn, use the right and left arrow keys, to move, press the Space Bar. Since this is from QBasic, the screen is very small, but I'm sure it can be changed to larger. The map is made using DATA statements which is really cool and easy for editing I'm sure. There's no enemies or shooting in this, it's just a small 3D walls and backdrop example.
Here is where it is posted online, someone that modified it put a description on this page with the code:
https://groups.google.com/g/comp.lang.basic.misc/c/oSTeNJJhnDY/m/Z0w3_y2WOSYJ
Here is the code, enjoy!
Code: (Select All)
'=======================================================================
' RAY CASTER 3D sorta ENGINE thingymajig
'=======================================================================
' Wrote this about a month ago, it's a sort of wolfenstien\doom
' lookalike but all in native QBasic source! Uses an interesting ray
' tracing technique could be optimized x1000 Infact, it's being
' converted to ASM and stuff like textures will be added and maybe a bit
' of shading
'
' Anyway, this code is _public domain_, change it, modify it, whatever,
' it only took about 40 mins in total, So whatever.. you have fun with
' it <grin>
'
' Cheers, {:o) Peter Cooper
' Minor clean-up by Brent P. Newhall
' Left arrow == Move left
' Right arrow == Move right
' [SPACE] == Move
' [ESC] == Quit
' Ceilings/floors added by Nick Cangiani
' nic...@gnn.com
DECLARE SUB screensetup ()
DECLARE SUB makeworld ()
DECLARE SUB maketables ()
Dim Shared st%(0 To 360)
Dim Shared ct%(0 To 360)
Dim Shared a$(1 To 10)
Dim Shared grid(1 To 12, 1 To 12)
px% = 15: py% = 35: sa% = 0
Print "Please wait...";
Randomize Timer
makeworld
maketables
screensetup
m% = 1
Do
If m% = 1 Then
If P = 2 Then PCopy 2, 0 Else PCopy 3, 0
If P = 2 Then P = 3 Else P = 2
m% = 0
End If
For t% = sa% To sa% + 59 Step 1
xb = st%(t% Mod 360) / 100 'get inc
yb = ct%(t% Mod 360) / 100 'get inc
bx = px% 'decimal copy
by = py% 'decimal copy
l% = 0 'reset length
Do
bx = bx + xb
by = by + yb
l% = l% + 1
'k% = ASC(MID$(a$(CINT(by / 10)), CINT(bx / 10), 1)) - 48
k% = grid(CInt(by / 10), CInt(bx / 10))
Loop Until k% <> 0
'LOCATE 1, 1
'PRINT l%; 'this would print the distance to wall from player
X% = (t% - sa%) * 5
dd% = (1000 / l%)
'LINE (X%, 1)-(X% + 5, 99 - dd%), 15, BF 'paint ceiling
'LINE (X%, 101 + dd%)-(X% + 5, 200), 2, BF 'paint floor
Line (X%, 100 - dd%)-(X% + 5, 100 + dd%), k%, BF 'paint walls
Line (X%, 100 - dd%)-(X% + 5, 100 - dd%), 0 'top lines
Line (X%, 100 + dd%)-(X% + 5, 100 + dd%), 0 'bottom lines
Next t%
PCopy 0, 1
Do: in$ = InKey$: Loop Until in$ <> ""
Select Case in$
Case Chr$(0) + "M" ' [LEFT]
sa% = sa% + 3
m% = 1
Case Chr$(0) + "K" ' [RIGHT]
sa% = (sa% + 357) Mod 360
m% = 1
Case Chr$(27) ' [ESC]
quit = 1
Case " " ' [SPACE]
Oldpx% = px%: Oldpy% = py% ' Save where you are
px% = px% + (st%(t% Mod 360) / 50)
py% = py% + (ct%(t% Mod 360) / 50)
If grid(CInt(py% / 10), CInt(px% / 10)) > 0 Then 'Walking thru walls?
px% = Oldpx% ' Forget it! Don't move
py% = Oldpy%
End If
m% = 1
End Select
Loop Until quit > 0
Screen 0
Width 80, 25
System
' Level data (this way you can have walls colored 10, 11, etc.)
' 12x12
Data 1,9,1,9,1,9,1,9,1,9,1,9
Data 9,0,4,0,0,0,0,0,0,5,0,1
Data 1,0,12,0,0,0,0,0,0,13,0,9
Data 9,0,4,0,0,0,0,0,0,5,0,1
Data 1,0,12,0,0,0,0,0,0,13,0,9
Data 9,0,0,0,0,1,1,0,0,0,0,1
Data 1,0,0,0,0,1,1,0,0,0,0,9
Data 9,0,12,0,0,0,0,0,0,0,0,1
Data 1,0,4,0,0,0,0,0,3,11,0,9
Data 9,0,12,0,0,0,0,0,11,3,0,1
Data 1,0,4,0,0,0,0,0,0,0,0,9
Data 9,1,9,1,9,1,9,1,9,1,9,1
' Old level. If you want it, come and get it.
' 1, 9, 1, 9, 1, 9, 1, 9, 1, 9
' 9, 0, 0, 0, 0, 0, 0, 0, 0, 1
' 1, 0, 0, 0, 0, 0, 0, 4, 0, 9
' 9, 0, 1, 0, 0, 0, 5, 0, 0, 1
' 1, 0, 2, 0, 0, 4, 0, 0, 0, 9
' 9, 0, 3, 0, 0, 0, 0, 0, 0, 1
' 1, 0, 0, 0, 0, 7, 8, 0, 0, 9
' 9, 0, 5, 0, 0, 8, 7, 0, 0, 1
' 1, 0, 6, 0, 0, 0, 0, 0, 0, 9
' 9, 1, 9, 1, 9, 1, 9, 1, 9, 1
Sub maketables ()
' Peters boring _yawn_ table creation
For tmp1% = 0 To 360
st%(tmp1%) = Sin(tmp1% * .0174) * 100
If tmp1% Mod 100 = 0 Then Print ; ".";
Next tmp1%
For tmp1% = 0 To 360
ct%(tmp1%) = Cos(tmp1% * .0174) * 100
If tmp1% Mod 100 = 0 Then Print ; ".";
Next tmp1%
End Sub
Sub makeworld ()
' Read in this level's data
For j = 1 To 12
For i = 1 To 12
Read grid(i, j)
Next i
Next j
' Peter Coopers demonstration level. Change it if you wish! Each number
' is a color number
'a$(1) = "1919191919"
'a$(2) = "9000000001"
'a$(3) = "1000000409"
'a$(4) = "9010005001"
'a$(5) = "1020040009"
'a$(6) = "9030000001"
'a$(7) = "1000078009"
'a$(8) = "9050087001"
'a$(9) = "1060000009"
'a$(10) = "9191919191"
End Sub
Sub screensetup ()
Screen 7, , 2, 0
Cls
'WINDOW SCREEN (1, 1)-(320, 200)
' Sky
Line (0, 0)-(300, 99), 3, BF
For cnt = 1 To 10 ' Clouds
a = Int(Rnd * 319)
b = Int(Rnd * 80 + 10)
c = Int(Rnd * 50)
d = Int(Rnd * 10): d = d / 100
Circle (a, b), c, 1, , , d: Paint (a, b), 1
Circle (a, b), c, 15, , , d: Paint (a, b), 15
Next cnt
Line (301, 0)-(319, 199), 0, BF ' Erase clouds on right
' Obelisk
'LINE (200, 20)-(240, 99), 0, BF
'LINE (201, 21)-(239, 98), 8, BF
Line (200, 20)-(220, 15), 8 ' Building (gray)
Line (220, 15)-(240, 20), 8
Line (200, 20)-(200, 99), 8
Line (240, 20)-(240, 99), 8
Line (200, 99)-(240, 99), 8
Paint (220, 50), 8
For cnt = 1 To 20 ' Lights
PSet (Int(Rnd * 38 + 201), Int(Rnd * 80 + 20)), 14
Next cnt
Line (200, 20)-(220, 15), 0 ' Building (border)
Line (220, 15)-(240, 20), 0
Line (219, 15)-(219, 99), 0
Line (200, 20)-(200, 99), 0
Line (240, 20)-(240, 99), 0
' Sun
Circle (50, 30), 10, 14: Paint (50, 30), 14, 14
PCopy 2, 3
For Y% = 100 To 199
For X% = 0 To 300
If Rnd > .5 Then c% = 6 Else c% = 0
PSet (X%, Y%), c%
Next X%
Next Y%
Screen 7, , 3, 0
For Y% = 100 To 199
For X% = 0 To 300
If Rnd > .5 Then c% = 6 Else c% = 0
PSet (X%, Y%), c%
Next X%
Next Y%
Screen 7, , 0, 1
End Sub
RE: 1990's 3D Doom-Like Walls Example - SierraKen - 01-06-2025
Here is a search list of other links to different variations of this program (and some others) that some of you might want to check out.
https://groups.google.com/g/comp.lang.basic.misc/search?q=3d%20walls
RE: 1990's 3D Doom-Like Walls Example - SquirrelMonkey - 01-06-2025
I remember that program! Does PCOPY work with higher color modes in QB64?
RE: 1990's 3D Doom-Like Walls Example - SierraKen - 01-06-2025
(01-06-2025, 06:51 AM)SquirrelMonkey Wrote: I remember that program! Does PCOPY work with higher color modes in QB64? That's awesome SquirrelMonkey! I wondered if anyone here used that newsgroup like I did. I had a huge QBasic website in Geocities back then too.
I just looked up PCOPY and it says any SCREEN mode should work. You can read about it here:
https://qb64phoenix.com/qb64wiki/index.php/PCOPY
RE: 1990's 3D Doom-Like Walls Example - Petr - 01-06-2025
Interesting. Thnaks for sharing. PCOPY is possible using in 32 bit Screens.
RE: 1990's 3D Doom-Like Walls Example - a740g - 01-11-2025
@SierraKen I wanted to mess with raycasters for a long time. And thanks to, I had a bit of fun with this.
I re-wrote this (almost entirely) for QB64-PE v4. Hopefully it will be easy to understand even without comments.
It currently only renders solid walls and brute forces it's way.
![[Image: Screenshot-2025-01-12-024619.png]](https://i.ibb.co/x8V15YN/Screenshot-2025-01-12-024619.png)
Code: (Select All)
' Solid-wall raycaster by a740g
' Does not use DDA-based optimizations (yet)
' Performance may suffer on low-end / old hardware
_DEFINE A-Z AS LONG
OPTION _EXPLICIT
CONST SCREEN_WIDTH& = 640&
CONST SCREEN_HEIGHT& = 400&
CONST SCREEN_HALF_WIDTH& = SCREEN_WIDTH \ 2&
CONST SCREEN_HALF_HEIGHT& = SCREEN_HEIGHT \ 2&
CONST SCREEN_MODE& = 256&
CONST RENDER_FPS& = 60&
CONST PLAYER_FOV& = 60&
CONST PLAYER_HALF_FOV& = PLAYER_FOV \ 2&
CONST RAYCAST_INCREMENT_ANGLE! = PLAYER_FOV / SCREEN_WIDTH
CONST RAYCAST_PRECISION! = 64!
CONST MAP_DEFAULT_BOUNDARY_COLOR~& = 7
CONST PLAYER_MOVE_SPEED! = 0.1!
CONST PLAYER_LOOK_SPEED! = 0.1!
CONST AUTOMAP_SCALE& = 4
CONST AUTOMAP_PLAYER_RADIUS& = 2
CONST AUTOMAP_PLAYER_COLOR~& = 15
CONST AUTOMAP_PLAYER_CAMERA_COLOR~& = 14
TYPE Vector2i
x AS LONG
y AS LONG
END TYPE
TYPE Vector2f
x AS SINGLE
y AS SINGLE
END TYPE
TYPE Camera
angle AS SINGLE
direction AS Vector2f
END TYPE
TYPE Player
position AS Vector2f
camera AS Camera
END TYPE
RANDOMIZE TIMER
$RESIZE:SMOOTH
SCREEN _NEWIMAGE(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_MODE)
_ALLOWFULLSCREEN _SQUAREPIXELS , _SMOOTH
REDIM map(0, 0) AS _UNSIGNED LONG
RESTORE level_data
MakeWorld map()
DIM environment AS LONG
environment = MakeEnvironment
DIM player AS Player
player.position.x = 6!
player.position.y = 3!
player.camera.angle = 90!
UpdatePlayerCamera player
DIM automap AS LONG
automap = MakeAutomap(map())
_MOUSEHIDE
DO
HandleInput player, map()
RenderFrame player, map(), environment, automap
_DISPLAY
_LIMIT RENDER_FPS
LOOP UNTIL _KEYHIT = 27
SYSTEM
' Level data:
' Width,Height
' Wall colors in hexadecimal
level_data:
DATA 24,20
DATA 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
DATA 9,0,0,C,0,0,0,0,0,5,0,9,0,0,0,0,0,0,0,0,0,0,0,9
DATA 9,0,0,C,0,0,0,0,0,D,0,9,0,0,C,0,0,0,0,0,0,0,0,9
DATA 9,0,0,C,0,0,0,0,0,5,0,0,0,0,C,0,0,0,0,0,0,D,0,9
DATA 9,0,0,C,0,0,0,0,0,D,0,0,0,0,C,0,0,0,0,0,0,D,0,9
DATA 9,0,0,0,0,1,9,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,9
DATA 9,0,0,0,0,9,1,0,0,0,0,9,0,0,0,0,0,1,1,0,0,0,0,9
DATA 9,0,C,0,0,0,0,0,0,0,0,0,0,0,C,0,0,0,0,0,0,0,0,9
DATA 9,0,C,0,0,0,0,0,B,B,0,0,0,0,C,0,0,0,0,0,B,B,0,9
DATA 9,0,C,0,0,0,0,0,B,B,0,0,0,0,C,0,0,0,0,0,B,B,0,9
DATA 9,0,4,0,0,0,0,0,0,0,0,0,0,0,1,9,1,9,1,9,1,9,1,9
DATA 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9
DATA 9,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,9
DATA 9,0,1,0,0,0,5,0,0,0,0,0,0,0,1,0,0,0,0,0,0,5,0,9
DATA 9,0,2,0,0,4,0,0,0,0,0,9,0,0,2,0,0,0,0,0,0,0,0,9
DATA 9,0,B,0,0,0,0,0,0,0,0,9,0,0,B,0,0,0,0,0,0,0,0,9
DATA 9,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,9
DATA 9,0,5,0,0,8,7,0,0,0,0,0,0,0,5,0,0,8,7,0,0,0,0,9
DATA 9,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,9
DATA 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9
SUB MakeWorld (map( ,) AS _UNSIGNED LONG)
DIM m AS Vector2i
READ m.x, m.y
REDIM map(0 TO m.x - 1, 0 TO m.y - 1) AS _UNSIGNED LONG
DIM d AS STRING
FOR m.y = 0 TO UBOUND(map, 2)
FOR m.x = 0 TO UBOUND(map, 1)
READ d
map(m.x, m.y) = VAL("&H" + d)
NEXT m.x
NEXT m.y
END SUB
FUNCTION MakeEnvironment&
CONST PANORAMA_WIDTH& = SCREEN_WIDTH * 4
CONST SUN_RADIUS& = 20
CONST SUN_COLOR& = 14
CONST CLOUD_COUNT& = 10
CONST CLOUD_COLOR& = 15
CONST BUILDING_COLOR& = 8
DIM oldDest AS LONG: oldDest = _DEST
DIM img AS LONG: img = _NEWIMAGE(PANORAMA_WIDTH, SCREEN_HEIGHT, SCREEN_MODE)
_DEST img
LINE (0, 0)-(PANORAMA_WIDTH - 1, SCREEN_HALF_HEIGHT - 1), 3, BF
DIM x AS LONG: x = SUN_RADIUS + (PANORAMA_WIDTH - 2 * SUN_RADIUS - 1) * RND
DIM y AS LONG: y = SUN_RADIUS + (SCREEN_HALF_HEIGHT - 2 * SUN_RADIUS - 1) * RND
CIRCLE (x, y), SUN_RADIUS, SUN_COLOR
PAINT (x, y), SUN_COLOR, SUN_COLOR
DIM AS LONG i, j
FOR i = 1 TO CLOUD_COUNT
j = (PANORAMA_WIDTH \ 8) * RND
x = j + (PANORAMA_WIDTH - 2 * j) * RND
y = j + (SCREEN_HALF_HEIGHT - 2 * j) * RND
CIRCLE (x, y), j, CLOUD_COLOR, , , RND / 10!
PAINT (x, y), CLOUD_COLOR
NEXT i
x = (PANORAMA_WIDTH - 80) * RND
LINE (x, 40)-(x + 40, 30), BUILDING_COLOR
LINE (x + 40, 30)-(x + 80, 40), BUILDING_COLOR
LINE (x, 40)-(x, SCREEN_HALF_HEIGHT - 1), BUILDING_COLOR
LINE (x + 80, 40)-(x + 80, SCREEN_HALF_HEIGHT - 1), BUILDING_COLOR
LINE (x, SCREEN_HALF_HEIGHT - 1)-(x + 80, SCREEN_HALF_HEIGHT - 1), BUILDING_COLOR
PAINT (x + 24, 100), BUILDING_COLOR
FOR i = 1 TO 20
PSET (2 + x + RND * 76, 40 + RND * 160), SUN_COLOR
NEXT i
LINE (x, 40)-(x + 40, 30), 0
LINE (x + 40, 30)-(x + 80, 40), 0
LINE (x + 38, 30)-(x + 38, SCREEN_HALF_HEIGHT - 1), 0
LINE (x, 40)-(x, SCREEN_HALF_HEIGHT - 1), 0
LINE (x + 80, 40)-(x + 80, SCREEN_HALF_HEIGHT - 1), 0
FOR i = SCREEN_HALF_HEIGHT TO SCREEN_HEIGHT - 1
LINE (0, i)-(PANORAMA_WIDTH, i), 6, , _IIF(i AND 1, &B1010101010101010, &B0101010101010101)
LINE (0, i)-(PANORAMA_WIDTH, i), 8, , _IIF(i AND 1, &B0101010101010101, &B1010101010101010)
NEXT i
_DEST oldDest
MakeEnvironment = img
END FUNCTION
SUB UpdatePlayerCamera (player AS Player)
DIM ra AS SINGLE: ra = _D2R(player.camera.angle)
player.camera.direction.x = COS(ra)
player.camera.direction.y = -SIN(ra)
END SUB
SUB HandleInput (player AS Player, map( ,) AS _UNSIGNED LONG)
DIM mouseUsed AS _BYTE
DIM m AS Vector2i
WHILE _MOUSEINPUT
m.x = m.x + _MOUSEMOVEMENTX
m.y = m.y + _MOUSEMOVEMENTY
mouseUsed = _TRUE
WEND
_MOUSEMOVE SCREEN_HALF_WIDTH, SCREEN_HALF_HEIGHT
IF mouseUsed THEN
player.camera.angle = (player.camera.angle + m.x * PLAYER_LOOK_SPEED)
IF player.camera.angle >= 360! THEN player.camera.angle = player.camera.angle - 360!
IF player.camera.angle < 0! THEN player.camera.angle = player.camera.angle + 360!
UpdatePlayerCamera player
END IF
DIM keyboardUsed AS _BYTE, position AS Vector2f
IF _KEYDOWN(87) _ORELSE _KEYDOWN(119) THEN
position.x = player.position.x + player.camera.direction.x * PLAYER_MOVE_SPEED
position.y = player.position.y + player.camera.direction.y * PLAYER_MOVE_SPEED
keyboardUsed = _TRUE
END IF
IF _KEYDOWN(83) _ORELSE _KEYDOWN(115) THEN
position.x = player.position.x - player.camera.direction.x * PLAYER_MOVE_SPEED
position.y = player.position.y - player.camera.direction.y * PLAYER_MOVE_SPEED
keyboardUsed = _TRUE
END IF
IF _KEYDOWN(65) _ORELSE _KEYDOWN(97) THEN
position.x = player.position.x - player.camera.direction.y * PLAYER_MOVE_SPEED
position.y = player.position.y + player.camera.direction.x * PLAYER_MOVE_SPEED
keyboardUsed = _TRUE
END IF
IF _KEYDOWN(68) _ORELSE _KEYDOWN(100) THEN
position.x = player.position.x + player.camera.direction.y * PLAYER_MOVE_SPEED
position.y = player.position.y - player.camera.direction.x * PLAYER_MOVE_SPEED
keyboardUsed = _TRUE
END IF
IF keyboardUsed THEN
m.x = position.x
m.y = position.y
IF m.x >= 0 _ANDALSO m.y >= 0 _ANDALSO m.x <= UBOUND(map, 1) _ANDALSO m.y <= UBOUND(map, 2) _ANDALSO map(m.x, m.y) = 0 THEN
player.position = position
END IF
END IF
END SUB
FUNCTION MakeAutomap& (map( ,) AS _UNSIGNED LONG)
DIM img AS LONG: img = _NEWIMAGE((UBOUND(map, 1) + 1) * AUTOMAP_SCALE, (UBOUND(map, 2) + 1) * AUTOMAP_SCALE, SCREEN_MODE)
_CLEARCOLOR 0, img
MakeAutomap = img
END FUNCTION
SUB DrawAutomap (player AS Player, map( ,) AS _UNSIGNED LONG, automapImg AS LONG)
DIM oldDest AS LONG: oldDest = _DEST
_DEST automapImg
CLS
DIM AS Vector2i p, o
DIM mapHeight AS LONG: mapHeight = UBOUND(map, 2)
FOR p.y = 0 TO mapHeight
FOR p.x = 0 TO UBOUND(map, 1)
o.x = p.x * AUTOMAP_SCALE
o.y = (mapHeight - p.y) * AUTOMAP_SCALE
LINE (o.x + 1, o.y + 1)-(o.x + AUTOMAP_SCALE - 1, o.y + AUTOMAP_SCALE - 1), map(p.x, p.y), BF
LINE (o.x, o.y)-(o.x + AUTOMAP_SCALE, o.y + AUTOMAP_SCALE), 7, B
NEXT p.x
NEXT p.y
p.x = AUTOMAP_PLAYER_RADIUS + player.position.x * AUTOMAP_SCALE
p.y = AUTOMAP_PLAYER_RADIUS + (mapHeight - player.position.y) * AUTOMAP_SCALE
o.x = p.x + player.camera.direction.x * AUTOMAP_SCALE
o.y = p.y - player.camera.direction.y * AUTOMAP_SCALE
CIRCLE (p.x, p.y), AUTOMAP_PLAYER_RADIUS, AUTOMAP_PLAYER_COLOR
LINE (p.x, p.y)-(o.x, o.y), AUTOMAP_PLAYER_CAMERA_COLOR
_DEST oldDest
_PUTIMAGE (0, 0), automapImg
END SUB
SUB DrawBackground (player AS Player, environmentImg AS LONG)
DIM srcX AS LONG: srcX = (player.camera.angle / 360!) * _WIDTH(environmentImg)
IF srcX + SCREEN_WIDTH > _WIDTH(environmentImg) THEN
DIM partialWidth AS LONG: partialWidth = _WIDTH(environmentImg) - srcX
_PUTIMAGE (0, 0)-(partialWidth - 1, SCREEN_HEIGHT - 1), environmentImg, , (srcX, 0)-(_WIDTH(environmentImg) - 1, _HEIGHT(environmentImg) - 1)
_PUTIMAGE (partialWidth, 0)-(SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1), environmentImg, , (0, 0)-(SCREEN_WIDTH - partialWidth - 1, _HEIGHT(environmentImg) - 1)
ELSE
_PUTIMAGE (0, 0)-(SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1), environmentImg, , (srcX, 0)-(srcX + SCREEN_WIDTH - 1, _HEIGHT(environmentImg) - 1)
END IF
END SUB
SUB RenderFrame (player AS Player, map( ,) AS _UNSIGNED LONG, environmentImg AS LONG, automapImg AS LONG)
DrawBackground player, environmentImg
DIM rayAngle AS SINGLE
rayAngle = player.camera.angle - PLAYER_HALF_FOV
IF rayAngle < 0! THEN rayAngle = rayAngle + 360!
DIM i AS LONG, wallColor AS _UNSIGNED LONG, wallHeight AS LONG
DIM AS Vector2f rayPosition, rayDirection
DIM rayAngleRadian AS SINGLE, mapPosition AS Vector2i, distance AS SINGLE
FOR i = 0 TO SCREEN_WIDTH - 1
rayAngleRadian = _D2R(rayAngle)
rayDirection.x = COS(rayAngleRadian) / RAYCAST_PRECISION
rayDirection.y = -SIN(rayAngleRadian) / RAYCAST_PRECISION
rayPosition = player.position
DO
rayPosition.x = rayPosition.x + rayDirection.x
rayPosition.y = rayPosition.y + rayDirection.y
mapPosition.x = rayPosition.x
mapPosition.y = rayPosition.y
IF mapPosition.x < 0 _ORELSE mapPosition.y < 0 _ORELSE mapPosition.x > UBOUND(map, 1) _ORELSE mapPosition.y > UBOUND(map, 2) THEN
wallColor = MAP_DEFAULT_BOUNDARY_COLOR
EXIT DO
END IF
wallColor = map(mapPosition.x, mapPosition.y)
LOOP WHILE wallColor = 0
IF wallColor THEN
distance = SQR((player.position.x - rayPosition.x) ^ 2! + (player.position.y - rayPosition.y) ^ 2!) * COS(_D2R(player.camera.angle - rayAngle))
wallHeight = SCREEN_HALF_HEIGHT / distance
LINE (i, SCREEN_HALF_HEIGHT - wallHeight)-(i, SCREEN_HALF_HEIGHT + wallHeight), wallColor
END IF
rayAngle = rayAngle + RAYCAST_INCREMENT_ANGLE
IF rayAngle >= 360! THEN rayAngle = rayAngle - 360!
NEXT i
DrawAutomap player, map(), automapImg
END SUB
Next stop, DDA, texturemapping and voxelspace.
RE: 1990's 3D Doom-Like Walls Example - SierraKen - 01-15-2025
Wow this sounds GREAT! But I got an error on line 170, Array _IIF Not Defined. Or is that a new command or old command we don't use anymore? I'm using QB64 Phoenix Edition 3.14.1
Oh I see, _IFF is used with 4.0.0 or higher. I'll try to download the newest one.
RE: 1990's 3D Doom-Like Walls Example - SierraKen - 01-15-2025
FANTASTIC JOB!!! The window is larger and the movement is incredibly smooth! Good job so far! I hope you looked at the other URL of other versions of it too, there might be some code of other things like textures on another version maybe. I also wonder if the map of walls can be expanded to a larger area? I'm guessing it can, imagine the games people could make with this!
RE: 1990's 3D Doom-Like Walls Example - a740g - 01-15-2025
(01-15-2025, 05:39 AM)SierraKen Wrote: FANTASTIC JOB!!! The window is larger and the movement is incredibly smooth! Good job so far! I hope you looked at the other URL of other versions of it too, there might be some code of other things like textures on another version maybe. I also wonder if the map of walls can be expanded to a larger area? I'm guessing it can, imagine the games people could make with this!
Thanks!
I'll try to make another version with texture-mapped walls, floor, and ceiling. I also wrote a QB64-PE implementation of the VoxelSpace raytracer here: https://qb64phoenix.com/forum/showthread.php?tid=3372
You can very easily edit the map size and the map.
https://github.com/a740g/QB64-PE-Museum/blob/f9556e89310d1d9259779f8ae60f6d9c0698cfd8/a740g/RayCaster/raycaster.bas#L93
I've included the latest version in the link above. If you click on the link, the first two numbers are the width and height of the map. Then all one needs to do is edit the data and update the wall colors.
RE: 1990's 3D Doom-Like Walls Example - NakedApe - 01-15-2025
Dang, @a740g, that's super cool and done in very few LOC! Sweet job. The only minor bummer for me is the use of mousemove that causes the .25 sec delay in the Mac world, but dimming that line out and going fullscreen fixes it. Kudos to you.
|