发表于: 4/28/2023
突然发现还没有关于最开始就完成的 “切屏” 部分的内容,也是突然发现这东西还有必要拉出来说一嘴的价值。
一切的起因
虽然在RTS类游戏里大部分人的浏览信息的方式都是鼠标移到屏幕边缘 “拖拽” 过去,不过这更像是表达一种“我要操作那边的单位,给我过去”的想法,而这样也挺麻烦的,有时候我们只是想稍微往那边看看。 在我游戏的过程中发现了一种更为舒适的移动屏幕的方式 “中键拖屏” (什么键都可以啦),按下那个键,屏幕(或者说地图,或者说摄像机)就会跟随鼠标开始移动。
随意的实现 精确的计算
在最初的版本中,通过记录按下 “那个键” 时的鼠标位置和摄像机位置,在鼠标移动时通过系数放大Input.mousePosition
的变化量将其施加给摄像机。
Camera.main.transform.position = camPos - Camera.main.orthographicSize / 20 * CameraSpeed * (Input.mousePosition - initialPos);
通过精心调整CameraSpeed和配合orthographicSize的除数,甚至在支持摄像机缩放的情况下拖动可以完美跟手,可喜可贺!
不过这显然存在一个问题,Input.mousePosition
到世界坐标是显示相关的,一般来讲用鼠标操作游戏物体时都是要转换的。
//var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
能出问题的地方就一定会出问题
因为我有两块不同分辨率的屏幕,把Unity窗口拖过来就发现 “拖动” 不跟手了。
简单的修复
不得不说这就是先人的智慧,你看注释都留好了,只需要小小的修改……
var mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Camera.main.transform.position = camPos - (mousePosition - initialPos);
于是就炸了,拖动距离一远摄像机就开始狂抖。
而据Log显示Camera.main.transform.position
并不像在Inspector里一样不停来回变化。
把设置摄像机位置的代码移到LateUpdate中有效果吗,并没有。
真·先人的智慧
所幸,在我无数个早夭的项目里发现了这样一段代码:
Vector3 m = new(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
Camera.main.transform.position -= m * mainPlay.MouseSensitivity;
虽然没能避免用系数接近真实的移动,不过把从 “The Key” 按下到抬起过程的大Delta分散到了每一帧,这或许有帮助。
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetKey(KeyCode.Mouse2))
{
Vector3 mouseDelta = mousePos - lastMousePos;
Camera.main.transform.position -= mouseDelta;
}
lastMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
完美,任何分辨率,任何缩放都完美。
直到最后仍然未解的烂片
其实这个代码并不太符合我的风格,在同一个Update里出现了两个理应是相同的变量进行了两次一样的转换
——我本来是想这么说的,我想了一天一夜,在一个没有午休的中午过后,写到了这里
——于是突然我意识到这两个看似相同的东西实则不同
——摄像机移动了,于是转换的坐标也改变了
而lastMousePos不变则是应该的,我们要的正是 “地图跟随鼠标” 。
所以一切的抖动大抵都出自摄像机移动后,lastMousePos发生漂移,而此前的思路根本上就有问题——跟手的拖动,initialPos与lastPos是相同的,所以每一次Update中计算出的差值并非鼠标全过程的{位移^delta},而是殊途同归的小小增量。