[Unity] Joystick 제작 원리

728x90

유니티 조이스틱 시스템 제작 방법

유니티로 모바일 게임을 제작할 때 조이스틱 시스템을 가져와 플레이어의 움직임을 구현하곤 한다. 보통은 애셋을 가져다 쓰기 때문에 조이스틱 제작 방법이 어렵다고 생각하나, 사실은 기본적인 이동 공식과 Vector3 자료형 값 만으로 구현할 수 있다. 조이스틱의 원리 역시 방향 설정(방향 벡터)과 관련이 있기 때문이다.

 

조이스틱 제작에 대한 기본적인 아이디어는 다음과 같다.

 1. 조이스틱을 만들고 싶다.

    - UI가 마우스를 따라서 이동하도록 처리

    - 조이스틱이 가리키는 방향을 찾고 싶다

    - <방향 벡터 : 움직인 지점 - 원래 있던 지점>

2. 플레이어의 방향을 찾는다.

 

외부 클래스를 static으로 선언해 플레이어 이동에 가져오는 방법

// 플레이어 이동 스크립트
float h = Joystick.GetAxis("Horizontal)";
float v = Joystick.GetAxis("Vertical");

Vector3 dir = Vector3.right * h + Vector3.up * v;
dir.Normalize();

transform.position += dir * speed * Time.deltaTime;
public Class Joysitc
{
	static bool bDown = false;
    static Vector3 lastMousePos;
    
    public static float GetAxis(string axis)
   {
   		if(axis == "Horizontal")
        	return GetDirection().x;
        else if(axis == "Vertical")
        	return GetDirection().y;
        else
        	return 0;
   }
   
   public static Vector3 GetDirection()
   {
   		Vector3 dir = Vector3.zero;
        if(Input.GetButtonDown("Fire1"))
        {
        	bDown = true;
            lastMousePos = Input.mousePosition;
        }
        if(Input.GetButtonUp("Fire1"))
        	bDown = false;
        if(bDown)
        	dir = Input.mousePostion - lastMousePos;
        
        return dir.normalized;
   }
}

다음과 같이 Joystick 클래스를 만들어서 플레이어 이동 스크립트에 가져왔다. 이렇게 할 경우 플레이어 이동 뿐만 아니라, 여러 다른 캐릭터 이동 스크립트에서도 사용할 수 있기 때문에 사용성이 향상된다는 장점이 있다.(유틸리티 코드)

그 외에 Event Trigger의 마우스 클릭 이벤트를 사용해서 만들수 도 있다. 그 부분은 더 공부를 해서 구현해볼 것이다.

 

 

조이스틱 생성 및 이동범위 제한 응용 기능 제작 방법

추가적으로 화면을 터치했을 때 마다 조이스틱의 초기 생성 위치가 설정되고, 조이스틱의 드래그 이동 범위를 제한해주는 방법도 응용해서 구현해 볼 수 있겠다. 기본적으로 방향 벡터를 이용해 조이스틱의 드래그 UI를 보여주고 movVector 변수를 더해 범위 내로 이동을 제한하는 방식으로 아이디어를 구상해 볼 수 있겠다. 또한 Mathf.Clamp 함수를 사용해 조이스틱 초기 생성 위치에서 이동 범위를 제한할 수도 있겠다.

// 움직이는 데 사용될 방향
    public Vector3 dir;

    // 조이스틱 배경 이미지
    public RectTransform joystickBG;
    // 조이스틱 스틱
    public RectTransform stick;

    // 처음 마우스를 누른 위치
    Vector3 basePos;
    // 드래그 시 현재 위치
    Vector3 currentPos;

    // Start is called before the first frame update
    void Start()
    {
        // 조이스틱을 보이게 설정한다
        joystickBG.gameObject.SetActive(false);
        stick.gameObject.SetActive(false);
    }

    // 처음 마우스를 눌렀을 때
    public void OnStickDown()
    {
        // 그 위치를 기준점으로 잡고
        basePos = Input.mousePosition;

        // 조이스틱을 그 위치로 지정한다
        joystickBG.anchoredPosition = basePos;
        stick.anchoredPosition = basePos;

        // 조이스틱을 보이게 설정한다
        joystickBG.gameObject.SetActive(true);
        stick.gameObject.SetActive(true);

        // 방향을 초기화한다
        dir = Vector3.zero;
    }

    // 드래그하면
    public void OnStickDrag()
    {
        // 현재 위치를 저장하고
        currentPos = Input.mousePosition;

        // 기준점으로부터의 거리를 80으로 제한한다
        Vector3 v = Vector3.ClampMagnitude(currentPos - basePos, 80f);

        // 스틱의 위치를 기준점에서 v를 더한 위치로 지정한다
        stick.anchoredPosition = basePos + v;

        // 뱡항을 갱신한다
        dir = v.normalized;
    }

    public void OnStickUp()
    {
        // 조이스틱을 보이지 않게 설정한다
        joystickBG.gameObject.SetActive(false);
        stick.gameObject.SetActive(false);

        // 방향을 초기화한다
        dir = Vector3.zero;
    }
if (Input.GetButtonDown("Fire1"))
        {
            // 시작점이 발생(조이스틱의 시작점)
            startPoint = Input.mousePosition;

            // 시작점 UI가 나오게
            startPoint_UI.SetActive(true);
            startPoint_UI.transform.position = startPoint;

            // 움직이는 점 UI가 나오게
            movePoint_UI.SetActive(true);
            movePoint_UI.transform.position = startPoint;
        }

        // 클릭을 하고 있는 동안
        if(Input.GetButton("Fire1"))
        {
            movePoint = Input.mousePosition;

            // UI가 마우스를 따라다니게
            movePoint_UI.transform.position = movePoint;
            // 방향
            moveDir = movePoint - startPoint;
            moveDir.Normalize();

            // 만약 시작점과 움직이는 점의 거리가 30이 넘으면
            if(Vector3.Magnitude(movePoint-startPoint)>=30)
            {
                // 거리를 30으로 제한
                movePoint_UI.transform.position = startPoint_UI.transform.position + moveDir * 30f;
            }
        }
728x90