'=========================================================================== ' Subject: OPTIMIZED RAYCASTER Date: 10-30-98 (13:57) ' Author: Anders Olofsson Code: QB, QBasic, PDS ' Origin: anders.olofsson@mail.bip.net Packet: GRAPHICS.ABC '=========================================================================== ' Raycaster, by Anders Olofsson 1998 ' e-mail: anders.olofsson@mail.bip.net ' ' This raycaster is basically a heavily modified version ' of Peter Cooper's raycaster, but it's optimized... ' ' To test the fps-rate, press "f" and to change resolution, ' use the "+"/"-" keys. ' ' On a very, very slow math weak SX machine, I get about 25-30 fps when ' compiled. ' ' Compile for best performance! ' DEFINT A-Z DECLARE FUNCTION KeyStat% () DECLARE SUB InitPalette () DECLARE SUB pal (C%, r%, g%, B%) DECLARE SUB WalkAround () DECLARE SUB InitTables () DECLARE FUNCTION Keyboard% () DECLARE SUB Readlevel () DIM SHARED Walls(1 TO 30, 1 TO 30) AS INTEGER DIM SHARED Sine(0 TO 360) AS INTEGER, Cosine(0 TO 360) AS INTEGER DIM SHARED PlayerX AS SINGLE, PlayerY AS SINGLE, MaxX, MaxY, ScreenStep CONST RotateStep = 3 CONST Compass = 0 CONST WallColor = 1, FloorColor = 65, SkyColor = 64 CONST CompassColor = 66, CompassBorderColor = 67 ' Recommended: 4 to 10 ScreenStep = 5 SCREEN 13 RESTORE Level1 InitTables Readlevel WalkAround END Level1: DATA 30,30 : 'Max X&Y DATA 10,10 : 'Start of player DATA 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,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,1,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,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,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,1 DATA 1,0,0,0,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,1 DATA 1,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,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,1 DATA 1,0,0,0,1,0,0,0,0,0,1,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,1,0,0,0,0,0,1,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1 DATA 1,0,0,0,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,1 DATA 1,0,0,0,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,1 DATA 1,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,1 DATA 1,0,0,0,1,0,0,1,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,1,0,0,1,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,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1 DATA 1,0,0,0,1,0,0,1,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,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,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,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,1 DATA 1,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,1 DATA 1,0,0,0,1,0,0,1,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,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1 DATA 1,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,0,1,0,1 DATA 1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1 DATA 1,0,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,1,1,1,0,1 DATA 1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1 DATA 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,1,1,1,1,1 SUB InitPalette FOR I = 1 TO 63 pal 64 - I, I \ 4, I \ 4, I NEXT pal 64, 45, 45, 63 pal 65, 10, 15, 10 END SUB SUB InitTables Rad! = (4 * ATN(1)) / 180 FOR T% = 0 TO 360 Sine(T%) = SIN(T% * Rad!) * 100 Cosine(T%) = COS(T% * Rad!) * 100 NEXT END SUB FUNCTION Keyboard DO S$ = INKEY$ LOOP UNTIL LEN(S$) IF LEN(S$) = 1 THEN Keyboard = ASC(S$) ELSEIF LEN(S$) = 2 THEN Keyboard = -ASC(RIGHT$(S$, 1)) END IF END FUNCTION FUNCTION KeyStat DEF SEG = &H40: KeyStat = PEEK(&H17) END FUNCTION SUB pal (C, r, g, B) OUT &H3C8, C: OUT &H3C9, r: OUT &H3C9, g: OUT &H3C9, B END SUB SUB Readlevel READ MaxX, MaxY READ PlayerX, PlayerY FOR X = 1 TO MaxX FOR Y = 1 TO MaxY READ Wall: Walls(X, Y) = Wall NEXT NEXT END SUB SUB Scroll (Dir, X1, Y1, X2, Y2) REDIM Buffer(((X2 - X1) * 10)) AS INTEGER IF Dir = 1 THEN FOR Y = Y1 TO Y2 STEP 10 IF Y > Y2 THEN EXIT FOR IF Buffer(0) THEN PUT (X1, Y - 13), Buffer, PSET GET (X1, Y)-(X2, Y + 10), Buffer NEXT ELSEIF Dir = 2 THEN FOR Y = Y2 TO Y1 STEP -10 IF Y < Y1 THEN EXIT FOR IF Buffer(0) THEN PUT (X1, Y + 13), Buffer, PSET GET (X1, Y)-(X2, Y + 10), Buffer NEXT ELSEIF Dir = 3 THEN FOR X = X2 TO X1 STEP -10 IF X < X1 THEN EXIT FOR IF Buffer(0) THEN PUT (X + 15, Y1), Buffer, PSET GET (X, Y1)-(X + 10, Y2), Buffer NEXT ELSEIF Dir = 4 THEN FOR X = X1 TO X2 STEP 10 IF X > X2 THEN EXIT FOR IF Buffer(0) THEN PUT (X - 15, Y1), Buffer, PSET GET (X, Y1)-(X + 10, Y2), Buffer NEXT END IF END SUB SUB WalkAround InitPalette DrawStep = 320 \ ScreenStep pal 255, 60, 60, 60: COLOR 255 GOSUB DrawScreen DO Keys = Keyboard KeyBits = KeyStat Shift = ((KeyBits AND 2) OR (KeyBits AND 1)) <> 0 Alt = (KeyBits AND 8) <> 0 SELECT CASE Keys CASE 102, 70 'FPS test LOCATE 1, 1: PRINT "This will take five seconds." PRINT " Press a key... ": SLEEP: X$ = INKEY$ T! = TIMER: FPS = 0 DO GOSUB DrawScreen: FPS = FPS + 1 LOOP UNTIL TIMER - T! > 5 FPS = FPS \ 5 LOCATE 1, 1: PRINT "FPS rate is"; FPS CASE 43 ' Decrease screen-step IF ScreenStep > 3 THEN ScreenStep = ScreenStep - 1: DrawStep = 320 \ ScreenStep: GOSUB DrawScreen LOCATE 1, 1: PRINT "Resolution ="; ScreenStep CASE 45 ' Increase screen-step IF ScreenStep < 10 THEN ScreenStep = ScreenStep + 1: DrawStep = 320 \ ScreenStep: GOSUB DrawScreen LOCATE 1, 1: PRINT "Resolution ="; ScreenStep CASE 8 ' Rotate 180 degrees FOR I = 1 TO 15 Current = (Current + 12) MOD 360: GOSUB DrawScreen: WAIT &H3DA, 8 NEXT CASE -77 'Right IF Shift THEN Current = Current + RotateStep Current = Current + RotateStep: GOSUB DrawScreen CASE -75 IF Shift THEN Current = Current - RotateStep Current = Current - RotateStep: IF Current < 0 THEN Current = Current + 360 GOSUB DrawScreen CASE -72 opx = PlayerX: opy = PlayerY IF Shift = 0 THEN PlayerX = PlayerX + (Sine((Count - 30) MOD 360) / 50) PlayerY = PlayerY + (Cosine((Count - 30) MOD 360) / 50) ELSE PlayerX = PlayerX + (Sine((Count - 30) MOD 360) / 50) * 2 PlayerY = PlayerY + (Cosine((Count - 30) MOD 360) / 50) * 2 END IF IF Walls(((PlayerX + 1) * 99) \ 1000 + 1, ((PlayerY + 1) * 99) \ 1000 + 1) THEN LOCATE 1, 1: PRINT "Did'nt you see that wall??": PlayerX = opx: PlayerY = opy ELSE GOSUB DrawScreen END IF CASE -80 opx = PlayerX: opy = PlayerY IF Shift = 0 THEN PlayerX = PlayerX - (Sine((Count - 30) MOD 360) / 50) PlayerY = PlayerY - (Cosine((Count - 30) MOD 360) / 50) ELSE PlayerX = PlayerX - (Sine((Count - 30) MOD 360) / 50) * 2 PlayerY = PlayerY - (Cosine((Count - 30) MOD 360) / 50) * 2 END IF IF Walls(((PlayerX + 1) * 99) \ 1000 + 1, ((PlayerY + 1) * 99) \ 1000 + 1) THEN LOCATE 1, 1: PRINT "You don't have eyes in your neck...": PlayerX = opx: PlayerY = opy ELSE GOSUB DrawScreen END IF END SELECT LOOP UNTIL Keys = 27 EXIT SUB DrawScreen: px = (PlayerX + 1) * 99: py = (PlayerY + 1) * 99 FOR Count = Current TO Current + DrawStep C = Count MOD 360: Sin1 = Sine(C): Cos1 = Cosine(C) DrawX = px: DrawY = py: Distance = 0 DO DrawX = DrawX + Sin1: DrawY = DrawY + Cos1 Distance = Distance + 1 Wall = Walls(DrawX \ 1000 + 1, DrawY \ 1000 + 1) LOOP UNTIL Wall 'LOCATE 1, 1: PRINT Distance: SLEEP X = (Count - Current): X = X * ScreenStep Avg = (1000 \ Distance): ColorAdd = Distance \ 5: IF ColorAdd > 60 THEN ColorAdd = 60 LINE (X, 0)-STEP(ScreenStep, 99 - Avg), SkyColor, BF LINE (X, 101 + Avg)-(X + ScreenStep, 200), FloorColor, BF LINE (X, 100 - Avg)-(X + ScreenStep, 100 + Avg), ColorAdd + WallColor, BF NEXT IF Compass THEN CIRCLE (25, 180), 15, CompassBorderColor PAINT (27, 182), CompassColor, CompassBorderColor PSET (25, 180), 100: DRAW "C12TA" + STR$(Current MOD 360) + "D10" END IF RETURN END SUB