【问题标题】:How to control an animation by touch position along a path in Unity3D?如何通过沿Unity3D中的路径触摸位置来控制动画?
【发布时间】:2013-08-15 15:24:46
【问题描述】:

我有一个游戏对象,我想沿特定路径/曲线设置动画,但动画应该由鼠标/触摸位置控制。因此,当我触摸/单击游戏对象并将手指/鼠标移动到路径上/附近(或者可能更容易向下移动)时,游戏对象应该遵循其定义的路径。

我喜欢 iTween,但我认为在这里找不到使用它的解决方案,对吧?

编辑:添加图片:

【问题讨论】:

  • 有没有一些图像或图表可以用来说明这个概念的例子?
  • @Blue 添加了请求的图像。
  • 简单但说明性的图像 - 正是我们所需要的!在这些情况下,有几种方法,包括捕捉和补间您的输入。 @Heisenbug 的回答太棒了,以它为起点,看看它是否对您有所帮助。

标签: animation path unity3d itween


【解决方案1】:

这比您想象的要简单得多。

基本上,这是一个将函数(将输入作为参数)重新映射到另一个函数(表示沿路径的位置)的问题。 有几种方法可以做到这一点,具体取决于您要实现的确切效果。

您必须做出的最重要的选择是:

  • 如何描述路径/曲线
  • 如何处理输入

示例

对于路径,一种简单灵活的方法是使用某种样条曲线,例如三次Bézier curve。它很容易实现,Unity3D 提供了内置函数来绘制它们。看看Handles.DrawBezier

基本上,Bézier 函数将域 t 中的参数 t 作为输入,并作为结果返回空间中的一个点(您喜欢 2D 或 3D)。 B(0) 给出曲线起点,B(1) 终点。 (旁注:该函数不是线性的,因此在一般情况下以恒定速率递增 t 不会产生沿曲线以恒定速度移动。这 paper 可能有用)。

对于输入的问题,我想到的更简单的解决方案如下:

  • 在某处累积描述从触摸开始位置到当前触摸位置的偏移量的向量。 (Here 的触摸处理方法,请看deltaPosition)。

类似:

if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) 
{
  offsetFromStartPos += Input.GetTouch(0).deltaPosition;
}

假设您要向上/向下滑动手指以沿路径向前/向后移动对象。为您的手指选择“移动”距离(输入函数的域)以完成沿路径的移动曲线并使用该距离对偏移量进行归一化,以便将输入重新映射到[0,1] 域。

float t = offsetFromStartPos.y / maxDistanceAlongYAxis;
Vector3 pos = CalculateBezier(t);
transform.position = pos;

这只是将您引向正确方向的提示。

【讨论】:

  • 嘿,谢谢!这是一个很好的提示,我将通过它并尝试一些测试。也许“Slerp”在这里也可以提供帮助。
  • +1 我喜欢这样的答案,你会得到提示,而不是“粘贴此代码”。它促进了正确方向的思考,并帮助用户解决问题而不是粘贴答案。
  • 这很有帮助,但该图显示了各个方向的运动......如何将任意运动映射到 t?
【解决方案2】:

我用键盘试过了,它工作正常, 但不是用鼠标或触摸

using System;
using UnityEngine;

public class Collector : MonoBehaviour
{
    public Transform startPoint;
    public Transform middlePoint;
    public Transform endPoint;

    public float curveSpeed = 0.5f;
    //public float speed = 0f;
    private int _direction = 1;

    private bool _isObjectSelected;
    private Vector3 _mouseLastPosition;
    private float _journeyLength;
    private Vector3 _offsetPos;

    private float _currentTime = 0;

    private void Start()
    {
        _journeyLength = Vector3.Distance(startPoint.position,
                                            endPoint.position);

        UpdateJourney(0);
    }

    private void OnMouseDown()
    {
        if (_isObjectSelected)
            return;

        _offsetPos = Vector3.zero;
        _mouseLastPosition = Input.mousePosition;
        _isObjectSelected = true;
    }

    private void OnMouseUp()
    {
        _isObjectSelected = false;
    }

    private void OnMouseExit()
    {
        _isObjectSelected = false;
    }

    private void OnMouseDrag()
    {
        if (_isObjectSelected)
        {
            Debug.LogError("Mouse drag");
            Vector3 currentPosition = Input.mousePosition;
            _offsetPos += currentPosition - _mouseLastPosition;

            float distCovered = _offsetPos.y / _journeyLength;
            UpdateJourney(distCovered);
            _mouseLastPosition = currentPosition;
        }
    }

    private void UpdateJourney(float time)
    {
        if (time < 0)
            time = 0;
        else if (time > 1)
            time = 1;

        _currentTime = time;

        transform.position = 
            QuadraticCurve(startPoint.position, 
                            middlePoint.position, 
                            endPoint.position, 
                            _currentTime);

        transform.rotation = Quaternion.Euler(
                            new Vector3(0, 0, 
                                QuadraticCurve(0, 45, 90, _currentTime)));
    }

    private void Update()
    {
        // moving on path using keyboard input
        float direction = Input.GetAxisRaw("Horizontal");
        if (Math.Abs(direction) > 0.1f)
        {
            _currentTime += Time.deltaTime * curveSpeed * direction;
            UpdateJourney(_currentTime);
        }
    }

    private static Vector3 Lerp(Vector3 start, Vector3 end, float time)
    {
        return start + (end - start) * time;
    }

    private static Vector3 QuadraticCurve(Vector3 start, Vector3 middle, Vector3 end, float time)
    {
        Vector3 point0 = Lerp(start, middle, time);
        Vector3 point1 = Lerp(middle, end, time);
        return Lerp(point0, point1, time);
    }

    private static float QuadraticCurve(float start, float middle, float end, float time)
    {
        float point0 = Mathf.Lerp(start, middle, time);
        float point1 = Mathf.Lerp(middle, end, time);
        return Mathf.Lerp(point0, point1, time);
    }
}

【讨论】:

    猜你喜欢
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多