짧은 설명
- 협업 중 의사소통은 중요하다
- 프레임 워크에서 사용 안하는 파일 제거
- 프로젝트 이름 변경
- 프로젝트 파일명이 쓰여지는 부분 수정
- 바이너리 폴더(bin) 수정
- .vs, gitignore 같은 폴더 또는 파일은 협업할때 삭제를 해줘야한다.
- 다른사람의 설정과 맞지 않을 수 있기 때문이다.
프레임워크 수정
SortingLayers sortingLayer = SortingLayers::Default;
int sortingOrder = 0; //이것을 기준으로 작은 숫자가 먼저 그려질 것이다.
std::list<GameObject*> sortedObjects(gameObjects);
//함수 객체 사용
//DrawOrderComparer -> 임시객체를 만들어서 매개변수로 전달하는 것이다.
sortedObjects.sort(DrawOrderComparer());
/*
//GameObject*인 이유 ; 위의 리스트 데이터형이 GameObject*니까
sortedObjects.sort(
[](const GameObject* a, const GameObject* b)
{
if (a->sortingLayer != b->sortingLayer)
{
return a->sortingLayer < b->sortingLayer;
}
return a->sortingOrder < b->sortingOrder;
}
);
*/
//헤더파일
struct DrawOrderComparer
{
//함수객체 사용
bool operator()(const GameObject* a, const GameObject* b)
{
return a->sortingOrder < b->sortingOrder;
}
};
- 그리기 순서 적용
- 리스트를 레이어, Order 2개를 기준으로 그리려는 것이다.
- 정렬 → 그리기 순서로 진행된다.
- 매 프레임마다 정렬하기 때문에 업데이트 되어서 정렬이 이루어지고 그리기 순서가 바뀌어진다.
void Scene::Draw(sf::RenderWindow& window)
{
~~
for (auto obj : sortedObjects)
{
//활성화 된 오브젝트만 드로우 진행
if (obj->GetActive())
{
obj->Draw(window);
}
}
// 추가할 오브젝트 검사 후 배열에 추가
for (GameObject* go : objectsToAdd)
{
//중복 검사 후 없으면 추가
if (std::find(gameObjects.begin(), gameObjects.end(), go) == gameObjects.end())
{
gameObjects.push_back(go);
}
}
objectsToAdd.clear(); //이걸 안하면 다음 프레임에 또 담고를 반복한다.
// 삭제도 같은 작용
for (GameObject* go : objectsToRemove)
{
gameObjects.remove(go);
}
objectsToRemove.clear();
}
GameObject* Scene::AddGameObject(GameObject* go)
{
objectsToAdd.push_back(go);
return go;
}
void Scene::RemoveGameObject(GameObject* go)
{
go->SetActive(false); //업데이트 되거나 드로우 못하게 비활성화
objectsToRemove.remove(go);
}
- GameObject 지연 추가, 삭제
- 계속 추가를 하게되면 추가중 추가를 하게되니 프로그램이 멈추게 된다.
- update 또는 draw 도중 gameobject를 수정하면 iterator 무효, 중복 처리, 크래시 등의 문제가 발생한다.
- Addlist, Removelist 생성
- Addlist : 루프 도중 추가 요청한 오브젝트 임시 저장
- Removelist : 루프 도중 삭제 요청한 오브젝트 임시 저장
- draw를 마지막에 해야하는 이유 : 그리기가 끝난 후에 안전하게 수정해야하기 때문이다.
- 주의점
- 넣은 다음 한번 비워줘야한다. → 리스트.clear()
- 중복 추가 방지 → std::find(추가 리스트 검사)
- 바로 삭제 금지 → go→SetActive(false) 비활성화로 드로우와 업데이트를 못하게 막아야한다.
//키와 키에 따른 값이다.
static std::unordered_map<Axis, AxisInfo> axisInfoMap;
//축 가져오기
static float GetAxisRaw(Axis axis); //해당 축의 -1 0 1 반환
static float GetAxis(Axis axis); //정해진 시간만큼의 value가 반환되는 함수
축 입력 기능
// 가로축 키 할당
AxisInfo infoH;
infoH.axis = Axis::Horizontal;
infoH.positivies.push_back(sf::Keyboard::Right);
infoH.positivies.push_back(sf::Keyboard::D);
infoH.negativies.push_back(sf::Keyboard::Left);
infoH.negativies.push_back(sf::Keyboard::A);
axisInfoMap.insert({ Axis::Horizontal, infoH });
// 세로축 키 할당
AxisInfo infoV;
infoV.axis = Axis::Vertical;
infoV.positivies.push_back(sf::Keyboard::Down);
infoV.positivies.push_back(sf::Keyboard::S);
infoV.negativies.push_back(sf::Keyboard::Up);
infoV.negativies.push_back(sf::Keyboard::W);
axisInfoMap.insert({ Axis::Vertical, infoV });
- 상하좌우 + 대각선 → 8방향 (탑뷰)
- 축을 입력하고 → float 값 반환
float InputMgr::GetAxisRaw(Axis axis)
{
// held 키에서 뒤쪽에 있는 값을 받아서 값을 넘긴다.
//키를 매개변수로 넘겨서 iterator 데이터형으로 반환
auto findIt = axisInfoMap.find(axis);
if (findIt == axisInfoMap.end()) //키가 없는경우
{
return 0.f;
}
const AxisInfo axisInfo = findIt->second; //축값 저장
//이걸 뒤에서부터 순회해야한다.
auto it = heldKeys.rbegin(); //rbegin() : 역방향 시작 iterator(위치) 반환 함수
while (it != heldKeys.rend()) //역방향 순회
{
sf::Keyboard::Key code = *it; //지금 순회하고있는 iterator의 값
if (Contains(axisInfo.positivies, code)) //키보드의 키가 들어있는지 확인
{
return 1.f;
}
if (Contains(axisInfo.negativies, code)) //키보드의 키가 들어있는지 확인
{
return -1.f;
}
++it;
}
return 0.0f;
}
- 우키 : 1.f , 좌키 : -1.f
- 상키 : -1.f , 하키 : 1.f
sf::Vector2f dir;
dir.x = InputMgr::GetAxisRaw(Axis::Horizontal);
dir.y = InputMgr::GetAxisRaw(Axis::Vertical);
sf::Vector2f pos = testGo->GetPosition();
pos += dir * 100.f * dt;
testGo->SetPosition(pos);
- 시간의 흐름에 따라 값을 증가시켜주면 점진적으로 증가하는 값을 만들 수 있다.
- 함수 2개 : -1 0 1 즞각 변환 함수 , 값이 들어오면 해당 값까지 점진적으로 증가하는 함수
- 히트박스(버튼 누르는 방식)은 2개 동시 입력이 불안정하다.
- 2개 들어오면 2개의 방법중 하나를 쓴다.
- 중립축을 하나 더 만들어서 처리한다.
- 나중에 입력된 값으로 처리한다. (지금은 이거로 처리)
- 아니면, 먼저 들어온 값으로 처리한다.
- 마우스 입력 기능
case sf::Event::MouseButtonPressed:
if (mouseButtonCondition[ev.mouseButton.button] == 0)
{
mouseButtonCondition[ev.mouseButton.button] = 1;
}
else if (mouseButtonCondition[ev.mouseButton.button] == 1)
{
mouseButtonCondition[ev.mouseButton.button] = 2;
}
break;
case sf::Event::MouseButtonReleased:
mouseButtonCondition[ev.mouseButton.button] = 3;
break;
bool InputMgr::Contains(const std::vector<int>& list, sf::Mouse::Button button, int condition)
{
return list[button] == condition;
}
if (InputMgr::GetMouseButtonDown(sf::Mouse::Left))
{
std::cout << InputMgr::GetMousePosition().x << ", " << InputMgr::GetMousePosition().y << std::endl;
}
프레임워크 수정 할 부분
- 업데이트 → draw 순서로 진행된다.
- gameObjects에 담겨진 순서대로 그려지고 있다.
- 숫자로 오름차순으로 정렬해서 작은 숫자 순서대로 그린다.
- 레이어로 그룹을 나눈다.
- 레이어 설정에 따라 그리기 순서가 달라진다.
- 같은 레이어는 숫자 순서에 따라서 그려지는 순서가 달라진다.
- 숫자 순서, 레이어 순서 2개의 멤버가 필요하다.
- Scene Draw 함수 수정
- 게임 오브젝트 별로 레이어, 그리기 순서에 따라 정렬해서 그 순서로 그려야한다.
- 그리기 순회를 돌면서 정렬시킨다.
- 비효율적이니 나중에 선택적으로 고쳐라
sortedObjects.sort();
- 이렇게 하면 원하는대로 동작 안함
- 이유 : 포인터 형으로 정렬되기에 예외가 나던가, 주소값을 기준으로 정렬된다.
- 해결법 : 정렬 기준을 매개변수로 넘길 수 있다. - 3가지 방법
-
- 게임 오브젝트의 함수 기준으로 넘긴다.
-
- 람다식으로 정렬기준을 만드는 경우 -게임 오브젝트 포인터형이 넘어올때 어떤게 더 크다 작다를 비교할 수 이따.
- bool 형을 반환하는 변수 2개를 넘기면 된다.
- a > b로 하면 정수형 기준으로 정렬된다.
bool (a, b)
return a > b -> 멤버의 sortingOrder에 접근
그거에 맞게 정렬이 된다.
//GameObject*인 이유 ; 위의 리스트 데이터형이 GameObject*니까
sortedObjects.sort(
[](const GameObject* a, const GameObject* b)
{
if (a->sortingLayer != b->sortingLayer)
{
return a->sortingLayer < b->sortingLayer;
}
return a->sortingOrder < b->sortingOrder;
}
);
- sort 함수로 멤버 변수를 받는 변수를 bool 형으로 받을 수 있도록 반환받는다.
- bool 형이 반환되게 된다.
- 둘 중 누가 더 큰지 확인하고, 더 작은 수를 먼저 그리기 위해 사용한다.
- 편하긴한데 조금 어렵다.
- 함수 객체 사용
// 헤더 파일
struct DrawOrderComparer
{
bool operator()(const GameObject* a, const GameObject* b)
{
return a->sortingOrder < b->sortingOrder;
}
};
//함수 객체 사용
//DrawOrderComparer -> 임시객체를 만들어서 매개변수로 전달하는 것이다.
sortedObjects.sort(DrawOrderComparer());
- 값을 비교해서 true false를 반환한다.
- 솔트는 최적화가 필요하니 각자 공부해서 최적화를 적용시켜야한다.
AddGameObject 수정
수정 부분
- push_back의 지연이 필요하다.
- Framework에서 씬매니저의 업데이트를 호출할때 저장과 삭제를 담아놨다가, 프레임이 끝났을 때 넣거나 뺴야한다.
- 삭제 리스트, 추가 리스트를 만들어서 정리해야한다.
그리기 순서 정리
비주얼 스튜디오 깃허브 레포지토리 생성
- 보기
- git 변경 내용
- 레포지토리 만들기 가능
rbegin
- 역방향 위치 반환 함수다.
- ++를 하면 역방향으로 증가하게 된다.
- begin이 나오면 정지하게 된다.