在最近的工作中任务是制作一个导览图系统,需要用到的一个需求就是可以拖动和放大地图,参考网上有很多UI描点大法的实现,我想尝试在摄像机上去实现。
由于地图偏平面,我使用的是用2D模式下的摄像机,将摄像机的Projection(投影)属性设置成,Orthographic。
我首先想到的是通过直接改变摄像机Size实现缩放效果,通过 Input.GetAxis("Mouse ScrollWheel")获取鼠标滚轮的滚动量来改变Size的大小。
public Camera me_camera; // 参与变换的摄像机
public Vector2 range_size = new Vector2(1, 5); // 通过这个来控制Size缩放量
// 位置缩放
public void ScreenZoom()
{
float v = Input.GetAxis("Mouse ScrollWheel"); //获取鼠标滚轮方向
float old_size = me_camera.orthographicSize; // 计算摄像机原来的大小
// 计算移动后的大小
float size = Mathf.Clamp(old_size - v, range_size.x, range_size.y);
me_camera.orthographicSize = size;
}
不过这个效果emmm怎么说吧,通过和别人的地图作比较发现,还是差一些意思。
文章来源地址https://www.toymoban.com/news/detail-492711.html
最后还是找到一个贴子参考,看了他人的文章一下子悟了,参考文章如下。
根据观察,我发现一个规律,别人的缩放是在视点缩放,在摄像机size缩小时位置会无限接近视点位置,而且的移动的长度(相对摄像机到视点的位置)和摄像机size缩放的倍数是相同的,比如摄像机size比原来缩小了 1/2 摄像机就会向视点位置移动原位置的 1/2 。
假设摄像机原来大小是oldSize、位置是pos,缩小后的大小是size、位置是newPos, 视点使用鼠标位置为mousePos,所以得到如下公式:
其中因为视点到摄像机的位置是在坐标系上的,要排除掉原点到摄像机的距离,因为其他条件是已知的,将公式简化则可以得到 newPos。
代码修改如下:
public Camera me_camera; // 参与变换的摄像机
public Vector2 range_size = new Vector2(1, 5); // 通过这个来控制Size缩放量
/// <summary>
/// 根据视点缩放
/// </summary>
public void AnchorZoom()
{
float v = Input.GetAxis("Mouse ScrollWheel");
// 计算摄像机原来的大小
float old_size = me_camera.orthographicSize;
// 计算移动后的大小
float size = Mathf.Clamp(old_size - v, range_size.x, range_size.y);
// 计算摄像机的缩放倍数
float pro = (old_size - size) / old_size;
// 公式
Vector3 position = me_camera.transform.position + (me_camera.ScreenToWorldPoint(Input.mousePosition) - me_camera.transform.position) * pro;
// 应用大小缩放
me_camera.orthographicSize = size;
//位置缩放
me_camera.transform.position = new Vector3(position.x, position.y, me_camera.transform.position.z);
}
其中,mousePosition 的值需要经过ScreenToWorldPoint( ) 方法来转换成世界坐标去进行运算。
缩放搞定,然后是平移功能。摄像机平移功能比较简单,我直接采用的就是平移的方法。
// 参与变换的摄像机
public Camera me_camera;
// 通过这个来控制画面缩放量
public Vector2 range_size = new Vector2(2, 5);
public void ScreenMove()
{
// 鼠标 左键
float x = Input.GetAxis("Mouse X");
float y = Input.GetAxis("Mouse Y");
if (Input.GetMouseButton(0))
{
// 相机位置的偏移量(Vector3类型,实现原理是:向量的加法)
Vector3 moveDir = (x * -me_camera.transform.right) + (y * -me_camera.transform.up);
// 使平移速度被size影响 size 越小移动越慢
float speed = (me_camera.orthographicSize / range_size.y) * 0.5f;
moveDir = moveDir * speed;
// 限制y轴的偏移量
me_camera.transform.position += moveDir;
}
}
制作一个将摄像机的可移动画面划一个范围,超过范围慢慢会回来的效果。于是我将摄像机想象成一个矩形rect,在它的外面有一个更大的矩形rangeRect,然后你只需要判断rect是不是在rangeRect里面。在Unity中直接有Rect可以使用,只需要取分别的顶点在世界坐标里的位置就可以了,这样就可以算出宽和高。
加上限制的平移代码如下:
// 参与变换的摄像机
public Camera me_camera;
// 通过这个来控制画面缩放量
public Vector2 range_size = new Vector2(2, 5);
// 限制运动范围矩形
Rect rect, rangeRect;
void Start()
{
Camera.main.orthographicSize = range_size.y;
// 在这里定义矩形限制的范围
var Start_leftTop = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
var Start_rightButtom = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
rangeRect = new Rect(Start_leftTop.x, Start_leftTop.y, Mathf.Abs(Start_rightButtom.x - Start_leftTop.x), Mathf.Abs(Start_rightButtom.y - Start_leftTop.y));
Camera.main.orthographicSize = range_size.x;
}
void Update()
{
ScreenMove();
}
public void ScreenMove()
{
// 鼠标 左键
float x = Input.GetAxis("Mouse X");
float y = Input.GetAxis("Mouse Y");
if (Input.GetMouseButton(0))
{
// 相机位置的偏移量(Vector3类型,实现原理是:向量的加法)
Vector3 moveDir = (x * -me_camera.transform.right) + (y * -me_camera.transform.up);
// 使平移速度被size影响 size 越小移动越慢
float speed = (me_camera.orthographicSize / range_size.y) * 0.5f;
moveDir = moveDir * speed;
// 限制y轴的偏移量
me_camera.transform.position += moveDir;
}
else //限制摄像机运动范围
{
UpdateNowCameraRect();
//是否出顶
if (rect.y > rangeRect.y)
{
float d = rect.y - rangeRect.y;
me_camera.transform.position -= new Vector3(0, d * 0.05f, 0);
}
// 底低于底部
if (rect.y - rect.height < rangeRect.y - rangeRect.height)
{
float d = (rangeRect.y - rangeRect.height) - (rect.y - rect.height);
me_camera.transform.position -= new Vector3(0, -d * 0.05f, 0);
}
// 低于最左边
if (rect.x < rangeRect.x)
{
float d = rangeRect.x - rect.x;
me_camera.transform.position -= new Vector3(-d * 0.05f, 0, 0);
}
// 高于最右边
if (rect.x + rect.width > rangeRect.x + rangeRect.width)
{
float d = (rect.x + rect.width) - (rangeRect.x + rangeRect.width);
me_camera.transform.position -= new Vector3(d * 0.05f, 0, 0);
}
}
}
/// <summary>
/// 更新当前摄像机的矩形
/// </summary>
void UpdateNowCameraRect()
{
var Now_leftTop = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
var Now_rightButtom = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
rect.Set(Now_leftTop.x, Now_leftTop.y, Mathf.Abs(Now_rightButtom.x - Now_leftTop.x), Mathf.Abs(Now_rightButtom.y - Now_leftTop.y));
}
平移和缩放都完成,最终效果如下。
最后附上所有代码,里面有触控屏上的移动方法,直接下载用就行,因为太长我就不再这里展示啦。
https://download.csdn.net/download/HunagJingLiao/87267232文章来源:https://www.toymoban.com/news/detail-492711.html
到了这里,关于在Unity中通过Camera实现类似地图拉拽缩放的功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!