我有一个游戏对象,我想沿着特定的路径/曲线制作动画,但动画应该由鼠标/触摸位置控制。因此,当我触摸/单击游戏对象并将手指/鼠标移动到路径上/附近(或者可能更容易向下移动)时,游戏对象应该遵循其定义的路径。
我喜欢 iTween,但我认为在这里找不到使用它的解决方案,对吧?
编辑:添加图像:
这比你想象的要简单得多。
基本上这是一个将函数(将输入作为参数)重新映射到另一个函数(表示沿路径的位置)的问题。有几种方法可以做到这一点,具体取决于您要实现的精确效果。
您必须做出的最重要的选择是:
例子
对于路径,一种简单灵活的方法是使用某种样条曲线,例如三次贝塞尔曲线。它易于实现并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;
这只是将您引向正确方向的提示。
我尝试使用键盘并且它工作正常,但没有使用鼠标或触摸
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);
}
}