오브젝트를 선택된 상태로 만들기 : (1) bool
오브젝트를 선택된 상태로 만들기 : (2) 이미지로 만들기
오브젝트를 선택된 상태로 만들기 : (3) Shader Outline
오브젝트를 선택된 상태로 만들기 : (4) 오브젝트를 하나만 선택하기
여러 오브젝트(블럭, Block) 중 하나만 선택하도록 해보자.
선택된 오브젝트는 outline이 나타나도록 한다.
먼저 카메라에 SelectBlock.cs를 추가한다.
카메라를 기준으로 Raycast를 이용해 블럭을 선택한다.
SelectBlock은 카메라에만 존재하므로 싱글턴으로 만들면 좋다.
static SelectBlock instance = null;
public static SelectBlock Instance
{
get
{
if (null == instance) instance = FindObjectOfType<SelectBlock>();
return instance;
}
}
void Awake()
{
if (null == instance) instance = this;
}
오브젝트가 선택된 경우, Outline이 추가되는 것은 아래의 코드로 분리한다. (링크의 OnMouseDown/Up)
object를 넘겨주면 outline을 추가하고 remove에서 renderer를 넘겨주면 원래의 material로 변경한다.
Material outline;
Renderer renderers;
List<Material> materialList = new List<Material>();
void addOutline(Transform obj)
{
if (obj == null) return;
renderers = obj.GetComponent<Renderer>();
materialList.Clear();
materialList.AddRange(renderers.sharedMaterials);
materialList.Add(outline);
renderers.materials = materialList.ToArray();
}
void removeOutline(Renderer renderer)
{
if (renderer != null)
{
materialList.Clear();
materialList.AddRange(renderer.sharedMaterials);
materialList.Remove(outline);
renderer.materials = materialList.ToArray();
}
}
오브젝트의 해제와 선택은 아래와 같다.
해제 - 현재 선택된 오브젝트를 null로 변경하고 outline 제거
선택 - selectedTarget을 선택한 오브젝트로 변경하고 outline을 추가
Transform selectedTarget;
void clearTarget()
{
if (selectedTarget == null) return;
selectedTarget = null;
removeOutline(renderers);
}
void selectTarget(Transform obj)
{
if (obj == null) return;
selectedTarget = obj;
addOutline(obj);
}
이제 Update에서 Raycast로 오브젝트를 선택하면 된다.
특정 오브젝트만 선택되도록 하기 위해 LayerMask = "Block"을 이용하였다.
RaycastHit hit;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.red);
int layer = 1 << LayerMask.NameToLayer("Block");
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layer))
{
Transform obj = hit.transform;
selectTarget(obj);
}
}
}
선택하고 싶은 오브젝트에 Layer = "Block"으로 변경해두고 테스트해보자.
오브젝트를 선택해보자. outline이 추가된다.
그러나 다른 오브젝트를 눌러도 이전에 선택된 오브젝트가 해제되지 않는다.
여기까지의 코드는 아래와 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SelectBlock : MonoBehaviour
{
RaycastHit hit;
Transform selectedTarget;
Material outline;
Renderer renderers;
List<Material> materialList = new List<Material>();
static SelectBlock instance = null;
public static SelectBlock Instance
{
get
{
if (null == instance) instance = FindObjectOfType<SelectBlock>();
return instance;
}
}
void Awake()
{
if (null == instance) instance = this;
}
void Start()
{
outline = new Material(Shader.Find("Draw/OutlineShader"));
}
void addOutline(Transform obj)
{
if (obj == null) return;
renderers = obj.GetComponent<Renderer>();
materialList.Clear();
materialList.AddRange(renderers.sharedMaterials);
materialList.Add(outline);
renderers.materials = materialList.ToArray();
}
void removeOutline(Renderer renderer)
{
if (renderer != null)
{
materialList.Clear();
materialList.AddRange(renderer.sharedMaterials);
materialList.Remove(outline);
renderer.materials = materialList.ToArray();
}
}
void clearTarget()
{
if (selectedTarget == null) return;
selectedTarget = null;
removeOutline(renderers);
}
void selectTarget(Transform obj)
{
if (obj == null) return;
selectedTarget = obj;
addOutline(obj);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.red);
int layer = 1 << LayerMask.NameToLayer("Block");
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layer))
{
Transform obj = hit.transform;
selectTarget(obj);
}
}
}
}
간단한 해결방법은 오브젝트를 선택하기 전 해제를 먼저하면 된다.
selectedTarget 코드 전에 clearTarget을 호출하자.
void selectTarget(Transform obj)
{
if (obj == null) return;
clearTarget();
selectedTarget = obj;
addOutline(obj);
}
그리고 Raycast에서 Block을 선택하지 않은 경우 = LayerMask가 Block인 오브젝트를 못 찾은 경우에
오브젝트 선택을 해제하자.
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.red);
int layer = 1 << LayerMask.NameToLayer("Block");
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layer))
{
Transform obj = hit.transform;
selectTarget(obj);
}
else /* Block을 선택하지 않은 경우 */
{
clearTarget();
}
}
이제 오브젝트가 하나만 선택된다.
그리고 빈 공간(Block을 얻지 못한 경우)을 클릭하면 해제되는 것을 알 수 있다.
그러나 현재 같은 오브젝트를 누를 경우 선택이 해제가 되지 않는다.
selectTarget에 obj가 현재 선택된 오브젝트(selectedTarget)과 같은 경우에는 선택을 해제하는 코드를 추가한다.
void selectTarget(Transform obj)
{
if (obj == null) return;
if (obj == selectedTarget)
{
clearTarget();
return;
}
clearTarget();
selectedTarget = obj;
addOutline(obj);
}
이제 아래의 기능이 모두 작동한다.
- 오브젝트 선택
- 다른 오브젝트를 선택하면 기존 오브젝트 해제
- 빈 공간 선택 시 해제
- 같은 오브젝트를 선택하는 경우 해제
전체 코드는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SelectBlock : MonoBehaviour
{
RaycastHit hit;
Transform selectedTarget;
Material outline;
Renderer renderers;
List<Material> materialList = new List<Material>();
static SelectBlock instance = null;
public static SelectBlock Instance
{
get
{
if (null == instance) instance = FindObjectOfType<SelectBlock>();
return instance;
}
}
void Awake()
{
if (null == instance) instance = this;
}
void Start()
{
outline = new Material(Shader.Find("Draw/OutlineShader"));
}
void addOutline(Transform obj)
{
if (obj == null) return;
renderers = obj.GetComponent<Renderer>();
materialList.Clear();
materialList.AddRange(renderers.sharedMaterials);
materialList.Add(outline);
renderers.materials = materialList.ToArray();
}
void removeOutline(Renderer renderer)
{
if (renderer != null)
{
materialList.Clear();
materialList.AddRange(renderer.sharedMaterials);
materialList.Remove(outline);
renderer.materials = materialList.ToArray();
}
}
void clearTarget()
{
if (selectedTarget == null) return;
selectedTarget = null;
removeOutline(renderers);
}
void selectTarget(Transform obj)
{
if (obj == null) return;
if (obj == selectedTarget)
{
clearTarget();
return;
}
clearTarget();
selectedTarget = obj;
addOutline(obj);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.red);
int layer = 1 << LayerMask.NameToLayer("Block");
if (Physics.Raycast(ray, out hit, Mathf.Infinity, layer))
{
Transform obj = hit.transform;
selectTarget(obj);
}
else /* Block을 선택하지 않은 경우 */
{
clearTarget();
}
}
}
}
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
'개발 > Unity' 카테고리의 다른 글
유니티 - 스크립트로 레이어(Layer) 관리하기 (0) | 2022.05.23 |
---|---|
프로퍼티로 readonly 변수 만들기 (get; private set;) (0) | 2022.05.17 |
유니티 - 마우스 스크롤로 카메라 줌 인 / 아웃 (Camera Zoom in / out with a Mouse Scroll) (0) | 2022.05.14 |
유니티 Plane, 평면의 길이 (0) | 2022.05.14 |
유니티 - 간단한 투명 Material 만들기 (1) | 2022.05.14 |
댓글