오늘은 스테이지 구성을 위해 스테이지 필요한? 스테이지가 더 재밌게 굴러가기 위한 요소를 추가해보았다.
생각한 것은 스위치가 되는 곳에 플레이어 혹은 퍼즐이 닿게 되면 발판이 앞으로 움직여 다음 장소로 갈 수 있도록 하는 것이 였다.
그리고 플레이어 혹은 퍼즐이 떨어지면 다시 원래 위치로 발판이 돌아오도록 하였다.
하나 만 있으면 뭔가 머리 쓸 것이 없으니, 두개로 만들어 퍼즐을 몇 개 둘지 해서 다음 장소로 건너가는 것을 생각할 수 있게 했다.
[SerializeField] private GameObject[] movingFloor;
private float moveDistance = 8f;
private float moveSpeed = 8f;
private Vector3 initialPosition0;
private Vector3 targetPosition0;
private Vector3 initialPosition1;
private Vector3 targetPosition1;
private Vector3 secondTargetPosition1; // 두 번째 발판의 추가 목표 위치
private int playerORPuzzleOnCountO = 0; // 플레이어가 밟고 있는 발판의 개수
private Coroutine moveCoroutine;
private void Start()
{
if (movingFloor == null || movingFloor.Length < 2) return;
// 초기 위치 저장 및 목표 지점 저장
initialPosition0 = movingFloor[0].transform.position;
targetPosition0 = initialPosition0 + Vector3.forward * moveDistance;
initialPosition1 = movingFloor[1].transform.position;
targetPosition1 = initialPosition1 + Vector3.forward * moveDistance;
secondTargetPosition1 = targetPosition1 + Vector3.forward * moveDistance;
}
위치 스크립트이다. 앞으로 움직일 발판은 총 두개이니 배열로 받고 움직일 거리, 스피드를 변수로 받아주었다.
그리고 처음 위치를 저장하기 위해 첫 번째, 두 번째 발판의 위치를 시작할 때 저장해주고, 목적지 위치도 현재위치에서 목표거리를 더해준 값으로 저장해주었다. 두 번째 발판은 여기서 한 번 더 가야하니 한 번더 같은거리 만큼 더해주도록 초기 세팅을 잡아주었다.
private void OnCollisionEnter(Collision collision)
{
if (IsCollisionWithLayer(collision.gameObject))
{
playerORPuzzleOnCountO++;
StartMove();
Debug.Log(playerORPuzzleOnCountO);
}
}
private void OnCollisionExit(Collision collision)
{
if (IsCollisionWithLayer(collision.gameObject))
{
playerORPuzzleOnCountO--;
StartMove();
}
}
private void StartMove()
{
if (moveCoroutine != null) // 실행중이면 코루틴 종료
{
StopCoroutine(moveCoroutine);
}
if (playerORPuzzleOnCountO == 0)
{
moveCoroutine = StartCoroutine(MoveFloor(initialPosition0, initialPosition1));
}
else if (playerORPuzzleOnCountO == 1)
{
moveCoroutine = StartCoroutine(MoveFloor(targetPosition0, targetPosition1));
}
else if (playerORPuzzleOnCountO == 2)
{
moveCoroutine = StartCoroutine(MoveFloor(targetPosition0, secondTargetPosition1));
}
}
private IEnumerator MoveFloor(Vector3 target0, Vector3 target1)
{
Vector3 startPosition0 = movingFloor[0].transform.position;
Vector3 startPosition1 = movingFloor[1].transform.position;
float moveDistance0 = Vector3.Distance(startPosition0, target0);
float moveDistance1 = Vector3.Distance(startPosition1, target1);
// 이동 거리가 0이면 코루틴 종료
if (moveDistance0 == 0 && moveDistance1 == 0)
{
yield break;
}
float startTime = Time.time;
while (true)
{
// 경과 시간 계산
float elapsedTime = (Time.time - startTime) * moveSpeed;
// 진행 비율 계산 (0~1 사이 값으로 제한)
float progress0 = moveDistance0 > 0 ? Mathf.Clamp01(elapsedTime / moveDistance0) : 1f;
float progress1 = moveDistance1 > 0 ? Mathf.Clamp01(elapsedTime / moveDistance1) : 1f;
// 이동
movingFloor[0].transform.position = Vector3.Lerp(startPosition0, target0, progress0);
movingFloor[1].transform.position = Vector3.Lerp(startPosition1, target1, progress1);
// 두 발판이 목표 지점에 도달했는지 확인
if (progress0 >= 1f && progress1 >= 1f)
{
break;
}
yield return null;
}
// 최종 위치로 보정
movingFloor[0].transform.position = target0;
movingFloor[1].transform.position = target1;
moveCoroutine = null;
}
유니티 이벤트함수 oncollision을 통해 퍼즐 혹은 플레이어가 닿은 갯수를 더하고 빼며 코루틴을 실행시킨다.
사실 업데이트로 처리하면 간편하긴 하지만 계속 돌아간다는것이 신경쓰여, 코루틴으로 이동하도록 하였다.
넘어가서 퍼즐 혹은 플레이어가 닿으면 이미 실행중인 코루틴이 있다면 멈추게 해주고, 상태가 아무것도 닿지 않거나, 1개 닿았거나, 2개까지만 감지하며 되니, if문으로 각각이 도달해야할 초기위치면 초기위치, 목적지면 목적지를 넣어주어 코루틴을 실행한다.
코루틴에서 2개의 발판이 가야할 목적 위치를 받아주면, 현재위치를 시작위치로 캐싱해주고, 타겟위치를 통해 거리를 구해준다.
거리가 0이면 이미 도달한 것이므로 코루틴을 빠져나온다.
이제 조금 복잡해진다. 움직이는 경과 시간을 구해주기 위해 출발하기 시작한 시간을 변수로 만들어주고 와일문에서 현재 시간에서 시작시간을 빼주 뒤 움직임속도를 곱해주어서 얼마나 이동했는지 구해준다. 그리고 삼항 연산자를 통해 이동거리가 0보다 크면 전체 거리 분에 현재까지 이동한 거리를 출력하고 아니면 1를 출력한다.
1이 나오면 다 이동한것이다. 여기는 clamp01을 이용하여 0에서 1까지로 제한을 주었다.
뒤에 나올 lerp에서 사용하기 위함.
그리고 이동을 해준다. 각 발판의 위치를 lerp를 통해 부드럽게 시작위치에서 타켓 위치까지 아까구한 진행 비율로 계산하여준다. 0-1로 제한한 이유도 이거 때문이다. 0-1이 넘어가면 nnn뭐시기 오류가 계속 나기 시작하는데 위에서 방지한 덕분에 해결이다.
그리고 최종위치로 그냥 이동을 해주어야한다.
발판위치를 최종위치로 이유는 lerp를 사용하면 부동소수점 오차가 있어 끝까지 도달하지 못한채로 종료될 수 있어서 임의로 위치를 바꾸어 준것이다. 그래도 자연스럽게 다 도착하고 옮겨주는 거라 큰 문제는 없는 듯 하다.
이렇게 구성요소를 하나 추가 해 보았다. 이후에는 스테이지 위치 잡고 머터리얼과 라이팅 문제를 보며 그림자 문제.. 등 고민해보는 시간을 가졌다. 코드만 봐도 힘든데 그래픽도 넘나 어렵다.. 끝