The House of Hair Out - Explained First of all, a comment on the code layout. I originally worked through a PC 3D engine, in order to understand how 3D graphics was done. To save development time on the algorithms, I got them working on the PC first. So the code was written with the aim being to make as much as possible platform independent. I used Steve Dunn’s C++ classes and modified them a bit. Also, I worked off Peter Passmore’s original tutorial. The C++ is really only used to split the code into logical parts, I don’t really use its power. With the pressure of time, as I worked towards the Fame Game deadline, I neglected to keep everything in order. So the code is messy, and in some places diabolical, so be warned. For example, there are a couple of functions with the same name, but one has capitals in it. There is also a vast quantity of commented out code, so I recommend you load it into an editor where you can colour code comments. My classes are prefixed by As and then Ps for Playstation specific and Ga for game specific code. Anyway, I hope that you will make sense of enough of it so that it helps. Use it, and abuse it! I’d love to go through and tidy it up, but I’ll probably never get round to it. So I may as well give you the code now. Any questions, just email me, and I’ll try and get back to you. The main feature of this game is that the 3D space warps round in various ways. The principle is that nothing in the world has any fixed co-ordinates in 3D space. The player is essentially at the origin, and the world, and all the objects only exist relative to the player. The game loads in the map in binary form, it is converted from text format. The conversion function is done by AsArenaBuilder::ReadMap2, which was called by a PC program. The map is divided into a grid. In the code it is a 3D array. (But it could be a 2D array, since there is no definition of height. However, the map editor is just a text file, and by just changing the number of levels in the array, it means you can define the size of the map just about right, saving having to fill a big text file with redundant stuff.) The map file is divided into three parts. The first part represents the blocks that form the 3D world, and their textures. The second part represents stairs. The third part represents links between areas. In part one, each square (or cell) in the grid represents one cube block of the world. If you look at the game, you can see that the world is made up of cube areas, corresponding to the textures. The map is basically a collection of segments, distributed around the grid just to fit in. The values represent the texture format of each block. The second part has nonzero values representing stair blocks. Each stair block consists of both a top and bottom part, two blocks on top of each other. There are four different types, going up from left to right, right to left, up to down, and down to up. The third part represents links between the segments. Each link contains eight values, the first three are the grid position of the first block, the last three are the grid position of the second block. The 4th value represents the side of the first block that is connected to the second, either left, right, up or down (by up I mean forward, and down I mean backward). The 5th value represents the side of the second block that is connected to the first. The link can be symmetric or asymmetric. If symmetric, I have followed the convention of having the reverse link as the next in the list. You can link together any two blocks no matter where they are on the grid, and link them at a different orientation to each other. This allows you to create, for example, a triangular area of three corridors, but with the three corners all at right angles. In order to avoid the inevitable drawing problems this would create, I follow a rule which prevents any visual problems. The world, you will notice is made of corridors, rather than rooms. Every alternate block must be solid - you’ll see what I mean by looking at the map. The start of the hard level illustrates what I mean. You have an area of nine blocks - 3x3, but the centre one must be solid so you can’t see where it goes wrong. However, you can break the rules if you want. I make exceptions for the rooms with the symbol, but I’ve still laid them out so they don’t cause an error visually. To decide what needs to be drawn, I do a dynamic search each frame to identify which blocks are visible. Starting from the block you are in, I do a recursive search on the grid. See AsArenaBuilder::CalculateVisualMap. It does a kind of graph search, looking in each direction up/down/left/right. It calculates the offset of the block from your current position, so essentially your block is always the origin. If the next block in your search is through a link, the search applies the appropriate rotation and treats the block as though it was actually positioned next to the previous block. This means that it is drawn as though spatially thats where it is, allowing you to get up to all kinds of tomfoolery when mapmaking. Apart from textures that are rotated, its impossible to tell within the game where the links are, which is why I expected those of you who tried to map it, to get into difficulties. If the link is not symmetric, then you will see the scenery change as you move through the link, so I made nearly all the links symmetric. There are a couple of places where they aren’t symmetric, so to hide this, the surrounding areas on either side of the link are created exactly the same. But after you go round the corner and come back, the scenery has changed. I hope though that no-one ever saw scenery change in the game. Now comes the trick with the stairs. Stairs are completely irrelevant, they are just for visual variety. Because I’m always drawing blocks at an offset from the player, I put in a vertical offset whenever the block in the search is a stair block. At the beginning of the hard level, you can see this in action. When you are at the bottom of the stairs, blocks searched after the stairs are drawn high. When you are at the top of the stairs, blocks searched after the stairs are drawn low. I can only suggest you follow through the code and the map to confirm this to yourself. This is why the map could actually be laid out on a 2D grid. I only realised this late on. Areas where you can see yourself are created by putting links in to another block close by. Because you can see the same place in the map in two different places in 3D space, it means that some objects need have more than one coordinate position. I have allowed for up to 3 positions, because if you put in a link close by you can see yourself in two other places. The mirrored section requires only 2 positions. All objects have this facility. A list of blocks is built up. What is drawn is these blocks and the objects within them. The drawing function AsPSWorld::UpdateVisualMap operates slightly differently for blocks and objects. For those that are visible, the coordinates are found. If the block is rotated, due to a link, rotation is applied. Likewise, an object’s coordinates are rotated if the block it is within is rotated. This is inefficient, and I suspect is what causes the slowdown in some areas. Enemy AI? If the block they are in is visible from where you are, they go into chase mode. In that mode, they are able to look a little bit further than for real, around corners. But if you get more than two corners away, they can’t see you and will revert back to patrol mode. There are probably a zillion ways of making this more efficient. If you want to email me, you can do, although I won’t implement it myself. What I will do is collate the suggestions and put it on the newsgroup, so anyone else who has used the code will know about it. One thing I was going to do was encode the constants for left/right/up/down so that I can do all rotation type stuff in one line, rather than dozens of switch statements. Enjoy. Jeff Hannan