【问题标题】:Playing animation with swipe controls and transform.position problem Unity使用滑动控件播放动画和 transform.position 问题 Unity
【发布时间】:2019-04-16 13:39:04
【问题描述】:

我已经设置了我的滑动控件来改变我的播放器左/右/上/下,我已经限制了 3 行的移动; -1, 0, 1。一切正常,但运动一点也不流畅,玩家似乎正在从一个位置“传送”到另一个位置。我想通过播放动画来平滑运动,但结果是在玩家改变他的位置后播放动画。 有什么方法可以在玩家改变他的位置时播放动画,或者有什么方法可以平滑运动,使其看起来正确?

我已经尝试了所有方法,但现在我遇到了问题,请帮助

这是我的代码

  public class SwipeControls : MonoBehaviour {

    public float speed = 5.0f;
    private Vector3 startpos;  // start position
    private Vector3 endpos; //end position
    public int pozioma = 0;
    public int pionowa = 0;

    Animator anim;


    void Start() {
      GetComponent<Animator>();
    }

    void Update() {

      foreach (Touch touch in Input.touches) {

        Vector3 newPosition;
        if (touch.phase == TouchPhase.Began) {
          startpos = touch.position;
          endpos = touch.position;
        }

        if (touch.phase == TouchPhase.Moved) {
          endpos = touch.position;
        }

        if (touch.phase == TouchPhase.Ended) {
          newPosition = transform.position;

          if (Mathf.Abs(startpos.y - endpos.y) > Mathf.Abs(startpos.x - endpos.x)) {
            if ((startpos.y - endpos.y) > 100 && pionowa > -1) //swipe down
            {
              pionowa--;
              newPosition.y -= speed;
              transform.position = newPosition;
              anim.SetTrigger("Flydown");
            }

            if ((startpos.y - endpos.y) < -100 && pionowa < 1) //swipe up
            {
              pionowa++;
              newPosition.y += speed;
              transform.position = newPosition;
              anim.SetTrigger("Flyup");
            }
          }
          else {
            if ((startpos.x - endpos.x) > 100 && pozioma > -1)  //swipe left
            {
              pozioma--;
              newPosition.z -= speed;
              transform.position = newPosition;
              anim.SetTrigger("Flyleft");
            }
          }

          if ((startpos.x - endpos.x) < -100 && pozioma < 1) //swipe right
          {
            pozioma++;
            newPosition.z += speed;
            transform.position = newPosition;
            anim.SetTrigger("Flyright");
          }
        }
      }
    }
  }

【问题讨论】:

    标签: c# visual-studio unity3d


    【解决方案1】:

    修改你的代码而不是仅仅使用

    transform.position = newPosition;
    

    在所有位置使用

    transform.position = Vector3.Lerp(transform.position, newPosition, smooth * Time.deltaTime);
    

    其中 smooth 是浮点变量,分配它所需的值可能是 0.5f 或您想要的任何值

    注意:它实际上所做的是,它使游戏对象基于平滑值每帧移动很少

    【讨论】:

    • Lerp 使用的问题是它永远不会到达一个确切的位置!相反,它变得非常接近并且非常缓慢。这是稳定时的理想选择,例如一个光标,但在这种情况下不是可选的解决方案,OP 可能会移动到一个确切的位置。
    • 感谢您的回答。不幸的是,它什么也没做,它仍然是一样的。还有其他想法吗?
    • 通过使用协程尝试@derHugo 回答,顺便说一下,当您使用上述代码时,它只是被传送到那个新地方还是根本没有移动?
    • 和没有Lerp的时候基本一样
    【解决方案2】:

    请注意,我们不知道您的动画师设置。如果在这些动画片段中任何位置都有关键帧,那么动画师将始终否决脚本所做的任何事情!


    您可以使用CoroutineStartCoroutine 之类的方式来代替立即设置新位置(同时修复一些编码样式)

    public class SwipeControls : MonoBehaviour
    {
        // Flag for ignoring input until current animation finished
        private bool routineRunning;
    
        // Configure in the Inspector distance to swipe
        // in unity units
        [SerializeField] private float swipeDistance = 5;
    
        // configure this in the Inspector
        // How long should the swiping take in seconds
        [SerializeField] private float swipeDuration = 1;
    
        private Vector3 _startpos;  // start position
        private Vector3 _endpos; //end position
    
        public int pozioma = 0;
        public int pionowa = 0;
    
        private Animator _anim;
    
    
        private void Start()
        {
            GetComponent<Animator>();
        }
    
        private void Update()
        {
            // Ignore any Input while a routine is running
            if (routineRunning) return;
    
            foreach (var touch in Input.touches)
            {
                switch (touch.phase)
                {
                    case TouchPhase.Began:
                        _startpos = touch.position;
                        _endpos = touch.position;
                        break;
    
                    case TouchPhase.Moved:
                        _endpos = touch.position;
                        break;
    
                    case TouchPhase.Ended:
                        if (Mathf.Abs(_startpos.y - _endpos.y) > Mathf.Abs(_startpos.x - _endpos.x))
                        {
                            if (_startpos.y - _endpos.y > 100 && pionowa > -1) //swipe down
                            {
                                pionowa--;
                                StartCoroutine(MoveSmooth(Vector3.up * -1, swipeDuration));
                                _anim.SetTrigger("Flydown");
                            }
                            else if (_startpos.y - _endpos.y < -100 && pionowa < 1) //swipe up
                            {
                                pionowa++;
                                StartCoroutine(MoveSmooth(Vector3.up, swipeDuration));
                                _anim.SetTrigger("Flyup");
                            }
                        }
                        else
                        {
                            if (_startpos.x - _endpos.x > 100 && pozioma > -1) //swipe left
                            {
                                pozioma--;
                                StartCoroutine(MoveSmooth(Vector3.forward * -1, swipeDuration));
                                _anim.SetTrigger("Flyleft");
                            }
                            else if (_startpos.x - _endpos.x < -100 && pozioma < 1) //swipe right
                            {
                                pozioma++;
                                StartCoroutine(MoveSmooth(Vector3.forward, swipeDuration));
                                _anim.SetTrigger("Flyright");
                            }
                        }
                        break;
                }
            }
        }
    
        private IEnumerator MoveSmooth(Vector3 direction, float duration)
        {
            routineRunning = true;
    
            var currentPosition = transform.localPosition;
            var targetPosition = currentPosition + direction * swipeDistance;
    
            var timePassed = 0f;
            do
            {
                // Additionally add some ease in and out to the movement to get 
                // even smoother movement
                var lerpFactor = Mathf.SmoothStep(0, 1, timePassed / duration);
    
                // Interpolate the position between currentPosition and targetPosition
                // using the factor between 0 and 1
                transform.localPosition = Vector3.Lerp(currentPosition, targetPosition, lerpFactor);
    
                // increase by time since last frame
                timePassed += Time.deltaTime;
                // let this frame render and go on from
                // here in the next frame
                yield return null;
            } while (timePassed <= duration);
    
            // To avoid over or undershooting in the end set a fixed value
            transform.localPosition = targetPosition;
    
            routineRunning = false;
        }
    }
    

    我不知道您为什么要使用 y+=z+= .. 在我看来,这意味着相机在您的场景中面向左侧,例如rotation = 0, -90, 0 和例如position = 10, 0, 0 应该是这样的结果(注意我将相同的代码复制到 if(GetMouseButtonDown(0)) 等以模拟 PC 上的触摸。)

    【讨论】:

    • 感谢您的回答!所以现在它的运动更加流畅,但它只对正确的滑动做出响应,而不是向右滑动,而是向后移动,没有任何限制。我无法解决问题
    • 我使用y和z轴的原因是因为我已经从blender导入了我的角色模型并且我的左右滑动控制在z轴上
    • 我不知道这是否重要(因为它不会影响玩家的滑动动作)但角色是一个包含航路点路径的空游戏对象的孩子,所以玩家继续前进一条路径
    • 在这种情况下,您可能想要替换 Vector3.upVector3.forward(它们是 Unity 全局向量)而不是 transform.uptransform.forward 或者甚至可能是 transform.right(它们是对象本地方向向量)并使用方向(* -1
    • 我用玩家创建了一个新场景,没有路径并将 Vector3 更改为变换并且它正在工作,但是当玩家在路径上时,无论我向哪个方向滑动,它都只是向后移动而没有任何限制
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    相关资源
    最近更新 更多