//구글콘솔 광고 추가가

1. ui 부모 객체에 Grapic RayCast 컴포넌트 추가

2. 버튼위에서 다른 무언가로 버튼을 가려진게 없는지 확인

3. 씬안에 이벤트 시스템이 없는 지 확인

728x90

Layer Mask 와 Layer Tag 둘다 유니티에서 추가 해서 사용할 수 있다.


Tag : 각 게임 오브젝트를 구분하는 용도로 사용. OnCollision 과 OnTrigger에서 tag를 이용해 충돌한 오브젝트를 검사할수 있다.

Layer : 충돌 체크를 할수 있다. 또한 카메라 컴포넌트에서 컬링 마스크를 설정하기 위한 용도로 사용될수 있다.


int layerMask = (1 << 레이어 번호);   ex >> int layerMask = (1 << 8);

LayerMask layerMask = LayerMask.GetMask("레이어 이름");  

int layerMask = (1 << 레이어 번호) | (1 << 레이어 번호);

LayerMask layerMask = LayerMask.GetMask("레이어 이름") | LayerMask.GetMask("레이어 이름"); 

  •  | 를 사용하여 또는 이라는 의미로 레이어를 추가 할 수 있음

if (Input.GetMouseButtonDown(0)) //왼쪽 마우스 클릭시
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            Debug.DrawRay(Camera.main.transform.position, ray.direction * 100f, Color.red, 1.0f);

            LayerMask layerMask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall");

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f , layerMask))
            {
                Debug.Log($"Raycast Camera : {hit.collider.gameObject.name}");
            }
        }

 

728x90

   // transform.position = 좌표를 변환할때 씀

   // 방향을 가지고 연산을 할때는 transform.TransformDirection() 사용. >> 로컬에서 월드로 변환
  Vector3 look = transform.TransformDirection(Vector3.forward); // 플레이어가 바라보고 있는 방향을 월드로 표현한 벡터.
  Debug.DrawRay(transform.position + Vector3.up, look * 10 ,Color.green); // screen에서 플레이어 레이케스트 그려주기.


< 두가지의 레이케스트 구현 >
        1. 모든애들을 관통하는 레이케스트
        RaycastHit[] hits;
        hits = Physics.RaycastAll(transform.position + Vector3.up, look * 10, 10);
        foreach (RaycastHit _hit in hits)
        {
            Debug.Log($"Raycast : {_hit.collider.gameObject.name} !");
        }

        2. 하나만 타겟팅하는 레이케스트
        RaycastHit hit;
        if (Physics.Raycast(transform.position + Vector3.up , transform.forward * 10, out hit, 10))
        {
            Debug.Log($"Raycast : {hit.collider.gameObject.name} !");
        }


       if (Input.GetMouseButtonDown(0)) //왼쪽 마우스 클릭시
        {
           //클릭한 좌표의 월드좌표를 구하자 //레이가 쏴지는 과정
            Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane)); //마우스의 월드포지션
            Vector3 dir = mousePos - Camera.main.transform.position; //카메라 위치에서 화면까지 가는 방향벡터.
            dir = dir.normalized; //크기를 강제로 1로 해줘서 방향은 똑같지만 크기는 1로 만들어 둔다.


            //  dir * 100f >> Debug.DrawRay( , 방향 * 거리)를 넣어줘야 하니까 레이케스트에서 max 거리해준 만큼 곱하자
            Debug.DrawRay(Camera.main.transform.position, dir * 100f, Color.red, 1.0f);
         

            if (Physics.Raycast(Camera.main.transform.position, dir, out hit, 100.0f))  // 값이 true 일경우 무언가 충돌한거지
            {
                Debug.Log($"Raycast Camera : {hit.collider.gameObject.name}");
            }
        }


   < 마우스 좌표 확인 >

        // 최종적으로 화면안에 나오게 하려면 
        // Local <-> World <-> Viewport <-> Screen (2D 화면) Viewport 와 Screen 는 거의 비슷

       

        // Input.mousePosition >> 현재 마우스 좌표를 픽셀 좌표로 뽑아온다.
        Debug.Log(Input.mousePosition); // screen 좌표 출력(픽셀좌표가 곧 screen) 

 

        // Viewport 좌표 출력(픽셀과 상관없이 화면 비율의 좌표)
        Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); 
       


< 이미 유니티에 만들어 져있는 Ray를 이용해서 깔끔하게 작업하기 >

if (Input.GetMouseButtonDown(0)) //왼쪽 마우스 클릭시
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            Debug.DrawRay(Camera.main.transform.position, ray.direction * 100f, Color.red, 1.0f);

            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 100f))
            {
                Debug.Log($"Raycast Camera : {hit.collider.gameObject.name}");
            }       
        }


 

728x90

< RigidBody >

게임 오브젝트가 물리제어로 동작하게 한다. (중력의 영향을 받을수 있고 충돌체크를 할수있다.)

프로퍼티 : 

  • Mass : 오브젝트의 질량. ( 디폴트값은 킬로그램 )
  • Drag : 오브젝트가 힘에 의해 움직일 때, 공기저항의 영향을 미치는 정도. (0이면 공기저항 X, 무한대라면 오브젝트 즉시 정지)
  • Angular Drag : 오브젝트가 토크로 회전할 때 공기저항이 영향을 미치는 정도. (0이면 공기저항 X, 무한대라 하더라도 오브젝트의 회전이 멈추지 않음)
  • Use Gravity : 오브젝트가 중력의 영향을 받게 할지 안할지 체크.
  • Is Kinematic : 체크시 물리 시스템 무효(충돌체크 혹은 트리거 체크를 확인 하려면 체크 해제)
  • Freeze Position : 월드좌표계의 x, y, z축에서 이동하는 리지드바디를 선택적으로 중지.
  • Freeze Rotation : 로컬좌표계의 x, y, z축에서 회전하는 리지드바디를 선택적으로 중지

< Collision >

  1. 충돌 체크를 하기위해 사용하며, 충돌체크를 확인 하려면 오브젝트안에 RigidBody 컴포넌트가 붙어있어야 한다. (isKinematic은 체크 해제)
  2. 체크할 오브젝트들 안에 Collider 컴포넌트가 붙어있어야 한다.(isTrigger 체크를 해제 해줘야 Collision 확인 가능)

Collision 사용 예시 : 

- 플레이어와 충돌되는 모든 오브젝트 확인 ( 건물, 몬스터 등)

- 몬스터에게 닿는 플레이어의 피격 오브젝트 (총알 등)


< Trigger >

  1. 물리와 전혀 상관없이 범위안에 들어왔는지를 확인하기 위해 사용하며, 체크할 오브젝트들 안에 Collider 컴포넌트가 붙어있어야 한다.
  2. 체크할 오브젝트들 중 하나에는 isTrigger 체크가 되어있어야 하며, RigidBody 컴포넌트가 붙어있어야 한다.

Trigger 사용 예시 :

- 플레이어의 스킬 관련(무기나, 스킬에 Trigger를 붙여 체크)

- 플레이어의 이동 관련 (순간이동 위치, 씬 이동 등)

728x90

public class ResourceManager 
{
    public T Load<T>(string path) where T: Object
    {
        return Resources.Load<T>(path);
    }

    public GameObject Instantiate(string path, Transform parent = null)
    {
        GameObject prefab = Load<GameObject>($"Prefabs/{path}");
        if(prefab == null)
        {
            Debug.Log($"Failed to load Prefab : {path}");
            return null;
        }

        return Object.Instantiate(prefab, parent); 

    }

    public void Destroy(GameObject go)
    {
        if(go == null)
            return;

        Object.Destroy(go);
    }
}


return Object.Instantiate(prefab, parent); 

< Object를 붙여준 이유 >

안붙이면 ResourceManager클래스에있는 Instatiate()를 재귀적으로 호출하려 할테니 Object에 있는 instantiate()를 하세요라고 명시를 해준 것.


public class GameManagers : MonoBehaviour
{

    ResourceManager _resource = new ResourceManager();
    public static ResourceManager Resource { get { return Instance._resource; } }

}


게임매니저 클래스에서 ResourceManager 를 만들어 주고


public class PrefabTest : MonoBehaviour
{

    GameObject prefab;

    GameObject item;

 

    private void Start() 

    {

         item = GameManager.Resource.Instantiate("Item");      // 유니티에서 프리팹으로 만들어 둔 Item 생성

         GameManager.Resource.Destroy(item);                         // 제거

    }

}


프리팹사용을 원하는 클래스에서 GameManager를 통해 생성 가능


 

728x90

 


public class InputManager
    {
        public Action KeyAction = null;

        public void OnUpdate()
        {
            if (Input.anyKey == false)
            {
                return;
            }
            if(KeyAction != null)
            {
                KeyAction.Invoke();
            }
        }
    }


input 클래스에서는 플레이어의 키입력을 체크해서 키입력이 되었을 때 다른 클래스에 키입력을 받았다는 것을 알려준다.


public class GameManager : MonoBehaviour
{
    private static GameManager s_instance = null;
    public static GameManager instance { get { return s_instance; } }

    InputManager _input = new InputManager();
    public static InputManager Input { get { return instance._input; } }

    private void Update()
    {
        _input.OnUpdate();
    }

}


GameManager 클래스에선 MonoBehaviour를 상속 받지 않은 inputManager를 새롭게 할당해서 객체를 만들어주고,

Update()함수에서 inputManager 클래스에서 만들어 둔 OnUpdate()함수를 실행시켜준다.


public class PlayerController : MonoBehaviour
    {
        float playerSpeed = 10f;
        private void Start()
        {
            GameManager.Input.KeyAction -= OnKeyBoard;
            GameManager.Input.KeyAction += OnKeyBoard;

        }

        void OnKeyBoard()
        {

            if (Input.GetKey(KeyCode.W))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);
                transform.position += Vector3.forward * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.S))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);
                transform.position += Vector3.back * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.A))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);
                transform.position += Vector3.left * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.D))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);
                transform.position += Vector3.right * playerSpeed * Time.deltaTime;
            }

        }
    }


PlayerController 클래스에서는 Start() 함수에서 GameManager클래스에서 만들어뒀던 InputManager의 객체를 통해 KeyAction에 OnKeyBoard()함수를 등록시켜준다.

 

이때 -=를 +=하기전에 먼저 한번 해주는데 이유는, 다른 곳에서 모르고 추가로 등록해줄 경우를 대비해서

제거했다가 등록을 시켜준다. (삭제 해줬을 때 등록된 함수가 발견되지 않아도 예외가 발생하지 않음 )

중복으로 호출되는 것을 막아주기 위해 습관적으로 해두는게 좋을 것 같다.


 

728x90

// 절대값을 입력해서 회전을 하고 싶다면 

transform.eulerAngles를 사용.

ex) transform.eulerAngles = new Vector3(0.0f, Time.deltaTime * 100f, 0.0f);

- 각도가 360도를 초과하면 증가시키지 말고, 대신에 Transform.Rotate를 사용해야된다.

 

// 특정 축을 기준으로 얼마만큼 회전을 시키고 싶다 한다면

transform.Rotate()를 사용.

ex) transform.Rotate(new Vector3(0.0f, Time.deltaTime * 100f, 0.0f));

 

// 원하는 특정방향을 쳐다보고 싶게 하고 싶다면

transform.rotation = Quaternion.LookRotation(벡터방향);

 

// 자연스럽게 회전하면서 쳐다보고 싶다면

Quaternion.Slerp()를 사용.

transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(벡터방향), 0부터 1사이의 float값);

- float 값이 0일경우 transform.rotation = transform.rotation,

  float 값이 1일 경우 transform.rotation = Quaternion.LookRotation(벡터방향)이기 때문에 적절한 중간값으로 대입.

 

// < Quaternion.Slerp() > 구면 선형 보간

- public static Quaternion Slerp (Quaternion a, Quaternion b, float t);

: a와 b 사이에 구형으로 t씩 보간한다. 파라미터 t는 [0, 1] 범위로 고정.

 

// 짐벌락 확인 키워드( 짐벌락이란 : 같은방향으로 오브젝트의 두 회전 축이 겹치는 현상 )

euler(gimbal lock) explained

https://www.youtube.com/watch?v=zc8b2Jo7mno&ab_channel=GuerrillaCG

 

// player 이동키

  1. void playerMove()
        {
            float dirX = Input.GetAxis("Horizontal");
            float dirY = Input.GetAxis("Vertical");

            Vector3 dirXY = (Vector3.right * dirX) + (Vector3.forward * dirY);

            transform.position += dirXY * playerSpeed * Time.deltaTime;
        }
  2.   void playerMove2()
        {
            if (Input.GetKey(KeyCode.W))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);
                transform.position += Vector3.forward * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.S))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);
                transform.position += Vector3.back * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.A))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);
                transform.position += Vector3.left * playerSpeed * Time.deltaTime;
            }
            if (Input.GetKey(KeyCode.D))
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);
                transform.position += Vector3.right * playerSpeed * Time.deltaTime;
            }
        }
728x90

#1

공부하는 것들, 생각하는 것들을 저장해 두는 공간.

 

2022.08.10

 

++

혹시나 공부하시다가 이 블로그에 들어 왔다면 댓글이나 하트, 혹은 방명록 하나만 써주고 가시면 제가 기분이 좋습니다.

2024.09.20

728x90

+ Recent posts