2

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

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

编辑:添加图像:在此处输入图像描述

4

2 回答 2

4

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

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

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

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

例子

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

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

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

  • 在某处累积描述从触摸开始位置到当前触摸位置的偏移量的向量。(这里是如何处理触摸,看看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;

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

于 2013-08-15T16:46:22.607 回答
0

我尝试使用键盘并且它工作正常,但没有使用鼠标或触摸

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);
    }
}
于 2019-09-03T06:47:23.193 回答