Part 17: Doors - Part 1: Editor and drawing
Downloads
The graphics
In the editor
<?xml version="1.0" encoding="ISO-8859-1"?>
<doors>
<door name="Porticullis">
<image1>Porticullis_1.png</image1>
<image2>Porticullis_2.png</image2>
<image3>Porticullis_3.png</image3>
</door>
<door name="Wooden Door">
<image1>Wooden_Door_1.png</image1>
<image2>Wooden_Door_2.png</image2>
<image3>Wooden_Door_3.png</image3>
</door>
<door name="Iron Door">
<image1>Iron_Door_1.png</image1>
<image2>Iron_Door_2.png</image2>
<image3>Iron_Door_3.png</image3>
</door>
<door name="Ra Door">
<image1>Ra_Door_1.png</image1>
<image2>Ra_Door_2.png</image2>
<image3>Ra_Door_3.png</image3>
</door>
</doors>
In the editor we would like to see the doors in different orientations.
<?xml version="1.0" encoding="ISO-8859-1"?>
<walls>
<wall name="Nothing">
</wall>
<wall name="Simple">
[...]
</wall>
<wall name="Portrait">
[...]
</wall>
<wall name="Door Side">
<image>DoorSide.png</image>
</wall>
</walls>
This way it's easy to draw in the editor any type of door by simply setting it's side walls.
Parameters of a door
<tiles>
<tile name="Empty">
</tile>
<tile name="Ground">
[...]
</tile>
<tile name="Door">
<image>Tile.png</image>
<param type="door">Type</param>
<param type="door_ornate">Ornate</param>
<param type="bool">hasButton</param>
<param type="bool">isHorizontal</param>
<param type="bool">isBreakable</param>
<param type="bool">isOpened</param>
<param type="bool">isMoving</param>
<param type="int">pos</param>
</tile>
</tiles>
As all these types of parameters are already used for the walls, it is a simple copy/paste job to add them to the tiles.
#define LOAD_PARAM(_enum,_struct,_type,_expr) \
case _enum: \
{ \
_type value; \
fread(&value, sizeof(value), 1, handle); \
((_struct*)mParams[i])->mValue = (_expr); \
} \
break;
void CWall::load(FILE* handle)
{
uint8_t type;
fread(&type, 1, 1, handle);
setType(type);
std::vector<CParamType>& paramTypes = map.mWallsParams[mType];
for (size_t i = 0; i < paramTypes.size(); ++i)
{
switch (paramTypes[i].mType)
{
LOAD_PARAM(eParamOrnate, CParamOrnate, uint8_t, value)
LOAD_PARAM(eParamInt, CParamInt, int32_t, value)
LOAD_PARAM(eParamBool, CParamBool, uint8_t, (value == 0 ? false : true))
default:
break;
}
}
}
And the loading of a tile looks like that:
void CTile::load(FILE* handle)
{
uint8_t type;
fread(&type, 1, 1, handle);
setType(type);
std::vector<CParamType>& paramTypes = map.mTilesParams[mType];
for (size_t i = 0; i < paramTypes.size(); ++i)
{
switch (paramTypes[i].mType)
{
LOAD_PARAM(eParamOrnate, CParamOrnate, uint8_t, value)
LOAD_PARAM(eParamDoor, CParamDoor, uint8_t, value)
LOAD_PARAM(eParamDoorOrnate, CParamDoorOrnate, uint8_t, value)
LOAD_PARAM(eParamInt, CParamInt, int32_t, value)
LOAD_PARAM(eParamBool, CParamBool, uint8_t, (value == 0 ? false : true))
default:
break;
}
}
}
Drawing in the game
// table for the left part of the frame
SDoorElem tabLeftFrame[WALL_TABLE_HEIGHT][WALL_TABLE_WIDTH] =
{
// Row 3 (farthest)
{
{"", 0, 0, 0, 0, 0, 0}, // 03
{"Frame_Far_Left_0.png", 16, 59, 16, 59, 31, 101}, // 13
{"Frame_Left_0.png", 82, 60, 82, 60, 91, 101}, // 23
{"Frame_Far_Left_0.png", 141, 60, 147, 60, 150, 102}, // 33
{"", 0, 0, 0, 0, 0, 0} // 43
},
[...]
}
The drawing in done in the draw() function:
void CDoors::draw(QImage* image, CTile* tile, CVec2 tablePos)
{
if (isFacing(tile) == true)
{
drawFrameElement(image, tablePos, tabTopFrame, false);
drawFrameElement(image, tablePos, tabLeftFrame, false);
drawFrameElement(image, tablePos, tabRightFrame, true);
SDoorElem& cell = tabDoor[tablePos.y][tablePos.x];
if (cell.file[0] != 0)
{
int doorType = tile->getDoorParam("Type");
int doorNum = cell.file[0] - '0';
std::string fileName = doorsDatas[doorType].files[doorNum].toUtf8().constData();
drawDoor(image, tablePos, fileName);
}
}
}
I won't explain the drawFrameElement() and drawDoor() functions as they are easy to understand. They only read the coordinates in the
void CGame::displayMainView(QImage* image)
{
[...]
for (int y = 0; y < WALL_TABLE_HEIGHT; ++y)
for (int x = 0; x < WALL_TABLE_WIDTH; ++x)
{
[...]
if (tile != NULL)
{
// draw the walls
[...]
// draw the floor ornates
if (tile->getType() == eTileGround)
{
[...]
}
// draw objects back row
// draw the doors
if (tile->getType() == eTileDoor)
{
doors.draw(image, tile, tablePos);
}
// draw objects front row
// draw ennemies
}
}
}
}
The last graphic
void CGame::drawWall(QImage* image, CTile* tile, CVec2 tablePos, EWallSide side, bool flip)
{
[...]
// draw the ornates
CWall* wall = &tile->mWalls[playerSide];
if (wall->getType() == eWallSimple)
{
//------------------------------------------------------------------------------
// simple wall
[...]
}
else if (wall->getType() == eWallPortrait)
{
//------------------------------------------------------------------------------
// champion mirror
[...]
}
else if (wall->getType() == eWallDoorSide)
{
//------------------------------------------------------------------------------
// side of a door
if (tablePos == CVec2(2, 3) && side == eWallSideUp)
{
QImage doorFrame = fileCache.getImage("gfx/3DView/doors/Frame_Face_2.png");
graph2D.drawImage(image, CVec2(96, 33), doorFrame);
}
}
[...]
}
Now we have drawn all the doors of the first level if you test the game you will see that you can go through them even if