在 Unity3D 中拖动时保持相机和鼠标移动速度相同
Keeping camera & mouse movement speeds the same on Drag in Unity3D
这个问题有点长,请大家多多包涵。
我正在使用 Unity3D 的较新输入系统,我已经能够设置相机移动,因此当用户单击鼠标中键时,他们可以沿 X 轴和 Y 轴拖动相机。然而,它有一种非常视差的感觉,我正在努力避免这种情况。据我了解,这是因为鼠标移动速度和相机移动速度不一样 (See, visual)。
我的输入控制器class:
public class InputController : MonoBehaviour
{
private InputControls inputControls;
[Header("Camera Movement")]
[SerializeField] CameraController cameraController;
private InputAction.CallbackContext context;
void Awake()
{
inputControls = new InputControls();
}
private void Start()
{
inputControls.Mouse.MiddleButton.started += MiddleButton_started;
}
public void MiddleButton_started(InputAction.CallbackContext ctx)
{
context = ctx;
}
private void Update()
{
bool mouseIsDown = context.performed;
if (mouseIsDown)
{
Vector2 delta = inputControls.Mouse.DeltaPosition.ReadValue<Vector2>();
cameraController.Move(delta, false);
}
}
}
我的相机控制器class:
public class CameraController : MonoBehaviour
{
[SerializeField] Vector2 minPosition;
[SerializeField] Vector2 maxPosition;
[SerializeField] float speed = 3;
[SerializeField] float zPosition = -10f;
private Camera mainCam;
private void Start()
{
mainCam = GetComponent<Camera>();
}
public void Move(Vector2 deltaPosition, bool convertToViewportPoint = true)
{
if (convertToViewportPoint) deltaPosition = mainCam.ScreenToViewportPoint(deltaPosition);
Vector3 moveTo = new Vector3(deltaPosition.x, deltaPosition.y, 0);
Vector3 target = transform.position - moveTo;
float clampedX = Mathf.Clamp(target.x, minPosition.x, maxPosition.x);
float clampedY = Mathf.Clamp(target.y, minPosition.y, maxPosition.y);
transform.position = Vector3.Lerp(transform.position, new Vector3(clampedX, clampedY, -10), speed * Time.deltaTime);
}
}
现在,在这个版本的 CameraController 中,视差感可能来自 Lerp 速度恒定的事实,而鼠标移动的速度却不是。
但是,我已经用各种量级(即鼠标位置增量、当前鼠标位置、从鼠标位置增量减去当前鼠标位置等的量级等)进行了测试,一般情况下相同的结果 - 相机移动速度太快,反之亦然。
根据我对三角函数的有限但不断增长的理解,幅度表示矢量的速度,但我无法使相机移动速度和鼠标移动速度相匹配。我希望发生这种情况,以便当用户单击某个点时,该点在移动时通常会停留在光标下方 (See other visual)。
有人可以帮助我了解如何实现这一目标吗?
谢谢。
为了防止有人遇到这个问题,我所做的是在第一次单击鼠标时获取光标的位置。我们可以称之为 dragOrigin
。然后我们可以获取鼠标移动时位置的变化(通过 Unity 的输入系统轮询输入可以通过 Update 函数完成)。然后我们从 dragOrigin 中减去新的鼠标位置。一旦我们有了差异——我们称之为 deltaPosition
——我们只需将它添加到相机的当前位置。
为了确保速度与鼠标的速度匹配,运行deltaPosition和currentMousePosition通过SmoothDamp来获取变化的速度。它的幅度将是您希望相机移动的速度。
例如:
// Call this when the user first clicks the mouse.
// Lets assume this is part of a class that controls the camera.
public void SetDragOrigin(Vector2 mousePosition)
{
// could probably cache Camera.main for efficiency
dragOrigin = Camera.main.ScreenToWorldPoint(mousePosition);
}
// This is called in an update function of another class that deals with input.
// (Or perhaps you can simply pass the input controls to the class controlling the camera, but that's not the case here).
public void Move(Vector2 newMousePosition)
{
mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
Vector2 deltaPosition = dragOrigin - mousePosition;
Vector3.SmoothDamp(deltaPosition, mousePosition, ref dragVelocity, 0.1f, 250f, Time.deltaTime);
cameraPosition += new Vector3(deltaPosition.x, deltaPosition.y, 0) * dragVelocity.magnitude * Time.deltaTime;
// anything else you want to do like clamping camera position
// ....
}
这里要注意的一件事是,SmoothDamp
的第 5 个参数是 maxSpeed。我在此示例中对其进行了硬编码,但您可能想尝试一下。当我没有设置 maxSpeed 时,随着时间的推移 dragVelocity
会发生一些奇怪的事情,因此最好将 maxSpeed 设置为最适合您的值。
这个问题有点长,请大家多多包涵。
我正在使用 Unity3D 的较新输入系统,我已经能够设置相机移动,因此当用户单击鼠标中键时,他们可以沿 X 轴和 Y 轴拖动相机。然而,它有一种非常视差的感觉,我正在努力避免这种情况。据我了解,这是因为鼠标移动速度和相机移动速度不一样 (See, visual)。
我的输入控制器class:
public class InputController : MonoBehaviour
{
private InputControls inputControls;
[Header("Camera Movement")]
[SerializeField] CameraController cameraController;
private InputAction.CallbackContext context;
void Awake()
{
inputControls = new InputControls();
}
private void Start()
{
inputControls.Mouse.MiddleButton.started += MiddleButton_started;
}
public void MiddleButton_started(InputAction.CallbackContext ctx)
{
context = ctx;
}
private void Update()
{
bool mouseIsDown = context.performed;
if (mouseIsDown)
{
Vector2 delta = inputControls.Mouse.DeltaPosition.ReadValue<Vector2>();
cameraController.Move(delta, false);
}
}
}
我的相机控制器class:
public class CameraController : MonoBehaviour
{
[SerializeField] Vector2 minPosition;
[SerializeField] Vector2 maxPosition;
[SerializeField] float speed = 3;
[SerializeField] float zPosition = -10f;
private Camera mainCam;
private void Start()
{
mainCam = GetComponent<Camera>();
}
public void Move(Vector2 deltaPosition, bool convertToViewportPoint = true)
{
if (convertToViewportPoint) deltaPosition = mainCam.ScreenToViewportPoint(deltaPosition);
Vector3 moveTo = new Vector3(deltaPosition.x, deltaPosition.y, 0);
Vector3 target = transform.position - moveTo;
float clampedX = Mathf.Clamp(target.x, minPosition.x, maxPosition.x);
float clampedY = Mathf.Clamp(target.y, minPosition.y, maxPosition.y);
transform.position = Vector3.Lerp(transform.position, new Vector3(clampedX, clampedY, -10), speed * Time.deltaTime);
}
}
现在,在这个版本的 CameraController 中,视差感可能来自 Lerp 速度恒定的事实,而鼠标移动的速度却不是。
但是,我已经用各种量级(即鼠标位置增量、当前鼠标位置、从鼠标位置增量减去当前鼠标位置等的量级等)进行了测试,一般情况下相同的结果 - 相机移动速度太快,反之亦然。
根据我对三角函数的有限但不断增长的理解,幅度表示矢量的速度,但我无法使相机移动速度和鼠标移动速度相匹配。我希望发生这种情况,以便当用户单击某个点时,该点在移动时通常会停留在光标下方 (See other visual)。
有人可以帮助我了解如何实现这一目标吗?
谢谢。
为了防止有人遇到这个问题,我所做的是在第一次单击鼠标时获取光标的位置。我们可以称之为 dragOrigin
。然后我们可以获取鼠标移动时位置的变化(通过 Unity 的输入系统轮询输入可以通过 Update 函数完成)。然后我们从 dragOrigin 中减去新的鼠标位置。一旦我们有了差异——我们称之为 deltaPosition
——我们只需将它添加到相机的当前位置。
为了确保速度与鼠标的速度匹配,运行deltaPosition和currentMousePosition通过SmoothDamp来获取变化的速度。它的幅度将是您希望相机移动的速度。
例如:
// Call this when the user first clicks the mouse.
// Lets assume this is part of a class that controls the camera.
public void SetDragOrigin(Vector2 mousePosition)
{
// could probably cache Camera.main for efficiency
dragOrigin = Camera.main.ScreenToWorldPoint(mousePosition);
}
// This is called in an update function of another class that deals with input.
// (Or perhaps you can simply pass the input controls to the class controlling the camera, but that's not the case here).
public void Move(Vector2 newMousePosition)
{
mousePosition = mainCam.ScreenToWorldPoint(mousePosition);
Vector2 deltaPosition = dragOrigin - mousePosition;
Vector3.SmoothDamp(deltaPosition, mousePosition, ref dragVelocity, 0.1f, 250f, Time.deltaTime);
cameraPosition += new Vector3(deltaPosition.x, deltaPosition.y, 0) * dragVelocity.magnitude * Time.deltaTime;
// anything else you want to do like clamping camera position
// ....
}
这里要注意的一件事是,SmoothDamp
的第 5 个参数是 maxSpeed。我在此示例中对其进行了硬编码,但您可能想尝试一下。当我没有设置 maxSpeed 时,随着时间的推移 dragVelocity
会发生一些奇怪的事情,因此最好将 maxSpeed 设置为最适合您的值。