一.引言
前面介绍了GameObject相关的API,下面整理一下Unity中常用的一些组件
二.Time相关API
Time相关内容主要用于游戏中参与位移、记时、时间暂停等
- 时间缩放比例
时间停止通常用于游戏暂停,因为路程 = 时间*速度,时间是0倍,那自然是静止的//时间停止 //Time.timeScale = 0; //回复正常 //Time.timeScale = 1; //2倍速 //Time.timeScale = 2; - 帧间隔时间
帧间隔时间主要是用来计算位移,根据需求选择参与计算的间隔时间
如果希望游戏暂停时就不动的那就使用deltaTime
如果希望不受暂停影响就使用unscaledDeltaTime//帧间隔时间:最近的一帧 用了多长时间(秒) //受scale影响 print("帧间隔时间" + Time.deltaTime); //不受scale影响的帧间隔时间 print("不受scale影响的帧间隔时间" + Time.unscaledDeltaTime); - 游戏开始到现在的时间
主要用来计时单机游戏中计时//受scale影响 print("游戏开始到现在的时间:" + Time.time); //不受scale影响 print("不受scale影响的游戏开始到现在的时间:" + Time.unscaledTime); - 物理帧间隔时间 FixedUpdate
//受scale影响 print(Time.fixedDeltaTime); //不受scale影响 print(Time.fixedUnscaledDeltaTime); - 帧数
从开始到现在游戏跑了多少帧(次循环),常用于进行帧同步
Time.frameCount
三.基础组件Transform
游戏对象(GameObject)位移、旋转、缩放、父子关系、坐标转换等相关操作都由它处理
- Vector3基础
Vector3主要是用来表示三维坐标系中的 一个点 或者一个向量//申明 Vector3 v = new Vector3(); v.x = 10; v.y = 10; v.z = 10; //只传xy 默认z是0 Vector3 v2 = new Vector3(10, 10); //一步到位 Vector3 v3 = new Vector3(10, 10, 10); Vector3 v4; v4.x = 10; v4.y = 10; v4.z = 10; //Vector的基本计算 // + - * / Vector3 v1 = new Vector3(1, 1, 1); Vector3 v12 = new Vector3(2, 2, 2); // 对应用x+或者-x..... print(v1 + v12); print(v1 - v12); print(v1 * 10); print(v12 / 2); //常用 print(Vector3.zero);//000 print(Vector3.right);//100 print(Vector3.left);//-100 print(Vector3.forward);//001 print(Vector3.back);//00-1 print(Vector3.up);//010 print(Vector3.down);//0-10 //常用的一个方法 //计算两个点之间的距离的方法 print(Vector3.Distance(v1, v12)); - 位置相关概念
- 相对世界坐标系
this.gameObject.transform.position
通过position得到的位置是相对于世界坐标系的原点的位置,可能和面板上显示的是不一样的,因为如果对象有父子关系,并且父对象位置不在原点,那么和面板上肯定就是不一样的 - 相对于父对象的坐标系
this.transform.localPosition
这两个坐标对于我们来说很重要,如果你想以面板坐标为准来进行位置设置,那一定是通过localPosition来进行设置的 - 相对世界和相对父对象可能出现是一样的情况如下:
- 父对象的坐标就是世界坐标系原点(0,0,0)
- 对象没有父对象
- 位置的修改
注意:位置的赋值不能直接改变x,y,z 只能整体改变,不能单独改 x y z某一个值//this.transform.position.x = 10; //报错 this.transform.position = new Vector3(10, 10, 10); this.transform.localPosition = Vector3.up * 10; //如果只想改一个值x y和z要保持原有坐标一致 //1.直接赋值 this.transform.position = new Vector3(19, this.transform.position.y, this.transform.position.z); //2.先取出来 再赋值 //虽然不能直接改 transform的 xyz 但是 Vector3是可以直接改 xyz的 //所以可以先取出来改Vector3 再重新赋值 Vector3 vPos = this.transform.localPosition; vPos.x = 10; this.transform.localPosition = vPos; - 获取当前游戏物体的各个方向的朝向
我们知道世界坐标系是死的,但是游戏物体是活的,所以游戏物体不可能每时每刻都是和世界坐标系重合//如果你想得到对象当前的 一个朝向 //那么就是通过 trnasform.出来的 //对象当前的各朝向 //对象当前的面朝向 print(this.transform.forward); //对象当前的头顶朝向 print(this.transform.up); //对象当前的右手边 print(this.transform.right);
- 相对世界坐标系
- 位移相关
- 理解坐标系下的位移计算公式
路程 = 方向 * 速度 * 时间 - 实现位移的两种方式:
- 自己计算
用当前的位置 + 我要动多长距离 = 最终所在的位置//this.transform.position = this.transform.position + this.transform.up * 1 * Time.deltaTime; //因为我用的是 this.transform.forward 所以它始终会朝向相对于自己的面朝向去动 //this.transform.position += this.transform.forward * 1 * Time.deltaTime; //方向非常重要 因为 它决定了你的前进方向 //this.transform.position += Vector3.forward * 1 * Time.deltaTime; - 使用Unity提供的API
参数一:表示位移多少 路程 = 方向 * 速度 * 时间
参数二:表示 相对坐标系 默认 该参数 是相对于自己坐标系的记住这4种排列组合,一般使用API来进行位移//1相对于世界坐标系的 Z轴 动 始终是朝 世界坐标系 的 Z轴正方向移动 this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.World); //2相对于世界坐标的 自己的面朝向去动 始终朝自己的面朝向移动 this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.World); //3相对于自己的坐标系 下的 自己的面朝向向量移动 (一定不会这样让物体移动) XXXXXXX this.transform.Translate(this.transform.forward * 1 * Time.deltaTime, Space.Self); //4相对于自己的坐标系 下的 Z轴正方向移动 始终朝自己的面朝向移动 this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.Self);
- 自己计算
- 理解坐标系下的位移计算公式
- 角度和旋转角
角度和位移类似,也有相对世界和相对父对象两个参考系- 角度相关
//相对世界坐标角度 print(this.transform.eulerAngles); //相对父对象角度 print(this.transform.localEulerAngles); //注意:设置角度和设置位置一样 不能单独设置xyz 要一起设置 //如果我们希望改变的 角度 是面板上显示的内容 那一点是改变 相对父对象的角度 //this.transform.localEulerAngles = new Vector3(10, 10, 10); //this.transform.eulerAngles = new Vector3(10, 10, 10); print(this.transform.localEulerAngles);
- 旋转相关
// 也有不通过API进行旋转的,方式和位移相似,这里就不做介绍了,下面就直接展示API计算角度 //1、自转 //每个轴 具体转多少度 //第一个参数 相当于 是旋转的角度 每一帧 //第二个参数 默认不填 就是相对于自己坐标系 进行的旋转 //this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime); //this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime, Space.World); //2、相对于某个轴 转多少度 //参数一:是相对哪个轴进行转动 //参数二:是转动的 角度 是多少 //参数三:默认不填 就是相对于自己的坐标系 进行旋转 // 如果填 可以填写相对于 世界坐标系进行旋转 //this.transform.Rotate(Vector3.right, 10 * Time.deltaTime); //this.transform.Rotate(Vector3.right, 10 * Time.deltaTime, Space.World); //相对于某一个点转 //参数一:相当于哪一个点 转圈圈 //参数二:相对于那一个点的 哪一个轴转圈圈 //参数三:转的度数 旋转速度 * 时间 this.transform.RotateAround(Vector3.zero, Vector3.right, 10 * Time.deltaTime);
- 角度相关
- 缩放和看向
这里补充一个点,脚本中可以定义一个Transform的对象,在Inspector窗口中,可以直接将一个游戏物体拖入,也就是说一个游戏物体就是一个Transform- 缩放
缩放也是Transform的一部分,自然也会遵循世界坐标和相对父坐标两种情况注:缩放没有相关的API可以直接进行修改,只能手动去进行修改//相对世界坐标系 print(this.transform.lossyScale); //相对本地坐标系(父对象) print(this.transform.localScale); //注意: //1.同样缩放不能只改xyz 只能一起改(相对于世界坐标系的缩放大小只能得 不能改) //所以 我们一般要修改缩放大小 都是改的 相对于父对象的 缩放大小 localScale //this.transform.localScale = new Vector3(3, 3, 3);this.transform.localScale += Vector3.one * Time.deltaTime; - 看向
让一个物体盯着一个物体看,这个在VR中很有用,普通游戏开发也会用到,比如AI盯着玩家攻击,看向比较简单,就仅仅是一个API的使用//让一个对象的面朝向 可以一直看向某一个点或者某一个对象 //看向一个点 相对于世界坐标系的 //this.transform.LookAt(Vector3.zero); //看向一个对象 就传入一个对象的 Transform信息 public Transform lookAtObj; // 定义并拖入关联我们要看向的那个物体 this.transform.LookAt(lookAtObj);
- 缩放
四.父子关系及其操作
这个与之前提到的父子关系差不多,但是操作不同,并且通过Transform来操作父子关系更加强大
- 获取和设置父对象
注:通过API设置父对象时,第二个参数比较重要,决定添加父子依赖关系后,子对象所在的位置,区别就是是否会进行一个相对关系的转换//获取父对象 //print(this.transform.parent.name); //设置父对象 断绝父子关系 //this.transform.parent = null; //设置父对象 认爸爸 //this.transform.parent = GameObject.Find("Father2").transform; //通过API来进行父子关系的设置 //this.transform.SetParent(null);//断绝父子关系 //this.transform.SetParent(GameObject.Find("Father2").transform);//认爸爸 //参数一:我的父亲 //参数二:是否保留世界坐标的 位置 角度 缩放 信息 // true 会保留 世界坐标下的状态 和 父对象 进行计算 得到本地坐标系的信息 // false 不会保留 会直接把世界坐标系下的 位置角度缩放 直接赋值到 本地坐标系下 //this.transform.SetParent(GameObject.Find("Father3").transform, false); - 一键断绝与孩子的关联
使用一个API即可this.transform.DetachChildren(); - 获取子对象的操作
注:Find不能够寻找儿子以下的子物体,下面提供一个拓展方法来进行实现//按名字查找儿子 //找到儿子的 transform信息 //Find方法 是能够找到 失活的对象的 !!!!! GameObject相关的 查找 是不能找到失活对象的 print(this.transform.Find("Cube (1)").name); //他只能找到自己的儿子 找不到自己的孙子 !!!!!! //print(this.transform.Find("GameObject").name); //虽然它的效率 比GameObject.Find相关 要高一些 但是 前提是你必须知道父亲是谁 才能找 //遍历儿子 //如何得到有多少个儿子 //1.失活的儿子也会算数量 //2.找不到孙子 所以孙子不会算数量 print(this.transform.childCount); //通过索引号 去得到自己对应的儿子 //如果编号 超出了儿子数量的范围 那会直接报错的 //返回值 是 transform 可以得到对应儿子的 位置相关信息 this.transform.GetChild(0); for (int i = 0; i < this.transform.childCount; i++) { print("儿子的名字:" + this.transform.GetChild(i).name); }这里主要是使用一个递归,来完成对孩子深度查询/// <summary> /// 根据名字找到 子对象 不管藏多深 /// </summary> /// <param name="father">调用方法的对象</param> /// <param name="childName">要找的对象名字</param> /// <returns></returns> public static Transform CustomFind( this Transform father, string childName) { //如何查找子对象的子对象 //我要找的对象 Transform target = null; //先从自己身上的子对象找 target = father.Find(childName); if (target != null) return target; //如果在自己身上没有找到 那就去找自己的子对象的子对象 for (int i = 0; i < father.childCount; i++) { //让子对象去帮我找 有没有这个名字的对象 //递归 target = father.GetChild(i).CustomFind(childName); //找到了 直接返回 if (target != null) return target; } return target; } - 子物体的相关操作
//判断自己的爸爸是谁 //一个对象 判断自己是不是另一个对象的儿子 if(son.IsChildOf(this.transform)) { print("是我的儿子"); } //得到自己作为儿子的编号 print(son.GetSiblingIndex()); //把自己设置为第一个儿子 son.SetAsFirstSibling(); //把自己设置为最后一个儿子 son.SetAsLastSibling(); //把自己设置为指定个儿子 //就算你填的数量 超出了范围(负数或者更大的数) 不会报错 会直接设置成最后一个编号 son.SetSiblingIndex(1);
五.世界坐标系和本地坐标系的相互转换
该点主要是本地坐标系转世界坐标系比较有用,比如玩家释放一个技能后,应该出现在正前方的一个特效,这是相对于本地坐标系的,但是所有游戏物体都是建立在世界坐标系的基础上进行展现的,所以得转一下
- 世界坐标转本地坐标
如图所示,世界转本地的图解,这是xz平面,其他平面也同理,做垂线即可,那么本地转世界也是同理,下面就主要整理API的使用简单记忆就是Vector的转换是会受游戏物体的缩放而导致结果不同,这里有向量的转换,其实就是将向量进行平移,比如世界向量转本地向量,直接平移世界坐标中的向量到本地坐标系中,与本地坐标系的原点重合得到的本地坐标系的向量print(Vector3.forward); //世界坐标系 转本地坐标系 可以帮助我们大概判断一个相对位置 //世界坐标系的点 转换 为相对本地坐标系的点 //受到缩放影响 print("转换后的点 " + this.transform.InverseTransformPoint(Vector3.forward)); //世界坐标系的方向 转换 为相对本地坐标系的方向 //不受缩放影响 print("转换后的方向" + this.transform.InverseTransformDirection(Vector3.forward)); //受缩放影响 print("转换后的方向(受缩放影响)" + this.transform.InverseTransformVector(Vector3.forward)); - 本地坐标转世界坐标
//本地坐标系的点 转换 为相对世界坐标系的点 受到缩放影响 print("本地 转 世界 点" + this.transform.TransformPoint(Vector3.forward)); //本地坐标系的方向 转换 为相对世界坐标系的方向 //不受缩放影响 print("本地 转 世界 方向" + this.transform.TransformDirection(Vector3.forward)); //受缩放影响 print("本地 转 世界 方向" + this.transform.TransformVector(Vector3.forward));