Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
1990's 3D Doom-Like Walls Example
#1
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.ba...w3_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
Reply
#2
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.ba...3d%20walls
Reply
#3
I remember that program! Does PCOPY work with higher color modes in QB64?
Reply
#4
(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
Reply
#5
Interesting.  Thnaks for sharing. PCOPY is possible using in 32 bit Screens.


Reply
#6
@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]


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.  Big Grin
Reply
#7
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.
Reply
#8
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!
Reply
#9
(Today, 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! Smile 

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/...er.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.
Reply
#10
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.  Wink
Reply




Users browsing this thread: 4 Guest(s)