// enum 변환 방법
itemType = (변환할 Enum)Enum.Parse(typeof(변환할 Enum), 문자열);
// ex
ItemType itemType = (ItemType)Enum.Parse(typeof(ItemType), values[인덱스]);
// 숫자 변환 방법
//숫자 변환:
int.Parse(values[인덱스];
float.Parse(values[인덱스])
유니티 코루틴 공식문서에서 : 하지만 코루틴은 스레드가 아니라는 점을 명심해야 합니다. 코루틴의 동기 작업은 여전히 메인 스레드에서 실행됩니다. 메인 스레드에 소요되는 CPU 시간을 줄이려면 다른 스크립트 코드에서와 마찬가지로 코루틴의 작업 차단을 방지하는 것이 중요합니다. Unity 내에서 다중 스레드 코드를 사용하려면 C# 잡 시스템 을 고려하십시오.
코루틴은 "동기적(synchronous)"이면서도 "비동기적인 실행 패턴"을 제공하는 특별한 케이스 이다.
일단. IK가 무엇인지 알아야 한다. 유니티 공식문서에 따르면 , 대부분의 애니메이션은 스켈레톤의 조인트 각도를 미리 정해진 값으로 회전하여 만든다. 자식 뼈대 (조인트)는 부모 뼈대 (조인트)의 회전에 따라 변하고, 이런 방식을 순 운동학 (FK)라고 한다.
하지만 이런 방법을 반대로 바라본다면 더욱 유용하다. 오브젝트를 기준으로 뼈대 (조인트) 값을 계산하여 적용하는 것이다. 예를 들어 플레이어가 다른 오브젝트를 건드리거나, 울퉁불퉁한 표면 위에 캐릭터의 두 발이 자연스럽게 밀착해 있도록 할 수 있다. 이러한 접근법을 역운동학 (IK)라고 한다.
유니티 공식문서에 있는 IK 관련 이미지
IK를 적용하기 위해서는 아바타의 타입이 휴머노이드여야 한다.
📝사전준비
1. 플레이어의 Animator의 Layer의 설정에서 IK Pass 옵션을 체크해준다
2. 플레이어가 걸어갈 발판/경사로 등의 레이어를 Walkable로 지정해 준다
📝구현
PlayerAnimator.cs
public class PlayerAnimator : MonoBehaviour
{
[Header("===Animator===")]
[SerializeField] private Animator animator;
[Range(0, 1f)]
public float distanceToGround;
public LayerMask layerMask;
void Start()
{
animator = GetComponent<Animator>();
}
private void OnAnimatorIK(int layerIndex)
{
}
}
■ 공식문서에서는, IK 목표의 변환 가중치를 설정한다. ( 0 = IK전 원래 애니메이션에서 1 = 목표에서 )
■ 즉 가중치를 설정하여 원래 애니메이션과 , IK 조정 사이의 혼합정도를 결정한다.
□animator.SetIKRotationWeight()
■ SetIKPositionWeight과 같이 회전에 대한 가중치를 설정한다.
🔖 가중치 가중치가 0일 때 : 원래 애니메이션이 100% 적용된다. IK는 전혀 영향을 주지 않는다 가중치가 1일 때 : 조정이 100% 적용된다. 원래 애니메이션은 무시된다 가중치가 0 ~ 1 사이일 때 : 원래 애니메이션과 IK 조정값이 해당 비율로 혼합된다
🔖 여기서 AvaterIkGoal은 Enum으로, LeftFoot과 RightFoot은 Animator에 적용된 아바타의 Left Leg의 Foot과 , Right Leg의 Foot를 의미한다.
// left foot
RaycastHit hit;
Ray ray = new Ray(animator.GetIKPosition(AvatarIKGoal.LeftFoot) + Vector3.up, Vector3.down);
Debug.DrawRay(ray.origin, ray.direction * (distanceToGround + 1f), Color.red);
□ Ray 생성
■ 시작지점 : 아바타의 LeftFoot의 위치에서 1f 올라간 곳,
■ 방향 : 시작지점에서 아래쪽 방향
□ DrawRay로 레이를 그리면, 주황색 동그라미에서 시작하여 아래쪽으로 ray를 쏘고 있는 것을 확인할 수 있다.
if (Physics.Raycast(ray, out hit, distanceToGround + 1f , LayerManager.Instance.IgnorePlayerLayer))
{
if(hit.transform.gameObject.layer == LayerManager.Instance.WalkableLayerInt)
{
// 추가예정
// 플레이어 발 위치 , 회전 적용
}
}
□ Raycast
■플레이어를 제외한 오브젝트를 감지해야 하기 때문에 PlayerLayer을 제외한 레이어만 검사
■ 레이캐스트가 성공적으로 충돌체를 감지하면 , if문 실행
□ 해당 충돌체의 레이어가 'Walkable'이면?
■플레이어 발의 위치와 회전을 변경
(+) 레이어에 관해서
layer을 검사할 땐 layerMask의 인덱스 값으로 검사해야 하기 때문에 GetMask를 사용해 준다
해당코드는 어디에 있던지 상관없다
[SerializeField] private LayerMask ignorePlayerLayer; // 플레이어 레이어를 제외한 레이어
[SerializeField] private int walkableLayerInt;
void Start()
{
walkableLayerInt = LayerMask.NameToLayer("Walkable");
}
PlayerLayer을 뺀 LayerMask 정보는 인스펙터 창에서 PlayerLayer을 제외한 다른 레이어들을 체크해주면 된다.