Made in about an hour, in QB64
'(c) 2021, @_sorceress
' wasd + mouse to move.
' mouse control doesn't seem to work on linux. this is a bug in QB64.
SCREEN _NEWIMAGE(640, 480, 256)
_TITLE "Basic Raycatter"
'generate random test map
RANDOMIZE TIMER
DIM g(15, 15)
FOR x = 0 TO 15: FOR y = 0 TO 15
IF RND < .3 THEN gv = 1 ELSE gv = 0
IF x MOD 15 = 0 OR y MOD 15 = 0 THEN gv = 1
IF ABS(x - 5) + ABS(y - 5) < 3 THEN gv = 0
g(x, y) = gv
NEXT: NEXT
'player behaviour
px = 5: py = 5: pa = 0: pelev = 0
turnspeed = 5: walkspeed = 2.5
FPS = 30: dt = 1 / FPS
DO
'### input
fv = 0: sv = 0
IF ScanKey%(17) THEN fv = fv + walkspeed
IF ScanKey%(31) THEN fv = fv - walkspeed
IF ScanKey%(30) THEN sv = sv + walkspeed
IF ScanKey%(32) THEN sv = sv - walkspeed
WHILE _MOUSEINPUT
pa = pa + turnspeed * (_MOUSEMOVEMENTX / 1000)
pelev = pelev + turnspeed * (_MOUSEMOVEMENTY / 1000)
IF ABS(pelev) > 1 THEN pelev = SGN(pelev)
WEND
'### physics
pacos = COS(pa): pasin = SIN(pa)
xvt = fv * pacos + sv * pasin
yvt = fv * pasin - sv * pacos
xv = xv + (xvt - xv) * 4 * dt
yv = yv + (yvt - yv) * 4 * dt
px1 = px + xv * dt: py1 = py + yv * dt
x1 = px1: y1 = py: GOSUB cbox: IF ok = 0 THEN px = px1
x1 = px: y1 = py1: GOSUB cbox: IF ok = 0 THEN py = py1
'### raycatter
h0 = 240 - 240 * pelev
LINE (0, 0)-(639, h0), 11, BF
LINE (0, h0)-(639, 479), 8, BF
x = 320 * (1 - TAN(pa - 3.141 / 2)): y = h0 - 320
IF pasin > 0 THEN CIRCLE (x, y), 32, 14: PAINT (x, y + 30), 14, 14
FOR sx = 0 TO 639: e = sx / 320 - 1 'x-fov
x = px: y = py 'ray origin
rx = pacos - e * pasin: ry = pasin + e * pacos 'ray vector
d = 0: dd = .01 'terribly inefficient way of catting rays
WHILE g(INT(x), INT(y)) = 0
x = x + rx * dd: y = y + ry * dd: d = d + dd: dd = dd * 1.005
WEND
h = 100 / d 'draw column
LINE (sx, h0 - h)-(sx, h0 + h), (3 * INT(x) + INT(y)) MOD 7 + 1
NEXT
'### draw minimap
m = 8
FOR x = 0 TO 15: FOR y = 0 TO 15
LINE (x * m, y * m)-(x * m + m, y * m + m), g(x, y) * 8, BF
NEXT: NEXT
x = m * px: y = m * py: ux = m * pacos: uy = m * pasin
LINE (x - ux, y - uy)-(x + ux, y + uy), 3: LINE -(x - uy, y + ux), 3: LINE -(x + uy, y - ux), 3: LINE -(x + ux, y + uy), 3
'### text feedback
LOCATE 1, 20: PRINT px; py; pa; pelev
_DISPLAY: _LIMIT FPS
LOOP
'################################################################################
'collision box test. a must be smaller than 0.5 to work properly.
cbox:
a = .2
ok = g(INT(x1 - a), INT(y1 - a)) + g(INT(x1 + a), INT(y1 - a)) + g(INT(x1 - a), INT(y1 + a)) + g(INT(x1 + a), INT(y1 + a))
RETURN
'is key down?
FUNCTION ScanKey% (scancode%)
STATIC Ready%, keyflags%()
IF NOT Ready% THEN REDIM keyflags%(0 TO 127): Ready% = -1
i% = INP(&H60)
IF (i% AND 128) THEN keyflags%(i% XOR 128) = 0
IF (i% AND 128) = 0 THEN keyflags%(i%) = -1
K$ = INKEY$
ScanKey% = keyflags%(scancode%)
END FUNCTION
You made this in an hour? I can hardly type that fast :-D Very impressive.
QBasic, now that's a name I haven't heard in a long time. Neat that there're people out there still updating some kind of version of it!
You probably know this already (and also the least important thing ever), but; sometimes an inwards corner is missing a small sliver.
For anyone running Linux, you can put in some keyboard controls for view-direction by adding this to the source, between the other key handling (Q, E, R, F keys are used … the numbers seem to be the order in which they are on the keyboard, so maybe it's other keys in other layouts):
IF ScanKey%(16) THEN pa = pa - turnspeed / 50
IF ScanKey%(18) THEN pa = pa + turnspeed / 50
IF ScanKey%(19) THEN pelev = pelev - turnspeed / 100
IF ScanKey%(33) THEN pelev = pelev + turnspeed / 100
IF ABS(pelev) > 1 THEN pelev = SGN(pelev)
Otherwise it would seem I'm a bit too tired right now to mess with source code :-D
P.S. I'm with toasty, where's the cats?
The code is the manual. So cool B-)
This is really cool, @sorceress: not just that you built a raycaster in basic, and in so few lines, but in under an hour. Wow! I expect this would fit right in in a demoscene event.
The mipmap is a nice touch too. What more could we ask for? Well, perhaps a cat, given the name :P