热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

可直接使用的unity第三人称自由视角相机脚本

使用方法:将要控制的角色拖到TargetBody,将相机的焦点拖到CamerPivot,,建议CameraPivot是一个放在TargetBody下的子物体,并且位置应该是在Tar

使用方法:


将要控制的角色拖到TargetBody,将相机的焦点拖到CamerPivot,,建议CameraPivot是一个放在TargetBody下的子物体,并且位置应该是在TargetBody的头部.

注意:此脚本自动忽略"Ignore Raycast"层和"Mob"对相机视野的遮挡,也就是说,当相机被带有这两个层之一的物体遮挡时,相机不会自动移动到遮挡物之前,这是用于设置一些不应该触发相机防遮挡的物体用的,比如说怪物和玻璃等.




包含的功能有:

            1.控制人物转向,按下WASD按键时可直接控制目标物体(角色)插值转向.

            2.垂直视角限制,避免发生相机翻转的问题

            3.相机防遮挡


原理说明:

            1.通过四元数插值控制人物转向

            2.在unity中,水平视角的x欧拉角为0,向上直至垂直的欧拉角实际上为(0-90),而向下直至垂直的欧拉角实际上是(360-270).脚本中maxEvelation为最大仰角,maxDepression为最大俯角,假设此处最大俯角和最大仰角都为80,则在最大仰角达到80以上时,判断鼠标的输入,只有当鼠标输入为向下滑动时(此时鼠标的输入Input.getAxis("Mouse Y")>0)才允许滑动.同理,当最大俯角为80(360-80&#61;280)时,此时实际上的欧拉角为280-270,所以当x<280时,则只允许向上滑动(此时鼠标的输入Input.getAxis("Mouse Y")<0))

如图所示:


代码:

float eulerX &#61; transform.localEulerAngles.x;//相机的x欧拉角,也就是垂直方向.float inputY &#61; Input.GetAxis("Mouse Y");//垂直视野限制transform.RotateAround(CameraPivot.transform.position, CameraPivot.transform.up, rotateSpeed * Input.GetAxis("Mouse X"));if (eulerX > maxEvelation && eulerX <90){if (inputY > 0)transform.RotateAround(CameraPivot.transform.position, transform.right, -rotateSpeed * inputY);}else if (eulerX <360-maxDepression && eulerX > 270){if (inputY <0)transform.RotateAround(CameraPivot.transform.position, transform.right, -rotateSpeed * inputY);}else{transform.RotateAround(CameraPivot.transform.position, transform.right, -rotateSpeed * inputY);}

            3.相机防遮挡


先提前检测(自己)相机的应该在位置,从相机目标向相机发射一条射线,如果碰撞了,说明即将碰撞.则直接把位置调到碰撞点位置,但此时的位置正好在平面里,相机的一部分视野会透视,所以应该在再向相机靠近一点.

transform.position &#61; CameraPivot.transform.position &#43; (wallHit - CameraPivot.transform.position) * 0.8f;

注意,这里是提前判断,如果是直接更新相机位置后发现被遮挡再把位置移动到碰撞点,相机就会在碰撞点和应在位置来回切换.效果自然是有问题的.

最后说明相机的位置更新方法:

        相机的旋转通过RotateAround()来以目标相机焦点为中心进行旋转.旋转后根据当前位置和相机焦点位置相减得到方向向量,然后用相机焦点位置&#43;方向向量的单位向量*设置的距相机焦点的距离.

代码表示:

           offset &#61; transform.position - CameraPivot.transform.position;offset &#61; offset.normalized * freeDistance;transform.position &#61; CameraPivot.transform.position &#43; offset;



完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class FreeTPSCamera : MonoBehaviour {[Header("相机距离")]public float freeDistance &#61; 2;[Header("相机最近距离")]public float minDistance &#61; 0.5f;[Header("相机最远距离")]public float maxDistance &#61; 20;[Header("是否可控制相机距离(鼠标中键)")]public bool canControlDistance&#61;true;[Header("更改相机距离的速度")]public float distanceSpeed &#61; 1;[Header("视角灵敏度")]public float rotateSpeed &#61; 1;[Header("物体转向插值(灵敏度,取值为0到1)")]public float TargetBodyRotateLerp &#61; 0.3f;[Header("需要转向的物体")]public GameObject TargetBody;//此脚本能操作转向的物体[Header("相机焦点物体")]public GameObject CameraPivot;//相机焦点物体 [Header("&#61;&#61;&#61;锁敌&#61;&#61;&#61;")]public GameObject lockTarget&#61;null;public float lockSlerp&#61;1;public GameObject lockMark;private bool marked;[Header("是否可控制物体转向")]public bool CanControlDirection &#61; true;[Header("俯角(0-89)")]public float maxDepression&#61;80;[Header("仰角(0-89)")]public float maxEvelation&#61;80;private Vector3 PredictCameraPosition;private Vector3 offset;private Vector3 wallHit;private GameObject tmpMark;// Use this for initializationvoid Start () {offset &#61; transform.position - CameraPivot.transform.position;if (TargetBody &#61;&#61; null){TargetBody &#61; GameObject.FindGameObjectWithTag("Player");Debug.Log("未绑定目标物体&#xff0c;默认替换为Player标签的物体");}if (!CameraPivot){Debug.LogError("未绑定相机焦点物体");}}void LockTarget(){if(lockTarget){lockTarget &#61; null;marked &#61; false;Destroy(tmpMark);return;}Vector3 top &#61; transform.position &#43; new Vector3(0, 1, 0)&#43;transform.forward*5;LayerMask mask &#61; (1 < maxDepression && eulerX <90)//当向上角度越界时{if (inputY > 0)//如果鼠标时在向下滑动transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);//允许滑动}else if (eulerX <360-maxEvelation && eulerX > 270){if (inputY <0)transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);}else//角度正常时{transform.RotateAround(CameraPivot.transform.position, Vector3.right, -rotateSpeed * inputY);}}if (lockTarget){offset &#61; CameraPivot.transform.position - (lockTarget.transform.position);}else{offset &#61; transform.position - CameraPivot.transform.position;//以上方向发生了变化,记录新的方向向量}offset &#61; offset.normalized * freeDistance;///在一次FixedUpdate中,随时记录新的旋转后的位置,然后得到方向,然后判断是否即将被遮挡,如果要被遮挡,将相机移动到计算后的不会被遮挡的位置///如果不会被遮挡,则更新位置为相机焦点位置&#43;方向的单位向量*距离///if (Inwall())//预测会被遮挡{//print("Inwall");transform.position &#61; CameraPivot.transform.position &#43; (wallHit - CameraPivot.transform.position) * 0.8f;return;}else{transform.position &#61; CameraPivot.transform.position &#43; offset;}}// Update is called once per framevoid FixedUpdate () {FreeCamera();if(lockTarget){if (!marked){tmpMark &#61; Instantiate(lockMark, lockTarget.transform.position &#43; new Vector3(0, 2.5f, 0), transform.rotation);tmpMark.transform.forward &#61; -Vector3.up;marked &#61; true;}else{tmpMark.transform.position &#61; lockTarget.transform.position &#43; new Vector3(0, 2.5f, 0);//tmpMark.transform.forward&#61; -transform.up;tmpMark.transform.Rotate(Vector3.up *30* Time.fixedDeltaTime,Space.World);}}}private void Update(){if(Input.GetKeyDown(KeyCode.F)){LockTarget();}}
}



推荐阅读
author-avatar
mobiledu2502917563
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有