Partie 12: Les décors des murs - Partie 1
Téléchargements
Les décors
<?xml version="1.0" encoding="ISO-8859-1"?>
<ornates>
<ornate name="Aucun">
</ornate>
<ornate name="Fers">
<image_front>Manacles_front.png</image_front>
<image_side>Manacles_side.png</image_side>
<pos_front x="66" y="71"/>
<pos_side x="30" y="73"/>
</ornate>
</ornates>
Nous avons les fichiers graphiques pour nos 2 sprites qui correspondent aux murs les plus proches, et leurs coordonnées à l'écran.
Paramètres additionnels dans "walls.xml"
<?xml version="1.0" encoding="ISO-8859-1"?>
<walls>
<wall name="Rien">
</wall>
<wall name="Simple">
<image>Wall.png</image>
<param type="ornate">Decor</param>
</wall>
</walls>
Pour le moment on n'a qu'un type de paramètre. On le définit dans un enum pour que le code soit plus lisible quand on aura plus de types:
enum EParamType
{
eParamOrnate = 0,
};
Pour stocker les noms de paramètres dans le code, on définit un vecteur de vecteurs de structures CParamType dans la map:
struct CParamType
{
EParamType mType;
QString mName;
};
class CMap
{
[...]
std::vector<std::vector<CParamType>> mWallsParams; // liste des paramètres pour chaque type de mur
[...]
};
Il y a 2 vecteurs parce que:
void CEditor::readWallsDB(QString fileName)
{
[...]
while(!wall.isNull())
{
std::vector paramsTypesList;
if (wall.tagName() == "wall")
{
CWallData newWall;
[...]
while(!wallInfo.isNull())
{
if (wallInfo.tagName() == "image")
{
[...]
}
else if (wallInfo.tagName() == "param")
{
QString paramType = wallInfo.attribute("type");
if (paramType == "ornate")
{
CParamType newParamType;
newParamType.mType = eParamOrnate;
newParamType.mName = wallInfo.text();
paramsTypesList.push_back(newParamType);
}
}
wallInfo = wallInfo.nextSibling().toElement();
}
wallsDatas.push_back(newWall);
map.mWallsParams.push_back(paramsTypesList);
}
wall = wall.nextSibling().toElement();
}
}
Les valeurs des paramètres
class CParam
{
public:
EParamType mType;
};
class CParamOrnate : CParam
{
public:
CParamOrnate();
uint8_t mValue;
};
La classe CWall va contenir une liste de ces CParams:
std::vector<CParam*> mParams;
Mais en fait la classe CWall a complètememnt changé...
class CWall
{
public:
CWall();
virtual ~CWall();
void setType(uint8_t type);
uint8_t getType();
CWall& operator=(CWall& rhs);
void load(FILE* handle);
void save(FILE* handle);
std::vector<CParam*> mParams;
private:
void deleteParams();
uint8_t mType;
};
Laissez-moi vous expliquer ces fonctions.
uint8_t CWall::getType()
{
return mType;
}
deleteParams() efface la liste des paramètres:
void CWall::deleteParams()
{
for (size_t i = 0; i < mParams.size(); ++i)
delete mParams[i];
mParams.clear();
}
La fonction setType() change la valeur de mType. Et comme je l'ai dit, elle réalloue les paramètres pour ce type:
void CWall::setType(uint8_t type)
{
if (mType == type)
return;
mType = type;
// alloue les paramètres
deleteParams();
std::vector<CParamType>& paramTypes = map.mWallsParams[type];
for (size_t i = 0; i < paramTypes.size(); ++i)
{
CParam* newParam = NULL;
switch (paramTypes[i].mType)
{
case eParamOrnate:
newParam = (CParam*)(new CParamOrnate);
break;
default:
break;
}
mParams.push_back(newParam);
}
}
Donc j'ai du changer tous les endroits dans le code où le mType du mur était utilisé ou modifié pour les remplacer avec ces fonction "get" et "set".
Créer les widgets
import QtQuick 2.5
import QtQuick.Controls 1.4
Label {
height: 20
text: qsTr("Test")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
renderType: Text.QtRendering
}
... et "ParamComboBox.qml".
import QtQuick 2.5
import QtQuick.Controls 1.4
ComboBox {
property int identifier: -1
currentIndex: -1
onCurrentIndexChanged: bridge.setSelParamCombo(identifier, currentIndex);
}
On va ajouter ces widgets aux grilles dans les différentes "feuilles" de sélection, alors il faut qu'on récupère des pointeurs sur ces
QQuickItem* tileSelGrid;
QQuickItem* wallSelGrid;
QQuickItem* objSelGrid;
[...]
QObject *rootObject = engine.rootObjects().first();
tileSelGrid = qobject_cast(rootObject->findChild("tSelGrid"));
wallSelGrid = qobject_cast(rootObject->findChild("wSelGrid"));
objSelGrid = qobject_cast(rootObject->findChild("oSelGrid"));
Nos widgets seront créés dans la fonction toolSelect(), chaque fois qu'on sélectionne un seul mur:
void CEditor::toolSelect()
{
if (bridge.leftPressed == true)
{
[...]
switch (bridge.mTabIndex)
{
[...]
case eTabWalls:
if (isSelectSingleWall() == true)
{
EWallSide side = getWallSideAbs(mSelectStart);
uint8_t type = map.getTile(rect.tl)->mWalls[side].getType();
bridge.set_selWallType(type);
deleteParamItems(&mWallParamItems);
addWallParamsItems(type);
}
break;
default:
break;
}
bridge.updateQMLImage();
}
}
[...]
void CEditor::addWallParamsItems(uint8_t type)
{
CVec2 pos = mSelectStart / TILE_SIZE;
EWallSide side = getWallSideAbs(mSelectStart);
CWall* wall = &map.getTile(pos)->mWalls[side];
std::vector<CParamType>& sourceList = map.mWallsParams[type];
for (size_t i = 0; i < sourceList.size(); ++i)
{
CParam* param = wall->mParams[i];
if (sourceList[i].mType == eParamOrnate)
{
CParamOrnate* par = (CParamOrnate*)param;
addLabel(wallSelGrid, sourceList[i].mName + ":", &mWallParamItems);
addComboBox(wallSelGrid, bridge.ornatesList, &mWallParamItems, i, par->mValue);
}
}
}
Et voici les fonction qui chargent vraiment les qml et qui créent des widgets à partir d'eux. C'est un peu de la "magie Qt".
//---------------------------------------------------------------------------------------------
QQuickItem* CEditor::loadQml(QString file, QQuickItem* parent)
{
QQmlComponent component(myQmlEngine, QUrl(file));
QQuickItem* object = qobject_cast<QQuickItem*>(component.create());
QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership);
object->setParent(parent);
object->setParentItem(parent);
return object;
}
//---------------------------------------------------------------------------------------------
void CEditor::addLabel(QQuickItem* parent, QString text, std::vector<QQuickItem *> *list)
{
QQuickItem* object = loadQml("qrc:/ParamLabel.qml", parent);
object->setProperty("text", QVariant(text));
list->push_back(object);
}
//---------------------------------------------------------------------------------------------
void CEditor::addComboBox(QQuickItem* parent, QStringList& values, std::vector<QQuickItem*>* list, int id, int index)
{
QQuickItem* object = loadQml("qrc:/ParamComboBox.qml", parent);
object->setProperty("model", QVariant(values));
object->setProperty("identifier", QVariant(id));
object->setProperty("currentIndex", QVariant(index));
list->push_back(object);
}
Bon, c'était beaucoup de travail, mais maintenant on a un moyen d'ajouter des paramètres variés pour un type de mur donné.