
1.의사
- 조종사 발견 후, 탈 것을 통해 옮기기
- 조종사 정밀 검사 진행
- 조종사 치료
- 조종사에게 약 투여 후, 2층으로 이동
2.생화학자
- 모니터 UI 상호작용
- 화이트 보드, 메모 힌트 활용
- 액화 장치, 혼합기, 설명서
- 로켓 연료
3.기계공학자
- 모니터와 메모, 방 내부 힌트
4.전기공학자
- 제어 패널 전선 연결
- 2층 계단 내리기
- 계단에 놓인 장애물 파괴하기
5.협동 퀘스트
- 물 처리 시스템 수리하기
- 파이프 연결
- 비상식량 가져오기
- 탈출정 타고 탈출하기
1. 의사
- 조종사 발견 후, 탈 것을 통해 옮기기
- 조종사 정밀 검사 진행
- 조종사 치료
- 조종사에게 약 투여 후, 2층으로 이동
일단 Meta Space는 크게 5가지의 직업이 있다. 직업에 해당해서 각자 해결해야하는 퀘스트들이 주어지게 된다. 필자는 의사라는 직업을 구현하게 되었고, 퀘스트를 해결해야하는 방은 대부분 의무실 안이었다.
일단, 해당 게임의 대략적인 스토리가, 우주선에 소행성이 충돌해 살아남은 사람이 탈출정을 찾아서 대피하는 스토리인데, 여기서 의사는 탈출정의 정보를 주는 사람을 치료해주는 역할로 상정하고 시작하였다.
해당 기능을 구현하면서 제일 힘들었던 점은....수술 같은 장면을 구현할 때, 사전지식이 너무 부족하여 사실적인 구현을 하기가 너무 힘들었다는 점이다. 사실상 이런 스토리가 있는 주제를 개발할때 해당 스토리에 대한 탄탄한 이해를 위해 자문이나, 충분한 사전 조사를 행하고 진행했어야했지만 개발 과정에서 마감기한이 임박해 충분한 자문이나 사전조사를 하기 힘들었고, 조금 아쉽게 구현이 되었다..




void Update()
{
if (IsWheelchairNearby() && playerNearby && !isSittingInWheelchair)
{
sitWheelChairBtn.gameObject.SetActive(true);
}
else
{
sitWheelChairBtn.gameObject.SetActive(false);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject == player)
{
playerNearby = true;
Debug.Log("Player nearby");
}
}
}
private void sitWheelChairBtnClick()
{
if (wheelchair != null && IsWheelchairNearby())
{
SitInWheelchair();
}
}
private bool IsWheelchairNearby()
{
float distance = Vector3.Distance(transform.position, wheelchair.transform.position);
return distance <= interactionDistance;
}
public void SitInWheelchair()
{
transform.position = sitArea.position;
transform.rotation = sitArea.rotation;
transform.SetParent(wheelchair.transform);
isSittingInWheelchair = true;
npcAnimator.SetBool("Laying", false);
sitWheelChairBtn.gameObject.SetActive(false);
Debug.Log("NPC is now in the wheelchair.");
}


public void EnterInteraction()
{
// 상호작용 위치로 이동
mainCamera.transform.position = screenViewTransform.position;
mainCamera.transform.rotation = screenViewTransform.rotation;
// 카메라가 모니터를 바라보게 함
mainCamera.transform.LookAt(screenViewTransform);
LockCameraControl();
screenUIManager.ShowScreenUI(); // UI 활성화
otherCanvas.SetActive(false); // 다른 캔버스 숨기기
interactionPrompt.SetActive(false); // 텍스트 비활성화
isInteracting = true;
Debug.Log("상호작용 시작");
}


위의 NPC 애니메이션에서 이미 구현했지만, 휠체어를 플레이어가 끌면서 가는 것을 구현하기 위해서 여러 가지 고민을 하다가, 휠체어를 isInteracting 상태를 통해 상태를 구분해서 isInteracting 부모를 플레이어로 하여서, 적당한 힘을 줘서 자연스럽게 끄는것 같이 구현하였다.
휠체어 위치와 회전 정렬
상호작용이 시작되면 휠체어의 방향이 플레이어의 방향과 일치하도록 설정된다.
wheelchair.transform.rotation = player.transform.rotation
이를 통해 휠체어가 플레이어와 같은 방향을 바라보게 되어 시각적으로 자연스러운 상호작용이 된다.
또한 휠체어의 위치는 플레이어의 앞쪽에 배치되며
Vector3 newPosition = player.transform.position + player.transform.forward * offsetZ
휠체어의 y축 위치는 유지하여 휠체어가 공중에 뜨지 않도록 한다.
휠체어의 물리 설정
wheelchairRigidbody는 기본적으로 isKinematic = true로 설정되어 물리 계산에 영향을 받지 않도록 한다.
이는 휠체어가 상호작용 중에 물리적인 상호작용을 하지 않고 오직 플레이어의 움직임에 따라 이동하게 만들게 구현한것이다.
플레이어 이동과 휠체어 동기화
상호작용이 활성화되면, 플레이어의 입력에 따라 휠체어가 플레이어와 함께 움직이도록 설정하였다. Update() 메서드에서 플레이어의 입력(가로, 세로 축에 대한)을 받아 휠체어와 플레이어가 함께 움직인다.
movement.y = 0;을 통해 휠체어가 수직 방향으로 움직이는 것을 방지하여 수평 이동만 가능하도록 구현하였다.
수술 장면 같은 경우, operating 기계에 환자를 눕힌 후, 해당 모니터에 환자의 머리를 바라보는 카메라 뷰로 구현을 하고자 하였다.

이를 위해 로봇 치료실에서 수술 장면을 촬영할 카메라를 하나 두고, Render Texture를 생성하여 카메라의 Target Texture을 해당 텍스처로 설정한 뒤 material의 Shader를 Unlit/Texture 로 설정하여 해당 texture를 메인 텍스처로 두어 수술 장면을 라이브로 볼 수 있는 모니터를 구현하였다.


[ VR게임 ]
[ PC - 멀티 버전 ]
우리는 이 두가지 중에 HostMode로 구현하였고, 동기화를 위해서 Networked Object로 객체를 관리하며, 상태 동기화를 위해 State Authority를 사용하였다. 또, 물리 상호작용의 동기화는 Networked RigidBody를 통해 구현하였으며, 호스트가 물리 계산을 담당했다.
Networked Rigidbody 3D와 동기화 문제
Networked Rigidbody 3D를 사용하면 Fusion Runner가 물리 시뮬레이션과 관련된 처리(ex. 위치, 속도)를 자동으로 생성하게 된다. 그러나 중요한 점은 기본 설정으로 클라이언트 동기화가 비활성화되어 있다는 점이다.. Networked Rigidbody 3D를 씬에서 사용하니 Runner에서 Default로 클라이언트 시뮬레이션과 관련된 설정이 생성되어있었으며,

이렇게, Client Physics Simulation 값이 Disabled로 설정되어있다.. 이거 때문에 되던 client 동기화가 아무것도 안돼서 며칠간 고통 받았지만 다른 분들은 참고해서 수정하시길 바라는 마음에 업로드합니다..

이렇게, Simulate Always로 설정해주었다.
onTriggerEnter 이슈 (2번 실행되는 문제)
그렇게, 장장 3개월동안
등등 여러가지 도전을 해보았던 프로젝트였다. 아쉬운 점도 많았지만, 이 프로젝트를 통해 많은 공부가 되었다. 다음 프로젝트는 꼭 좋은 결과를 내보고 싶다..!
끝...!