数学:如何通过拖放(Canvas, 2D)来旋转轮子?
Math: How to spin a wheel by drag&drop (Canvas, 2D)?
我正在努力使用可能简单的数学运算 spin/rotate 使用拖放的轮子。
Canvas(Unity UI)中有一个径向布局,它已经可以通过设置一个名为 StartAngle 的 属性 在 0-360 范围内旋转.此 Radial 中有项目,因此 StartAngle 用于第一个项目并将所有子元素放置在布局半径周围。
我想为项目实现拖放功能,这样您就可以四处拖动子对象,径向会相应地(无限地)旋转。
现在,我将此作为起点:
public void OnDrag(PointerEventData eventData)
{
var delta = eventData.delta.x * Time.deltaTime;
var newAngle = radialLayout.StartAngle + delta;
if (newAngle >= 360)
newAngle = newAngle - 360;
else if (newAngle < 0)
newAngle = Mathf.Abs(360 - newAngle);
radialLayout.StartAngle = newAngle;
}
有点效果,但感觉不是很流畅。这是针对 mobile/touch,因此我希望同时考虑拖动操作的 X 和 Y 增量。显然,我的例子中没有考虑 y 增量,我不知道如何正确地合并它。用户可能会在任一轴上进行线性拖放,或者 he/she 也可能会像圆形拖动一样进行。
那么如何将鼠标移动映射到 0-360 度的旋转角度,以便感觉良好?
编辑:感谢您的帮助,我现在是这样做的:
public void OnDrag(PointerEventData eventData)
{
// Note the "Head-Minus-Tale rule for Vector subtraction, see http://www.maths.usyd.edu.au/u/MOW/vectors/vectors-3/v-3-7.html
// vSourceToDestination = vDestination - vSource;
// First, we draw a vector from the center point of the radial to the point where we started dragging
var from = dragStartPoint - (Vector2)radialLayout.transform.position;
// Next, we draw a vector from the center point of the radial to the point we are currently dragging on
var to = eventData.position - (Vector2)radialLayout.transform.position;
// Now, we calculate the angle between these two:
var dragAngle = Vector2.SignedAngle(from, to);
// Lerping makes movement fast at the beginning slow at the end
var lerpedAngle = Mathf.Round(Mathf.LerpAngle(radialLayout.StartAngle, dragAngle, 0.5f));
radialLayout.StartAngle = lerpedAngle;
}
我不知道你所有的代码和类型,但我有一个想法。我现在无法对此进行测试,也无法保证它甚至可以像这样工作,但我希望这个想法变得清晰。
我可能更愿意使用
// This is the vector from the center of the object to the mouse/touch position
// (in screen pixel space)
var touchDirection = eventData.position - Camera.main.WorldToScreenPoint(transform.position);
// angle between the Up (Y) axis and this touchDirection
// for the angle the length of the up vector doesn't matter so there is
// no need to convert it to pixel space
var targetAngle = Vector2.SignedAngle(Vector2.up, touchDirection);
// since the returned angle might be negative wrap it to get values 0-360
if(targetAngle < 0) targetAngle += 360;
// Now either simply use Lerp
// this would simply interpolate each frame to the middle of both values
// the result is a fast movement at the beginning and a very slow at the end
radialLayout.StartAngle = Mathf.Lerp(radialLayout.StartAngle, targetAngle, 0.5f);
// or maybe use a fixed speed like 30°/second
var difference = targetAngle - radialLayout.StartAngle;
radialLayout.StartAngle += Mathf.Sign(difference) * Mathf.Min(30f * Time.deltaTime, Mathf.Abs(difference));
在智能手机上打字,但我希望思路清晰
我正在努力使用可能简单的数学运算 spin/rotate 使用拖放的轮子。
Canvas(Unity UI)中有一个径向布局,它已经可以通过设置一个名为 StartAngle 的 属性 在 0-360 范围内旋转.此 Radial 中有项目,因此 StartAngle 用于第一个项目并将所有子元素放置在布局半径周围。
我想为项目实现拖放功能,这样您就可以四处拖动子对象,径向会相应地(无限地)旋转。
现在,我将此作为起点:
public void OnDrag(PointerEventData eventData)
{
var delta = eventData.delta.x * Time.deltaTime;
var newAngle = radialLayout.StartAngle + delta;
if (newAngle >= 360)
newAngle = newAngle - 360;
else if (newAngle < 0)
newAngle = Mathf.Abs(360 - newAngle);
radialLayout.StartAngle = newAngle;
}
有点效果,但感觉不是很流畅。这是针对 mobile/touch,因此我希望同时考虑拖动操作的 X 和 Y 增量。显然,我的例子中没有考虑 y 增量,我不知道如何正确地合并它。用户可能会在任一轴上进行线性拖放,或者 he/she 也可能会像圆形拖动一样进行。
那么如何将鼠标移动映射到 0-360 度的旋转角度,以便感觉良好?
编辑:感谢您的帮助,我现在是这样做的:
public void OnDrag(PointerEventData eventData)
{
// Note the "Head-Minus-Tale rule for Vector subtraction, see http://www.maths.usyd.edu.au/u/MOW/vectors/vectors-3/v-3-7.html
// vSourceToDestination = vDestination - vSource;
// First, we draw a vector from the center point of the radial to the point where we started dragging
var from = dragStartPoint - (Vector2)radialLayout.transform.position;
// Next, we draw a vector from the center point of the radial to the point we are currently dragging on
var to = eventData.position - (Vector2)radialLayout.transform.position;
// Now, we calculate the angle between these two:
var dragAngle = Vector2.SignedAngle(from, to);
// Lerping makes movement fast at the beginning slow at the end
var lerpedAngle = Mathf.Round(Mathf.LerpAngle(radialLayout.StartAngle, dragAngle, 0.5f));
radialLayout.StartAngle = lerpedAngle;
}
我不知道你所有的代码和类型,但我有一个想法。我现在无法对此进行测试,也无法保证它甚至可以像这样工作,但我希望这个想法变得清晰。
我可能更愿意使用
// This is the vector from the center of the object to the mouse/touch position
// (in screen pixel space)
var touchDirection = eventData.position - Camera.main.WorldToScreenPoint(transform.position);
// angle between the Up (Y) axis and this touchDirection
// for the angle the length of the up vector doesn't matter so there is
// no need to convert it to pixel space
var targetAngle = Vector2.SignedAngle(Vector2.up, touchDirection);
// since the returned angle might be negative wrap it to get values 0-360
if(targetAngle < 0) targetAngle += 360;
// Now either simply use Lerp
// this would simply interpolate each frame to the middle of both values
// the result is a fast movement at the beginning and a very slow at the end
radialLayout.StartAngle = Mathf.Lerp(radialLayout.StartAngle, targetAngle, 0.5f);
// or maybe use a fixed speed like 30°/second
var difference = targetAngle - radialLayout.StartAngle;
radialLayout.StartAngle += Mathf.Sign(difference) * Mathf.Min(30f * Time.deltaTime, Mathf.Abs(difference));
在智能手机上打字,但我希望思路清晰