【问题标题】:Rotate 2D Sprite with Virtual Joystick使用虚拟操纵杆旋转 2D 精灵
【发布时间】:2018-07-23 05:04:31
【问题描述】:

我正在尝试使用操纵杆沿 z 轴旋转游戏对象,但它会旋转 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);
            }
        }
    }

【问题讨论】:

  • 我以前见过这个问题,之所以没有回答,是因为不清楚你到底在做什么。您的意思是用操纵杆将播放器旋转到面向 x 或 -x 的相反方向?任何视觉或视频示例都会很有用
  • 我用参考图像更新了问题。 @程序员
  • 在 100% 不知道它的作用的情况下,您是否尝试过与 Quaternion.Euler(0, 0, 45f) 而不是 Quaternion.Euler(0, 45f, 0) 相乘? :)
  • 我试图改变 Quaternion.Euler(0, 0, 45f) 但是在这样做之后,玩家汽车就像地狱一样吓坏了,我的意思是位置和旋转的每个值都在改变 - @WouterHuysentruit跨度>
  • 而且仅供参考,此代码不是我编写的,它是 Unity Store 中用于 3D 字符而非 2D 的插件。我只是想让它适用于 2D。

标签: c# user-interface unity3d joystick


【解决方案1】:

您不需要问题中的大部分代码,这真的很简单。

1。用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中的代码运行,以免干扰协程功能。

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

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);
    }
}

【讨论】:

  • 啊,非常好,它起作用了,但唯一的问题是当我离开操纵杆时,它的旋转立即设置为 0,这看起来太奇怪了。我该如何解决? @程序员
  • 检查我的编辑。如果您有新的不相关问题,请创建一个新问题。
  • 你看到编辑了吗?
  • 是的,我检查了它,有一个问题是我不希望操纵杆缓慢返回中心,所以我已经修复了它,但我没有得到平滑的旋转。 @程序员
  • 您所要做的就是删除 "//Slowly returns thumbstick" 部分下的代码,但保留 "//Slowly 返回目标下的代码反对原始位置”。这是一件非常简单的事情。
【解决方案2】:

您的函数会计算出您想要查看的点:

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 度 - 我会看看你的场景就知道你为什么需要这个......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 2021-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多