말감로그

[Unity] 1. 로또번호 룰렛판 돌리기 본문

Unity

[Unity] 1. 로또번호 룰렛판 돌리기

habbn 2023. 5. 9. 18:43
728x90

0~9 까지 있는 숫자판을 게이지의 파워만큼 돌려 5개의 로또 번호를 뽑는 룰렛 게임을 만들어보도록 합니다.

 

  1.  화면에 놓일 오브젝트를 모두 나열한다. 
    •  룰렛(roulette) , 바늘(needle) , 게이지바(PwBar, PwText) , 문구(HelpText) , 리셋 버튼(Reset_Btn), 숫자표시 UI
  2.  오브젝트를 움직일 수 있는 컨트롤러 스크립트를 정한다.
    • Roulette Controller
  3.  오브젝트를 자동으로 생성할 수 있도록 제너레이터 스크립트를 정한다.
    • 해당하는 오브젝트가 없으므로 사용 X
  4.  UI를 갱신할 수 있도록 감독 스크립트를 준비한다.
    • GameMgr
  5.  스크립트를 만드는 흐름을 생각한다.
    • 컨트롤러 스크립트 -> 제너레이터 스크립트 -> 감독 스크립트 순서로 만든다.

 

RouletteController 

 

1. 룰렛판 돌리기

 

 

회전 속도와 최대 힘(속도) 멤버 변수를 선언해 줍니다.

 

public class RouletteController : MonoBehavior
{
    float rotSpeed = 0; 	//회전 속도
    float m_MaxPower = 80.0f;	//최대 힘(속도) 변수

 

Update()함수에 마우스를 누르고 있는 동안 회전 속도를 설정하고 손가락을 떼는 순간 회전 속도 만큼 회전시키도록 구현한다.

 

if(Input.GetMouseButton(0) == true 는 마우스를 누르고 있는 동 true를 리턴하는 함수이고, 

(0)은 왼쪽 마우스 클릭, (1)은 오른쪽 마우스 클릭, (2)는 휠 클릭을 의미한다. 

Input.GetMouseButtonDown(0) //왼쪽 마우스를 눌렀을 때 

 

회전속도(rotSpeed)가 최대 속도(m_MaxPower, 80.0f)보다 커지면 회전속도를 최대 속도(80.0f)로 지정한다.

또한 회전속도(rotSpeed)가 0.1f보다 작거나 같아지면 룰렛이 멈춘 상태로 판단하여 룰렛을 완전 멈추게 한다.

 

void Update()
{
    //마우스를 누르고 있는 동안 회전 속도를 설정한다.
    if(Input.GetMouseButton(0) == true)
    {
    	this.rotSpeed += (Time.deltaTime* 50.0f);	//누르고 있는 동안 속도가 조금씩 증가
        if(m_MaxPower < rotSpeed)	
           rotSpeed = m_MaxPower;	
    }
    
    //마우스를 누르고 있다가 손가락을 떼는 순간 회전시킨다.
    if(Input.GetMouseButtonUp(0) == true)
    {
    	transform.Rotate(0, 0, this.rotSpeed);	//회전 속도만큼 회전시킨다.
        
        this.rotSpeed *= 0.98f;	//룰렛을 감속시킨다.
        
        if(this.rotSpeed <= 0.1f)	//룰렛이 멈춘 상태로 판단
           this.rotSpeed = 0.0f;	//룰렛을 완전 멈춤
     }
}

 

 

2. 게이지 바 채우기

 

UI 멤버 변수를 생성하고  Update 함수 안에 fillAmount 를 사용하여 바를 채워주고 텍스트를 표시해준다.

 

fillAmount는 0~1의 값을 가지고 있으며 그 사이의 값을 이용해서 비율대로 이미지가 표시됩니다. 0이면 아무것도 보이지 않고 1이면 100% 다 보이게 되는 방식이다.

 

public class RouletteController : MonoBehavior
{
    float rotSpeed = 0; 	//회전 속도
    float m_MaxPower = 80.0f;	//최대 힘(속도) 변수
    
    public Image m_PwBarImg = null;  //게이지 바 이미지 연결용 UI 변수
    public Text m_PwText = null;     //게이지 바 텍스트 연결용 UI 변수
    
 		:
        
    void Update()
    {
    		:
        	
       	m_PwBarImg.fillAmount = rotSpeed / m_MaxPower; //0 ~ 1 사이 값으로 바 채워줌
        m_PwText.text = (int)(m_PwBarImg.fillAmount * 100.0f) + "/100";
     }

 

3. 숫자 값을 얻어오는 함수 생성

 

EulerAngle(오일러 각)을 활용하여 바늘이 가리키고 있는 숫자 값을 가져온다.

EulerAngle은 x,y,z  3개의 축을 기준으로 0~360도만큼 회전시키는 기능으로 0~359.999f까지의 값을 환산해서 전달해 준다.

a_Angle은 z축(회전축)이다.

//룰렛이 멈췄을 때 바늘이 가리키고 있는 숫자 값을 얻어오는 함수
void GetCurNumber()
{
    float a_Angle = transform.eulerAngles.z;	
    
    int a_Num = 0;
    
    if((342.0f <= a_Angle && a_Angle <360.0f) ||	
    	(0.0f <= a_Angle && a_Angle <18.0f))
    {	
    	a_Num = 7;
    }
    else if (18.0f <= a_Angle && a_Angle < 54.0f)	
    {
        a_Num = 8;
    }
    else if (54.0f <= a_Angle && a_Angle < 90.0f)	
    {
        a_Num = 9;
    }
    else if (90.0f <= a_Angle && a_Angle < 126.0f)	
    {
        a_Num = 0;
    }
    else if (126.0f <= a_Angle && a_Angle < 162.0f)	 
    {
        a_Num = 1;
    }
    else if (162.0f <= a_Angle && a_Angle < 198.0f)	
    {
        a_Num = 2;
    }
    else if (198.0f <= a_Angle && a_Angle < 234.0f)
    {	
        a_Num = 3;
    }
    else if (234.0f <= a_Angle && a_Angle < 270.0f)	 
    {
        a_Num = 4;
    }
    else if (270.0f <= a_Angle && a_Angle < 306.0f)	
    {
        a_Num = 5;
    }
    else if (306.0f <= a_Angle && a_Angle < 342.0f)	
    {
        a_Num = 6;
    }

 

룰렛이 멈췄을 때 바늘이 가리키고 있는 숫자 값을 얻어와야 하기 때문에 룰렛이 멈췄을 때 코드 밑에 GetCurNumber() 함수를 작성한다.

 

if(this.rotSpeed <= 0.1f)
{
    this.rotSpeed = 0.0f;
    
    GetCurNumber();
}

 

 

4.  GameMgr에 있는 SetNumber() 호출하기

 

GetCurNumber()로 바늘이 가리키고 있는 숫자 값을 얻어왔으니 이 번호를 표시할 수 있도록 GameMgr에 있는 SetNumber() 함수를 호출한다.

GameMgr a_GameMgr = null;
GameMgr a_GObj = GameObject.Find("GameMgr");	    //Hierarchy 목록에서 GameMgr 찾음
if(a_GObj != null)	                            //잘 찾았으면
    a_GameMgr = a_GObj.GetComponent<GameMgr>();	    //GameMgr 스크립트를 찾아와

if(a_GameMgr != null)				    //스크립트를 잘 찾았으면
    a_GameMgr.SetNumber(a_Num);	                    //SetNumber 호출해줘

 

완성 소스

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class RouletteController : MonoBehaviour
{
    float rotSpeed = 0; //회전 속도 
    float m_MaxPower = 80.0f;   //최대 힘(속도) 변수

    public Image m_PwBarImg = null;
    public Text m_PwText = null;

    void Start()
    {
        Application.targetFrameRate = 60; //실행 프레임 속도 60프레임으로 고정 시키기.. 코드
        QualitySettings.vSyncCount = 0;
        //모니터 주사율(플레임율)이 다른 컴퓨터일 경우 캐릭터 조작시 빠르게 움직일 수 있다.
    }
    
    void Update()
    {
        if(GameMgr.s_State == GameState.PowerIng)
        {
            // 마우스를 누르고 있는 순간 회전 속도를 설정한다.  
            if(Input.GetMouseButton(0)==true) 
            {
                // 마우스가 UI 위에 있다면..
                if (IsPointerOverUIObject() == true)
                    return;

                this.rotSpeed += (Time.deltaTime * 50.0f);  //속도 조금씩 증가
                if (m_MaxPower < rotSpeed)  
                    rotSpeed = m_MaxPower;  
            }
            //마우스를 누르고 있다가 손가락을 떼는 순간 
            if(Input.GetMouseButtonUp(0)==true)
            {   
                GameMgr.s_State = GameState.RotateIng; //룰렛 회전 상태
            }
        }
        else if(GameMgr.s_State == GameState.RotateIng)
        {
            transform.Rotate(0, 0, this.rotSpeed);	// 회전 속도만큼 룰렛을 회전시킨다.
            this.rotSpeed *= 0.98f;	// 룰렛을 감속시킨다.

            if(this.rotSpeed <= 0.1f)   //룰렛이 멈춘 상태로 판단
            {
                this.rotSpeed = 0.0f;   //룰렛을 완전 멈춤
                GameMgr.s_State = GameState.PowerIng;   //다시 힘 조절 상태로 변경
                
                GetCurNumber();
            }
        }
        m_PwBarImg.fillAmount = rotSpeed / m_MaxPower;  //0 - 1사이 값으로 바 채워줌
        m_PwText.text = (int)(m_PwBarImg.fillAmount * 100.0f) + "/100";
    }

    //룰렛이 멈췄을 때 바늘이 가리키고 있는 숫자 값을 얻어오는 함수
    void GetCurNumber()
    {
        float a_Angle = transform.eulerAngles.z;	//회전 축

        int a_Num = 0;
        if ((342.0f <= a_Angle && a_Angle < 360.0f) ||
            (0.0f <= a_Angle && a_Angle < 18.0f))
        {
            a_Num = 7;
        }
        else if (18.0f <= a_Angle && a_Angle < 54.0f)
        {
            a_Num = 8;
        }
        else if (54.0f <= a_Angle && a_Angle < 90.0f)
        {
            a_Num = 9;
        }
        else if (90.0f <= a_Angle && a_Angle < 126.0f)
        {
            a_Num = 0;
        }
        else if (126.0f <= a_Angle && a_Angle < 162.0f)
        {
            a_Num = 1;
        }
        else if (162.0f <= a_Angle && a_Angle < 198.0f)
        {
            a_Num = 2;
        }
        else if (198.0f <= a_Angle && a_Angle < 234.0f)
        {
            a_Num = 3;
        }
        else if (234.0f <= a_Angle && a_Angle < 270.0f)
        {
            a_Num = 4;
        }
        else if (270.0f <= a_Angle && a_Angle < 306.0f)
        {
            a_Num = 5;
        }
        else if (306.0f <= a_Angle && a_Angle < 342.0f)
        {
            a_Num = 6;
        }
        
        GameMgr a_GameMgr = null;
        GameObject a_GObj = GameObject.Find("GameMgr");
        if (a_GObj != null)                             
            a_GameMgr = a_GObj.GetComponent<GameMgr>(); 

        if (a_GameMgr != null)                          
            a_GameMgr.SetNumber(a_Num);               
    }

    public static bool IsPointerOverUIObject() //UGUI의 UI들이 먼저 피킹되는지 확인하는 함수
    {
        PointerEventData a_EDCurPos = new PointerEventData(EventSystem.current);

        #if !UNITY_EDITOR && (UNITY_IPHONE || UNITY_ANDROID)

			        List<RaycastResult> results = new List<RaycastResult>();
			        for (int i = 0; i < Input.touchCount; ++i)
			        {
				        a_EDCurPos.position = Input.GetTouch(i).position;  
				        results.Clear();
				        EventSystem.current.RaycastAll(a_EDCurPos, results);
                        if (0 < results.Count)
                            return true;
			        }

			        return false;
        #else
                a_EDCurPos.position = Input.mousePosition;
                List<RaycastResult> results = new List<RaycastResult>();
                EventSystem.current.RaycastAll(a_EDCurPos, results);
                return (0 < results.Count);
        #endif

    }
}

 

  • UI 위에 마우스가 있는지? 확인하는 함수
  • using UnityEngine.EventSystems; 필요
public static bool IsPointerOverUIObject() //UGUI의 UI들이 먼저 피킹되는지 확인하는 함수
    {
        PointerEventData a_EDCurPos = new PointerEventData(EventSystem.current);

        #if !UNITY_EDITOR && (UNITY_IPHONE || UNITY_ANDROID)

			        List<RaycastResult> results = new List<RaycastResult>();
			        for (int i = 0; i < Input.touchCount; ++i)
			        {
				        a_EDCurPos.position = Input.GetTouch(i).position;  
				        results.Clear();
				        EventSystem.current.RaycastAll(a_EDCurPos, results);
                        if (0 < results.Count)
                            return true;
			        }

			        return false;
        #else
                a_EDCurPos.position = Input.mousePosition;
                List<RaycastResult> results = new List<RaycastResult>();
                EventSystem.current.RaycastAll(a_EDCurPos, results);
                return (0 < results.Count);
        #endif

 

 

 

GameMgr 스크립트 작성

 

1. enum 열거형을 사용하여 게임의 상태를 나타낸다. 정수값 대신 사용되는 별칭 집합으로 가독성을 높여줍니다.

 

public enum GameState
{
    PowerIng = 0,   // 파워를 올릴 수 있는 상태
    RotateIng = 1,  // 룰렛이 돌고 있는 상태
    GameEnd = 2	    // 게임 종료 상태를 의미함
}

 

 

2. 로또 번호를 표시하는 SetNumber() 함수를 작성합니다. 

 

RouletteController 스크립트 GetCurNumber 함수에서 숫자 값을 얻어온 변수 a_Num을 가져와 로또 번호를 표시해줍니다.

 

public class Gamemgr : MonoBehaviour
{
    public static GameState s_State = GameState.PowerIng;
    
    int m_NumCount = 0;           // 로또 번호 인덱스 카운트용 변수
    public Text[] NumberTexts;    // 로또 번호 표시 UI 연결용 변수
		:
        
    public void SetNumber(int a_Num)	
    {
        if(m_NumCount < NumberTexts.Length)
        {
            NumberTexts[m_NumCount].text = a_Num.ToString();	
            m_NumCount++;
            
            if(NumberTexts.Length <= m_NumCount)   //5개 번호 다 표시되면
            {
            	s_State = GameState.GameEnd;	  // 게임 종료
            }
        }
    }

 

3. Reset 버튼 함수를 작성합니다.

 

리셋 버튼을 누르면 GameScene으로 씬 전환할 수 있도록 SceneManager.LoadScene() 함수를 사용합니다.

 

using UnityEngine.SceneMangement;

 

SceneManager.LoadScene() 를 사용하기 위해서는 코드 상단에 Scene을 관리하는 SceneManagement를 추가해줍니다.

 

public class GameMgr : MonoBehaviour
{
           	 :
    public Button Reset_Btn = null;   //리셋버튼 UI 연결용 변수
    
    void Start()
    {
    	s_State = GameState.PowerIng;  //초기화
        
        if(Reset_Btn != null)    //Reset_Btn이 잘 연결되어 있으면
        	Reset_Btn.onClick.AddListener(ResetClick);
     }
     		:
     void ResetClick()
     {
     	s_State = GameState.GameEnd;	//게임 종료 상태
        SceneManager.LoadScene("GameScene");	//GameScene으로 씬전환
      }
 }

 

 

완성 소스

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public enum GameState   //정수값 대신 사용되는 별칭 집합
{
    PowerIng  = 0,  //파워를 올릴 수 있는 상태
    RotateIng = 1,  //룰렛이 돌고 있는 상태
    GameEnd   = 2   //게임 종료 상태를 의미함
}

public class GameMgr : MonoBehaviour
{
    public static GameState s_State = GameState.PowerIng;   //GameState를 PowerIng로 설정

    int m_NumCount = 0;         //로또 번호 인덱스 카운트용 변수
    public Text[] NumberTexts;  //로또 번호 표시 UI 연결용 변수

    public Button Reset_Btn =null;
    
    void Start()
    {
        s_State = GameState.PowerIng;   // 초기화

        if (Reset_Btn != null)
            Reset_Btn.onClick.AddListener(ResetClick);
    }
   
    void Update()
    {
      
    }

    public void SetNumber(int a_Num)	//숫자 등록
    {
        if(m_NumCount < NumberTexts.Length)
        {
            NumberTexts[m_NumCount].text = a_Num.ToString();
            m_NumCount++;

            if(NumberTexts.Length <= m_NumCount)
            {
                //게임 종료
                s_State = GameState.GameEnd;
            }
        }
    } 
    
    void ResetClick()	//Reset
    {
        s_State = GameState.GameEnd;
        SceneManager.LoadScene("GameScene");
    }
}

 

728x90