Partie 18: Portes - Partie 2: Collisions, ouverture et décors
Téléchargements
Collisions
void CPlayer::moveIfPossible(EWallSide side)
{
CVec2 newPos = pos;
[...]
CTile* tile = map.getTile(pos);
CTile* destTile = map.getTile(newPos);
bool canMove = true;
if (tile->mWalls[side].getType() != 0)
{
canMove = false;
}
else if (destTile == NULL)
{
canMove = false;
}
else if (destTile->getType() == eTileDoor && doors.isOpened(destTile) == false)
{
canMove = false;
}
if (canMove == true)
pos = newPos;
}
Le bouton
struct SButtonElem
{
int16_t x, y;
float scale;
};
SButtonElem tabButton[WALL_TABLE_HEIGHT][WALL_TABLE_WIDTH] =
{
// Rang 3 (le plus loin)
{
{0, 0, 0.0}, // 03
{0, 0, 0.0}, // 13
{137, 74, 0.43}, // 23
{197, 72, 0.43}, // 33
{0, 0, 0.0} // 43
},
// Rang 2
{
{0, 0, 0.0}, // 02
{0, 0, 0.0}, // 12
{150, 75, 0.66}, // 22
{0, 0, 0.0}, // 32
{0, 0, 0.0} // 42
},
// Rang 1
{
{0, 0, 0.0}, // 01
{0, 0, 0.0}, // 11
{167, 76, 1.0}, // 21
{0, 0, 0.0}, // 31
{0, 0, 0.0} // 41
},
// Rang 0 (le plus proche)
{
{0, 0, 0.0}, // 00
{0, 0, 0.0}, // 10
{0, 0, 0.0}, // 20
{0, 0, 0.0}, // 30
{0, 0, 0.0} // 40
}
};
Ensuite, dans CDoors::draw() on fait le dessin et on ajoute une zone souris quand la porte est devant nous.
void CDoors::draw(QImage* image, CTile* tile, CVec2 tablePos)
{
if (isFacing(tile) == true)
{
//-------------------------------------------------------------------------------------
// dessine l'encadrement
drawFrameElement(image, tablePos, tabTopFrame, false);
drawFrameElement(image, tablePos, tabLeftFrame, false);
drawFrameElement(image, tablePos, tabRightFrame, true);
//-------------------------------------------------------------------------------------
// dessine le bouton
if (tile->getBoolParam("hasButton") == true)
{
SButtonElem& cell = tabButton[tablePos.y][tablePos.x];
CVec2 pos(cell.x, cell.y);
float scale = cell.scale;
if (scale != 0.0f)
{
QImage button = fileCache.getImage("gfx/3DView/doors/Button.png");
static const float shadowLevels[] = {0.0f, 0.2f, 0.4f};
float shadow = shadowLevels[WALL_TABLE_HEIGHT - 2 - tablePos.y];
graph2D.darken(&button, shadow);
graph2D.drawImageScaled(image, pos, button, scale);
if (tablePos == CVec2(2, 2))
{
CRect rect(pos,
CVec2(pos.x + button.width() - 1, pos.y + button.height() - 1));
mouse.addArea(eMouseAreaG_DoorButton, rect, (void*)tile);
}
}
}
//-------------------------------------------------------------------------------------
// dessine la porte avec le décor
drawDoor(image, tablePos, tile);
}
}
Finalement dans CGame::update() où on teste les zones souris, on teste si le bouton est cliqué.
void CGame::update(SMouseArea* clickedArea)
{
doors.update();
if (clickedArea != NULL)
{
if (mouse.mButtonPressing == true)
{
if (clickedArea->type == eMouseAreaG_Champion)
{
[...]
}
else if (clickedArea->type == eMouseAreaG_DoorButton)
{
CTile* tile = (CTile*)clickedArea->param1;
bool isOpened = tile->getBoolParam("estOuverte");
tile->setBoolParam("estOuverte", !isOpened);
}
}
}
}
A des fins de test, j'ai ajouté un bouton à chaque porte dans le premier niveau, comme on n'a pas encore vu les
Ouvrir les portes
// Met à jour les animations des portes
void CDoors::update()
{
for (int y = 0; y < map.mSize.y; ++y)
for (int x = 0; x < map.mSize.x; ++x)
{
CTile* tile = map.getTile(CVec2(x, y));
if (tile->getType() == eTileDoor)
{
bool isHorizontal = tile->getBoolParam("estHorizontale");
int animLenght = (isHorizontal == false ? 88 : 48) * DOOR_POS_FACTOR;
int pos = tile->getIntParam("pos");
bool isOpened = tile->getBoolParam("estOuverte");
if (isOpened == false)
{
if (pos < 0)
{
tile->setBoolParam("estEnMouvement", true);
pos += animLenght / DOOR_ANIMATION_TIME;
tile->setIntParam("pos", pos);
}
if (pos >= 0)
{
tile->setBoolParam("estEnMouvement", false);
tile->setIntParam("pos", 0);
}
}
else
{
if (pos > -animLenght)
{
tile->setBoolParam("estEnMouvement", true);
pos -= animLenght / DOOR_ANIMATION_TIME;
tile->setIntParam("pos", pos);
}
if (pos <= -animLenght)
{
tile->setBoolParam("estEnMouvement", false);
tile->setIntParam("pos", -animLenght);
}
}
}
}
}
Maintenant, les constantes ont besoin d'être un peu expliquées.
Les portes verticales
void CDoors::drawDoor(QImage* image, CVec2 tablePos, CTile* tile)
{
SDoorElem& cell = tabDoor[tablePos.y][tablePos.x];
int doorNum = cell.file[0] - '0';
if (doorNum >= 0)
{
//----------------------------------------------------------------------------
// récupère l'image de la porte
int doorType = tile->getDoorParam("Type");
std::string fileName = std::string("gfx/3DView/doors/") + doorsDatas[doorType].files[doorNum].toUtf8().constData();
QImage doorImage = fileCache.getImage(fileName);
[...]
//----------------------------------------------------------------------------
// dessin
bool isHorizontal = tile->getBoolParam("estHorizontale");
int doorPos = tile->getIntParam("pos") / DOOR_POS_FACTOR;
if (isHorizontal == false)
{
//----------------------------------------------------------------------------
// porte verticale
static const int doorScalesY[] = {88, 61, 38};
float scale = doorScalesY[WALL_TABLE_HEIGHT - 2 - tablePos.y];
doorPos = (doorPos * scale) / 88;
CVec2 pos(cell.x, cell.y + doorPos);
QRect clip(cell.cx1, cell.cy1,
cell.cx2 - cell.cx1 + 1, cell.cy2 - cell.cy1 + 1);
graph2D.drawImage(image, pos, doorImage, 0, false, clip);
}
else
{
//----------------------------------------------------------------------------
// porte horizontale
[...]
}
}
}
Les portes horizontales
void CDoors::drawDoor(QImage* image, CVec2 tablePos, CTile* tile)
{
SDoorElem& cell = tabDoor[tablePos.y][tablePos.x];
int doorNum = cell.file[0] - '0';
if (doorNum >= 0)
{
//----------------------------------------------------------------------------
// récupère l'image de la porte
[...]
//----------------------------------------------------------------------------
// dessin
bool isHorizontal = tile->getBoolParam("estHorizontale");
int doorPos = tile->getIntParam("pos") / DOOR_POS_FACTOR;
if (isHorizontal == false)
{
//----------------------------------------------------------------------------
// porte verticale
[...]
}
else
{
//----------------------------------------------------------------------------
// porte horizontale
static const int doorScalesX[] = {96, 64, 44};
float scale = doorScalesX[WALL_TABLE_HEIGHT - 2 - tablePos.y];
doorPos = (doorPos * scale) / 96;
CVec2 pos(cell.x + doorPos, cell.y);
int halfwidth = (cell.cx2 - cell.cx1 + 1) / 2;
QRect clip1(cell.cx1, cell.cy1,
halfwidth + doorPos, cell.cy2 - cell.cy1 + 1);
graph2D.drawImage(image, pos, doorImage, 0, false, clip1);
pos.x = cell.x - doorPos;
QRect clip2(cell.cx1 + halfwidth - doorPos, cell.cy1,
halfwidth + doorPos, cell.cy2 - cell.cy1 + 1);
graph2D.drawImage(image, pos, doorImage, 0, false, clip2);
}
}
}
Les décors des portes
<?xml version="1.0" encoding="ISO-8859-1"?>
<door_ornates>
<door_ornate name="Aucun">
</door_ornate>
<door_ornate name="Entree Donjon">
<image>Dungeon_Entrance.png</image>
<pos x="0" y="0"/>
</door_ornate>
</door_ornates>
Le chargement de cette base de données est la même chose que ce que nous avons déjà fait de nombreuses fois...
void CDoors::drawDoor(QImage* image, CVec2 tablePos, CTile* tile)
{
SDoorElem& cell = tabDoor[tablePos.y][tablePos.x];
int doorNum = cell.file[0] - '0';
if (doorNum >= 0)
{
//----------------------------------------------------------------------------
// récupère l'image de la porte
[...]
//----------------------------------------------------------------------------
// récupère l'image du décor
int ornateType = tile->getDoorOrnateParam("Decor");
std::string ornateName = doorOrnatesDatas[ornateType].file.toUtf8().constData();
QImage ornateImage;
CVec2 ornatePos;
if (ornateName.empty() == false)
{
// réduit le décor, l'assombrit, et le dessine sur l'image de la porte
ornateImage = fileCache.getImage(std::string("gfx/3DView/door_ornates/") + ornateName);
static const float shadowLevels[] = {0.0f, 0.2f, 0.4f};
float shadow = shadowLevels[WALL_TABLE_HEIGHT - 2 - tablePos.y];
graph2D.darken(&ornateImage, shadow);
ornatePos = doorOrnatesDatas[ornateType].pos;
float scale = doorImage.width() / 96.0;
ornatePos *= scale;
graph2D.drawImageScaled(&doorImage, ornatePos, ornateImage, scale);
}
//----------------------------------------------------------------------------
// dessin
[...]
}
}
On verra plus tard que ces décors réservent encore bien des surprises...