mirror of
https://github.com/mehah/otclient
synced 2026-08-15 16:29:06 -04:00
fix: incorrect draw order of creature when walking diagonally (#1793)
Bug Fixes: - Improved creature positioning while walking across tiles, including diagonal movement. - Corrected rendering order so walking creatures appear properly relative to non-walkable ground objects. - Improved display of stationary creatures and local-player positioning. - Removed visual inconsistencies caused by outdated virtual-tile rendering behavior.
This commit is contained in:
parent
5a33b4a166
commit
46ec6f13de
2 changed files with 61 additions and 50 deletions
|
|
@ -742,6 +742,18 @@ void Creature::updateWalkingTile()
|
|||
g_gameConfig.getSpriteSize() + (m_walkOffset.y - displacementY),
|
||||
g_gameConfig.getSpriteSize(), g_gameConfig.getSpriteSize());
|
||||
|
||||
for (int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
|
||||
for (int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
|
||||
Rect virtualTileRect((xi + 1) * g_gameConfig.getSpriteSize(), (yi + 1) * g_gameConfig.getSpriteSize(), g_gameConfig.getSpriteSize(), g_gameConfig.getSpriteSize());
|
||||
|
||||
// only render creatures where bottom right is inside tile rect
|
||||
if (virtualTileRect.contains(virtualCreatureRect.bottomRight()))
|
||||
newWalkingTile = g_map.getOrCreateTile(getPosition().translated(xi, yi, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// NW - for the effect of going behind the object west of it, walking creature will be drawn in front of the object for the half of the way, and after behind
|
||||
// SE - for the effect of going in front the object south of it, walking creature will be drawn behind the object for the half of the way, and after in front
|
||||
if (m_walkedPixels < g_gameConfig.getSpriteSize() / 2) {
|
||||
if (m_direction == Otc::Direction::NorthWest)
|
||||
newWalkingTile = m_walkingTile ? m_walkingTile : getTile();
|
||||
|
|
@ -749,20 +761,6 @@ void Creature::updateWalkingTile()
|
|||
newWalkingTile = g_map.getTile(getPosition().translated(-1, -1, 0));
|
||||
}
|
||||
|
||||
for (int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
|
||||
for (int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
|
||||
Rect virtualTileRect((xi + 1) * g_gameConfig.getSpriteSize(), (yi + 1) * g_gameConfig.getSpriteSize(), g_gameConfig.getSpriteSize(), g_gameConfig.getSpriteSize());
|
||||
|
||||
// when creature is moving to the upper left tile, because of drawing order (we want creature to be behind the object to the left if its a tree for example)
|
||||
if (m_direction == Otc::Direction::NorthWest && virtualTileRect.contains(virtualCreatureRect.topLeft())) {
|
||||
newWalkingTile = g_map.getOrCreateTile(getPosition().translated(xi, yi, 0));
|
||||
} else if (virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
|
||||
// only render creatures where bottom right is inside tile rect
|
||||
newWalkingTile = g_map.getOrCreateTile(getPosition().translated(xi, yi, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newWalkingTile == m_walkingTile) return;
|
||||
|
||||
const auto& self = static_self_cast<Creature>();
|
||||
|
|
|
|||
|
|
@ -78,12 +78,37 @@ void Tile::draw(const MapPosInfo& mapRect, const Point& dest, const int flags, L
|
|||
return;
|
||||
}
|
||||
|
||||
// when walking diagonally over a tile that has a object on it like a tree the creature should be rendered behind it
|
||||
// i.e. render creature first then the tree
|
||||
std::vector<ThingPtr> skipped_non_walkable;
|
||||
for (const auto& thing : m_things) {
|
||||
if (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
// delay drawing after NE/SW walking creature
|
||||
if (thing->isNotWalkable()) {
|
||||
skipped_non_walkable.push_back(thing);
|
||||
continue;
|
||||
}
|
||||
|
||||
drawThing(thing, dest, flags, drawElevation);
|
||||
}
|
||||
|
||||
drawAttachedEffect(dest, dest, lightView, false);
|
||||
|
||||
if (hasCommonItem()) {
|
||||
for (auto& item : std::ranges::reverse_view(m_things)) {
|
||||
if (!item->isCommon()) continue;
|
||||
drawThing(item, dest, flags, drawElevation);
|
||||
}
|
||||
}
|
||||
|
||||
// when walking diagonally over a tile that has a non-walkable object on it (for example - a tree) the creature should be drawn behind it
|
||||
if (hasWalkingCreature()) {
|
||||
g_drawPool.setDrawOrder(DrawOrder::THIRD);
|
||||
for (const auto& creature : m_walkingCreatures) {
|
||||
if (creature->getDirection() == Otc::Direction::NorthEast || creature->getDirection() == Otc::Direction::SouthWest) {
|
||||
// if creature is stepping into this tile then draw it later
|
||||
if (creature->getLastStepToPosition() == getPosition())
|
||||
continue;
|
||||
|
||||
const auto& cDest = Point(
|
||||
dest.x + ((creature->getPosition().x - m_position.x) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor(),
|
||||
dest.y + ((creature->getPosition().y - m_position.y) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor()
|
||||
|
|
@ -100,21 +125,8 @@ void Tile::draw(const MapPosInfo& mapRect, const Point& dest, const int flags, L
|
|||
g_drawPool.resetDrawOrder();
|
||||
}
|
||||
|
||||
for (const auto& thing : m_things) {
|
||||
if (!thing->isGround() && !thing->isGroundBorder() && !thing->isOnBottom())
|
||||
break;
|
||||
|
||||
for (const auto& thing : skipped_non_walkable)
|
||||
drawThing(thing, dest, flags, drawElevation);
|
||||
}
|
||||
|
||||
drawAttachedEffect(dest, dest, lightView, false);
|
||||
|
||||
if (hasCommonItem()) {
|
||||
for (auto& item : std::ranges::reverse_view(m_things)) {
|
||||
if (!item->isCommon()) continue;
|
||||
drawThing(item, dest, flags, drawElevation);
|
||||
}
|
||||
}
|
||||
|
||||
// after we render 2x2 lying corpses, we must redraw previous creatures/ontop above them
|
||||
if (m_tilesRedraw) {
|
||||
|
|
@ -155,26 +167,6 @@ void Tile::drawCreature(const MapPosInfo& mapRect, const Point& dest, const int
|
|||
if (!forceDraw && !m_drawTopAndCreature)
|
||||
return;
|
||||
|
||||
g_drawPool.setDrawOrder(DrawOrder::THIRD);
|
||||
for (const auto& creature : m_walkingCreatures) {
|
||||
// already drawn by this point
|
||||
if (creature->getDirection() == Otc::Direction::NorthEast || creature->getDirection() == Otc::Direction::SouthWest)
|
||||
continue;
|
||||
|
||||
const auto& cDest = Point(
|
||||
dest.x + ((creature->getPosition().x - m_position.x) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor(),
|
||||
dest.y + ((creature->getPosition().y - m_position.y) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor()
|
||||
);
|
||||
|
||||
if (flags == Otc::DrawLights)
|
||||
creature->drawLight(cDest, lightView);
|
||||
else {
|
||||
creature->draw(cDest, flags & Otc::DrawThings);
|
||||
creature->drawInformation(mapRect, cDest + creature->getDrawElevation() * g_drawPool.getScaleFactor(), flags);
|
||||
}
|
||||
}
|
||||
g_drawPool.resetDrawOrder();
|
||||
|
||||
bool localPlayerDrawed = false;
|
||||
if (hasCreatures()) {
|
||||
for (const auto& thing : m_things) {
|
||||
|
|
@ -190,6 +182,27 @@ void Tile::drawCreature(const MapPosInfo& mapRect, const Point& dest, const int
|
|||
}
|
||||
}
|
||||
|
||||
g_drawPool.setDrawOrder(DrawOrder::THIRD);
|
||||
for (const auto& creature : m_walkingCreatures) {
|
||||
// already drawn by this point
|
||||
if (creature->getDirection() == Otc::Direction::NorthEast || creature->getDirection() == Otc::Direction::SouthWest)
|
||||
if (creature->getLastStepToPosition() != getPosition())
|
||||
continue;
|
||||
|
||||
const auto& cDest = Point(
|
||||
dest.x + ((creature->getPosition().x - m_position.x) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor(),
|
||||
dest.y + ((creature->getPosition().y - m_position.y) * g_gameConfig.getSpriteSize() - creature->getDrawElevation()) * g_drawPool.getScaleFactor()
|
||||
);
|
||||
|
||||
if (flags == Otc::DrawLights)
|
||||
creature->drawLight(cDest, lightView);
|
||||
else {
|
||||
creature->draw(cDest, flags & Otc::DrawThings);
|
||||
creature->drawInformation(mapRect, cDest + creature->getDrawElevation() * g_drawPool.getScaleFactor(), flags);
|
||||
}
|
||||
}
|
||||
g_drawPool.resetDrawOrder();
|
||||
|
||||
// draw the local character if he is on a virtual tile, that is, his visual position is not the same as the server.
|
||||
if (!localPlayerDrawed && g_game.getLocalPlayer() && !g_game.getLocalPlayer()->isWalking() && g_game.getLocalPlayer()->getPosition() == m_position) {
|
||||
drawThing(g_game.getLocalPlayer(), dest, flags, drawElevation, lightView);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue