오전에는 어제 못다한 작업을 진행했습니다.
우선 아이템이 재획득 불가해지는 현상이 가끔 발생하는 이유로 추정되는 코드를 발견해서 제거했습니다.
void AVGMissionItemBase::OnRep_ItemStateTag()
{
if (ItemStateTag == VigilantMissionTags::ItemCarried)
{
MeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
else if (ItemStateTag == VigilantMissionTags::ItemInactive)
{
MeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
}
}
위 함수는 모든 미션 아이템이 상속하는 부모 클래스의 함수입니다. 상태 스테이트 테그의 값에 따라 Collsion 설정을 바꾸어주고 있는데 현제 장착물의 충돌체 설정은 EquippmentComponent에서 일괄 처리하고 있기에 이는 설계상 맞지 않은 코드입니다. EquippmentComponent가 완성되기 이전에 작성된 코드이기에 시야 밖에 놓여져 있었습니다. 오류 발생빈도도 네트워크 지연이 발생될 때 가끔 생기는 정도여서 혼자 테스트할 때는 찾기 어려웠습니다.
이후로는 코드의 최적화 및 튜터님께 받은 리뷰를 참고하여 코드를 수정했습니다.
미션에 사용되는 기믹에 랜덤하게 인덱스를 변경하는로직이 존재합니다.
미리 수를 배열에 저장해두고 랜덤하게 하나를 선택, 기믹에 배정하고 선택된 것을 배열에서 제거하는 식으로 구현을 햇습니다.
제거 시 RemoveAt을 사용했는데 RemoveAtSwap이 더 효율적이기에 교체를 진행했습니다.
RemoveAtSwap은 중간원소를 지운 뒤 뒤쪽 원소를 당기지 않습니다. 맨 뒤 자리의 것을 빈자리에 넣는 방식이어서 시간 복잡도가 O(1)입니다.
랜덤하게 숫자를 뽑는 지금과 같이, 순서가 중요하지 않을 때 사용할 수 있는 방법입니다.
| 항목 | RemoveAt | RemoveAtSwap |
|---|---|---|
| 순서 유지 | O | X |
| 삭제 후 이동 | 뒤 원소들 전부 이동 | 마지막 원소만 교체 |
| 성능 | 상대적으로 느림 | 상대적으로 빠름 |
| 추천 상황 | UI 목록, 정렬 유지 | 액터 목록, 타깃 풀 |
VGMissionCombat와 VGMissioinTimedCombat의 경우 겹치는 코드가 상당히 많았습니다. VGMissionCombat에서 제한시간에 대한 내용을 추가한 것이 VGMissioinTimedCombat이기에 당연하다면 당연한 상황이었습니다. VGMissioinTimedCombat이 VGMissionCombat을 상속하게 하여 중복되는 코드를 대거 제거했습니다.
조건식을 좀 더 효율적으로 수정하고, 오탈자 및 과한 수치들을 조정했습니다.
오후에는 반격하는 Sandbag을 구현하기 위해 BP에서 작업을 진행했습니다. 그러나 오후는 물론 저녁에도 시간을 쏟았음에도 구현하는데 실패하고 말았습니다.
서버에서의 동작과 클라이언트에서의 동작을 올바르게 분리하지 못한 것 같습니다. 둘 모두에서 동작해야 하거나 클라이언트에서 동작해야하는 로직이 서버에서만 동작하는 것인지, 클라이언트에서는 반격 시의 동작이 제대로 동작하지 못했습니다. 서버 축에서도 로그의 출력이 되질 않았고요.
결국 익숙하지 않은 BP에서의 작업을 포기하고 C++에서의 구현을 하기로 결정했습니다.
처음에는 무식하게 반복문을 4개 사용했습니다. 이후 while과 direction vector를 사용해서 코드를 더 보기 좋게 변경했습니다.
while 문 안에서 한 줄이 끝났는 지를 판별하는 부분에서 curQuery[0], curQuery[1]을 하는 게 아니라 0을 사용하는 바람에 오답이 나오고 있던 것을 뒤늦게 수정했습니다.
#include <string>
#include <vector>
#include <cmath>
using namespace std;
vector<int> solution(int rows, int columns, vector<vector<int>> queries) {
vector<int> answer;
vector<vector<int>> maps(rows,vector<int>(columns));
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
maps[i][j] = i*columns + (j + 1);
}
}
vector<pair<int,int>> direction = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
for(int i = 0; i < queries.size(); i++)
{
vector<int> curQuery = queries[i];
int row = curQuery[0] - 1;
int col = curQuery[1] - 1;
int prevValue = maps[row][col];
int minValue = prevValue;
int index = 0;
while(index < 4)
{
int newRow = row + direction[index].first;
int newCol = col + direction[index].second;
if(newRow < curQuery[0] - 1 || newCol < curQuery[1] - 1 ||
newRow >= curQuery[2] || newCol >= curQuery[3])
{
index++;
continue;
}
int temp = maps[newRow][newCol];
maps[newRow][newCol] = prevValue;
prevValue = temp;
if(minValue > prevValue)
{
minValue = prevValue;
}
row = newRow;
col = newCol;
}
answer.push_back(minValue);
}
return answer;
}