요즘 혼자 개발중인 게임에서 복권 컨텐츠를 넣으면서 복권기능을 만들어 보았습니다.
UGUI에 마스킹을 적용해서 복권 긁는듯한 효과를 만들었습니다.
1. Canvas에 이미지 추가(배경)
하이러키 구조는 위와같이 했습니다.
캔버스에 배경 이미지(Lottery)를 만들었습니다.
- contents : 복권을 긁었을때 출력될 컨텐츠(컨텐츠는 입맛대로 구현하시면됩니다)
- cover : 복권 긁는 효과를 만들어 넣을 커버
2. Image 클래스 확장
1 2 3 4 5 6 7 8 9 10 11 12 | public class CutoutMaskImage : Image { public override Material materialForRendering { get { Material result = new Material(base.materialForRendering); result.SetInt("_StencilComp", (int)CompareFunction.Equal); return result; } } } | cs |
마스킹 영역만 투명하게 만들기 위해서 위와같이 Image를 상속받아 클래스를 만들어줍니다.
cover 오브젝트에 CutoutMaskImage 스크립트를 추가해줍니다.
커버 이미지를 만들어서 SourceImage에 추가해주셔도 됩니다. 그런데 전 간단하게 색만 설정해서 만들어 주었습니다.
3. 마스킹 Prefab 만들기
투명하게 만들부분을 표현하기 위해 마스크 프리팹을 만들어주겠습니다.
SpriteMask 컴포넌트를 추가해 주었습니다.
그리고 maskPrefab 오브젝트를 프리팹으로 만들어줍니다.
4. 코딩하기
기본적인 준비는 끝났고, 이벤트를 입력받아 효과를 주는 간단한 코딩만 남아있습니다.
저는 TestLottery.cs 라는 스크립트를 만들어서 사용했습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public class TestLottery : MonoBehaviour { /// <summary> /// 마스크 오브젝트 프리팹 /// </summary> public GameObject objMask; /// <summary> /// 이미지 커버 /// </summary> public Image imageCover; /// <summary> /// 캔버스 루트 /// </summary> private Canvas m_RootCanvas; /// <summary> /// 커버이미지 RectTransform /// </summary> private RectTransform m_CoverRectTransform; /// <summary> /// 포인트 다운 플래그 /// 포인트 다운 후 드래그 이벤트 발생시 마스크 오브젝트 추가함 /// </summary> private bool m_IsPointDown; /// <summary> /// 매 프레임마다 마스크 오브젝트를 생성해주어도 되지만 /// 너무 많은 오브젝트 생성을 방지하기위해 딜레이를 줌 /// </summary> private float m_MaskDelay; } | cs |
기본적인 변수들은 위와 같습니다.
캔버스 루트와 커버이미지 RectTransform은 마스크 오브젝트 생성시 UI포지션이 맞춰서 생성해주기 위해 필요합니다.
- Obj Mask : 마스크 프리팹
- Image Cover : 커버이미지
를 연결해줍니다.
1 2 3 4 5 6 | private void Start() { m_IsPointDown = false; m_RootCanvas = GetComponentInParent<Canvas>(); m_CoverRectTransform = imageCover.GetComponent<RectTransform>(); } | cs |
Start 함수에서 나머지 변수들을 초기화를 해 줍니다.
이제 마스크 오브젝트를 생성하는 코드를 작성해주겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private void AddMask() { if (m_MaskDelay > 0) return; if (Input.GetMouseButton(0)) { m_MaskDelay = 0.05f; var mask = Instantiate(objMask, imageCover.transform); Vector3 pos = Input.mousePosition; Vector2 outLocalPos = Vector2.zero; if (RectTransformUtility.ScreenPointToLocalPointInRectangle( m_CoverRectTransform, pos, (this.m_RootCanvas.renderMode == RenderMode.ScreenSpaceOverlay) ? null : this.m_RootCanvas.worldCamera, out outLocalPos)) { mask.transform.localPosition = outLocalPos; } } } | cs |
입력받은 좌표를 UI 좌표로 변경해주고 그 좌표에 마스크오브젝트를 생성해줍니다.
5. 이벤트 추가
cover에서 이벤트가 발생할때 마스크를 추가해주어야 하기 때문에 cover에 이벤트 트리거를 추가해 줍니다.
Down, Drag, Up 이벤트 트리거를 추가해주고
이벤트가 발생했을때 호출될 함수들을 만들어 주도록 하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public void OnImagePointDown() { m_IsPointDown = true; AddMask(); } public void OnImageDrag() { if (m_IsPointDown) AddMask(); } public void OnImagePointUp() { m_IsPointDown = false; m_MaskDelay = 0; } | cs |
OnImagePointDown() 함수에서 플래그를 true로 바꿔주고 마스크를 추가합니다.
OnImageDrag() 함수에서 플래그가 true 일때 계속 마스크를 추가해주도록 합니다.
OnImagePointUp() 함수에서 플래그를 false로 바꾸고 딜레이를 0으로 설정합니다.
여기까지 오셨다면 복권 긁는 효과는 완성되었습니다.
잘 활용하셔서 멋진 게임 만드시길 바랍니다.
6. 전체코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | public class TestLottery : MonoBehaviour { /// <summary> /// 마스크 오브젝트 프리팹 /// </summary> public GameObject objMask; /// <summary> /// 이미지 커버 /// </summary> public Image imageCover; /// <summary> /// 캔버스 루트 /// </summary> private Canvas m_RootCanvas; /// <summary> /// 커버이미지 RectTransform /// </summary> private RectTransform m_CoverRectTransform; /// <summary> /// 포인트 다운 플래그 /// 포인트 다운 후 드래그 이벤트 발생시 마스크 오브젝트 추가함 /// </summary> private bool m_IsPointDown; /// <summary> /// 매 프레임마다 마스크 오브젝트를 생성해주어도 되지만 /// 너무 많은 오브젝트 생성을 방지하기위해 딜레이를 줌 /// </summary> private float m_MaskDelay; private void Start() { m_IsPointDown = false; m_RootCanvas = GetComponentInParent<Canvas>(); m_CoverRectTransform = imageCover.GetComponent<RectTransform>(); } private void Update() { if (m_MaskDelay > 0) m_MaskDelay -= Time.deltaTime; } public void OnImagePointDown() { m_IsPointDown = true; AddMask(); } public void OnImageDrag() { if (m_IsPointDown) AddMask(); } public void OnImagePointUp() { m_IsPointDown = false; m_MaskDelay = 0; } private void AddMask() { if (m_MaskDelay > 0) return; if (Input.GetMouseButton(0)) { // 0.05초에 한번씩 오브젝트 생성 m_MaskDelay = 0.05f; // 마스크 오브젝트를 cover 오브젝트 하위에 붙임 var mask = Instantiate(objMask, imageCover.transform); Vector3 pos = Input.mousePosition; Vector2 outLocalPos = Vector2.zero; // 화면좌표를 UI좌표로 수정후 마스크 오브젝트 위치 설정 if (RectTransformUtility.ScreenPointToLocalPointInRectangle( m_CoverRectTransform, pos, (this.m_RootCanvas.renderMode == RenderMode.ScreenSpaceOverlay) ? null : this.m_RootCanvas.worldCamera, out outLocalPos)) { mask.transform.localPosition = outLocalPos; } } } } | cs |
댓글 없음:
댓글 쓰기