我目前正在将一个Graph映射到扫雷类网格,其中每个Block代表一个节点。这是我的Graph
类:
class Graph : public sf::Drawable
{
public:
Graph(uint32_t numNodesWidth, uint32_t numNodesHeight);
[[nodiscard]] std::vector<Node> & operator[](std::size_t i)
{ return data[i]; }
[[nodiscard]] sf::Vector2u dimension() const
{ return {static_cast<uint32_t>(data.size()),
static_cast<uint32_t>(data[0].size())};}
...
...
private:
std::vector<std::vector<Node>> data;
};
下面是构造函数的实现:
Graph::Graph(uint32_t numNodesWidth, uint32_t numNodesHeight)
{
data.resize(numNodesHeight);
for(auto & row : data)
{
row.resize(numNodesWidth);
}
}
在另一个类中,我读取鼠标坐标并将其转换为"图形坐标":
sf::Vector2u translatedCoords = toGraphCoords(sf::Mouse::getPosition(window), nodeSize_);
bool inBounds = checkGraphBounds(translatedCoords, graph.dimension());
以下是辅助函数:
sf::Vector2u toGraphCoords(sf::Vector2i mouseCoord, sf::Vector2f nodeSize)
{
return {static_cast<uint32_t>(mouseCoord.y / nodeSize.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize.x)};
}
bool checkGraphBounds(sf::Vector2u mouseCoord, sf::Vector2u bounds)
{
return mouseCoord.x >= 0 &&
mouseCoord.y >= 0 &&
mouseCoord.x < bounds.x &&
mouseCoord.y < bounds.y ;
}
当我尝试使用这些新的检查坐标时,我得到了vector subscript out of range 1655
错误,这有点奇怪,有人能向我解释我做错了什么吗?当我试图将鼠标悬停在"边界"之外时,这个错误总是显示出来。在第一个或最后一个节点的后面或前面。
提前感谢。
不能保证bounds <= num_nodes * node_size
。这是特别危险的,因为涉及到整数除法,这意味着您可以随意舍入。
你可以打乱代码,直到这样的保证存在,但有一个更好的方法。
如果checkGraphBounds()
函数的运算与网格的运算相同,则可以确定结果将与网格一致,无论它与边界如何相关。
理想的方法是实际使用toGraphCoords()
作为它的一部分:
bool checkGraphBounds(sf::Vector2u mouseCoord, const Graph& graph,
sf::Vector2f nodeSize)
{
auto coord = toGraphCoords(mouseCoord, nodeSize);
return coord.x >= 0 &&
coord.y >= 0 &&
coord.x < graph.dimensions().x &&
coord.y < graph.dimensions().y) ;
}
有了这个,你就可以正式保证如果mouseCoord
通过了测试,static_cast<uint32_t>(mouseCoord.x / nodeSize.x)}
肯定会返回一个不大于graph.dimensions().x
的值。
就我个人而言,我会将这两个函数组合为Graph
方法,如下所示:
class Graph : public sf::Drawable {
// Make nodeSize a member of the Graph
sf::Vector2f nodeSize_;
// This is one of the cases where caching an inferable value is worth it.
sf::Vector2u dimensions_;
public:
std::optional<sf::Vector2u> toGraphCoords(sf::Vector2i mouseCoord) {
sf::Vector2u coord{
static_cast<uint32_t>(mouseCoord.y / nodeSize_.y),
static_cast<uint32_t>(mouseCoord.x / nodeSize_.x)};
};
// No need to compare against 0, we are dealing with unsigned ints
if(coord.x < dimensions_.x &&
coord.y < dimensions_.y ) {
return coord;
}
return std::nullopt;
}
// ...
};
用法:
void on_click(sf::Vector2i mouse_loc) {
auto maybe_graph_coord = the_graph.toGraphCoords(mouse_loc);
if(maybe_graph_coord) {
sf::Vector2u graph_coord = *maybe_graph_coord;
// ...
}
}