Allow the player to dig the node the camera is into

That allows them to escape from being unable to move due to being trapped with the camera inside a node (assuming the node is diggable).

Note: The implementation is a bit of a hack. It doesn't consider the lookAt direction.
This commit is contained in:
Pedro Gimeno 2020-02-17 18:15:09 +01:00 committed by Quentin Bazin
parent e5b5ba9568
commit ae9b47e018
2 changed files with 36 additions and 6 deletions

View File

@ -250,19 +250,49 @@ void BlockCursor::draw(gk::RenderTarget &target, gk::RenderStates states) const
} }
glm::ivec4 BlockCursor::findSelectedBlock() const { glm::ivec4 BlockCursor::findSelectedBlock() const {
glm::dvec3 lookAt{m_player.pointTargetedX() - m_player.camera().getPosition().x,
m_player.pointTargetedY() - m_player.camera().getPosition().y,
m_player.pointTargetedZ() - m_player.camera().getPosition().z};
glm::dvec3 position{m_player.camera().getPosition().x, glm::dvec3 position{m_player.camera().getPosition().x,
m_player.camera().getPosition().y, m_player.camera().getPosition().y,
m_player.camera().getPosition().z}; m_player.camera().getPosition().z};
int_fast32_t bestX = int_fast32_t(floor(position.x));
int_fast32_t bestY = int_fast32_t(floor(position.y));
int_fast32_t bestZ = int_fast32_t(floor(position.z));
// Deal with a degenerate case: camera in the middle of a block
uint_fast32_t blockID = m_world.getBlock(bestX, bestY, bestZ);
const Block &block = Registry::getInstance().getBlock(blockID);
if(blockID && block.drawType() != BlockDrawType::Liquid) {
// We're inside a node, therefore there's no face, but we still need
// to return a valid block. We use face 6 for that. For rightclicks,
// it should attempt to place the block on the same node clicked, and
// fail because it's already occupied. For digs, it should just dig
// the node.
return glm::ivec4{bestX, bestY, bestZ, 6};
}
// Still the degenerate case, but this time for the sub-case where
// the coordinates of the player are exact integers, thus lying exactly
// between two faces (or four, if it's in a corner). In this situation,
// the raycasting algorithm allows us to get rid of all blocks except for
// the one in the northwest corner. Deal with that case here.
// NOTE: We don't deal with height because it's unlikely that the
// camera ends up being at an integer position.
if(double(bestX) == position.x && double(bestZ) == position.z) {
blockID = m_world.getBlock(bestX - 1, bestY, bestZ - 1);
const Block &block = Registry::getInstance().getBlock(blockID);
if(blockID && block.drawType() != BlockDrawType::Liquid) {
return glm::ivec4{bestX - 1, bestY, bestZ - 1, 6};
}
}
glm::dvec3 lookAt{m_player.pointTargetedX() - m_player.camera().getPosition().x,
m_player.pointTargetedY() - m_player.camera().getPosition().y,
m_player.pointTargetedZ() - m_player.camera().getPosition().z};
// Ray casting algorithm to find out which block we are looking at // Ray casting algorithm to find out which block we are looking at
const double maxReach = 10.; const double maxReach = 10.;
double bestDepth; double bestDepth;
int_fast8_t bestFace = -1; int_fast8_t bestFace = -1;
int_fast32_t bestX = 0, bestY = 0, bestZ = 0;
glm::dvec3 lookAtN = glm::normalize(lookAt); glm::dvec3 lookAtN = glm::normalize(lookAt);

View File

@ -101,7 +101,7 @@ void BlockCursorRaycast::rayCastToAxis(const Axis axis, const glm::dvec3 &positi
break; break;
} }
int_fast32_t firstNodeRow = int_fast32_t(floor(posCoord)); int_fast32_t firstNodeRow = lookAtCoord < 0. ? int_fast32_t(floor(posCoord)) : int_fast32_t(ceil(posCoord)) - 1;
int_fast32_t lastNodeRow = int_fast32_t(floor(posCoord + lookAtCoord * maxReach)); int_fast32_t lastNodeRow = int_fast32_t(floor(posCoord + lookAtCoord * maxReach));
int_fast8_t dir = (lookAtCoord > 0.) - (lookAtCoord < 0.); int_fast8_t dir = (lookAtCoord > 0.) - (lookAtCoord < 0.);