머리가 한없이 뒤로 돌아서 몸을 뚫고 나간다면 생물이라고 볼 수 없을 것이다.
그래서 종속되는 신체가 머리의 특정한 z축 각도의 범위 안에 존재하도록 제한해주어야 한다.
간단히 그림으로 풀어보면 아래와 같다.
몸통이 머리의 후방 지정 각도 내에 존재해야 하고 그 범위를 벗어나지 않아야 한다.
우선 자식(타겟)이 월드 상에서 부모 z축의 어느 각도에 존재하는지 구한다.
// 부모에 대한 자식의 방향 구하기
Vector3 direction = target.position - transform.position;
// 부모위치에 대한 자식의 z축 회전 값
float targetAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
if (targetAngle < 0)
targetAngle += 360;
그리고 부모가 z축이 얼마나 회전했는지 구한다.
float selfAngle = transform.eulerAngles.z; // 내 자신이 회전한 정도(각도)
if (selfAngle < 0)
selfAngle += 360;
[부모 회전 각도] - [자식의 각도]를 해주면 부모의 대한 자식 위치의 상대적인 각도를 구할 수 있다.
예를 들어서 자식이 부모 중심의 45도 위치에 있고, 부모가 45도 회전해있으면 자식의 상대적인 각도는 0도가 된다.
float diffAngle = targetAngle - selfAngle; // 나-타겟 각도 => 상대적인 각
if (diffAngle < 0)
diffAngle += 360;
자식의 상대적인 각도를 원하는 범위 내에 존재하도록 값을 조정해주고,
부모의 회전 값에 더해서 실제로 부모의 중심으로부터 자식이 존재할 각도finalAngle
를 구해준다.
그리고 그 값으로 자식을 위치시킨다.
if (diffAngle < 180 - angleConstraint) diffAngle = 180 - angleConstraint;
if (diffAngle > 180 + angleConstraint) diffAngle = 180 + angleConstraint;
float finalAngle = diffAngle + selfAngle; // 타겟을 위치시킬 각도
Quaternion rotation = Quaternion.Euler(0, 0, finalAngle);
target.position = transform.position + (rotation * Vector3.right) * 1;
위 코드로 머리-몸통 한 개 만 연결했을 때는 정말 잘 됐다.
그런데 몸통을 10개씩 만들었을 때는 두 번째 몸통부터는 뻣뻣한 모습을 보였다.
모든 자식들은 부모를 쳐다보아야 내가 생각했던 움직임이 나온다는 것을 깨달았고 적용하였다.
Vector3 targetToMe = transform.position - target.position;
float targetToMeAlngle = Mathf.Atan2(targetToMe.y, targetToMe.x) * Mathf.Rad2Deg;
target.rotation = Quaternion.Euler(0, 0, targetToMeAlngle);
public class DegreeTest : MonoBehaviour
{
public Transform target;
public float angleConstraint = 30; // 제한할 각도의 절반 크기
void Update()
{
if(target != null)
{
// 타겟이 내 z축 어느 각도에 있는지 출력
Vector3 direction = target.position - transform.position; // 방향 구하기
float targetAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; // 나의 z를 축으로 타겟의 z 각도
if (targetAngle < 0)
targetAngle += 360;
float selfAngle = transform.eulerAngles.z; // 내 자신이 회전한 정도(각도)
if (selfAngle < 0)
selfAngle += 360;
float diffAngle = targetAngle - selfAngle; // 나-타겟 각도 => 상대적인 각
if (diffAngle < 0)
diffAngle += 360;
if (diffAngle < 180 - angleConstraint) diffAngle = 180 - angleConstraint;
if (diffAngle > 180 + angleConstraint) diffAngle = 180 + angleConstraint;
float finalAngle = diffAngle + selfAngle; // 타겟을 위치시킬 각도
Quaternion rotation = Quaternion.Euler(0, 0, finalAngle);
target.position = transform.position + (rotation * Vector3.right) * 1;
// 타겟이 나 바라보게
Vector3 targetToMe = transform.position - target.position;
float targetToMeAlngle = Mathf.Atan2(targetToMe.y, targetToMe.x) * Mathf.Rad2Deg;
target.rotation = Quaternion.Euler(0, 0, targetToMeAlngle);
Debug.Log("내 회전 각도: " + selfAngle + " 내 중심에 대한 타겟의 각도: " + targetAngle + "내 방향에 따른 타겟의 각도 :" + diffAngle);
}
}
}
이런 것들을 할 때마다 수학이 발목을 잡는다.
삼각함수의 이론은 알아도 적용하는 것은 또 차원이 다르다는 것을 항상 느낀다.