如何 使 rts 相机 在 Unity 中 缩放 时 平滑

现在 我 正 试图 使 rts 相机 缩放 与 平移 时 , 接近 地面 。我 现在 的 问题 是 , 我 使用 鼠标 滚轮 缩放 , 它 使 缩放 感觉 像 它 的 滞后 。它 看 起来 像 是 跳跃 了 一些 Y 值 和 瞬间 移动 , 而 不是 平滑 地 移动 到 所 需 的 位置 。此外 , 我 还 想 知道 如何 使 相机 停止 在 最 小 Y 值 , 因为 现在 发生 的 是 , 它 停止 在 22 左右 , 而 不是 20 , 这 是 我 的 最 小 Y 值 的 相机 移动 。


我 试 着 在 我 的 numpad 上 用 + 和 - 缩放 , 它 按照 我 想 要 的 方式 工作 ( 平稳 地 放大 和 缩小 而 不 跳 过 ) , 但 并 不 是 所有 的 玩家 都 有 numpad , 我 觉得 用 鼠标 滚轮 缩放 更 合适 。


{


private const int levelArea = 100;


private const int scrollArea = 25;

private const int scrollSpeed = 25;

private const int dragSpeed = 70;


private const int zoomSpeed = 50;


// Maximum/minimum zoom distance from the ground

public int zoomMin = 20;

public int zoomMax = 120;


private const int panSpeed = 40;


// Minimal/maximal angles for camera

private const int panAngleMin = 30;

private const int panAngleMax = 90;



void Update()

{

    // Init camera translation for this frame.

    var translation = Vector3.zero;


    // Zoom in or out

    var zoomDelta = Input.GetAxis("Mouse ScrollWheel") * zoomSpeed * Time.deltaTime;

    if (zoomDelta != 0)

    {

        translation -= Vector3.up * zoomSpeed * zoomDelta;

    }


    // Start panning camera if zooming in close to the ground or if just zooming out.

    var pan = transform.eulerAngles.x - zoomDelta * panSpeed;

    pan = Mathf.Clamp(pan, panAngleMin, panAngleMax);

    // When to start panning up the camera

    if (zoomDelta < 0 || transform.position.y < (zoomMax -20))

    {

        transform.eulerAngles = new Vector3(pan, 0, 0);

    }


我希望从相机现在所在的位置到滚动进/出后所需的位置有一个平滑的过渡。我还想知道如何使相机停止在最小/最大变焦距离,而不是停止接近它。谢谢你的帮助。摄像机移动的视频:https://youtu.be/Lt3atJEaOjA


呼如林
浏览 267回答 2
2回答

HUH函数

好 的 , 我 现在 要 做 三 件 事 。First and foremost, I'm going to recommend that if you're working with advanced camera behavior, you probably want to at least consider using Cinemachine.我 想 亲自 给 你 讲解 一下 , 但 鉴于 我 缺乏 亲身 经历 , 我 可能 会 给 你 带来 伤害 。有 很多 很 好 的 教程 在 那里 。youtube 和 谷歌 应该 提供 。我要做的第二件事是用我能管理的最直接的方式解决你的问题,然后,我们再看看是否能想出一个更好的方法来解决你的问题。所以,这里的关键是Unity的滚轮输入是非常二进制的。当你检查一个滚轮轴时,结果直接基于自上次帧更新以来你的滚轮经历了多少次“点击”,但你真正想要的是一些有一点给予的东西。默认情况下,Unity实际上可以对大多数轴输入执行此操作:您可能会注意到,如果您在默认Unity项目中使用WASD,则会有一种“滞后”现象,您的手指会离开按键,但仍会从输入.获取轴()对于几个帧。这与重力输入设置中的值,以及输入.GetAxisRaw()函数实际上是用来完全规避这一点的。不管出于什么原因,滚轮轴似乎不受轴重力的影响,所以我们本质上必须自己实现类似的东西。// Add this property to your class definition (so it persists between updates):private float wheelAxis = 0;// Delete this line:var zoomDelta = Input.GetAxis("Mouse ScrollWheel") * zoomSpeed * Time.deltaTime;// And put these three new lines in its place:wheelAxis += Input.GetAxis("Mouse ScrollWheel");wheelAxis = Mathf.MoveTowards(wheelTotal, 0f, Time.deltaTime);var zoomDelta = Mathf.Clamp(wheelAxis, -0.05f, 0.05f) * zoomSpeed * Time.deltaTime;好的,我们在这里做一些事情。每次更新时,我们都会将当前滚轮值添加到轮轴。接下来,我们将电流Time.deltatime“重力”通过数学函数移动到()得双曲余切值.最后,我们称之为“老”缩放增量经过简单修改代码:我们约束轮轴与Mathf.Clamp以尝试和调节变焦可以发生得多快。您 可以 通过 几 种 方式 修改 此 代码 。If you multiply the Time.deltaTime parameter you can affect how long your input will "persist" for. If you mess with the Mathf.Clamp() values, you'll get faster or slower zooming.总 而言 之 , 如果 您 只 想 在 对 代码 进行 最 小 更改 的 情况 下 实现 平滑 缩放 , 这 可能 是 最 好 的 选择 。这样 啊 !现在 我们 已经 完成 了 这些 , 让 我们 来 讨论 一下 您 的 代码 , 以及 您 是 如何 处理 问题 的 , 看看 我们 是否 能 找到 一 个 稍微 干净 一些 的 解决 方案 。让一台好的相机工作起来是非常重要的。你的代码看起来像我看到的很多试图解决复杂问题的代码:看起来您添加了一些功能,然后对其进行了测试,发现了一些崩溃的边缘情况,然后修补了这些情况,然后尝试在旧代码上实现新功能,但它以各种其他方式中断,等等,我们在这一点上得到的有点混乱。你的代码最大的问题是摄像头位置摄像头自转紧密地联系在一起。当与字符工作时,这通常是好的,但当与相机工作时,你想要打破这一点。想想摄像头是以及相机是什么查看作为非常独立的事情来记录。因此 , 这里 有 一 个 工作 的 相机 脚本 , 你 应该 能够 插入 和 运行 :using UnityEngine;public class RTSCamera : MonoBehaviour{&nbsp; &nbsp; public float zoomSpeed = 100f;&nbsp; &nbsp; public float zoomTime = 0.1f;&nbsp; &nbsp; public float maxHeight = 100f;&nbsp; &nbsp; public float minHeight = 20f;&nbsp; &nbsp; public float focusHeight = 10f;&nbsp; &nbsp; public float focusDistance = 20f;&nbsp; &nbsp; public int panBorder = 25;&nbsp; &nbsp; public float dragPanSpeed = 25f;&nbsp; &nbsp; public float edgePanSpeed = 25f;&nbsp; &nbsp; public float keyPanSpeed = 25f;&nbsp; &nbsp; private float zoomVelocity = 0f;&nbsp; &nbsp; private float targetHeight;&nbsp; &nbsp; void Start()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Start zoomed out&nbsp; &nbsp; &nbsp; &nbsp; targetHeight = maxHeight;&nbsp; &nbsp; }&nbsp; &nbsp; void Update()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var newPosition = transform.position;&nbsp; &nbsp; &nbsp; &nbsp; // First, calculate the height we want the camera to be at&nbsp; &nbsp; &nbsp; &nbsp; targetHeight += Input.GetAxis("Mouse ScrollWheel") * zoomSpeed * -1f;&nbsp; &nbsp; &nbsp; &nbsp; targetHeight = Mathf.Clamp(targetHeight, minHeight, maxHeight);&nbsp; &nbsp; &nbsp; &nbsp; // Then, interpolate smoothly towards that height&nbsp; &nbsp; &nbsp; &nbsp; newPosition.y = Mathf.SmoothDamp(transform.position.y, targetHeight, ref zoomVelocity, zoomTime);&nbsp; &nbsp; &nbsp; &nbsp; // Always pan the camera using the keys&nbsp; &nbsp; &nbsp; &nbsp; var pan = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")) * keyPanSpeed * Time.deltaTime;&nbsp; &nbsp; &nbsp; &nbsp; // Optionally pan the camera by either dragging with middle mouse or when the cursor touches the screen border&nbsp; &nbsp; &nbsp; &nbsp; if (Input.GetMouseButton(2)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pan -= new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")) * dragPanSpeed * Time.deltaTime;&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var border = Vector2.zero;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Input.mousePosition.x < panBorder) border.x -= 1f;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Input.mousePosition.x >= Screen.width - panBorder) border.x += 1f;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Input.mousePosition.y < panBorder) border.y -= 1f;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (Input.mousePosition.y > Screen.height - panBorder) border.y += 1f;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pan += border * edgePanSpeed * Time.deltaTime;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; newPosition.x += pan.x;&nbsp; &nbsp; &nbsp; &nbsp; newPosition.z += pan.y;&nbsp; &nbsp; &nbsp; &nbsp; var focusPosition = new Vector3(newPosition.x, focusHeight, newPosition.z + focusDistance);&nbsp; &nbsp; &nbsp; &nbsp; transform.position = newPosition;&nbsp; &nbsp; &nbsp; &nbsp; transform.LookAt(focusPosition);&nbsp; &nbsp; }}虽然我鼓励你在自己的时间里去经历它,但我不打算拖你走过它的每一寸,相反,我只会把主要的症结过一遍。The key idea here is that rather than controlling the camera's height and orientation directly, we just let the scrollwheel dictate where want the camera's height to be, and then we use Mathf.SmoothDamp() to move the camera smoothly into that position over several frames.( Unity 有 很多 像 这样 有用 的 功能 。Consider Mathf.MoveTowards() for an alternative interpolation method.)在 最 后 , 我们 并 没有 直接 调整 摄像 机 的 旋转 值 , 而是 在 我们 面前 靠近 地面 的 地方 选择 一 个 点 , 然后 直接 将 摄像 机 对准 那个 点 。通过保持摄像机的位置和方向完全独立,以及分离出摄像机高度的“动画”,我们避免了很多麻烦,并消除了许多混乱交织的错误的可能性。希望 能 帮 上 忙 。

慕莱坞森

Cinemachine是相当不错的,但我建议人们在使用Cinemachine之前自己学习相当多的东西,这样你就能更好地了解后台发生了什么。
打开App,查看更多内容
随时随地看视频慕课网APP