움직이는 발판을 타고 플레이어가 이동하는 기믹을 만들고자 했다.
움직이는 발판(Dotween 사용)
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FloatingPath : MonoBehaviour
{
public Ease ease;
public Transform waypoint1;
public Transform waypoint2;
public Transform waypoint3;
private Vector3[] wayPoints;
private void Start()
{
DOTween.Init(false, true, LogBehaviour.ErrorsOnly);
wayPoints = new Vector3[4];
wayPoints.SetValue(waypoint1.position, 0);
wayPoints.SetValue(waypoint2.position, 1);
wayPoints.SetValue(waypoint3.position, 2);
wayPoints.SetValue(transform.position, 3);
transform.DOPath(wayPoints, 6.0f, PathType.Linear).SetEase(ease).SetLoops(-1, LoopType.Restart);
}
}
특정 좌표를 빙글빙글 돌도록 만들었다.
그런데 이때 문제가 생겼는데 플레이어가 발판 위에 고정이 안되는 문제였다.
해결 방법을 회의하다 보니 저번 프로젝트 발표회 때 누군가 플레이어를 발판의 자식으로 설정해서 해결한 것을 생각했다.
플레이어를 발판의 자식으로 두면 플레이어의 이동좌표 + 발판의 이동좌표가 알아서 진행될 것이였다.
따라서 플레이어를 발판의 자식으로 넣는 코드를 생각해냈다.
플레이어의 부모 설정 코드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CheckPlate : MonoBehaviour
{
bool _isPlate;
private void Update()
{
CheckUnderPlate();
}
private void OnDrawGizmos()
{
DrawCheckVolume();
}
private void DrawCheckVolume()
{
_isPlate = Physics.BoxCast(transform.position, transform.lossyScale / 2.0f, Vector3.down, out RaycastHit hit,
Quaternion.identity, 2f, LayerMask.GetMask("Ground"), QueryTriggerInteraction.Ignore);
if (_isPlate)
{
Gizmos.DrawRay(transform.position, Vector3.down * hit.distance);
// Hit된 지점에 박스를 그려준다.
Gizmos.DrawWireCube(transform.position + Vector3.down * hit.distance, transform.lossyScale);
}
else
{
Gizmos.DrawRay(transform.position, Vector3.down * 2f);
}
}
private void CheckUnderPlate()
{
_isPlate = Physics.BoxCast(transform.position, transform.lossyScale / 2.0f, Vector3.down, out RaycastHit hit,
Quaternion.identity, 2f, LayerMask.GetMask("Ground"), QueryTriggerInteraction.Ignore);
if (_isPlate)
{
//부모로 설정
transform.SetParent(hit.transform);
}
else
{
transform.SetParent(null);
}
}
}
발견한 문제점
이렇게 코드를 짜고 실행했더니 플레이어가 발판 위에 얌전히 있는 경우가 있었지만, 어떤 경우에는 발판의 움직임을 따라가지 못해 점점 미끄러지는 문제가 발생했다.
따로 코드나 인스펙터 창의 값들을 수정하지 않았음에도 되는 경우가 있고 안되는 경우가 있었다.
해결시도
튜터님과 상의해본 결과 플레이어와 발판 사이에 마찰력을 넣어보는 시도를 했다.
- . Physics Material을 생성하고 마찰력을 10 이상으로 늘렸다.
- 하지만 플레이어와 발판 모두 rigid body가 없기 때문에 작동이 안되는 듯 했다.
- 원래는 시간 조절 때문에 character controller로 구현했지만 이에 대한건 나중에 생각해 보기로 하고 rigid body를 추가했다.
- 하지만 여전히 원하는대로 작동하지 않았다.
특이사항 발견
그러던 중 플레이어 인스펙터창을 켜놓고 실행할 때, 닫았을 때의 차이로 인해 위의 문제가 발생한다는 것을 확인했다.
- 플레이어 인스펙터 창을 열면 플레이어는 얌전히 발판 위에 붙어있다.
- 플레이어 인스펙터 창을 닫으면 플레이어는 발판위에서 밀려났다.
- 플레이어 인스펙터 창의 InputSystem 컴포넌트를 닫으면 발판 위에서 밀려났다.
플레이어의 이동은 Update에서 불러오기 때문에 프레임으로 인한 문제가 아닐까 추측할 수 있었다.
문제해결
발판의 움직임은 Dotween으로 구현, 플레이어의 움직임은 Update문에서 처리하기 때문에 발판과 플레이어 사이의 이동속도 차이가 발생한다고 추측했다.
검색해보니 Dotween에서도 TimeScale에 영향을 받도록 하는 방법이 있었다. 바로 .SetUpdate(true)이다.
그 중에서도 좀 더 조사해보니 4가지 UpdateType이 존재했다.
- Normal
- Late
- Fixed
- Manual
우리는 플레이어의 움직임을 관리할 것이니 물리를 담당할 Fixed 선택했다.
Dotween의 DOPath에 .SetUpdate(UpdateType.Fixed, true) 을 추가하니 정상적으로 잘 작동하는 모습을 볼 수 있었다.
'TIL' 카테고리의 다른 글
2024/01/19 TIL (0) | 2024.01.19 |
---|---|
2024/01/18 TIL (0) | 2024.01.18 |
2024/01/16 TIL (Character Controller TroubleShooting) (0) | 2024.01.17 |
2024/01/15 TIL (0) | 2024.01.15 |
2024/01/12 TIL (0) | 2024.01.13 |