Partie 35: Téléporteurs
Téléchargements
Paramètres des téléporteurs
<tile name="Teleporteur">
<image>Teleporter.png</image>
<param type="int">Niveau</param>
<param type="int">X</param>
<param type="int">Y</param>
<param type="enum" values="Haut;Gauche;Bas;Droite;Aucun">Cote</param>
<param type="bool">pourChampions</param>
<param type="bool">pourObjets</param>
</tile>
Comme les escaliers, les téléporteurs peuvent vous amener à un autre niveau à une position (X,Y).
Graphismes
QImage wallGfx = fileCache.getImage(fileName);
CVec2 wallPos(tileInfo->x, tileInfo->y);
QImage teleportGfx = fileCache.getImage("gfx/3DView/Teleporter.png");
// crée l'image du téléporteur
QImage tempImg(wallGfx.size(), QImage::Format_ARGB32);
tempImg.fill(TRANSPARENT);
int subImgX = (wallGfx.size().width() + teleportGfx.size().width() - 1) / teleportGfx.size().width();
int subImgY = (wallGfx.size().height() + teleportGfx.size().height() - 1) / teleportGfx.size().height();
[...]
for (int y = 0; y < subImgY; ++y)
for (int x = 0; x < subImgX; ++x)
{
CVec2 subImgPos(x * teleportGfx.size().width(),
y * teleportGfx.size().height());
[...]
graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
}
// assombrit
int shadow = WALL_TABLE_HEIGHT - 2 - tablePos.y;
if (shadow < 0)
shadow = 0;
graph2D.darken(&tempImg, (float)shadow * 0.2f);
// dessine l'image
graph2D.drawImageWithMask(image, wallPos, tempImg, wallGfx);
Animation
int random = game.frameCounter / 20;
[...]
// crée l'image du téléporteur
[...]
random = (random * 31415821 + 1) % 100000000;
for (int y = 0; y < subImgY; ++y)
for (int x = 0; x < subImgX; ++x)
{
[...]
bool flip = ((random & 1) != 0);
int angle = ((random >> 1) % 4) * 90;
graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
}
La case entière
struct STelepTile
{
char file[16];
uint16_t x, y;
};
static const STelepTile gTelepTiles[WALL_TABLE_HEIGHT][WALL_TABLE_WIDTH][3] =
{
// Rang 3 (le plus loin)
{
{{"Wall02_F.png", 0, 58}, {"", 0, 0}, {"Wall13_L.png", 8, 58}}, // 02
{{"Wall12_F.png", 7, 58}, {"", 0, 0}, {"Wall23_L.png", 78, 59}}, // 12
{{"Wall22_F.png", 77, 58}, {"", 0, 0}, {"", 0, 0} }, // 22
{{"Wall32_F.png", 146, 58}, {"Wall23_R.png", 134, 59}, {"", 0, 0} }, // 32
{{"Wall42_F.png", 216, 58}, {"Wall33_R.png", 180, 58}, {"", 0, 0} } // 42
},
// Rang 2
{
{{"", 0, 0}, {"", 0, 0}, {"Wall12_L.png", 0, 57}}, // 01
{{"Wall11_F.png", 0, 52}, {"", 0, 0}, {"Wall22_L.png", 60, 52}}, // 11
{{"Wall21_F.png", 59, 52}, {"", 0, 0}, {"", 0, 0} }, // 21
{{"Wall31_F.png", 164, 52}, {"Wall22_R.png", 146, 52}, {"", 0, 0} }, // 31
{{"", 0, 0}, {"Wall32_R.png", 216, 57}, {"", 0, 0} } // 41
},
// Rang 1
{
{{"", 0, 0}, {"", 0, 0}, {"", 0, 0} }, // 00
{{"Wall10_F.png", 0, 42}, {"", 0, 0}, {"Wall21_L.png", 33, 42}}, // 10
{{"Wall20_F.png", 32, 42}, {"", 0, 0}, {"", 0, 0} }, // 20
{{"Wall30_F.png", 191, 42}, {"Wall21_R.png", 164, 42}, {"", 0, 0} }, // 30
{{"", 0, 0}, {"", 0, 0}, {"", 0, 0} } // 40
},
// Rang 0 (le plus proche)
{
{{"", 0, 0}, {"", 0, 0}, {"", 0, 0} }, // 00
{{"", 0, 0}, {"", 0, 0}, {"Wall20_L.png", 0, 33}}, // 10
{{"Wall20_F.png", 32, 42}, {"Wall20_R.png", 191, 33}, {"Wall20_L.png", 0, 33}}, // 20
{{"", 0, 0}, {"Wall20_R.png", 191, 33}, {"", 0, 0} }, // 30
{{"", 0, 0}, {"", 0, 0}, {"", 0, 0} } // 40
}
};
Remarquez que cette table contient le cas où on est à l'intérieur du téléporteur (ligne 20).
void CTiles::drawTeleporter(QImage* image, CVec2 tablePos)
{
for (int i = 0; i < 3; ++i)
{
int random = game.frameCounter / 20;
const STelepTile* tileInfo = &gTelepTiles[tablePos.y][tablePos.x][i];
if (tileInfo->file[0] != 0)
{
static char fileName[256];
sprintf(fileName, "gfx/3DView/walls/%s", tileInfo->file);
QImage wallGfx = fileCache.getImage(fileName);
CVec2 wallPos(tileInfo->x, tileInfo->y);
QImage teleportGfx = fileCache.getImage("gfx/3DView/Teleporter.png");
// crée l'image du téléporteur
QImage tempImg(wallGfx.size(), QImage::Format_ARGB32);
tempImg.fill(TRANSPARENT);
int subImgX = (wallGfx.size().width() + teleportGfx.size().width() - 1) / teleportGfx.size().width();
int subImgY = (wallGfx.size().height() + teleportGfx.size().height() - 1) / teleportGfx.size().height();
random = (random * 31415821 + 1) % 100000000;
for (int y = 0; y < subImgY; ++y)
for (int x = 0; x < subImgX; ++x)
{
CVec2 subImgPos(x * teleportGfx.size().width(),
y * teleportGfx.size().height());
bool flip = ((random & 1) != 0);
int angle = ((random >> 1) % 4) * 90;
graph2D.drawImage(&tempImg, subImgPos, teleportGfx, angle, flip);
}
// assombrit
int shadow = WALL_TABLE_HEIGHT - 2 - tablePos.y;
if (shadow < 0)
shadow = 0;
graph2D.darken(&tempImg, (float)shadow * 0.2f);
// dessine l'image
graph2D.drawImageWithMask(image, wallPos, tempImg, wallGfx);
}
}
}
Rentrer dedans
void CPlayer::teleport()
{
CTile* tile = map.getTile(pos);
int level = tile->getIntParam("Niveau");
CVec2 newPos = CVec2(tile->getIntParam("X"), tile->getIntParam("Y"));
int side = tile->getEnumParam("Cote");
if (side == eWallSideMax)
side = dir;
if (level != game.currentLevel)
{
game.loadLevel(level, newPos, side);
}
else
{
player.pos = newPos;
player.dir = side;
}
sound->play(player.pos, "sound/Buzz.wav");
shouldTeleport = false;
}
Ici, c'est pratiquement la même chose que pour les escaliers, à part que l'on ne va pas toujours dans un autre
Poser des objets dedans
else if (clickedArea->type == eMouseAreaG_DropObject)
{
CVec2 pos = CVec2((int)clickedArea->param1, (int)clickedArea->param2);
int side = (int)clickedArea->param3;
[... pose l'objet]
if (side == eWallSideMax)
{
CVec2 mapPos = pos / 2;
CTile* tile = map.getTile(mapPos);
if (tile->getType() == eTileTeleporter && tile->getBoolParam("forObjects") == true)
teleportStacks(mapPos);
}
}
La fonction teleportStacks() va téléporter tout les tas d'objets qui sont dans la case donnée.
void CGame::teleportStacks(CVec2 mapPos)
{
CTile* tile = map.getTile(mapPos);
std::vector<CObjectStack> copyStacks;
// copie les tas
for (int y = 0; y < 2; ++y)
for (int x = 0; x < 2; ++x)
{
CVec2 objPos = mapPos * 2 + CVec2(x, y);
CObjectStack* stack = map.findObjectsStack(objPos, eWallSideMax);
if (stack != NULL)
{
CObjectStack copy = *stack;
copy.mPos = CVec2(x, y);
copyStacks.push_back(copy);
map.removeObjectsStack(objPos, eWallSideMax);
}
}
Ensuite, si le téléporteur mène à un autre niveau, on le charge (après avoir sauvegardé quelques données).
int lastLevel = currentLevel;
CVec2 lastPos = player.pos;
uint8_t lastDir = player.dir;
int level = tile->getIntParam("Niveau");
CVec2 newPos = CVec2(tile->getIntParam("X"), tile->getIntParam("Y"));
// charge le niveau de destination
if (level != currentLevel)
loadLevel(level, CVec2(), 0);
Après ça, on repose tous les objets des tas copiés à la position de destination.
// mets les tas à la nouvelle position
for (size_t i = 0; i < copyStacks.size(); ++i)
{
CVec2 objPos = newPos * 2 + copyStacks[i].mPos;
CObjectStack* stack = map.addObjectsStack(objPos, eWallSideMax);
for (size_t j = 0; j < copyStacks[i].getSize(); ++j)
stack->addObject(copyStacks[i].getObject(j));
}
Et finalement, si on a changé de niveau, on revient à celui de départ.
// recharge le dernier niveau
if (level != lastLevel)
loadLevel(lastLevel, lastPos, lastDir);
}
Bugs corrigés dans l'éditeur