找回密码
 立即注册
查看: 328|回复: 1

[笔记] unity 摄像机跟随与切换代码怎么写?

[复制链接]
发表于 2022-12-5 13:41 | 显示全部楼层 |阅读模式
unity 摄像机跟随与切换代码怎么写?
发表于 2022-12-5 13:47 | 显示全部楼层
由于在游戏行业从业多年,很多同学也是从这里起步的,看着很基础,但是要写得非常简单易懂,了解整个框架,还是需要些许实践的,这个大概聊下。
当然越是基础的逻辑,网上实例代码就会越多,如RTS相机,FPS/TPP等,都是3C(Camera,Character,Controller)体验的核心内容,待会举个具体的RTS例子。
在游戏开发中,相机的控制的划分方法比较多,可以根据用途用法,功能来区分,比如过场,转场,剧情,等等,在电影中也有很多专业的镜头用语和镜头语言,表现方法,算是易学难精吧。好了回到题主的问题,主要是镜头的跟随和切换。这个主要的应用场景应该是FPP/TPP,即第一人称镜头和三人称镜头。咱们重点说下这两种情况的实现和用法。
Unity属于左手系(假定目光平视所及方向为+Z轴,头顶朝向为+Y轴,右手沿肩方向为+X,轴可以理解为不动的,固定的事物),对应于航空和机器人等行业,用于控制镜头的专业术语,像Roll(翻滚Z,可以理解为绕Z轴旋转),Pitch(俯仰X,理解为绕X旋转),Yaw(偏航Y,同理),主要通过一人称的视角来形象描述相对旋转坐标系,参考系是本身的局部坐标系,咱们再在这个基础上进一步抽象一下这个问题,相机的控制无非是绕着某个具体的点(将跟随目标抽象)旋转,或者平移(这里不考虑缩放),这个过程是相对于跟随目标对象的世界坐标系而言的,当然相机本身相对于局部坐标系也有对应旋转和平移(特殊转场,过渡的镜头特写等都会有)因此只要知道了相机如何围绕着某个点旋转,或者相机跟目标如何保持同一个朝向移动相同的位移,就能解决题主的问题了,切换只是换个目标或者旋转平移到某个位置罢了,另外FPP和TPP本质上只是相机的朝向不一样,位置不一样罢了。
为什么要这么来说明呢?因为咱们的相机在Unity引擎中进行具体的控制,需要用到这些概念,只有关联起来,代码的含义才会变得清晰起来,需要注意的是,引擎提供给咱们的是怎样的一个接口和机制,这个可能是新同学遇到的困惑,如mono behavior 脚本类似于一个状态机,每帧执行一次Update函数,输入也是类似的机制,一帧获取一次用户的输入(delta)。
接下来给点提示代码(理解背后的逻辑了,思路,细节可以各取所需,只是形式差异)
第一步,加上一个名字叫做Camera的mono behavior 脚本(自己创建一个空的也行)。


第二步,在脚本中写入
float Speed = 8.0f;
float ZoomSpeed = 200.0f;
float RotateSpeed = 20.0f;
//该函数只会在脚本构造完成后执行一遍,记录自身起始位置
void Start()
{
      Vector3 rot = transform.eulerAngles;
      rotationX = rot.x;
      rotationY = rot.y;
}


//需要先定义好输入轴,名字没有报错的话需要加一下
//该函数每帧调用一次
void Update()
{
//获取水平和垂直方向的输入(delta)水平轴名字属于自定义的,没有这个名字绑定的可能会报错,需要在输入设置中设置
float horizontalInput = transform.position.y * Input.GetAxis("Horizontal");
float verticalInput = transform.position.y * Input.GetAxis("Vertical");
float scrollInput = -Mathf.Log(transform.position.y) * Input.GetAxis("Mouse ScrollWheel");
//获取相机的朝向 按时间片来做插值
Vector3 forwardMove = transform.forward;
        forwardMove.y = 0;
        forwardMove.Normalize();
        forwardMove *= verticalInput * Speed * Time.deltaTime;
        Vector3 verticalMove = new Vector3(0, scrollInput * ZoomSpeed * Time.deltaTime, 0);
        Vector3 rightMove = transform.right * horizontalInput * Speed * Time.deltaTime;

//初级用法,用相机当前视角FPP下的三个输入意向矢量叠加成一个具体的位移矢量
Vector3 Move = verticalMove + forwardMove + rightMove;
//每帧设置一个根据输入叠加得到的位置坐标
transform.position += Move;
//2表示鼠标的右键,意为按下右键旋转视角
if (Input.GetMouseButton(2))
{
            float mouseX = Input.GetAxis("Mouse X");
            float mouseY = -Input.GetAxis("Mouse Y");
            RotateCamera(mouseX, mouseY);
  }


void RotateCamera(float mouseX, float mouseY)
    {
        rotationY += mouseX * RotateSpeed * 0.02f;
        rotationX += mouseY * RotateSpeed * 0.02f;
//四元数可以非常方便得表示绕某个坐标轴的旋转,其实可以写成一个很简单的公式,目标位置=朝向+单位向量*间隔距离,这种实现方便控制跟随距离和切换目标,注意当前脚本的transform 表示当前挂在哪个对象上,这个对象的位置信息表示,如果切换目标可以把目标抽象成“点”,然后用该点算出相机位置,在当前transform 位置处和目标位置处进行按时间每帧插值计算即可
//代码形式为Vector TargetPos = 下一步你想要到达的目标点
        transform.rotation = Quaternion.Euler(rotationX, rotationY, 0.0f);
//transform.position = vector.Lerp(transform.position,TargetPos,Time.deltaTime*Speed)
//插值方式可以任意设定
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-21 20:28 , Processed in 0.091705 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表