 A BB4W Compendium freeman69@gmx.com

IDIC  Maze

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.   