public class CameraRaycaster : MonoBehaviour
{
private Camera _cam;
[Header("Set Raycast Config")]
[SerializeField][Range(0, 100)] private float _rayDistance = 100;
[SerializeField] private KeyCode _actionKey = KeyCode.Mouse0;
[SerializeField] private LayerMask _targetLayer = 0;
private void Awake() => Init();
private void Update() => RayShoot();
private void Init()
{
_cam = Camera.main;
//LayerUtil.AddLayer(ref _targetLayer, "Player", "Monster");
//LayerUtil.RemoveLayer(ref _targetLayer, "Item");
}
private void RayShoot()
{
if(!Input.GetKeyDown(_actionKey)) return;
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit, _rayDistance, _targetLayer))
{
Debug.Log($"검출 대상 Layer = {_targetLayer.value}");
Debug.Log($"오브젝트 검출 : Layer = {hit.transform.gameObject.layer}");
// 0000 0000 _ 0000 0000 _ 0000 0000 _ 0000 0000
// EX> Monster (9 Layer) 를 클릭해서 '제외'한다고 가정.
// hitLayerNumber = 9
int hitLayerNumber = hit.transform.gameObject.layer; // 마우스로 클릭한 오브젝트 layer 번호, 자릿수
// ...0000 0010 0000 0000
int hitLayer = (1 << hitLayerNumber); // 1을 왼쪽으로 hitLayerNumber 만큼 미룬다.
// ...1111 1101 1111 1111
int notLayer = ~hitLayer; // ~hitLayer -> not연산자 ~, 클릭한 오브젝트를 안보이게 하기 위해
// _cam.cullingMask = ...1111 1111 1111 1111
// not Layer = ...1111 1101 1111 1111
// And => ...1111 1101 1111 1111 => 둘다 1인것만 남긴다.
_cam.cullingMask &= notLayer;
}
}
// OR 연산
// 둘중 하나라도 1이면 1
// 중첩하고 싶은 레이어를 더할 때 쓸 수 있음.
//
// ...1000 0000
// OR ...0000 1000
// ---------------
// => ...1000 1000
// NOT 연산
// 뒤집어버림
//
// ...0101 0010
// NOT => ...1010 1101
// AND 연산
// 둘 다 1이어야 1이 나옴.
// 하나라도 0이면 0이 나온다.
//
// ...1010 0010
// AND ...0010 0100
// ---------------
// => ...0010 0000
}
public static class LayerUtil
{
public static void AddLayer(ref LayerMask target, params string[] names)
{
foreach(string n in names)
{
target |= 1 << LayerMask.NameToLayer(n);
}
}
public static void RemoveLayer(ref LayerMask target, string name)
{
target &= ~(1 << LayerMask.NameToLayer(name)); // name으로 layer의 번호를 반환, 그리고 반전, 엔드 연산
}
}