If these tiles are always the same width and height - and you like the GRID squared technique.... (meaning 2 dimensional - any size - works out like a sheet of Graph paper)....
I personally would make a 24 BMP file... and use colors to indicate WHICH kind of Tile. Like RED=255 = WALL, BLUE=255 = Door.
(So I can use MSPaint to make levels)
I would use code like this to read the BMP file:
(This code snip is for reading a Bitmap and Coming up with HEIGHT info based on color - but if you stick to the part that reads a bitmap and stuffs it into a memblock as a simple GRID XxZ - You might see what I mean)
//-----------------------------------------------------------------------------------------
void ApplyHeightMap(
int p_MemID,
float p_Scale,
char *p_szFilename,
int p_UnusedFileID,
int p_UnusedMemID
){
//-----------------------------------------------------------------------------------------
int ObjectID=0;
int Limbs=0;
int MeshFacesPerTileX=0;
int MeshFacesPerTileZ=0;
int MeshTotalFaces=0;
int MeshPolyCount=0;
int MeshVertices=0;
int TilesX=0;
int TilesZ=0;
int Tiles=0;
float TileSizeX=0;
float TileSizeZ=0;
// Our Fancy Terrain Limb Demographics - Emulating a regular data structure
// during dev - and seems sound enough to just kept it :)
//--------------------------------------------------------------
int p=0;
ObjectID= dbMemblockDword(p_MemID,p);p+=4;
Limbs= dbMemblockDword(p_MemID,p);p+=4;
MeshFacesPerTileX= dbMemblockDword(p_MemID,p);p+=4;
MeshFacesPerTileZ= dbMemblockDword(p_MemID,p);p+=4;
MeshTotalFaces= dbMemblockDword(p_MemID,p);p+=4;
MeshPolyCount= dbMemblockDword(p_MemID,p);p+=4;
MeshVertices= dbMemblockDword(p_MemID,p);p+=4;
TilesX= dbMemblockDword(p_MemID,p);p+=4;
TilesZ= dbMemblockDword(p_MemID,p);p+=4;
Tiles= dbMemblockDword(p_MemID,p);p+=4;
TileSizeX= dbMemblockFloat(p_MemID,p);p+=4;
TileSizeZ= dbMemblockFloat(p_MemID,p);p+=4;
//--------------------------------------------------------------
int GridX=MeshFacesPerTileX*TilesX;
int GridZ=MeshFacesPerTileZ*TilesZ;
int BmpWidth;
int *ptrBmpWidth;
int BmpHeight;
int BmpDepth;
float fBmpWidth;
int EvenWidth2;
float fEvenWidth1;
int ypos;
int padlen;int padlp;
int Ylp;
int Xlp;
int blue;int green;int red;
int junk;
unsigned char ucjunk;
dbOpenToRead(p_UnusedFileID,p_szFilename);
dbReadByte(p_UnusedFileID,&ucjunk);
dbReadByte(p_UnusedFileID,&ucjunk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&BmpWidth);
dbReadLong(p_UnusedFileID,&BmpHeight);
junk=dbReadWord(p_UnusedFileID);
BmpDepth=dbReadWord(p_UnusedFileID);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
dbReadLong(p_UnusedFileID,&junk);
if(BmpDepth==24){
ypos=BmpHeight-1;
fBmpWidth=BmpWidth;
fEvenWidth1=(fBmpWidth*3)/4;
EvenWidth2=(BmpWidth*3)/4;
padlen=0;
if(fEvenWidth1!=EvenWidth2){
fEvenWidth1=fEvenWidth1-EvenWidth2;
padlen=4-(fEvenWidth1*4);
};
dbMakeMemblock(p_UnusedMemID,BmpWidth*BmpHeight*4);
for(Ylp=0;Ylp<BmpHeight;Ylp++){
dbSetCursor(300,10);dbPrint("Size:");
dbSetCursor(360,10);dbPrint(dbStr(BmpWidth));
dbSetCursor(420,10);dbPrint(dbStr(BmpHeight));
dbSetCursor(310,20);dbPrint("Row:");
dbSetCursor(360,20);dbPrint(dbStr(Ylp));
dbSync();
for(Xlp=0;Xlp<BmpWidth;Xlp++){
blue=dbReadByte(p_UnusedFileID);
green=dbReadByte(p_UnusedFileID);
red=dbReadByte(p_UnusedFileID);
dbWriteMemblockDword(p_UnusedMemID,(Xlp+(ypos*BmpWidth))*4,(blue+green+red)/3);
//dbSetCursor(300,0);
//dbPrint(dbStr(Xlp));
//dbSetCursor(300,20);
//dbPrint(dbStr(Ylp));
//dbSetCursor(300,40);
//dbPrint(dbStr((blue+green+red)/3));
//dbSync();
};
ypos-=1;
if(padlen!=0){
for(padlp=0;padlp<padlen;padlp++){
dbReadByte(p_UnusedFileID);//padbyte
};
};
};
};//endif
dbCloseFile(p_UnusedFileID);
//--------------------------------- Now Apply The Height Data
float fx=0;float fz=0; // Terrain Verts
float fxInc=BmpWidth/((float)GridX);
float fzInc=BmpHeight/((float)GridZ);
float fbmpx=0;float fbmpy=0;
p=0;
for(fz=0;fz<=GridZ;fz++){
for(fx=0;fx<=GridX;fx++){
SetVertHeight(
p_MemID,
fx,
fz,
dbMemblockDword(p_UnusedMemID,p)*p_Scale
);
fbmpx+=fxInc;
p=((int)fbmpx+((int)fbmpy*BmpWidth))*4;
};
fbmpx=0;
fbmpy+=fzInc;
};
dbDeleteMemblock(p_UnusedMemID);
};
Then- in that part where it says APPLY BITMAP - Paste Your Sprites - where the TYPE of Sprite is based on color, and the position is the GRIDX and GRIDY positions Times the WIDTH/Height Value per Sprite Tile (MINUS the Screen X,Y offset if you have a 2d scroller)
Now - I'm thinking you would make a little system that has another memblock - stuffed with the SPRITE ID of the Tiles in the SAME XxY as the Memblock with the colors.
So - One Memblock XxY's = SPRITE TYPE (Door, Wall)
Other Memblock XxY's has the Sprite ID - (Zero being no sprite assigned)
then if a player hits a sprite - you look in MemBlock2 to find the Sprite ID - and now you know the X,Y position of said door and by looking in the First MEmblock - you know if it is in fact a door.
Now... This isn't the FASTEST method to have in you main loop - scanning Memblocks of anysize might be a bit much - BUT - By having an array of doors, and "Stuff" you pick up - you''l be able to loop through much less stuff to see if its a door Sprite ID or a Ammo Sprite or whatever - and ALL ELSE = Wall. (Or You have to get a little fancier when different Wall TYPES act different.. Bounce bullets back - or absorb whatever)