C ++: std :: vector - std :: find & std :: distance - PullRequest
0 голосов
/ 16 февраля 2020

Для контекста моего вопроса я опишу, чего я в конечном итоге пытаюсь достичь - я разрабатываю игру, у меня есть модель .obj, которую я использую в качестве местности, и я должен обновить высоту игроков как они пересекают местность (потому что местность далеко не ровная). В настоящее время я достигаю этого, выполняя следующее: когда я загружаю me sh (terrain.obj), я сохраняю все его вершины (каждая вершина - это Vector3f объект, который имеет x y и z значение) в std::vector<Vector3f> meshVertices, затем каждую секунду в «основной игре l oop» я прохожу oop через каждый из Vector3f объектов в meshVertices и проверяет его значение x и z против значений игроков x и z, если они сталкиваются, я устанавливаю высоту игроков как значение y соответствующего объекта Vector3f.

Эта система фактически работает и обновляет рост моих игроков когда они перемещаются по местности, единственная проблема заключается в том, что мой подход проверки каждой вершины me sh против позиции игрока каждую секунду убивает мою частоту кадров, мне нужна гораздо лучшая система.

Теперь я буду опишите мой новый оптимизированный подход в попытке сохранить частоту кадров - во-первых, при создании me sh я не просто храню каждую Vector3f вершину в одной std::vector<Vector3f>, я сохраняю x y и z значения каждая Vector3f вершина меня sh в трех отдельных std::vector<Vector3f> с именами meshVerticesX, mechVerticesY и meshVerticesZ. These std::vector можно увидеть в следующем коде:

for (Vector3f currentVertex : meshVertices) { 
            meshVerticesX.push_back((int)currentVertex.GetX());
}
for (Vector3f currentVertex : meshVertices) {
            meshVerticesZ.push_back((int)currentVertex.GetZ());
}
for (Vector3f currentVertex : meshVertices) {
            meshVerticesY.push_back((int)currentVertex.GetY());
}

Теперь каждую секунду я получаю x и z значение позиции игрока (приведенное к int, потому что мне хочется сделать эта система будет работать со значениями типа int, а не с плавающими значениями, для сравнения будет намного легче позже), а затем отправлять их функциям, которые проверяют, существуют ли они в упомянутых выше meshVerticesX и mechVerticesZ, возвращая bool, код, ответственный это выглядит следующим образом:

int playerPosX = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetX();
int playerPosZ = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetZ();
bool x = meshObjects[0]->checkMeshVerticesX(playerPosX);
bool z = meshObjects[0]->checkMeshVerticesZ(playerPosZ);

Функции checkMeshVerticesX и checkMeshVerticesZ следующие:

bool Mesh::checkMeshVerticesX(int playerPosX)
{
    return std::find(meshVerticesX.begin(), meshVerticesX.end(), playerPosX) != meshVerticesX.end();
}
bool Mesh::checkMeshVerticesZ(int playerPosZ)
{
    return std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerPosZ) != meshVerticesZ.end();
}

Использование возвращенных логических значений (true, если игроки позиция была в соответствующем std::vector или ложь, если это не так) Затем я вызываю другую функцию (getMeshYHeight), которая также получает пройденные позиции игроков x и z, которая затем проверяет индекс соответствующих std::vector '(meshVerticesX & meshVerticesZ), где совпадение было найдено, затем проверяет, равны ли эти индексы, и если да, возвращает int этого индекса из meshVerticesY std::vector, упомянутого ранее, этот код можно увидеть в fo llowing:

if (x == true & z == true) {// boolean values returned by checkMeshVerticesX & checkMeshVerticesZ
        int terrainVertexYHeight = meshObjects[0]->getMeshYHeight(playerPosX, playerPosZ);
        freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->SetY(terrainVertexYHeight);
    }

Функция getMeshYHeight выглядит следующим образом:

int Mesh::getMeshYHeight(int playerXPos, int playerZPos) {//15/2/20
    auto iterX = std::find(meshVerticesX.begin(), meshVerticesX.end(), playerXPos) != meshVerticesX.end();
    auto iterZ = std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerZPos) != meshVerticesZ.end();
    int indexX = std::distance(meshVerticesX.begin(), iterX);
    int indexZ = std::distance(meshVerticesZ.begin(), iterZ);
    if (indexX == indexZ)
    {
        return meshVerticesY[indexX];
    }
}

Идея заключается в том, что если индекс из meshVerticesX и meshVerticesZ std::vectors ' s для исходного совпадения проверки, тогда они должны быть значениями x и z исходного объекта Vector3f, когда я впервые сделал me sh, как описано ранее, и поэтому тот же индекс в meshVerticesY должен содержать те же самые Vector3f Значение y объектов, поэтому верните его и используйте его для установки высоты игроков.

Проблема в том, что я не могу даже проверить, работает ли это, потому что строка кода int indexX = std::distance(meshVerticesX.begin(), iterX); выдает ошибку, сообщающую аргументы, переданные std::distance, неверны (он говорит, что iterX - это bool вместо int, как я и думал).

Так что мой вопрос - во-первых, если я уклонюсь ' Не было бы этой ошибки, мой подход даже работал? и если да, то как я могу исправить ошибку?

Ответы [ 2 ]

2 голосов
/ 16 февраля 2020

Я как-то потерялся в вашей логике c где-то посередине, но для решения рассматриваемой проблемы: iterX - это глупость!

auto iterX = std::find(...) != meshVerticesX.end();

В этом выражении find возвращает итератор , который вы сравниваете с другим итератором, meshVerticesX.end (). Результатом этого выражения (оператор сравнения) является bool, который затем присваивается iterX, поэтому автоматически выводит, что iterX должен иметь тип bool.

0 голосов
/ 16 февраля 2020

если бы вы конвертировали координаты x, y вашей местности в целые, вам может потребоваться масштабировать ее, а затем, когда вы загрузите me sh, вы можете просто сохранить значение z для каждой точки x, y (вам может потребоваться какое-то среднее по квадрату 1x1). Теперь вам не нужно искать столкновения, вместо этого для каждого объекта в игре вы можете просто посмотреть его значение z по его (масштабированным) координатам x, y.

...