Copyright (C) 2000-2012 |
GNU Info (gawkinet.info)MAZEMAZE: Walking Through a Maze In Virtual Reality =============================================== In the long run, every program becomes rococo, and then rubble. Alan Perlis By now, we know how to present arbitrary `Content-type's to a browser. In this node, our server will present a 3D world to our browser. The 3D world is described in a scene description language (VRML, Virtual Reality Modeling Language) that allows us to travel through a perspective view of a 2D maze with our browser. Browsers with a VRML plugin enable exploration of this technology. We could do one of those boring `Hello world' examples here, that are usually presented when introducing novices to VRML. If you have never written any VRML code, have a look at the VRML FAQ. Presenting a static VRML scene is a bit trivial; in order to expose `gawk''s new capabilities, we will present a dynamically generated VRML scene. The function `SetUpServer' is very simple because it only sets the default HTML page and initializes the random number generator. As usual, the surrounding server lets you browse the maze. function SetUpServer() { TopHeader = "<HTML><title>Walk through a maze</title>" TopDoc = "\ <h2>Please choose one of the following actions:</h2>\ <UL>\ <LI><A HREF=" MyPrefix "/AboutServer>About this server</A>\ <LI><A HREF=" MyPrefix "/VRMLtest>Watch a simple VRML scene</A>\ </UL>" TopFooter = "</HTML>" srand() } The function `HandleGET' is a bit longer because it first computes the maze and afterwards generates the VRML code that is sent across the network. As shown in the STATIST example (Note: STATIST), we set the type of the content to VRML and then store the VRML representation of the maze as the page content. We assume that the maze is stored in a 2D array. Initially, the maze consists of walls only. Then, we add an entry and an exit to the maze and let the rest of the work be done by the function `MakeMaze'. Now, only the wall fields are left in the maze. By iterating over the these fields, we generate one line of VRML code for each wall field. function HandleGET() { if (MENU[2] == "AboutServer") { Document = "If your browser has a VRML 2 plugin,\ this server shows you a simple VRML scene." } else if (MENU[2] == "VRMLtest") { XSIZE = YSIZE = 11 # initially, everything is wall for (y = 0; y < YSIZE; y++) for (x = 0; x < XSIZE; x++) Maze[x, y] = "#" delete Maze[0, 1] # entry is not wall delete Maze[XSIZE-1, YSIZE-2] # exit is not wall MakeMaze(1, 1) Document = "\ #VRML V2.0 utf8\n\ Group {\n\ children [\n\ PointLight {\n\ ambientIntensity 0.2\n\ color 0.7 0.7 0.7\n\ location 0.0 8.0 10.0\n\ }\n\ DEF B1 Background {\n\ skyColor [0 0 0, 1.0 1.0 1.0 ]\n\ skyAngle 1.6\n\ groundColor [1 1 1, 0.8 0.8 0.8, 0.2 0.2 0.2 ]\n\ groundAngle [ 1.2 1.57 ]\n\ }\n\ DEF Wall Shape {\n\ geometry Box {size 1 1 1}\n\ appearance Appearance { material Material { diffuseColor 0 0 1 } }\n\ }\n\ DEF Entry Viewpoint {\n\ position 0.5 1.0 5.0\n\ orientation 0.0 0.0 -1.0 0.52\n\ }\n" for (i in Maze) { split(i, t, SUBSEP) Document = Document " Transform { translation " Document = Document t[1] " 0 -" t[2] " children USE Wall }\n" } Document = Document " ] # end of group for world\n}" Reason = "OK" ORS "Content-type: model/vrml" Header = Footer = "" } } Finally, we have a look at `MakeMaze', the function that generates the `Maze' array. When entered, this function assumes that the array has been initialized so that each element represents a wall element and the maze is initially full of wall elements. Only the entrance and the exit of the maze should have been left free. The parameters of the function tell us which element must be marked as not being a wall. After this, we take a look at the four neighbouring elements and remember which we have already treated. Of all the neighbouring elements, we take one at random and walk in that direction. Therefore, the wall element in that direction has to be removed and then, we call the function recursively for that element. The maze is only completed if we iterate the above procedure for _all_ neighbouring elements (in random order) and for our present element by recursively calling the function for the present element. This last iteration could have been done in a loop, but it is done much simpler recursively. Notice that elements with coordinates that are both odd are assumed to be on our way through the maze and the generating process cannot terminate as long as there is such an element not being `delete'd. All other elements are potentially part of the wall. function MakeMaze(x, y) { delete Maze[x, y] # here we are, we have no wall here p = 0 # count unvisited fields in all directions if (x-2 SUBSEP y in Maze) d[p++] = "-x" if (x SUBSEP y-2 in Maze) d[p++] = "-y" if (x+2 SUBSEP y in Maze) d[p++] = "+x" if (x SUBSEP y+2 in Maze) d[p++] = "+y" if (p>0) { # if there are univisited fields, go there p = int(p*rand()) # choose one unvisited field at random if (d[p] == "-x") { delete Maze[x - 1, y]; MakeMaze(x - 2, y) } else if (d[p] == "-y") { delete Maze[x, y - 1]; MakeMaze(x, y - 2) } else if (d[p] == "+x") { delete Maze[x + 1, y]; MakeMaze(x + 2, y) } else if (d[p] == "+y") { delete Maze[x, y + 1]; MakeMaze(x, y + 2) } # we are back from recursion MakeMaze(x, y); # try again while there are unvisited fields } } automatically generated by info2www version 1.2.2.9 |