今天主要是简单的模拟下吃鸡游戏的第三人称摄像机的实现。

观察

我们玩过吃鸡手游的都知道,吃鸡的人物跟随的摄像机有两种状态

1. 滑动屏幕的时候,摄像机左右上下移动,人物也会跟随着左右移动,上下抬头低头(播放相应的动画,但是不上下移动)。摄像机始终保持着观察人物背面。左右可以360度旋转,上下会有个最大值和最小值的限制,无法达到0度往上看或90度往下看。

2. 按住拖动右上角小眼睛按钮,摄像机左右上下移动,人物不会跟随着左右转动,头会左右上下摆动。几乎可以360度观察人物。上下左右的限制与情况1相同。

在不考虑头部转动的情况下,可以总结出两种情况摄像机的转动围绕人物的规则都是一样的,即以一个固定半径形成的球面上移动,除去了球面的最上和最下的部分,视角始终看向球心。而当滑动屏幕的情况下,人物也随之左右自转,保持摄像机观察人物的正背面。

分析

根据表现的现象,我们可以分析出我们需要实现的逻辑。我们可以想象人物的正后面有一条直线line,方向为(0,0,-1),摄像机离人物距离为distance,初始值摄像机的位置为(0,0,-distance)

当摄像机进行360度移动的时候,我们可以把移动操作拆分为两个步骤,首先是摄像机垂直移动,即以人物为中心,半径为distance的圆上移动。设垂直角度为α(0<min<α<max<90),则摄像机的高度y轴为distance*sin α,离人物的z轴距离为distance*cos α。此时摄像机的位置为(0,distance*sin α,-distance*cos α)

然后在之前的基础上,我们对摄像头进行水平移动,即以人物头顶高度distance*sin α的点为中心,半径为distance*cos α的圆上移动。设水平角度为β,则摄像机x轴为distance*cos α * sin β,z轴距离则更新为distance*cos α * cos β。

所以我们可以用两个角度α,β,来控制摄像机的转动,上下移动更新α值,左右移动更新β值,摄像机的位置为(distance*cos α * sin β, distance*sin α, -distance*cos α * cos β),摄像机始终看向(LookAt)人物

接着我们要区分两种情况的人物状态,当滑动屏幕的时候,人物会随之一起反方向转动,从而保证摄像机始终观察着人物背面。所以当摄像机水平转了β度时,人物的转向应该为(0, -β, 0)。而按住小眼睛的时候,人物不需要随之移动,但是当松开小眼睛的时候,摄像头需要回归原始位置,所以在按下的时候,我们需要纪录按下时摄像机的偏移角度,以供松开时复原。

实现

Demo中我们一共有四个cs文件,一个控制小眼睛按钮,一个控制屏幕滑动,一个控制人物移动,最后一个就是控制摄像机了。

还有需要搭建一个简单的测试场景,里面有一个方块模拟角色,一个plane做地面,然后添加一个UGUI的Button做小眼睛按钮。

首先是人物移动的控制器PlayerController,就是做了简单的位移

using UnityEngine;namespace Test
{public class PlayerController : MonoBehaviour{//速度转换const float SPEED_CONVERTER = 0.3f;void Update(){float inputV = Input.GetAxis("Vertical");float inputH = Input.GetAxis("Horizontal");this.transform.position += this.transform.forward * inputV * SPEED_CONVERTER;this.transform.position += this.transform.right * inputH * SPEED_CONVERTER;}}
}

接着是我们的摄像机控制器ThridPlayerCameraController,对摄像机的转动进行操作

using UnityEngine;namespace CameraTool
{[RequireComponent(typeof(Camera))]public class ThridPlayerCameraController : MonoBehaviour{[SerializeField] Transform m_target;//相机与人物距离[SerializeField] float m_distance = 5;//初始化的偏移角度,以人物的(0,0,-1)为基准[SerializeField] float m_offsetAngleX = 0;[SerializeField] float m_offsetAngleY = 45;//相机与人物的坐标的偏移量Vector3 m_offsetVector;//纪录偏移角度用于复原float m_recordAngleX;float m_recordAngleY;//相机是否在旋转,旋转中需要一直重新计算 m_offsetVectorbool m_isRotateing = false;//弧度,用于Mathf.Sin,Mathf.Cos的计算const float ANGLE_CONVERTER = Mathf.PI / 180;//相机上下的最大最小角度const float MAX_ANGLE_Y = 80;const float MIN_ANGLE_Y = 10;Transform m_trans;public Transform mineTransform{get{if (m_trans == null){m_trans = this.transform;}return m_trans;}}GameObject m_go;public GameObject mineGameObject{get{if (m_go == null){m_go = this.gameObject;}return m_go;}}void Start(){CalculateOffset();}void LateUpdate(){//相机坐标 = 人物坐标 + 偏移坐标mineTransform.position = m_target.position + m_offsetVector;mineTransform.LookAt(m_target);}void Update(){if (m_isRotateing){CalculateOffset();}}//计算偏移,可以想象成在一个球面转,m_distance为半径,m_offsetAngleY决定了相机的高度y//高度确定后,就是在一个圆面上转,根据m_offsetAngleX计算出x与zvoid CalculateOffset(){m_offsetVector.y = m_distance * Mathf.Sin(m_offsetAngleY * ANGLE_CONVERTER);float newRadius = m_distance * Mathf.Cos(m_offsetAngleY * ANGLE_CONVERTER);m_offsetVector.x = newRadius * Mathf.Sin(m_offsetAngleX * ANGLE_CONVERTER);m_offsetVector.z = -newRadius * Mathf.Cos(m_offsetAngleX * ANGLE_CONVERTER);}//开始旋转,纪录当前偏移角度,用于复原public void StartRotate(){m_isRotateing = true;m_recordAngleX = m_offsetAngleX;m_recordAngleY = m_offsetAngleY;}//旋转,修改偏移角度的值,屏幕左右滑动即修改m_offsetAngleX,上下滑动修改m_offsetAngleYpublic void Rotate(float x, float y){if (x != 0){m_offsetAngleX += x;}if (y != 0){m_offsetAngleY += y;m_offsetAngleY = m_offsetAngleY > MAX_ANGLE_Y ? MAX_ANGLE_Y : m_offsetAngleY;m_offsetAngleY = m_offsetAngleY < MIN_ANGLE_Y ? MIN_ANGLE_Y : m_offsetAngleY;}}//旋转结束,如需要复原镜头则,偏移角度还原并计算偏移坐标public void EndRotate(bool isNeedReset = false){m_isRotateing = false;if (isNeedReset){m_offsetAngleY = m_recordAngleY;m_offsetAngleX = m_recordAngleX;CalculateOffset();}}}
}

接着就是两个UI控制器UIController 和 SmallEyeController,实现IDragHandler, IBeginDragHandler, IEndDragHandler接口

using UnityEngine;
using UnityEngine.EventSystems;namespace Test
{public class UIController : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler{[SerializeField] Transform m_target;[SerializeField] CameraTool.ThridPlayerCameraController m_thridCamera;//滑动的偏移转换为角度偏移的系数const float DRAG_TO_ANGLE = 0.5f;Vector2 m_previousPressPosition;float m_angleX, m_angleY;public void OnBeginDrag(PointerEventData eventData){m_previousPressPosition = eventData.position;m_thridCamera.StartRotate();}public void OnDrag(PointerEventData eventData){//滑动屏幕,人物和摄像机一起旋转(人物只转Y轴,即左右旋转)m_angleX = (eventData.position.x - m_previousPressPosition.x) * DRAG_TO_ANGLE;m_angleY = (eventData.position.y - m_previousPressPosition.y) * DRAG_TO_ANGLE;m_thridCamera.Rotate(-m_angleX, -m_angleY);m_target.Rotate(new Vector3(0, m_angleX, 0));m_previousPressPosition = eventData.position;}public void OnEndDrag(PointerEventData eventData){m_thridCamera.EndRotate();}}
}
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;namespace Test{public class SmallEyeController : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler{[SerializeField] CameraTool.ThridPlayerCameraController m_thridCamera;const float DRAG_TO_ANGLE = 0.5f;Vector2 m_previousPressPosition;float m_angleX, m_angleY;Image m_image;void Start(){m_image = GetComponent<Image>();}public void OnBeginDrag(PointerEventData eventData){m_previousPressPosition = eventData.position;m_thridCamera.StartRotate();m_image.color = Color.gray;}public void OnDrag(PointerEventData eventData){//滑动小眼睛按钮,只旋转摄像机m_angleX = (eventData.position.x - m_previousPressPosition.x) * DRAG_TO_ANGLE;m_angleY = (eventData.position.y - m_previousPressPosition.y) * DRAG_TO_ANGLE;m_thridCamera.Rotate(-m_angleX, -m_angleY);m_previousPressPosition = eventData.position;}public void OnEndDrag(PointerEventData eventData){m_image.color = Color.white;m_thridCamera.EndRotate(true);}}
}

效果图

Unity 第三人称 摄像机相关推荐

  1. Unity Cinemachine之第三人称摄像机CinemachineFreeLook属性详解

    演示 CinemachineFreeLook是一个第三人称视角相机插件,功能非常强大,内置了很多属性可以供开发者根据需求进行调整. 创建   首先是Cinemachine插件的导入,如果是2018以后 ...

  2. Unity第三人称的实现思路(二)

    Unity第三人称的实现思路(二) 锁定视角动画设置 锁定视角摄像机 角色朝向控制 主要代码 这一次我们在上一篇自由视角的基础上加上锁定视角的功能,没有看过上一篇的点下方链接. Unity第三人称的实 ...

  3. unity第三人称射击游戏_在游戏上第3部分完美的信息游戏

    unity第三人称射击游戏 Previous article 上一篇文章 The economics literature distinguishes the quality of a game's ...

  4. 【C#】【Unity】第三人称摄像机跟随人物移动时碰撞到墙壁等,摄像机不穿越墙壁

    目前大部分第三人称游戏的摄像机在遇到墙壁等狭隘空间的时候,都选择让摄像机不穿越到墙壁里面,而是让摄像机保持在墙壁表面. 分析情况:(红色方框为摄像机 黑色方框为墙壁) 当前情形摄像机还没达到墙壁摄像机 ...

  5. unity 第三人称射击游戏中如何防止跟随摄像机穿墙?

    在制作3d射击类游戏中,会遇到跟随角色的摄像机会穿透墙壁导致视野不佳情况,下面,介绍一下具体的解决方法. 我们需要用到的原理就是unity中射击线函数.具体的原理是,从相机的跟随点向相机的方向发射一条 ...

  6. 【Unity3D游戏开发学习笔记】(七)上帝之眼—第三人称摄像机的简单实现(跟随视角,自由视角)

    陆陆续续又开始更新自己的博客,看来自我驱动能力还是不够啊= =,废话不多说了,之前的内容大概说了一下Unity的一些基础知识,接下来我们将要对一些基本功能做一些学习.大家都知道,一个游戏,少不了摄像机 ...

  7. Unity 第三人称射击游戏视角控制与武器瞄准

    ===================更新一下源工程链接: 链接:https://pan.baidu.com/s/15bxH-MPregp2ZIN92fK7XA 提取码:e7bp ========== ...

  8. Unity3D第三人称摄像机控制脚本

    好久没有敲Blog该.感谢您的留言.注意.私人信件和其他支持,但我似乎没有办法继续自己曾经写了一篇博客系列,因为我在网上找到有关unity3D太少的内容,U3D相关的文章!.. 第三人称视角 第三人称 ...

  9. Unity第三人称控制实现方式

    第三人称移动,主要两个部分,一是人物,二是相机. 先说人物,unity其实提供了一个CharacteController组件可以方便地用于控制人物移动,但是这个组件会与刚体冲突.如果使用Charact ...

最新文章

  1. redis(3)redis的基础入门(java)
  2. 去掉word注释里的横线
  3. 高低压验电笔应用口诀及使用方法
  4. 《研磨设计模式》chap16 模板方法模式
  5. jena 学习思路(转)
  6. Fence Repair POJ - 3253
  7. 深入剖析kafka架构内部原理
  8. Kullback–Leibler divergence(相对熵,KL距离,KL散度)
  9. IDEA设置注释配置时获取不到参数的解决办法
  10. Memcache的最佳实践方案
  11. Python生成高斯白噪声white noise
  12. 整理一年中使用到的工具和类库,可能正有你需要的!
  13. eNSP入门-基本配置
  14. wox wpm 安装 有道插件
  15. 排列组合数计算公式及性质
  16. h3c 抓包么 能通过debug_华三路由器可以抓包吗 路由器密码
  17. java 实现图片水印 文字水印
  18. qq远程控制 总是提示权限不足
  19. 不想升级,iOS系统自动更新可彻底关闭! 2016-05-23 16:38 更新/自动/on 昨天笔者发布了一篇关于iOS系统总提醒更新,到底要不要升级的文章,不少读者在微信上留言给笔者, iPhon
  20. CMake命令之add_custom_comand 和 add_custom_target

热门文章

  1. C++练习:编写程序实现歌唱大赛选手成绩计算功能
  2. 浮点数加减运算左规右规
  3. access 查找工龄大于30_Access操作题
  4. UE4 pbr概念理解
  5. python网球比赛模拟主持稿_主持人大赛模拟主持稿
  6. 语句摘抄——第27周
  7. 社交网站需要多大的服务器空间,社交app选多大云服务器
  8. WPF 录屏软件研发心得及思路分享(已结束开发)
  9. 常见的端口号以及协议
  10. USACO——Mixing Milk 混合牛奶