(* 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;
(* 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);
(* 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 *)