묻공러
[게임 수학] tangent
묻공러
묻지마공부
묻공러
전체
오늘
어제
  • 분류 전체보기 (506) N
    • C (54)
      • [코드조선] C 핵심 (35)
      • [언어본색] C 기초 (19)
    • C++ (72)
      • [루키스] C++ (9)
      • [루키스] 콜백함수 (6)
      • [루키스] STL (8)
      • [루키스] Modern C++ (11)
      • [노코프] C++ (10)
      • [노코프] Tips (16)
      • [일지] C++ (12)
    • C# (12) N
      • [루키스] C# (9) N
      • [루키스] 자료구조 (3) N
      • [루키스] 실전 문법 (0)
    • 자료구조 & 알고리즘 (50)
      • [코드조선] C 자료구조 & 알고리즘 (6)
      • [합격자되기] C++ 코딩테스트 (12)
      • [루키스] C++ 자료구조 & 알고리즘 (32)
    • CS (69)
      • [널널한 개발자] CS 개론 (19)
      • [혼자 공부하는] 컴퓨터 구조 (16)
      • [혼자 공부하는] 운영체제 (18)
      • [널널한 개발자] 네트워크 (16)
    • 게임 그래픽스 (46)
      • [전북대] OpenGL (25)
      • [일지] DirectX (21)
    • 게임 엔진 - 언리얼 (123)
      • [코드조선] 언리얼 (53)
      • [코드조선] 언리얼 데디서버 (8)
      • [일지] 언리얼 (59)
      • [일지] 언리얼 (2) (3)
    • 게임 엔진 - 유니티 (8) N
      • [최적화] 유니티 (4) N
      • [루키스] 유니티 (4) N
    • 게임 서버 (17)
    • 게임 수학 & 물리 (19)
      • 게임 수학 (12)
      • 게임 물리 (7)
    • GIT & GITHUB (4)
    • 영어 (18)
      • [The Outfit] 대본 공부 (11)
      • the others (7)
    • 그 외 (14)
      • In (5)
      • Out (5)
      • Review (4)

인기 글

최근 글

hELLO · Designed By 정상우.
게임 수학 & 물리/게임 수학

[게임 수학] tangent

2023. 10. 16. 07:16

tangent

게임에서

cos sin은 각에 관련된 것이었고
tangent도 마찬가지로 각도와 관련이 있고 기울기가 핵심이다

 

tan θ는 높이/밑변으로 c/b이다

이는 결국 a가 1이라는 가정하에, sin θ / cos θ를 의미한다


우리가 원하는 건 tan θ가 아닌

tan를 뺀 θ 이기 때문에 
arcTan(역삼각함수)을 이용해서 θ 를 구할 수 있다

θ = c/b의 arcTan

 

 

유니티의 Atan()

유니티에서는 역삼각함수로 쉽게 바꿀 수 있는 Atan과 Atan2가 있다

Mathf.Atan(parameter)을 이용하면

길이의 비율을 (y / x)을 인자로 작성하면 된다

 

Mathf.Atan2(parameter 01, parameter 02)을 이용하면

길이의 비율을 (y, x)를 순서대로 인자로 작성하면 된다

 

 

Atan() 예시

적용 사례로는

간단하게 포탑과 플레이어가 있다고 한다면

포탑이 플레이어의 위치를 추적해 그 플레이어에 맞는 각도로 움직이는 것이다

 

위의 사례를 구현하기 위해

먼저 플레이어(빨간 공)가 계속 위아래로 계속 움직이도록

플레이어(빨간 공)에 추가할 sin을 이용한 MoveUpDown 스크립트를 작성하면 아래와 같다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoveUpandDown : MonoBehaviour
{
    [Range(10, 50)]
    public float speed = 10.0f;
    [Range(1, 5)]
    public float scalar = 1.0f;
    public float degree = 0.0f;

    float y = 0.0f;

    // Start is called before the first frame update
    void Start()
    {
        y = transform.position.y;
    }

    // Update is called once per frame
    void Update()
    {
        degree += Time.deltaTime * speed;

        Vector3 direction = new Vector3(transform.localPosition.x, y + Mathf.Sin(Degree2Rad(degree)) * scalar, 0);
        transform.localPosition = direction;
    }

    float Degree2Rad(float degree)
    {
        return degree * Mathf.PI / 180;
    }
}

 

그리고 포탑이 플레이어의 위치에 따라

각도를 계산하여 그 방향으로 회전을 하도록(바라보도록) 하는 TargetRotate 스크립트는 아래와 같이 작성할 수 있다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TargetRotate : MonoBehaviour
{
    public Transform Target;
    public Transform Root;
    public Transform Shot;

    private float degree;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Target != null)
        {
            float x = Target.position.x - Root.position.x;
            float y = Target.position.y - Root.position.y;
            float tan = y / x;

            float radianTan = Mathf.Atan(tan);
            degree = Rad2Degree(radianTan);

            Root.localRotation = Quaternion.Euler(0, 0, degree);
        }
    }

    float Rad2Degree(float rad)
    {
        return rad * 180 / Mathf.PI;
    }
}

 

이에 따른 결과물은 아래와 같다

 

 

이제 포탑에서 총이 발사되도록 구현하려면

기존의 TargetRotate 스크립트를 변형하여 TargetRotateByShot 스크립트 만들면 된다

CreateShot 함수를 호출해 총알을 발사하게끔 아래와 같이 작성 가능하다

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TargetRotateByShot : MonoBehaviour
{
    public Transform Target;
    public Transform Root;
    public GameObject Shot;

    private float degree;

    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("CreateShot", 1.0f, 1.0f);
    }

    // Update is called once per frame
    void Update()
    {
        if (Target != null)
        {
            float x = Target.position.x - Root.position.x;
            float y = Target.position.y - Root.position.y;
            float tan = y / x;

            float radianTan = Mathf.Atan(tan);
            degree = Rad2Degree(radianTan);

            Root.localRotation = Quaternion.Euler(0, 0, degree);
        }
    }

    float Rad2Degree(float rad)
    {
        return rad * 180 / Mathf.PI;
    }

    private void CreateShot()
    {
        if(Shot != null)
        {
            GameObject obj = Instantiate<GameObject>(Shot, Root.position, Quaternion.identity);
            ShotMove shotMove = obj.GetComponent<ShotMove>();

            if (transform.localPosition.x > 0)
                degree += 180;

            shotMove.SetDegree(degree);

            Destroy(obj, 20.0f);
        }
    }
}

 

이처럼

sin의 성질을 활용한 빨간 공과

각도를 찾아낼 수 있는 tangent의 성질을 활용하여

Root를 기준으로 플레이어와의 각도를 알아내서

그 각도로 회전하며 총알이 발사되는 아래와 같은 결과물을 만들 수 있다

저작자표시 비영리 변경금지 (새창열림)

'게임 수학 & 물리 > 게임 수학' 카테고리의 다른 글

[게임 수학] 벡터의 기초 (2)  (0) 2023.10.17
[게임 수학] 벡터의 기초 (1)  (0) 2023.10.17
[게임 수학] sin, cos (2)  (0) 2023.10.16
[게임 수학] sin, cos (1)  (0) 2023.10.16
[게임 수학] 피타고라스의 정리  (0) 2023.10.15
'게임 수학 & 물리/게임 수학' 카테고리의 다른 글
  • [게임 수학] 벡터의 기초 (2)
  • [게임 수학] 벡터의 기초 (1)
  • [게임 수학] sin, cos (2)
  • [게임 수학] sin, cos (1)
묻공러
묻공러
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.