Vrije Universiteit Brussel - Faculteit Ingenieurswetenschappen

JJ3DLabyrinth


Initiele code

MODULE JJ3DLabyrinth;

(* A. imports *)
FROM Lib IMPORT Delay, RANDOMIZE, RANDOM;
FROM RealMath IMPORT pi, sqrt, cos, sin;
FROM JJ3D IMPORT Start3DPhysicalWorld, DrawEverything, ClearScreen, WaitUntilQPressed, WrStr, WrCard, WrInt, WrReal, WrBool, WrLn;
FROM JJ3D IMPORT Plot, Line, ThickLine, PlotText, Triangle, RectangleXY, RectangleYZ, RectangleXZ, Polygon, Cube, Block, Cilinder, Arrow3D;
FROM JJ3D IMPORT viewerX, viewerY, viewerZ, viewerAngle, PolarToCartesian, Radians2Degrees, Degrees2Radians;
FROM JJ3D IMPORT Set2DArea, Line2D, Disc2D, Arrow2D, SetControlValue, SetControlName;
FROM JJ3D IMPORT RED, GREEN, BLUE, CYAN, MAGENTA, GRAY, BROWN;
FROM JJ3D IMPORT BLACK, BRIGHTWHITE, WHITE, LIGHTRED, LIGHTGREEN, LIGHTBLUE, LIGHTCYAN, LIGHTMAGENTA, LIGHTYELLOW;
FROM Wimdows IMPORT UpdateWindow, GetKeyPressed, KeyDown, RgbColor, Lighter, Darker;
FROM Windows IMPORT VK_DOWN, VK_LEFT, VK_CONTROL, VK_RIGHT, VK_UP;
IMPORT IO;


(* B. constants == *)       
CONST DELAY = 50; (* determines the speed of the game *)
   ARENA_HEIGHT = 10;
     ARENA_WIDTH = 20;
     SIZE2D=200; (*the size of each cell is the double of this *)
     GHOST_SPEED=20;
     ARROW_SPEED=40;
     ARROW_LENGTH=500;
   
(* C. global variables == *)   
VAR
  arena: ARRAY [0..ARENA_HEIGHT*2+1],[0..ARENA_WIDTH*2+1] OF CHAR;
    ghostX, ghostY, ghostAngle: INTEGER;
    arrowX, arrowY, arrowAngle: INTEGER;
    arrowIsShot: BOOLEAN;
    ghostColor, arrowColor, objectColor: CARDINAL;

(* D. procedures == *)   
PROCEDURE DrawArena2D();
  VAR i,j: CARDINAL;
BEGIN
  FOR i := 0 TO ARENA_HEIGHT*2+1 DO
      FOR j := 0 TO ARENA_WIDTH*2+1 DO
          CASE arena[i][j] OF
              (* draw walls *)
                '|': Line2D( j*SIZE2D, (i-1)*SIZE2D, j*SIZE2D, (i+1)*SIZE2D, BLUE);
                |    '-': Line2D( (j-1)*SIZE2D, i*SIZE2D, (j+1)*SIZE2D , i*SIZE2D, BLUE);
                | 'b': Disc2D(j*SIZE2D, i*SIZE2D, 5, objectColor);
            ELSE
            END (* case *)
      END;
    END;
    (* D1. Andere objecten *)
   
   
END DrawArena2D;   

PROCEDURE DrawArena3D();
  VAR i,j: CARDINAL;
BEGIN
  FOR i := 0 TO ARENA_HEIGHT*2+1 DO
      FOR j := 0 TO ARENA_WIDTH*2+1 DO
        CASE arena[i][j] OF
            (* draw walls *)
                '|': RectangleYZ((i-1)*SIZE2D, 0, (i+1)*SIZE2D, SIZE2D*4, j*SIZE2D , Lighter(GREEN, 15),TRUE);                           
                |    '-': RectangleXZ((j-1)*SIZE2D, 0, (j+1)*SIZE2D , SIZE2D*4, i*SIZE2D, GREEN, TRUE);
                (* draw other things *)
                | 'b':  Block(j*SIZE2D - 60, i*SIZE2D - 60, 0, 120, 120, 500, objectColor, TRUE);
            ELSE
                     
            END (* case *)
      END;
    END;
    (* D2. Andere objecten *)
   

END DrawArena3D;
   
(* Given the y-coordinate, in which row of the arena are we?
   returns -1 when out of arena *)
PROCEDURE RowIndex(y: INTEGER): INTEGER;
  VAR r: INTEGER;
BEGIN
  IF y < 0 THEN
      RETURN -1;
    END;
    r := y / SIZE2D / 2;
    IF r > ARENA_HEIGHT THEN
      RETURN -1;
    END;
    RETURN r * 2 + 1;
END RowIndex;

(* Given the x-coordinate, in which column of the arena are we?
   returns -1 OR SIZE+1 when out of arena *)
PROCEDURE ColumnIndex(x: INTEGER): INTEGER;
  VAR c: INTEGER;
BEGIN
  IF x < 0 THEN
      RETURN -1;
    END;
    c := x / SIZE2D / 2;
    IF c > ARENA_WIDTH THEN
      c := ARENA_WIDTH + 1;
    END;
    RETURN c * 2 + 1;
END ColumnIndex;

PROCEDURE Distance(x1, y1, x2, y2: INTEGER): INTEGER;
BEGIN
 RETURN VAL(INTEGER, sqrt((VAL(REAL, x1) - VAL(REAL, x2))*(VAL(REAL, x1) - VAL(REAL, x2)) + (VAL(REAL, y1) - VAL(REAL, y2))*(VAL(REAL, y1) - VAL(REAL, y2))));
END Distance;

(* Returns TRUE if outside playfield if you move from (x,y) to (x+vx, y+vy) *)   
PROCEDURE OutsideArena(x, y, vx, vy: INTEGER): BOOLEAN;
BEGIN
  RETURN (RowIndex(y+vy) = -1) OR  (ColumnIndex(x+vx) = -1);
END OutsideArena;

(* Returns TRUE if there is a wall if you move from (x,y) to (x+vx, y+vy) *)   
PROCEDURE IsWall(x, y, vx, vy: INTEGER): BOOLEAN;
  VAR r1, r2, c1, c2: INTEGER;
        rowOK, colOK: BOOLEAN;   
BEGIN
  IF (vx = 0) AND (vy = 0) THEN
      RETURN FALSE;
    END;
  r1 := RowIndex(y); r2 := RowIndex(y+2*vy);
    c1 := ColumnIndex(x); c2 := ColumnIndex(x+2*vx);
(*    IO.WrStr("(");IO.WrInt(r1, 0);IO.WrStr(",");IO.WrInt(c1, 0);IO.WrStr(") to (");IO.WrInt(r2, 0);IO.WrStr(",");IO.WrInt(c2, 0); IO.WrStr("): ");*)
    IF (r2 = r1) OR (c1 < 0) THEN
      rowOK := TRUE;
    ELSE
      rowOK := arena[(r1+r2)/2][c1] # '-';
(*        IO.WrChar(arena[(r1+r2)/2][c1]); IO.WrStr("- is stop");*)
    END;
    IF (c2 = c1) OR (r1 < 0) THEN
      colOK := TRUE;
    ELSE
      colOK := arena[r1][(c1+c2)/2] # '|';
(*        IO.WrChar(arena[r1][(c1+c2)/2]); IO.WrStr("| is stop");*)
    END;
(*    IO.WrLn;*)
    RETURN NOT (colOK AND rowOK);
END IsWall;   
(* angle in degrees *)
PROCEDURE SpeedAngleToXY(speed, angle: INTEGER; VAR x, y: INTEGER);
  VAR radians:REAL;
BEGIN
  radians := FLOAT(angle) * pi /180.;
  y := VAL(INTEGER, FLOAT(speed) * cos(radians  ));
  x := VAL(INTEGER, FLOAT(speed) * sin(radians ));
END SpeedAngleToXY;


(* E. Module variables == *)
VAR   
  key, ctr, i: CARDINAL;
    stop, ctrlDown: BOOLEAN;
    time, dX, dY, acceleration, row, column, random: INTEGER;   
   
BEGIN
  (* F. INITIALIZATION == *)
    ghostColor := RgbColor(230, 120, 125);
    arrowColor:= LIGHTYELLOW;
    objectColor := RgbColor(200, 100, 50);
   
    arena[20] :="+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
  arena[19] :="|       | |                       |     |";
  arena[18] :="+ + + + + + + + + + + + + + + + + + + + +";
  arena[17] :="|         |                E       m|   |";
  arena[16] :="+ + + + +-+ + + + + + + + + +-+-+ + + + +";
  arena[15] :="| |            b        |        m m|   |";
  arena[14] :="+ + +-+-+ + + + +-+ + + + + + +-+-+ + + +";
  arena[13] :="|     |   |             |m m            |";
  arena[12] :="+ + + + + + + +-+ + + + +-+-+ + + + + + +";
  arena[11] :="|   |     |              G   e          |";
  arena[10] :="+ + + + +-+ + + + + + + + +-+-+-+ + + + +";
  arena[9]  :="|  a    |            x                  |";
  arena[8]  :="+ + + + + + + +-+-+ + + + + + + + + + + +";
  arena[7]  :="|       |       |  a                    |";
  arena[6]  :="+ + + + + + + + + + + + + + + + +-+-+ + +";
  arena[5]  :="|                       |     |         |";
  arena[4]  :="+ + + + +-+-+ + + + + + + + + + + + + + +";
  arena[3]  :="|       |        X            |     |   |";
  arena[2]  :="+ +-+ + +-+ + + + + + + + + + + + +-+ + +";
  arena[1]  :="| |b| | | |      b b b b b b b          |";
  arena[0]  :="+ + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+";
   
  time:=0;
    viewerY := -500;
  ghostX := 1*SIZE2D; (* initial coordinates of ghost *)
    ghostY := 1*SIZE2D;
    ghostAngle:= 90;
    arrowIsShot:=FALSE;
   
    (* G. Start 3D world == *)
  Start3DPhysicalWorld("Mijn 3D-spel") ;
    SetControlName(1, "Time"); SetControlName(2, "X"); SetControlName(3, "Y");SetControlName(4, "Row"); SetControlName(5, "Column");
  WrStr("Welkom tot dit 3D-spel! "); WrLn();
  WrStr("Hierin kan je naar hartelust rondlopen. "); WrLn();
    WrStr("Gebruik hiervoor de pijltjes-toetsen. Hou de ctrl-toets ingedrukt om te draaien en naar boven/beneden te bewegen. ");  WrLn();
    WrStr("Druk 'q' om te stoppen... ");  WrLn();
    RANDOMIZE;
       
    Set2DArea(-250, -500, 8250, 6700); (* this is the area of the 2D panel: bottom left and top right coordinates *)
   
    (* H. MAIN LOOP == *)
  WHILE NOT stop DO
   
      (* I. DRAW 3D-WORLD == *)
      ClearScreen();   (* first remove previous 3D-objects *)
        DrawArena3D();   (* draws labyrinth + game objects *)

       
        (* write things on text panel *)
        SetControlValue(1, time/1000);
        SetControlValue(2, viewerX); SetControlValue(3, viewerY);
        SetControlValue(4, RowIndex(viewerY)); SetControlValue(5, ColumnIndex(viewerX));
       
(*        WrStr("("); WrInt(viewerX); WrStr(";"); WrInt(viewerY); WrStr(") => in arena: (");WrInt(RowIndex(viewerY));WrStr(";");WrInt(ColumnIndex(viewerX));WrStr(")");WrLn;*)
       
        DrawEverything(); (* Draws 3D stuff + text on screen *)
       
        (* J. DRAW 2D-PANEL == *)
       
        (*x2d := 100+viewerX/25; y2d := 100 - viewerY/25;
        Disc2D(x2d, y2d, 2, RED); *)
        DrawArena2D();
        Disc2D(viewerX, viewerY, 2, RED);

       
        UpdateWindow(); (* Draws 2D stuff on screen *)
       
        (* K. WAIT A MOMENT == *)
      Delay(DELAY);
    time := time + DELAY;
       
        (* L. KEY HANDLING == *)
        dX:=0; dY:=0;
        WHILE GetKeyPressed(key)  DO
       
            (*  WrCard(key);WrStr(", ");*) (* uncomment to see which keys are pressed *)
            ctrlDown := KeyDown(17);
            CASE key OF
          VK_LEFT:
             IF ctrlDown THEN
                viewerAngle := viewerAngle - pi/36.0/2.0;
             ELSE
             dY := VAL(INTEGER, 25.0 * sin(viewerAngle));
               dX := - VAL(INTEGER, 25.0 * cos(viewerAngle));
             END;
        | VK_UP:
             IF ctrlDown THEN
               viewerZ := viewerZ + 25;
             ELSE
                     dY := VAL(INTEGER, 25.0 * cos(viewerAngle));
               dX := VAL(INTEGER, 25.0 * sin(viewerAngle));
             END;
           | VK_RIGHT:
             IF ctrlDown THEN
               viewerAngle := viewerAngle + pi/36.0/2.0;
             ELSE
               dY := - VAL(INTEGER, 25.0 * sin(viewerAngle));
               dX := VAL(INTEGER, 25.0 * cos(viewerAngle));
             END;
          | VK_DOWN:
             IF ctrlDown THEN
               viewerZ := viewerZ - 25;
             ELSE
               dY := - VAL(INTEGER, 25.0 * cos(viewerAngle));
               dX := - VAL(INTEGER, 25.0 * sin(viewerAngle));
             END;
            | ORD('q'), ORD('Q'):  (* now we quit *)
              stop := TRUE;
            (* L1. add more keys here *)
             ELSE
               (* another key that we will not handle *)
            END;  (* case *)
        END; (* while key pressed *)
       
        (* M. Objects move == *)
        (* check walls for player *)
        viewerX := viewerX + dX;
        viewerY := viewerY + dY;

       

       
       
       
        (* N. Check Collisions == *)

       
       
       
    END; (* main loop *)   
   
END JJ3DLabyrinth.