为了账号安全,请及时绑定邮箱和手机立即绑定

使用虚拟操纵杆旋转 2D Sprite

使用虚拟操纵杆旋转 2D Sprite

C#
繁星淼淼 2021-10-23 16:27:44
我正在尝试使用操纵杆沿 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);            }        }    }
查看完整描述

2 回答

?
蝴蝶刀刀

TA贡献1801条经验 获得超8个赞

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


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则Rigidbody2D.MoveRotation在FixedUpdate函数中使用。其余代码保持不变。


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

    }

}


查看完整回答
反对 回复 2021-10-23
?
catspeake

TA贡献1111条经验 获得超0个赞

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


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


查看完整回答
反对 回复 2021-10-23
  • 2 回答
  • 0 关注
  • 186 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信