绕圆形路径移动时抖动
Jitter when moving around a circular path
这是一个非常奇怪的错误。我创建了以下脚本,旨在通过围绕圆形路径移动并面向鼠标来计算在我的游戏中发射射弹的位置:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileFire : MonoBehaviour
{
[System.Serializable]
public class ButtonDirectionSet {
public string button;
public float direction;
public bool degrees = true;
}
public GameObject projectile;
public Vector2 centerPoint;
public float radius = 1.0f;
public string fireButton = "Fire1";
public bool followMouse = false;
public bool followKeyboard = true;
public List<ButtonDirectionSet> buttonDirectionMap = new List<ButtonDirectionSet>();
public bool degrees = true;
public float direction;
private readonly float maxDirection = 360 * Mathf.Deg2Rad;
// Start is called before the first frame update
void Start()
{
foreach (ButtonDirectionSet set in buttonDirectionMap) {
if (set.degrees) {
set.direction *= Mathf.Deg2Rad;
}
}
if (degrees) {
direction *= Mathf.Deg2Rad;
}
}
void Update()
{
foreach (ButtonDirectionSet set in buttonDirectionMap) {
if (Input.GetButtonDown(set.button)) {
direction = set.direction;
}
}
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard) {
Vector3 mouse = Input.mousePosition;
mouse.z = transform.position.z - Camera.main.transform.position.z;
Vector3 mousePosition = transform.InverseTransformPoint(Camera.main.ScreenToWorldPoint(mouse));
float xPos = mousePosition.x - centerPoint.x;
if (Mathf.Abs(xPos) < 0.1f)
{
xPos = 0.1f * Mathf.Sign(xPos);
}
float yPos = mousePosition.y - centerPoint.y;
if (Mathf.Abs(yPos) < 0.1f)
{
yPos = 0.1f * Mathf.Sign(yPos);
}
direction = Mathf.Atan2(yPos, xPos);
}
if (direction < 0) direction += maxDirection;
transform.localPosition = centerPoint + (new Vector2(Mathf.Cos(direction), Mathf.Sin(direction)) * radius);
}
}
如果您将“跟随键盘”和“跟随鼠标”都设置为 true,则当您按住左键单击按钮时,对象应该朝向鼠标定位。在大多数情况下,这是有效的,但出于某种原因,即使我根本不移动鼠标,对象在一段时间内在两个不同位置之间快速变化的意义上也存在抖动。此外,即使我根本不移动鼠标,“方向”值也会以相同的速率自行切换。这种情况不会一直发生,但它确实经常发生,而且似乎是随机的。
我可以做些什么来减轻或消除这种行为?
由于方向也会抖动,所以你计算方向的方式有问题。
你的方向抖动的原因是 transform.InverseTransformPoint
。由于物体的位置发生了变化,每次移动鼠标相对于物体的位置也发生了变化,因此方向也发生了变化。
这里有两种方法:
1:
Vector2 direction;
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard)
{
Vector3 mouseOnScreen = Camera.main.ScreenToWorldPoint(Input.mousePosition) - new Vector3(centerPoint.x, centerPoint.y, 0);
direction = new Vector2(mouseOnScreen.x, mouseOnScreen.y);
}
transform.localPosition = centerPoint + (direction.normalized * radius);
这是一种不使用角度的简单方法。它获取鼠标在世界 space 中屏幕上的位置。然后它变成一个向量 2 所以 z 值不会影响它。然后,它将新位置设置为中心加上鼠标的方向,其大小为半径
2:
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard)
{
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition) - new Vector3(centerPoint.x, centerPoint.y, 0);
direction = Mathf.Atan2(mousePosition.y, mousePosition.x);
}
transform.localPosition = centerPoint + (new Vector2(Mathf.Cos(direction), Mathf.Sin(direction)) * radius);
这和你做的一样,但稍微清理了一下。这种方法不使用 transform.InverseTransformPoint
,而是减去 centerPoint。即returns从centerPoint到鼠标的向量,以centerPoint为原点。这也是第一个解决方案。
这是一个非常奇怪的错误。我创建了以下脚本,旨在通过围绕圆形路径移动并面向鼠标来计算在我的游戏中发射射弹的位置:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileFire : MonoBehaviour
{
[System.Serializable]
public class ButtonDirectionSet {
public string button;
public float direction;
public bool degrees = true;
}
public GameObject projectile;
public Vector2 centerPoint;
public float radius = 1.0f;
public string fireButton = "Fire1";
public bool followMouse = false;
public bool followKeyboard = true;
public List<ButtonDirectionSet> buttonDirectionMap = new List<ButtonDirectionSet>();
public bool degrees = true;
public float direction;
private readonly float maxDirection = 360 * Mathf.Deg2Rad;
// Start is called before the first frame update
void Start()
{
foreach (ButtonDirectionSet set in buttonDirectionMap) {
if (set.degrees) {
set.direction *= Mathf.Deg2Rad;
}
}
if (degrees) {
direction *= Mathf.Deg2Rad;
}
}
void Update()
{
foreach (ButtonDirectionSet set in buttonDirectionMap) {
if (Input.GetButtonDown(set.button)) {
direction = set.direction;
}
}
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard) {
Vector3 mouse = Input.mousePosition;
mouse.z = transform.position.z - Camera.main.transform.position.z;
Vector3 mousePosition = transform.InverseTransformPoint(Camera.main.ScreenToWorldPoint(mouse));
float xPos = mousePosition.x - centerPoint.x;
if (Mathf.Abs(xPos) < 0.1f)
{
xPos = 0.1f * Mathf.Sign(xPos);
}
float yPos = mousePosition.y - centerPoint.y;
if (Mathf.Abs(yPos) < 0.1f)
{
yPos = 0.1f * Mathf.Sign(yPos);
}
direction = Mathf.Atan2(yPos, xPos);
}
if (direction < 0) direction += maxDirection;
transform.localPosition = centerPoint + (new Vector2(Mathf.Cos(direction), Mathf.Sin(direction)) * radius);
}
}
如果您将“跟随键盘”和“跟随鼠标”都设置为 true,则当您按住左键单击按钮时,对象应该朝向鼠标定位。在大多数情况下,这是有效的,但出于某种原因,即使我根本不移动鼠标,对象在一段时间内在两个不同位置之间快速变化的意义上也存在抖动。此外,即使我根本不移动鼠标,“方向”值也会以相同的速率自行切换。这种情况不会一直发生,但它确实经常发生,而且似乎是随机的。
我可以做些什么来减轻或消除这种行为?
由于方向也会抖动,所以你计算方向的方式有问题。
你的方向抖动的原因是 transform.InverseTransformPoint
。由于物体的位置发生了变化,每次移动鼠标相对于物体的位置也发生了变化,因此方向也发生了变化。
这里有两种方法:
1:
Vector2 direction;
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard)
{
Vector3 mouseOnScreen = Camera.main.ScreenToWorldPoint(Input.mousePosition) - new Vector3(centerPoint.x, centerPoint.y, 0);
direction = new Vector2(mouseOnScreen.x, mouseOnScreen.y);
}
transform.localPosition = centerPoint + (direction.normalized * radius);
这是一种不使用角度的简单方法。它获取鼠标在世界 space 中屏幕上的位置。然后它变成一个向量 2 所以 z 值不会影响它。然后,它将新位置设置为中心加上鼠标的方向,其大小为半径
2:
if ((followKeyboard && followMouse && Input.GetMouseButton(0)) || !followKeyboard)
{
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition) - new Vector3(centerPoint.x, centerPoint.y, 0);
direction = Mathf.Atan2(mousePosition.y, mousePosition.x);
}
transform.localPosition = centerPoint + (new Vector2(Mathf.Cos(direction), Mathf.Sin(direction)) * radius);
这和你做的一样,但稍微清理了一下。这种方法不使用 transform.InverseTransformPoint
,而是减去 centerPoint。即returns从centerPoint到鼠标的向量,以centerPoint为原点。这也是第一个解决方案。