freeman69@gmx.com
The first of a group of programs demonstrating basic 3D principles.
W = Forward
S = Back
A = Turn Anticlockwise
D = Turn Clockwise
This program covers perspective and inhibiting the drawing of planes not facing the viewer.
10 MODE 9:OFF
20 VDU 24,0;0;959;959;:REM Graphics window
30 ORIGIN 480,480
40 DIM map(9,9)
50 REM Read maze pattern into 'map' array
60 FOR z=0 TO 9:READ m$
70 FOR x=0 TO 9:map(x,9-z)=INSTR(" X",MID$(m$,x+1,1))-1
80 NEXT
90 NEXT
100 DIM box(9):box()=1,0,1,2,-1,2,-1,0,1,0:REM Wall square
110 VDU 23,23,2;0;0;0;:REM Line width 2
120 MAXd=9:REM Max depth of vision
130 px=6:pz=8:REM Location
140 pdir=3:REM 0=North, 1=East, 2=South, 3=West
150 lastr=-99:REM Used to inhibit drawing of left side of wall
160
170 SLOWDRAW=FALSE:REM Set to TRUE to see how it works
180 IF NOT SLOWDRAW THEN
190 *REFRESH OFF
200 ENDIF
210
220 REPEAT
230 CLS
240 COLOUR 7:PROCeyeball(px,pz,pdir)
250 COLOUR 1:PRINTTAB(px+30,9-pz);MID$("^>v<",pdir+1,1)
260 RECTANGLE -476,-480,955,956
270 *REFRESH
280 k$=CHR$(ASC(GET$)AND223)
290 IF k$="A" pdir-=1:IF pdir<0 pdir+=4
300 IF k$="D" pdir+=1:IF pdir>3 pdir-=4
310 IF k$="W" PROCreqmove(1)
320 IF k$="S" PROCreqmove(-1)
330 UNTIL FALSE
340 END
350
360 DEF PROCreqmove(d)
370 LOCAL x,z
380 CASE pdir OF
390 WHEN 0 : x=px:z=pz+d
400 WHEN 1 : x=px+d:z=pz
410 WHEN 2 : x=px:z=pz-d
420 WHEN 3 : x=px-d:z=pz
430 ENDCASE
440 IF FNwayclear(x,z) px=x:pz=z
450 ENDPROC
460
470 DEF FNwayclear(x,z)
480 IF x<0 OR x>9 OR z<0 OR z>9 THEN
490 =FALSE
500 ELSE
510 IF map(x,z)=0 THEN
520 =TRUE
530 ELSE
540 =FALSE
550 ENDIF
560 ENDIF
570
580 REM Reads the map array in a V shape extending from viewer
590 REM Always reads/scans: far to near, left to right
600 DEF PROCeyeball(px,pz,pdir)
610 LOCAL dx,dz,rx,rz,xb,zb
620 CASE pdir OF
630 WHEN 0 : dx=0:dz=-1:rx=1:rz=0:xb=px-MAXd:zb=pz+MAXd-1:REM N
640 WHEN 1 : dx=-1:dz=0:rx=0:rz=-1:xb=px+MAXd-1:zb=pz+MAXd:REM E
650 WHEN 2 : dx=0:dz=1:rx=-1:rz=0:xb=px+MAXd:zb=pz-MAXd+1:REM S
660 WHEN 3 : dx=1:dz=0:rx=0:rz=1:xb=px-MAXd+1:zb=pz-MAXd:REM W
670 ENDCASE
680 FOR d=0 TO MAXd-1
690 FOR r=d-MAXd TO MAXd-d
700 IF xb>=0 AND xb<=9 AND zb>=0 AND zb<=9 THEN
710 IF map(xb,zb)=1 PROCdrawwall(r,MAXd-d,pdir,xb,zb)
720 PRINTTAB(xb+30,9-zb);MID$(".X",map(xb,zb)+1,1);
730 ENDIF
740 xb+=rx
750 zb+=rz
760 NEXT
770 xb-=rx*(MAXd-d)*2
780 zb-=rz*(MAXd-d)*2
790 xb+=dx
800 zb+=dz
810 NEXT
820 ENDPROC
830
840 DEF PROCdrawwall(cx,cz,pdir,xb,zb)
850 LOCAL sf,h,x1,z1,x2,z2,sx1,sy1,sx2,sy2,ny
860 sf=960:h=1
870 FOR side=0 TO 3
880 x1=box(side*2+0)+cx*2:z1=box(side*2+1)+cz*2
890 x2=box(side*2+2)+cx*2:z2=box(side*2+3)+cz*2
900 sx1=sf*x1/z1:sy1=sf*h/z1
910 sx2=sf*x2/z2:sy2=sf*h/z2
920 ny=sx2-sx1
930 REM Does this side face the viewer? (side 1 never drawn)
940 IF ny>0 THEN
950 REM Prevent side(2) of current wall overwriting front of previous adjoining wall
960 IF side<>2 OR cx<>lastr+1 THEN
970 GCOL 0,5:MOVE sx1,sy1:MOVE sx1,-sy1:REM Solid wall
980 PLOT 85,sx2,sy2:PLOT 85,sx2,-sy2
990 GCOL 0,7:MOVE sx1,sy1:DRAW sx2,sy2:REM Outline
1000 DRAW sx2,-sy2:DRAW sx1,-sy1:DRAW sx1,sy1
1010 lastr=cx
1020 ENDIF
1030 ENDIF
1040 IF SLOWDRAW WAIT 1
1050 NEXT
1060 ENDPROC
1070
1080 DATA "XXXXXXXXXX"
1090 DATA "X X X"
1100 DATA "X XXXX X"
1110 DATA "X X X"
1120 DATA "X X X XXXX"
1130 DATA "XXX X X"
1140 DATA "X X XXX XX"
1150 DATA "X X X"
1160 DATA "X X X X"
1170 DATA "XXXXXXXXXX"
Maze: Code explained...
Drawing in 3D involves creating the illusion of depth upon a 2D screen (window).
PROCeyeball reads the 'map' data in the order in which they need to be drawn i.e. from far to near (scanning left to right). By amending line 170 SLOWDRAW=TRUE, the program will demonstrate how the contents of the image are created, wall segment by wall segment.
The illusion of depth is achieved by projecting points in 3D space onto our 2D window. This is accomplished using simple formulae:
Xs = f X / Z
Ys = f Y / Z
Where 'Xs','Ys' are the 2D screen co-ordinates and 'f' is a factor directly related to the angle of view:
The blue circles represent points in 3D space.
'w' is the width of the window.
'f' is the angle of view factor.
When f = w, the angle of view is approximately 53 degrees.
When f = w/2, the angle of view is 90 degrees.
(Note that complications arise when a line or plane intersects the window. The maze program was written so this situation does not arise: the viewer is always placed on the edge of the current grid square, with a view across the current grid square. i.e. not in the centre of a grid square.)
Hiding planes not facing the viewer:
This is a technique employed to reduce the amount of graphics needing to be drawn. Recall from the Vector Demo that we can determine which side of a line a point is. This principle can be applied to determine if a line is facing the viewer, or facing away. Lines 920 & 940 execute a simplified version of this test to determine which of the four sides of a wall segment (a square based column) face the viewer.
Side zero only faces the viewer when the wall segment is to our left.
Side 1 always faces away
Side 2 only faces the viewer when the wall segment is to our right.
(N.b. because we always draw wall segments from left to right, it is possible that side 2 of a wall segment may (incorrectly and) partially overwrite side 3 of the previously drawn, adjacent wall segment. Temporarily REM/remove line 960 to see how this error affects the display.)
Side 3 always faces the viewer.