繁体   English   中英

使用虚拟操纵杆旋转2D精灵

[英]Rotate 2D Sprite with Virtual Joystick

我正在尝试使用操纵杆沿z轴旋转GameObject,但其旋转y轴。 我可能会错过一些数学计算。 有帮助吗? 参考图片 在此处输入图片说明

void FixedUpdate()
    {
        // get input from joystick
        // get input from joystick
        rightJoystickInput = rightJoystick.GetInputDirection();

        float xMovementRightJoystick = rightJoystickInput.x; // The horizontal movement from joystick 02
        float zMovementRightJoystick = rightJoystickInput.y; // The vertical movement from joystick 02


        // if there is only input from the right joystick
        if (rightJoystickInput != Vector3.zero)
        {
            // calculate the player's direction based on angle
            float tempAngle = Mathf.Atan2(zMovementRightJoystick, xMovementRightJoystick);
            xMovementRightJoystick *= Mathf.Abs(Mathf.Cos(tempAngle));
            zMovementRightJoystick *= Mathf.Abs(Mathf.Sin(tempAngle));

            // rotate the player to face the direction of input
            Vector3 temp = transform.position;
            temp.x += xMovementRightJoystick;
            temp.z += zMovementRightJoystick;
            Vector3 lookDirection = temp - transform.position;
            if (lookDirection != Vector3.zero)
            {
                rotationTarget.localRotation = Quaternion.Slerp(rotationTarget.localRotation, Quaternion.LookRotation(lookDirection) * Quaternion.Euler(0, 45f, 0), rotationSpeed * Time.deltaTime);
            }
        }
    }

您不需要问题中的大多数代码,这确实很简单。

1 .Find与角度Mathf.Atan2然后与多个它Mathf.Rad2Deg

2。使用 Quaternion.Euler(new Vector3(0, 0, angle))获得旋转,然后将其应用于对象。

这应该是一个在Update功能不FixedUpdate因为FixedUpdate用于移动Rigidbody对象。

public Transform rotationTarget;
public bool flipRot = true;

void Update()
{
    rightJoystickInput = rightJoystick.GetInputDirection();

    float horizontal = rightJoystickInput.x;
    float vertical = rightJoystickInput.y;

    float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
    angle = flipRot ? -angle : angle;

    rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}

如果使用Rigidbody2D则在FixedUpdate函数中使用Rigidbody2D.MoveRotation 其余代码保持不变。

public Rigidbody2D rg2d;
public bool flipRot = true;

void FixedUpdate()
{
    rightJoystickInput = rightJoystick.GetInputDirection();

    float horizontal = rightJoystickInput.x;
    float vertical = rightJoystickInput.y;

    float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
    angle = flipRot ? -angle : angle;

    rg2d.MoveRotation(angle);
}

编辑

但是唯一的问题是,当我离开操纵杆时,其旋转立即设置为0,这看起来太奇怪了。 我该如何解决?

您必须检测何时在OnPointerUp释放操纵杆,然后慢慢将操纵杆重击回零位置。 您还必须将当前目标对象角度设为零或默认值,这应该在协程函数中完成。 调用OnPointerDown ,停止当前的协程函数。 防止在FixedUpdate手指时运行FixedUpdate的代码, FixedUpdate干扰协同程序功能。

为了完整起见,以下是操纵杆代码和上面的刚体答案的组合:

public class VirtualJoystickController : MonoBehaviour,
    IDragHandler, IPointerUpHandler, IPointerDownHandler
{
    private Image bgImg;
    private Image joystickImg;
    public float mas_distance = 7f;

    void Start()
    {
        bgImg = GameObject.Find("JoystickBGImage").GetComponent<Image>(); // the joysticks background
        joystickImg = GameObject.Find("Joystickthumb").GetComponent<Image>(); // the joystick object to use
    }

    private Vector3 _inputDirection = Vector3.zero;

    //the movementDirection
    public Vector3 joystickInputDirection
    {
        set
        {
            //Change only if value is different from old one
            if (_inputDirection != value)
            {
                _inputDirection = value;

                Debug.Log("Dir: " + _inputDirection);
            }
        }

        get
        {
            return _inputDirection;
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        dragJoyStick(eventData);
    }

    void dragJoyStick(PointerEventData eventData)
    {
        Vector3 tempDir = Vector3.zero;

        Vector2 pos = Vector2.zero;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle
            (bgImg.rectTransform,
            eventData.position,
            eventData.pressEventCamera,
            out pos))
        {

            pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
            pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y);

            float x = (bgImg.rectTransform.pivot.x == 1) ? pos.x * 2 + 1 : pos.x * 2 - 1;
            float y = (bgImg.rectTransform.pivot.y == 1) ? pos.y * 2 + 1 : pos.y * 2 - 1;

            tempDir = new Vector3(x, y, 0);

            if (tempDir.magnitude > 1)
            {
                tempDir = tempDir.normalized;
            }

            joystickImg.rectTransform.anchoredPosition = new Vector3(
              tempDir.x * (bgImg.rectTransform.sizeDelta.x / mas_distance),
                tempDir.y * (bgImg.rectTransform.sizeDelta.y / mas_distance));

            joystickInputDirection = tempDir;
        }
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        released = false;
        //Stop current coroutine
        if (retCoroutine != null)
            StopCoroutine(retCoroutine);

        if (eventData.pointerCurrentRaycast.gameObject == bgImg.gameObject ||
          eventData.pointerCurrentRaycast.gameObject == joystickImg.gameObject)
        {
            OnDrag(eventData);
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        released = true;

        //Stop current coroutine then start a new one
        if (retCoroutine != null)
            StopCoroutine(retCoroutine);
        retCoroutine = StartCoroutine(SlowReturn(returnTime));
    }

    IEnumerator SlowReturn(float duration)
    {
        RectTransform thumbstickTransform = joystickImg.rectTransform;

        Vector3 toPosition = Vector3.zero;
        float counter = 0;

        //Get the current position of the object to be moved
        Vector2 currentThumb = thumbstickTransform.anchoredPosition;

        while (counter < duration)
        {
            counter += Time.deltaTime;

            //Slowly returns thumbstick
            Vector2 tempThumbStickVal = Vector2.Lerp(currentThumb, toPosition, counter / duration);
            joystickInputDirection = tempThumbStickVal;
            thumbstickTransform.anchoredPosition = tempThumbStickVal;

            //Slowly returns the target Object to original pos
            float tempTargetObjAngle = Mathf.Lerp(angle, originalAngle, counter / duration);
            rg2d.MoveRotation(tempTargetObjAngle);

            yield return null;
        }
    }

    public float returnTime = 1.0f;
    public Rigidbody2D rg2d;
    public bool flipRot = true;
    const float originalAngle = 0;
    bool released = true;
    float angle;
    Coroutine retCoroutine;

    void FixedUpdate()
    {
        if (released)
            return;

        float horizontal = joystickInputDirection.x;
        float vertical = joystickInputDirection.y;

        angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
        angle = flipRot ? -angle : angle;

        rg2d.MoveRotation(angle);
    }
}

您的函数将计算您要查看的点:

Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;

这一点在XZ平面上,这就是为什么汽车在Y轴上旋转

如果要在Z轴上旋转,请按如下所示在XY平面上计算一个点:

Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.y += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;

PS:我不知道为什么要用Quaternion.Euler(0,45f,0)乘法-这是Y轴上的恒定角度,这仅意味着每个lookDirection都将旋转45度-我必须看一下现场知道为什么需要这个...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM