上一篇:
第三节
Scripts文件夹下新建CameraCotroller 脚本,先实现zoom功能
摄像头是orthographic正交视图,所以可以通过控制size达到zoom效果。手动调整size可以得到两点:不需要太远,不能太近导致负值翻转画面,所以可以用到mathf clamp控制取值范围。
开始编写脚本,加几点注释,
//通过改变size达到改变镜头远近,
//mathf.clamp方法限定取值范围,
//通过获取鼠标滚轮值达到目的
那么开始吧:
private void LateUpdate()
这里可以用update方法也行的,从执行顺序来说,鼠标滚轮控制加载不需要优先执行,
如果今后update方法里面要执行的信息较多,还是推荐用LateUpdate()稍晚加载zoom功能。
这里按初学者习惯,都放在update方法里好了
我们先获取size吧:
{
Camera.main.orthographicSize
这个数值是通过手动调整获得,初始size。我们可以修改为通过鼠标滚轮获取,
那么先顺便写一个debug测试是否能正确获取鼠标滚轮值的变化:
Debug.Log(Input.GetAxis("Mouse ScrollWheel"));
再补齐咱们size获取方式:
Camera.main.orthographicSize -= Input.GetAxis("Mouse ScrollWheel");
}
脚本挂载到maincamera,开始游戏测试看看log输出。
测试速度太慢,加个系数,比如10f;
测试ok,定义一个private float scrollSpeed =10f;系数改成scrollSpeed;
测试ok,现在需要控制拉近时滚动速度,降低速度达到平滑拉近效果
定义一个滚动倍数:
private float scrollMultiplier;
Update里输入
scrollMultiplier = Camera.main.orthographicSize * .1f;
Debug.Log(Input.GetAxis("Mouse ScrollWheel"));
Camera.main.orthographicSize -= Input.GetAxis("Mouse ScrollWheel")*(scrollSpeed*scrollMultiplier);
测试平滑拉近效果ok,再观察限制合适的size范围,最小1.3f,最大16f比较合适,使用mathf数学函数中的clamp方法限定
个人习惯,将所有相关系数都定义个变量名,
private readonly float minSize =2f;
private readonly float maxSize=20f;
Camera.main.orthographicSize显得太长,我们也改一改
开头定义 private float currentOrthoSize = 5f;
Update方法里修改:
增加一行:Camera.main.orthographicSize = currentOrthoSize;
同时将
Camera.main.orthographicSize =Mathf.clamp(Camera.main.orthographicSize-= Input.GetAxis("Mouse ScrollWheel")*(scrollSpeed*scrollMultiplier),minSize,Maxsize);
改为:
currentOrthoSize = Mathf.Clamp(currentOrthoSize -= Input.GetAxis("Mouse ScrollWheel") *
(scrollSpeed * scrollMultiplier), minSize, maxSize);
看上去舒服了一些,咱们保存,测试ok,zoom功能实现完毕
下一步实现鼠标中键按住后拖拽画面功能
我们想要在鼠标中键按下后,拖动鼠标,摄像机也跟随鼠标方向平移,那么我们要获取一个鼠标中键按下的初始位,然后定义一个偏移量
定义一个初始位,一个偏移量
private vector3 mouseOriginPoint;
private vector3 offset;
If (Input.getMouseButton(2))
{
Offset=(Camera.main.screenToWorldPoint(Input.mouse.Position)-Camera.main.tranform.position)
o
ffset是偏移量,
screenToWorldPoint见
【示例图】screentoworldpoint.jpg,
screenToWorldPoint - transform.position得到抓取点和咱们摄像头之间的偏移向量offset(值+方向),
因为咱们脚本是挂载到camera组件下的,所以可以去掉camera.main,直接写tranform.position,
【示意图】见offset.jpg,
如何计算则参考
【示意图】offset2.jpg
继续,判断是否在拖拽中
开头定义一个
private bool dragging;
UPdate里面继续写在鼠标中键按住的情况下,进行分析判断:
If(!dragging)
{
mouseOriginPoint=Camera.main.screenToWorldPoint(Input.mouse.Position);
dragging=true;
}
目的是只调用一次Input.mouse.Position赋值给OriginPoint,我们只需要获得一次初始拖拽点,当我们开始拖拽时候,我们不需要每一帧重复赋值给初始位。因此立马赋值dragging为true,使得下一帧执行lateupdate内容时候,跳出此if选择支
继续
拖拽初始位获得之后,我们再拿到拖拽过程中相机偏移位置就可以完成需求了:
之前在鼠标中键按住情况下,计算了初始位和偏移量offset,同时发送了一个dagging状态,我们在新的判断中,只需要读取dragging为true,就可以计算相机新的位置:
if(dragging)
{Tranform.position=mouseOriginPoint-offset;}
如何理解获得了相机偏移量,见
【示例图】camera movement.jpg
【camera movement2.jpg】
这里为大家简单介绍一下高中数学知识,向量的加减法。
向量相减规则:OB-OC,先首部相连,减向量OC终点C指向被减向量OB的终点B
向量相加则等于对角线向量。
originpoint-offset=
OA-(OB-OC)
=OA-OB+OC
=BA+OC
=OD+OC
=OE
获得最终摄像机position为E点,移动向量为CE,在这个正交45度xy轴双旋转镜头视角情况下,我们的CE和
BA也是平行且数值相等的。
最终效果就是,镜头位置相对于世界坐标系中的点,相减可以获得一个镜头相对于这个点的参考偏移量
我们简单总结下普通点和点之间移动变化量计算:
点A移动到B后,新点OA-旧点OB,则是A与B之间的移动量
有参考偏移量offset之后,一个点对于另一个点的移动量计算:
比如C点相对于B移动到A点之后,OA-OFFSET(参考偏移量),结果就是C相对于OB的偏移量CB为参考量,对于OA发生对应偏移,变成OE,我们根据E点位置可以获得最终偏移位置,以及偏移量,即图中的CE,类似于放风筝,风筝偏移地面一截绳子的长度,地面你移动到A点,风筝C相对于绳子,在空中也移动到E,就是这么个意思。CB这个向量作为参考系或者说一个限制轴,以它为规则,跟随BA行动,
表达式就是
OA-OFFSET
拖拽核心功能实现就是这样,我们测试下具体效果:
当前情况下,每次松开中键复原,再次按下中键后dragging还保持true,这会跳过执行第一个!dragging,从而获取不到新的originpoint,第一个if判断支不会更新当前鼠标中键按下originpoint位置,依然记录的是我们第一次鼠标中键按下的位置
这不符合我们实际游戏需求,因此,在第一个判断支后加入一个释放位
else
{
dragging =false;
}
具体位置在两个判断支中间:
if (Input.GetMouseButton(2))
{
offset = (Camera.main.ScreenToWorldPoint(Input.mousePosition) - Camera.main.transform.position);
if (!dragging)
{
dragging = true;
mouseOriginPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
我们的释放位放在这里↓↓↓↓↓
else
{
dragging = false;
}
我们的释放位放在这里↑↑↑↑↑↑
if (dragging)
{
transform.position = (mouseOriginPoint - offset);
}
这样我们每次拖拽完毕后,下次drag的时候,dagging就是false了,这样就会再判断一次mouseOriginPoint,获得新的初始位,而不至于回弹到最初的originpoint
拖拽功能实现完毕
第二块视角控制功能:拖拽,到此基本完成
我们再做个小优化,如果drag太远,设置一个按键(Home)回到初始位置
private Vector3 cameraOriginPosition;
private bool origin=true;
//判断一次初始摄像头位置
if (origin)
{
origin= false;
cameraOriginPosition = Camera.main.transform.position;
}
//按下h键回到初始摄像头位置
我们需要用到lerp指令平滑移动,需要设置一个摄像头初始位置startPosition和目标位置,targetPosition,总共归位时间lerpTime,目前持续时间currentDuration,一个平移速度goHomeSpeed,在实际应用中,因为我们键盘key状态无法通过Input方式持续每帧update都能获得,所以一个比较简单的方法就是通过检测一次H键,我们设定一个bool值开关,用来描述激活平移状态,这里设一个bool keyHit,默认false。
Vector3 startPos;
Vector3 targetPos;
float lerpTime = 2.0f;
float currentDuration;
bool keyHit = false;
private float goHomeSpeed = 3.0f;
要执行持续平移状态,我们要赋予检测h键按下激活状态开关。
if (Input.GetKey(KeyCode.H))
{
keyHit = true;
startPos = transform.position;
targetPos = cameraOriginPosition;
// currentDuration = 0;//这个在后面调试补充
}
在获得激活状态后,开始进行lerp平移,平移时间超过预定时间后,设置已经持续时间达到,设置了currentDuration等于预定时间,获得完整100%平移量,确保准确归位,虽然不太重要。
if (keyHit == true)
{
currentDuration += Time.deltaTime*goHomeSpeed;
if (currentDuration >= lerpTime)
{
currentDuration = lerpTime;
// keyHit = false;//这个在后面调试补充
}
float percentage = currentDuration / lerpTime;
transform.position = Vector3.Lerp(startPos, targetPos, percentage);
}
测试后发现结束平移lerp后无法操作,因为还在keyHit状态,持续运行最后这个判断中,因此加上keyHit=false;
再次测试可以正常操作了,但是第二次h键后会直接到达初始位,因为此刻currentDuration值是2,从而percentage直接就是100%,没有lerp过程,我们需要在第一个keyHit判断中键入currentDuration=0归零,再次测试ok。
下一篇: