[ProjectT]/개발일지

[21.11.23] 조이스틱 공격_01

치명적흑형 2021. 11. 24. 14:49

총구가 조이스틱 방향으로 회전한다

- 핸들의 Vector2와 Vector2.Zero를 Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg를 이용하여 각도 계산

- 플레이어 스케일이 -일때 각도에 180를 더해준다. (플레이어가 이동 방향에 때라 좌우 반전을 하기 때문)

- 조이스틱에서 손을 때면(핸들의 Vector2가 Vector2. Zero이면)

  총구가 플레이어의 전방을 바라본다 (Quaternion.Euler(0, 0, 0))

추가해야 되는 것

-조이스틱 방향으로 총알 발사

-총알은 화면 벽과 적에게 부딪히면 사라짐(벽이 둘러쌓여 있지만 화면 밖으로 나가도 삭제)

-적에게 부딪힐경우 데미지를 입힌다


무기 회전코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestPlayer : MonoBehaviour
{
    [SerializeField]
    private Joystick attackJoystick;

    [SerializeField]
    private GameObject weapon;

    public void FixedUpdate()
    {
        //공격
        Vector2 attackDir = Vector2.up * this.attackJoystick.Vertical + Vector2.right * this.attackJoystick.Horizontal;
        
        float weaponAngle = GetAngle(attackDir, Vector2.zero);
        
        //플레이어의 X축과 조이스틱이 반대일 경우
        if(this.transform.localScale.x < 0)
        {
            weaponAngle += 180;
        }
        //핸들의 위치가 (0,0)이라면 각도를 초기화
        if(this.attackJoystick.Direction == Vector2.zero)
        {
            this.weapon.transform.rotation = Quaternion.Euler(0, 0, 0);
        }
        else
        {
            this.weapon.transform.rotation = Quaternion.Euler(0, 0, weaponAngle);
        }
    }
    public static float GetAngle(Vector2 vStart, Vector2 vEnd)
    {
        Vector2 v = vEnd - vStart;

        return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
    }
}
무기의 회전을 transform.rotate에 weaponAngle을 넣었는데 weaponAngle이 계속 update되어 계속 회전하는 문제가 생김
(회전된 무기가 다시 회전하는 문제)

this.weapon.transform.rotation = Quaternion.Euler(0, 0, weaponAngle); 를 이용하여 해결
(회전한 Rotation을 무기의 rotation에 할당하는 방식)


Transform.Rotate
오브젝트를 회전 시킴
https://docs.unity3d.com/ScriptReference/Transform.Rotate.html

Quaternion.Euler
z축 주위로 z, x축 주위로 x, y축 주위로 y 각도만큼 회전한(순서대로) Rotation을 반환합니다.
https://docs.unity3d.com/kr/530/ScriptReference/Quaternion.Euler.html
두 벡터 사이의 각도를 구하는 공식

    using UnityEngine;
 
    // return : -180 ~ 180 degree (for unity)
    public static float GetAngle (Vector3 vStart, Vector3 vEnd)
    {
        Vector3 v = vEnd - vStart;
 
        return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
    }
 
 
출처: https://minhyeokism.tistory.com/19 [programmer-dominic.kim]

---------------------------------------------------------------------------

public static float GetAngle(Vector2 vStart, Vector2 vEnd)
{
    Vector2 v = vEnd - vStart;

    return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
}

벡터2로 변경하여 사용
----------------------------------------------------------------------------
반대로 회전될경우
public static float GetAngle(Vector3 vStart, Vector3 vEnd)
    {
        Vector3 v = vEnd - vStart;

        //return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
        return Mathf.Atan2(v.x, v.y) * Mathf.Rad2Deg;
    }

Mathf.Atan2(v.y, v.x) -> Mathf.Atan2(v.x, v.y)
----------------------------------------------------------------------------

Mathf.Atan2
Tan이 y/x인 각도를 라디안 단위로 반환합니다.
반환 값은 x축과 0에서 시작하여 (x,y)에서 끝나는 2D 벡터 사이의 각도입니다.
참고: 이 함수는 x가 0인 경우를 고려하여 0으로 나누기 예외를 던지지 않고 올바른 각도를 반환합니다.
https://docs.unity3d.com/ScriptReference/Mathf.Atan2.html

Mathf.Rad2Deg
라디안을 각도로 변환해주는 상수를 나타냅니다.(읽기전용)
이 값은 360 / (PI * 2)와 같습니다.
https://docs.unity3d.com/kr/530/ScriptReference/Mathf.Rad2Deg.html

전체코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestPlayer : MonoBehaviour
{
    public float speed;
    [SerializeField]
    private Joystick moveJoystick;
    [SerializeField]
    private Joystick attackJoystick;

    //플레이어 방향 0 or 1
    private int reverseScale = 0;

    [SerializeField]
    private GameObject weapon;

    public void FixedUpdate()
    {
        //이동(조이스틱)
        //Vector2 moveDir = Vector2.up * this.moveJoystick.Vertical + Vector2.right * this.moveJoystick.Horizontal;
        //Debug.Log(direction);
        //if (moveDir.x < 0)
        //{
        //    if(this.reverseScale != 0)
        //    {
        //        this.reverseScale = 0;
        //        this.transform.localScale = new Vector2(this.transform.localScale.x * -1, this.transform.localScale.y);
        //    }
        //}
        //else if (moveDir.x > 0)
        //{
        //    if (this.reverseScale != 1)
        //    {
        //        this.reverseScale = 1;
        //        this.transform.localScale = new Vector2(this.transform.localScale.x * -1, this.transform.localScale.y);
        //    }
        //}
        //this.transform.Translate(moveDir * this.speed * Time.deltaTime);

        //이동(키보드)

        //좌 이동
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            //방향 * 속도 * 시간
            this.transform.Translate(Vector2.left * this.speed * Time.deltaTime);

            if (this.reverseScale != 0)
            {
                this.reverseScale = 0;
                this.transform.localScale = new Vector2(this.transform.localScale.x * -1, this.transform.localScale.y);
            }
        }
        //우 이동
        if (Input.GetKey(KeyCode.RightArrow))
        {
            this.transform.Translate(Vector2.right * this.speed * Time.deltaTime);

            if (this.reverseScale != 1)
            {
                this.reverseScale = 1;
                this.transform.localScale = new Vector2(this.transform.localScale.x * -1, this.transform.localScale.y);
            }
        }
        //상 이동
        if (Input.GetKey(KeyCode.UpArrow))
        {
            this.transform.Translate(Vector2.up * this.speed * Time.deltaTime);
        }
        //하 이동
        if (Input.GetKey(KeyCode.DownArrow))
        {
            this.transform.Translate(Vector2.down * this.speed * Time.deltaTime);
        }



        //공격
        Vector2 attackDir = Vector2.up * this.attackJoystick.Vertical + Vector2.right * this.attackJoystick.Horizontal; //노멀라이즈?

        float weaponAngle = GetAngle(attackDir, Vector2.zero);
        if(this.transform.localScale.x < 0)
        {
            weaponAngle += 180;
        }
        if(this.attackJoystick.Direction == Vector2.zero)
        {
            this.weapon.transform.rotation = Quaternion.Euler(0, 0, 0);
        }
        else
        {
            this.weapon.transform.rotation = Quaternion.Euler(0, 0, weaponAngle);
        }
    }
    public static float GetAngle(Vector2 vStart, Vector2 vEnd)
    {
        Vector2 v = vEnd - vStart;

        return Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
    }
}

 


 

각도구하기 참고 블로그
https://wiseraintown.tistory.com/8