Funny you point that out. There's actually a story about the viewing height and the stairs.
How it all ended up playing like this (height of the point of view, speed, whatever) was all because of Stairs. You're totally right about stairs. The thing is, stairs are evil. I spent a dozen hours trying to solve the "stairs problem", browsing architectural websites all over the internet just to get it right. Stairs decided of all the proportions you see in the first person perspective.
Here is how I went:
1st pass, parsing the dungeon.dat file. Here the main difficulty was getting my mindset on playing with byte arrays and doing learning to code those binary operations something I never did before. I ended up with a cubic layout, with dimensions 3m/3m/3m for each "square". The feeling was very close to the one you get from original DM game, with a more or less central viewport and a familiar perspective. Then I had only walls and floor tiles.
2nd pass, I tried connecting levels together, and the nightmare began. For one, stairs are the result of a programming trick in DM/CSB. Their definition should be on 3 bits (2 bits for the direction (N/S/E/W) on the level, one bit for up/down), but unless I miss something they are only defined on 2 bits, one for "NS" or "EW", and one for Up/Down. So I had to either parse the surrounding walls to check which direction it really was. I tried that solution for a while, but I ran in another critical issue:
3rd pass, actually making the stairs. FTLs are a bunch of cheaters (and so is everyone). For them stairs are simply teleporters. I didn't want to do it their way at that point, so I tried to model actual stairs that feel right. And to achieve that, I remembered my old optional Architecture class at school, and the almighty golden rule of stair design:
60cm<2*(step height)+1*(step depth)<65cm
I tried straight stairs first. This would screw the level offsets and pit layouts badly and make the dungeon impossible to render, because the stairs would need to be like 6-7 tiles in horizontal length instead of just one. Simply impossible considering some stairs are in the middle of some levels.
I tried spiral stairs, but in order to build them you actually have to make sure that you can climb them, that is, that there is enough distance between the first step (0° rotation) and the ~270° step so you can fit more than a human body in height. It actually requires a lot of horizontal space to achieve that. in order to get enough height increments per rotation unit to be able to do a full circle, you need much, much more than 1 meters in width for your stair case. Besides, I needed a way to deal with all alignment possibilities, you could enter upstairs east and exit downstairs from east, west, north and south, so that was a no go.
So I hit my head on my keyboard a bit until I found out that I could get away with that kind of stair layout an by doubling the dimension of all tiles (6m/6m/6m). Which made some sense, considering I need to fit 4 characters/monsters on each tile. The cool thing about this stair tile is that you can also enter them from any direction and exit them from any other direction. So that solution made sense for my prototype.
Now imagine yourself in a 6m*6m*6m hallway, and you should probably get that sort of "shorty" feeling. I did all my tests using a small window from inside the unity editor.
Looking back at the result and reading your observations I guess I really should go back and scrap those daggerfall staircases of doom altogether, and go with a visual shader trick and a quick fade to black effect as a transition or something like that. But the whole "stairs" experiment was quite instructive in retrospect! The main lesson I learned here would be:
"Dungeon Master Is Not A Game About Stairs" 
----
Now about the dungeon.dat thing, yeah. In the "ressources" folder you will find a dungeondat.txt which is nothing but a renamed dungeon.dat file that Unity can open as a byte array on load. 44kb instead of 4mb for the xml version, and much, much faster. The code is in javascript and only the rendering part requires unity. It should be possible to run just the parsing of the file in a web browser without any need for unity, though I didn't actually try.
Sorry for the long post but let's explain that part:
This is the unity script: it's attached to a unity object
Code: Select all
function Start () { //the function called when the object is instanciated (game starts)
var dungeondat:TextAsset = Resources.Load("dungeondat"); // here we load the dungeon.dat file and turn it into bytes
db = new DungeonDatabase(dungeondat.bytes); //here we parse the bytes into a
//new DungeonDatabase object, which is described elsewhere
MoveToStartPosition(); //moves the camera to the start position
for(k = 0;k<db.header.GetNumberOfMaps();k++){ //for each level in the database
BuildLevel(k); //create the unity3d objects for the level
}
Here's the DungeonDatabase class
Code: Select all
class DungeonDatabase{
var bytes : byte[];
var header : HeaderReader;
var mapDefs : MapDefinitionReader;
var indexOfTilesWithObjectsOnThemReader : IndexOfTilesWithObjectsOnThemReader;
var listOfObjectIdsOfFirstObjectsOnTilesReader : ListOfObjectIdsOfFirstObjectsOnTilesReader;
var textDataReader : TextDataReader;
var doorReader : DoorReader;
var teleporterReader : TeleporterReader;
var textReader : TextReader;
var actuatorReader : ActuatorReader;
var creatureReader : CreatureReader;
var weaponReader : WeaponReader;
var clothReader : ClothReader;
var scrollReader : ScrollReader;
var potionReader : PotionReader;
var containerReader : ContainerReader;
var miscReader : MiscReader;
var missileReader : MissileReader;
var cloudReader : CloudReader;
var mapDataReader : MapDataReader;
function DungeonDatabase(bytes:byte[]){
ReadDungeon(bytes);
//..and do debug & testing stuff if needed
}
function ReadDungeon(byte[] bytes){
// bunch of code that initialises all the "readers"
}
}
The engine doesn't create "objects" for each elements in the dungeon. I use "readers" which parse the byte array of data in real time as fast as they can using methods that are expected. For instance to get the type of tile for coordinates i, j on level k, assuming your DungeonDatabase is "db", you just type this:
Code: Select all
var buffer:byte[] = db.mapDataReader.GetTilesBuffer(k); //gets the buffer that corresponds to the level k tile definition
var tile = db.mapDataReader.GetBufferedTile(buffer, i, j, k); // grabs the tile at coordinates i, j
var tileType = db.mapDataReader.GetBufferedTileType(buffer, i,j,k); // grabs the type of the tile (wall, floor, door, pit, stairs...)
if(DungeonStatics.TILE_TYPE_WALL == tileType){ //if it's a wall...
//...do whatever you want with it!
}