*충돌: 객체와 객체가 닿았다.
<Collider>
- Plane 만들기
1. Scene에서 create Plane으로 땅을 만들어 준다.
2. Assets 폴더 아래에 create Material을 통해 green 색을 만들어 준다. (땅의 색깔을 만들어 줌)

3. 해당 Material을 Plane의 Materials에 drag drop으로 옮겨서 Plane에 Materials를 바꿔준다.

- Collider
1. Player에게 중력을 주기위해 component로 Rigidbody를 추가한다.

2. 이렇게 한 후 Player를 공중에 띄우면 Player가 끝없이 내려간다.
3. Unity 공식 Document를 찾아보면, Collider가 있어야지만 object와 충돌이 일어난다.
Rigidbody 는 GameObject 가 물리 제어로 동작하게 합니다. 리지드바디는 힘과 토크를 받아 오브젝트가 사실적으로 움직이도록 해줍니다. 리지드바디가 포함된 모든 게임 오브젝트는 중력의 영향을 받아야 하며 스크립팅을 통해 가해진 힘으로 움직이거나 NVIDIA PhysX 물리 엔진을 통해 다른 오브젝트와 상호 작용해야 합니다.
콜라이더는 충돌이 일어나게 만들기 위해 리지드바디에 함께 추가해야 하는 또 다른 유형의 컴포넌트입니다. 두 개의 리지드바디가 서로 충돌하더라도 두 오브젝트 모두 콜라이더가 추가되어 있지 않으면 물리 엔진은 충돌을 연산하지 않습니다. 콜라이더가 없는 리지드바디는 물리 시뮬레이션 동안 서로를 지나쳐가기만 합니다.
4. Player(unity chan)에 Rigidbody뿐만아니라 Capsule Collider 를 추가한 후 Edit Collider를 클릭하여 Collider의 범위를 정해준다. 다음과 같이 캡슐모양 녹색 실선이 나타나고 범위를 정해준다. (* 다양한 Collider가 존재하지만, 여기서는 Capsule Collider를 사용한다.)

4. 이렇게 해서 Play를 한 후, Player를 위로 올리면, 끝없이 내려가지않고 Plane위에 안착한다.
5. 만일 Plane에 Mesh Collider를 선택하지않고 Play하면 위에서 처럼 끝없이 내려간다
=> Collider는 Collider 끼리 충돌
- Is Kinematic
1. 우선 Plane을 두개 만들어서 다음과 같이 설정 => Plane을 벽으로 만든다.

2. Play를 해서 벽에 Player를 충돌시키면 두 물체가 충돌되어 Player가 넘어진다. => 물리적인 힘이 Player에게 영향을 준다.
* 물리적인 힘을 무시하는 요소 => Is Kinematic
3. Is Kinematic이란? 물리가 영향을 줄지 말지를 선택함
Is Kinematic: 활성화되면 오브젝트는 물리 엔진으로 제어되지 않고 오로지 Transform 으로만 조작됩니다. 플랫폼을 옮기는 경우나 HingeJoint 가 추가된 리지드바디를 애니메이션화하는 경우에 유용합니다.
Rigidbody의 요소인 Is Kinematic을 Check를 하면 물리의 힘이 작용 x
Player를 공중에 띄우고 play를 하면 물리의 힘이 무시되기 때문에 중력이 무시되어 공중에서 이동한다.
언제 Is Kinematic 사용? object가 충돌하는 시점을 알 수 있다면 다양한 event로 처리 가능
<Collision event 처리>
- 기본 event
1. 다음과 같이 Cube를Scene에 넣는다.

2. 후에 Play를 하여 Player와 Cube를 부딪히면 Collision이 발생한다.
3. Collsion event 처리를 위해, TestCollsion.cs 를 만들고 다음과 같이 코드를 짠다.
=> OnCollisionEnter: 충돌 발생 이벤트 처리, OnTriggerEnter: 트리거 발생 이벤트 처리
*TestCollsion.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCollision : MonoBehaviour
{
// Collision event
private void OnCollisionEnter(Collision collsion)
{
Debug.Log("Collsion! ");
}
// Trigger event
private void OnTriggerEnter(Collider other)
{
Debug.Log("Trigger");
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
3. 다음 cs를 Player의 component로 추가한 후, play를 하면 console 창에 Collision event가 발생하여 'Collsion' 메세지가 발생 => 충돌이 날때마다 발생
4. * 처음에 Cube와 충돌하지않아도 Plane과 충돌했다 가정해서 Collision 발생 => Plane에 Mesh Collider를 끄고 Rigidbody의 Gravity를 끄고 Player를 하면 Cube와 충돌될 때만, Console창에 뜬다.
- Collision event 처리 + Is kinematic 외의 Trigger 발생
1. Rigidbody에 Is kinematic을 check하고 하면 event 발생 x
2. 만약 Player의 Capsule Collider의 Is Trigger가 check되어 있으면 Trigger event 발생(Capsule Collider가 check되어 있는 상태에서)
3. 만약 Cube의 Box Collider의 Is Trigger가 check 되어 있으면 Trigger event 발생(Box Collider가 check되어 있는 상태에서)
- Collision 발생 조건
1. 나한테 Rigidbody가 있어야한다. (IsKinematic: off)
2. 나한테 Collider가 있어야한다.(IsKinematic: off)
3. 상대한테 Collider가 있어야한다. (IsKinematic: off)
<Trigger>
- event 함수 보기
1. 아래의 매개변수에 Collision에 대한 정보가 들어 있음 => 내가 누구랑 부딪혔는지에 대해 알 수 있다.
*TestCollsion.cs
// Collision event
private void OnCollisionEnter(Collision collsion)
{
Debug.Log("Collsion! ");
}
* unity API의 Collision참고
collider: The Collider we hit (Read Only).
contact: CountGets the number of contacts for this collision.
contacts: The contact points generated by the physics engine. You should avoid using this as it produces memory garbage. Use GetContact or GetContacts instead.
gameObject: The GameObject whose collider you are colliding with. (Read Only).
impulse: The total impulse applied to this contact pair to resolve the collision.
relativeVelocity: The relative linear velocity of the two colliding objects (Read Only).
rigidbody: The Rigidbody we hit (Read Only). This is null if the object we hit is a collider with no rigidbody attached.
transform: The Transform of the object we hit (Read Only).
2. 다음과 같이 code를 바꾼후, play하여 cube에 부딪히면 부딪힌 객체의 이름을 알 수 있다.
*TestCollsion.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCollision : MonoBehaviour
{
// Collision event
private void OnCollisionEnter(Collision collsion)
{
Debug.Log($"Collsion! @ {collsion.gameObject.name} ");
}
private void OnTriggerEnter(Collider other)
{
Debug.Log("Trigger");
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

- Collision event가 발생하는 조건
이전에 배웠던,
1. 나한테 Rigidbody가 있어야한다. (IsKinematic: off)
2. 나한테 Collider가 있어야한다.(IsKinematic: off)
3. 상대한테 Collider가 있어야한다. (IsKinematic: off)
+ Unity Manual 참고: https://docs.unity3d.com/Manual/CollidersOverview.html -> Collision action Matrix
=>
1. 나 혹은 상대방한테 Rigidbody가 있어야한다. (IsKinematic: off)
2. 나한테 Collider가 있어야한다.(IsKinematic: off)
3. 상대한테 Collider가 있어야한다. (IsKinematic: off)
* 핵심적인 내용은 Is kinematic을 check하면 물리적인 영향을 받지 않음
- Trigger event가 발생하는 조건
물리적인 접촉이 아닌 어떠한 범위 내에 들어있는지 판단하는 것이 Trriger이다.
1. 둘 다 Collider가 있어야한다.
2. 둘 중 하나는 IsTrigger: On
3. 둘 중 하나는 RigidBody가 있어야한다.
=> Trigger는 다양한 이용분야에서 사용될 수 있다.
<Raycasting>
Raycasting: 광선을 쏴서 레이저와 부딪히는 물체가 없는지 판단하는 기술, 레이저가 Play등의 객체에 닿았다(객체의 Collider에 닿았다.) => 정보를 추출하여 선택한 상태로 바꾸는 것
- 기본 Raycasting
1. Physics.Raycast(Vector3 origin, Vector3 direction): 시작점 origin에서 방향 direction으로(무한대로) 레이저를 쏘아서 객체를 만나면 True 반환, 만나지않으면 False 반환
*TestCollision.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCollision : MonoBehaviour
{
// Collision event
private void OnCollisionEnter(Collision collsion)
{
Debug.Log($"Collsion! @ {collsion.gameObject.name} ");
}
private void OnTriggerEnter(Collider other)
{
Debug.Log($"Trigger @{other.gameObject.name} !");
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// 디버깅 레이저
Debug.DrawRay(transform.position, Vector3.forward, Color.red); //Vector3.forward 만큼만 레이저 쏜다.
if(Physics.Raycast(transform.position, Vector3.forward)); // 4번 버전 Physics.Raycast(Vector3 origin, Vector3 direction) 시작점 origin 에서 방향 direction: 객체를 만나면 True, 안만나면 False
{
Debug.Log("Raycast!");
}
}
}
2. 위에서 레이저의 길이를 지정해줘서 레이저 쏘기
: Physics.Raycast(Vector3 origin, Vector3 direction, float maxDistance) -> maxDistance (단위:m)만큼만 레이저 쏜다.
*TestCollsion.cs
void Update()
{
// 디버깅 레이저
Debug.DrawRay(transform.position + Vector3.up , Vector3.forward * 10, Color.red);
if(Physics.Raycast(transform.position + Vector3.up, Vector3.forward, 10)); //최대 10m 레이저 쏘게
{
Debug.Log("Raycast!");
}
}
3. RaycastHit 정보를 빼내기 위해 version12: Physics.Raycast(Vector3 origin, Vector3 direction,out RaycastHit hitinfo, float maxDistance)
Player가 가져오는 방향의 global 좌표를 가져오기 위해 transform.TransformDirection(Vector3.forward) 사용
*TestCollsion.cs
void Update()
{
Vector3 look = transform.TransformDirection(Vector3.forward); // Player가 바라보는 forward 방향을 local -> world로 변환 player의 local 좌표를
// 디버깅 레이저
Debug.DrawRay(transform.position + Vector3.up , look * 10, Color.red);
RaycastHit hit;
if(Physics.Raycast(transform.position + Vector3.up, look, out hit, 10)) // 4번 버전 Physics.Raycast(Vector3 origin, Vector3 direction) 시작점 origin 에서 방향 direction: 객체를 만나면 True, 안만나면 False
{
Debug.Log($"Raycast! @ {hit.collider.gameObject.name}");
}
}
4. 여러개의 Cube를 만들어서 Raycasting을 하여도 앞에 먼저 레이저가 닿은 객체에 대해서만 이름이 나온다.
-> 모든 객체를 찾기 위해서는 Physics.RaycastAll(Vector3 origin, Vector3 direction, float maxDistance) return RaycastHit[](배열 반환)
*TestCollsion.cs
void Update()
{
Vector3 look = transform.TransformDirection(Vector3.forward); // Player가 바라보는 forward 방향을 local -> world로 변환 player의 local 좌표를
// 디버깅 레이저
Debug.DrawRay(transform.position + Vector3.up , look * 10, Color.red);
RaycastHit[] hits ;
hits = Physics.RaycastAll(transform.position + Vector3.up, look, 10);
foreach (RaycastHit hit in hits)
{
Debug.Log($"Raycast {hit.collider.gameObject.name} !");
}
}
5. Player가 벽이나 다른 사물에 의해 가려졌을 때, Raycasting 기술을 사용하여 바로 사용자 앞으로 카메라를 가지고 가는 기술에 응용될 수 있다.
<투영>
* 기존의 좌표계를 볼때, Local 좌표계를 보고 이것을 World 좌표계로 가져온 후 우리가 바라보는 Screen(화면) 좌표계로 가져와야함.
Local <-> World <-> Viewport <-> Screen(화면) : World와 Screen사이에 Viewport라는 것도 있음
- 좌표계
1.Screen 좌표계: 다음과 같이 Input.mousePosition으로 Screen 좌표계를 가져올 수 있다. => 픽셀 좌표계라고도 볼 수 있음
*TestCollsion.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCollision : MonoBehaviour
{
// Collision event
private void OnCollisionEnter(Collision collsion)
{
Debug.Log($"Collsion! @ {collsion.gameObject.name} ");
}
private void OnTriggerEnter(Collider other)
{
Debug.Log($"Trigger @{other.gameObject.name} !");
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Debug.Log(Input.mousePosition);
}
}
2. Viewport: Screen과 유사하지만 비율로 나타낸다.
*TestCollsion.cs
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
}
- 카메라
1. 카메라에서
far는 얼마나 카메라가 넓게 바라보는가?
Near는 카메라와 찍는 공간 사이의 거리가 얼마인가?
2. 나중에 카메라로 바라본 Scene을 볼때는 Scene의 깊이 값이 없어진다. -> 카메라에서 바라본 모습만 보고 Player와 카메라 사이의 거리가 얼마인지 알 수 없다.
3. 카메라가 바라보는 큰 화면을 카메라의 작은 화면에 투영하기 때문에 (비율에 맞춰서 투영)
- 카메라와 Raycasting
1. 카메라에서 Raycasting 하여 어떤 객체를 누르면 레이저가 나오고 해당 객체의 이름이 뜬다.
Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane)) -> 카메라의 투영된 좌표계를 가져옴 (Input.mousePosition.x, Input.mousePosition.y를 통해) 해당 좌표를 World 좌표계로 바꾼다. * Camera.main.nearClipPlane: 카메라와 투영돤 좌표계 사이의 거리
*TestCollsion.cs
// Update is called once per frame
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
//Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
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;
Debug.DrawRay(Camera.main.transform.position, dir * 100.0f, Color.red, 1.0f);
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, dir, out hit, 100.0f))
{
Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
}
}
2. 더 쉽게 하는 방법
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
//Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
if (Input.GetMouseButtonDown(0))
{
// Ray함수를 통해 바로 World View로 가져올 수 있음
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f))
{
Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
}
}
}
<LayerMask>
Layer를 사용하면 내가 연산하고 싶은 Layer만 Raycasting이 가능하게 할 수 있다.
- Layer: 다음과 같이 32개의 Layer가 존재한다.

1. Layer를 다음과 같이 Monster와 Wall를 추가한다.
2. Cube에 Monster Layer를, Plane에 Wall Layer를 추가하여 다음과 같이 코드를 수정한다.
* Layer는 32비트로 표현되어 다음과 같이 1 << 8(1을 8자리만큼 옮김) 1<< 9 (1을 9자리만큼 옮김)
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
//Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); ;// Screen의 좌표를 바로 World 좌표로 가져옴
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
int mask = (1 << 8) | (1 << 9);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f, mask))
{
Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
}
}
}
3. 좀더 가독성 있게 mask를 다음과 같이 바꿔서 사용해 줄 수 있다.
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
//Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); ;// Screen의 좌표를 바로 World 좌표로 가져옴
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall") ;
// int mask = (1 << 8) | (1 << 9);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f, mask))
{
Debug.Log($"Raycast Camera @ {hit.collider.gameObject.name}");
}
}
}
<Tag>
- Tag
1. Tag를 이용하여 바로 GameObject에 추가할 수 있다.
2. GameObject.FindGameObjectWithTag("Monster"); 함수를 이용하여 Tag로 GameObject를 찾을 수 있음
3. 다음과 같이 Tag를 출력할 수 있다.
void Update()
{
//Debug.Log(Input.mousePosition); // Screen
//Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); // Viewport: Screen과 유사하지만 비율로 나타냄
if (Input.GetMouseButtonDown(0))
{
GameObject.FindGameObjectWithTag("Monster");
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); ;// Screen의 좌표를 바로 World 좌표로 가져옴
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall") ;
// int mask = (1 << 8) | (1 << 9);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f, mask))
{
Debug.Log($"Raycast Camera @ {hit.collider.gameObject.tag}");
}
}
}
'Development > 유니티' 카테고리의 다른 글
[섹션6] 애니메이션(Animation) (0) | 2021.07.21 |
---|---|
[섹션5]Camera(카메라) (0) | 2021.07.13 |
[섹션 3] 프래팹(Prefab) (0) | 2021.07.08 |
[섹션2] Transform(트랜스폼) (0) | 2021.07.06 |
[섹션1] 유니티 기본 구성 및 기초 (0) | 2021.06.29 |