每个MonoBehavior都有一个成员指向当前节点的transform组件 当然 还有别的属性可以获取: 控制可见性: 在这里 若game_root节点隐藏了 那么Cube和Sphere的可见性勾还是打上的 这就是activeSelf 场景树是有父子关系的 若父亲不可见 那么下面全部孩子都不可见 任何组件都会有数据成员指向该节点的transform示例 因此可以通过this来访问 transform组件不能有多个 只能有一个 无法删除 Unity的场景树是基于transform构建的 name其实是这里的名称: (类似于HTML的父子节点的查找…) 树形关系是由transform串联起来的 而并不是节点串联的 Find函数和FindChild函数返回的都是Transform对象 还可以按下标获取子节点: 任意组件都有gameObject和transform组件 且transform组件是gameObject必带的 根transform 比如game_root Main Camera 或是Directional Lignt 都是没有父节点的 相对来说 从子节点查找的性能会比全局查找高一些 可以为节点打上tag标签 然后根据标签查找 若有多个节点都是同样的tag 那么先找到哪个带有该tag的节点 就返回哪个 当然 也有函数可以查找多个 比如 若要查询敌人集合 可以将所有敌人都打上tag 然后一次性查询全部敌人 绝对坐标 即世界坐标 就是transform组件中的Position 例如 家的位置在地球的东经XX北纬XX 在代码中的相对坐标是localPosition 比如子节点的位置是(0,2,0) 而它的父节点的位置是(0,0,10) 那么 两个相加 子节点的世界坐标就是 (0,2,10) 若父节点还有父节点 那么还会继续叠加 每个组件都会在游戏刷新的时候调用Update生命周期 由于是每隔一段时间调用的 因此会产生时间间隔 用Time中的 对于前后左右上下 只需要三个向量即可 剩余三个是方向量 返回的是一个坐标 在游戏中的向前走 实际上就是在向前的方位上行走 forward up 和 right都是世界坐标系下的单位方向向量 表示的是方向 因此 在下面的例子中 cube_trans.forward就代表了模型在z轴的正方向 若有个球体 使用 有Space.World世界空间和Space.Self自己的空间 比如 按住Alt然后旋转画面 这是以节点为中心进行旋转的 这就是Space.Self自己的空间 若要平移物体 只需使用 默认是在原来的基础上按照x y z的方向来平移的 若要以世界坐标轴来平移 可以换添加一个构造参数 还可设置以使得以指定transform作为参照物移动 平移物体有两个关键:参考系 和 在该参考系下每个方向的分量 缩放 同样也是有x方向的缩放 y方向的缩放 和 z方向的缩放 使用localScale来控制缩放 这是相当于父节点而言的 查询缩放 还有个lossyScale 这是只读的 是相对于全局而言的 任何一个旋转都可以使用矩阵来进行表示 因此 矩阵法使用的并不多 欧拉角是用来唯一地确定定点转动刚体位置的三个一组独立角参量 由章动角θ 进动角ψ和自转角φ组成 欧拉角要按照一定的次序形成不同的角度 (就像是转魔方…) 在某些情况下不方便使用欧拉角 此时就需使用四元数了 欧拉角和四元数之间可以相互转化 在Unity的编辑器中 为了直观地显示旋转 使用的是欧拉角表示法 使用Quaternion的 这个是直接到了指定角度 这是和Rotate()的区别 调用transform的 同样的 Rotate不仅只能以自己旋转 也支持传入构造参数 改变参照物 能够以世界空间和指定参照物来旋转 在三维空间中 有个轴既垂直于初始位置 又垂直于结束位置 这个轴就是方向 Rotate是逆时针为负 顺时针为正 使用 使用 头顶方向 有了目标点的位置 可以计算出旋转角度 有了角度和旋转向量 那么就能组成一个四元数 组成一个旋转方位 Vector3若表示三维坐标 则表示一个立方体的点(带有三条坐标轴) 向量的加减法直接将每个分量加减即可 向量乘以比例系数即可缩放 有(x1,y1,z1)和(x2,y2,z2) 单位向量就是 因此: 可改为 Lerp求两个向量之间的线性插值 如下图 若t=0 就在A点 绕着球面以弧形移动 用 分别是: 每个gameObject下面都有一个transform 每个MonoBehavior组件都会拿到gameObject 总而言之 所有组件都会有transform和gameObject 只需要在泛型 获取节点上所挂载的所有为该类型的组件 除了通过类型 还可以根据组件实例的名称获取 传入字符串格式的名称即可 上述代码的特点 都是从 也可通过组件 获取当前组件所挂载的节点的其它组件 如此 即可在一个组件里调用其它另外的组件里的方法了 只需要加上public的数据成员 即可将该数据成员绑定到对应的编辑器上了 然后就会识别到了:
六、transform组件
🚩transform组件的作用:
每个MonoBehavior都有成员gameObject
指向该脚本的组件实例所挂载的节点对象🚩代码控制属性
void Start () { // this.gemeObject 组件实例所挂载的场景的节点对象 Debug.Log(this.gameObject.name); }
Debug.Log(this.gameObject.layer); Debug.Log(this.gameObject.tag);
🚩可见性
Debug.Log(this.gameObject.activeSelf); // 自己是否可见 Debug.Log(this.gameObject.activeInHierarchy); // 自己在体系中是否可见 // 设置可见性 this.gameObject.SetActive(true);
但是他们其实已经不可见了(在game_root这个体系中) 因此 这就是activeInHierarchy
🚩父子关系
通过任何一个组件来获得每一个节点的transformthis.transform
同理 transform也是一个组件 因此也有一个gemeObject指向其挂载的节点Debug.Log(this.transform.gameObject.name);
🚩场景树的构建方式
game_root有个transform指向了gameObject
在它下面有棵树保存了它的孩子 – Cube和Sphere 实际上是Cube的transform和Sphere的transform
其实整个场景树是由transform组件构成的 每个transform都会指向节点
🚩Find和FindChild按名称查找
// 获取指定的transform Transform trans=this.transform.Find("Cube"); // 名称注意大小写 GameObject cube = trans.gameObject; Debug.Log(cube.name);
trans=this.transform.FindChild("Sphere"); GameObject sphere=trans.gameObject; Debug.Log(sphere.name);
区别:
Find可以去子节点的子节点中查找 (需写多层路径 比如Cube/Sphere代表Cube节点下的Sphere子节点)
而FindChild则无此功能// parent属性 Debug.Log(trans.parent.gameObject.name);
🚩GetChild按下标获取子节点
Debug.Log(this.transform.GetChild(0).gameObject.name); // Cube Debug.Log(this.transform.GetChild(1).gameObject.name); // Sphere
因此 只要获得transform那么就能获取到gameObject了
transform是三维位置定位最重要的组件 节点的位置都是由transform进行控制的
且transform是帮助建立场景树的
除了可以基于transform查找 还可以基于gameObject的全局查找:// 基于GameObject的查找 查找的是GameObject而不是transform了 Debug.Log(GameObject.Find("game_root/Sphere").name);
🚩tag标签
(类似于HTML的根据class或id查找…)
点击的Add Tag…
点击小加号
然后输入名称即可
然后即可选择标签了:
在查找的时候 标签就是标签 和路径无关 无论在什么路径下 只要打了标签 那么直接根据标签名查找即可// 基于Tag标签名的全局查找 Debug.Log(GameObject.FindWithTag("mytag").name); // Cube
只会返回一个 而不是返回多个
FindGameObjectsWithTag()
返回的是GameObject数组// 查找多个 GameObject[] gameObjects=GameObject.FindGameObjectsWithTag("mytag"); for (int i=0;i<gameObjects.Length;i++) { Debug.Log(gameObjects[i].name); }
🚩绝对坐标系和相对坐标系
当根节点移动位置后 Cube的坐标还是不会改变 但实际上世界坐标已经改变了
因此 可以知道 相对坐标即为相对于父节点的位置
而世界坐标即相对于世界(整个场景)的位置
而人在家的XX方向XX距离的位置
那么 将这两个坐标叠加 即为人的世界坐标了代码中的坐标
// 在Unity的编辑器中的position是相对坐标 而代码中的position并不是!乃是绝对坐标 Debug.Log(this.transform.position); // 在代码中的相对坐标是localPosition Debug.Log(this.transform.localPosition);
Transform cube=this.transform.FindChild("Cube"); // 在Unity的编辑器中的position是相对坐标 而代码中的position并不是!乃是绝对坐标 Debug.Log(cube.position); // (1.0,4.0,0.0) // 在代码中的相对坐标是localPosition Debug.Log(cube.localPosition); // (0.0,4.0,0.0)
🚩距上一次刷新的时间 deltaTime/fixedDeltaTime
deltaTime
来获取
若在FixedUpdate生命周期中 则用fixedDeltaTime
来获取// 更新 void Update () { // deltaTime 距离上一次刷新的时间 float dt = Time.deltaTime; } // 根据物理时间更新(是固定的) void FixedUpdate() { // 物理引擎固定更新的时间间隔 在FixedUpdate中用的是fixedDeltaTime float dt = Time.fixedDeltaTime; }
🚩transform成员变量
三维坐标会有其三个方向 绿色是y 红色是x 蓝色是zDebug.Log(cube.forward);
Debug.Log(cube.right); Debug.Log(cube.up);
🚩方向向量
单位向量*标量(只有大小 没有方向的量)=该标量在该单位向量的x y z方向上的分解
若旋转了 那么cube_trans.forward也会自动随之改变public class game_scene : MonoBehaviour { Transform cube_trans; // Use this for initialization void Start () { cube_trans = this.transform.Find("Cube"); // 世界坐标下的前 右 上方向 // cube_trans.forward; } // Update is called once per frame void Update () { // 移动距离:10m/s 这是个标量(只有大小 没有方向的量) float s = 10 * Time.deltaTime; // 在该标量的方向上移动s // 单位向量*标量=该标量在该单位向量的x y z方向上的分解 cube_trans.position += cube_trans.forward * s; } }
🚩坐标的转换
局部坐标[/相对坐标]转换为世界坐标
要将该球体放置于世界坐标0,0,10的位置 那么只需在代码中修改该球体的position即可
还有个方法 使用TransformPoint
TransformPoint可以将当前局部坐标系下的坐标转换为世界坐标// 【将局部坐标转换为世界坐标】 // 即为 在以this.transform为原点的坐标系中将相对坐标0,0,0转换为世界坐标 // Vector3即为三维坐标的意思 Debug.Log(this.transform.TransformPoint(new Vector3(0, 1, 2)));
世界坐标转换为局部坐标[/相对坐标]
InverseTransformPoint
函数// 【将世界坐标转换为局部坐标】 // 即 对于世界坐标0,6,2 当前世界坐标(即this.transform)的相对位置 Vector3 local_post = this.transform.InverseTransformPoint(new Vector3(0, 6, 2)); Debug.Log(local_post);
🚩平移
Space.World和Space.Self
而Space.World是以世界坐标系的原点为旋转点进行旋转Translate
Translate()
即可void Update () { // 移动距离:10m/s 这是个标量(只有大小 没有方向的量) float s = 10 * Time.deltaTime; // 默认是在原来的基础上按照x y z的方向来平移 this.cube_trans.Translate(new Vector3(0, 0, s)); }
this.cube_trans.Translate(new Vector3(0, 0, s),Space.World);
this.cube_trans.Translate(new Vector3(0, 0, s), this.transform);
参考系有三个 分别是自己(Self) 和 世界(World) 和 自定义目标🚩缩放
若将父节点进行缩放 那么里面的所有子节点都会跟着缩放相应的大小 比例系数会影响子节点
改变缩放this.cube_trans.localScale = new Vector3(0.5f, 0.5f, 0.5f);
// 若父节点进行了缩放 那么比例系数会影响子节点 Debug.Log("localScale " + this.cube_trans.localScale);
// 整个对象在全局的缩放系数 Debug.Log(this.cube_trans.lossyScale);
🚩旋转的表示法
矩阵旋转
优点:旋转轴可以是任意向量
缺点:旋转其实只需要知道一个向量 + 一个角度 总共4个值的信息
但矩阵法却使用了16个元素 比较耗费内存欧拉角
若顺序不同 虽然是同样的角度 但是最终的结果值也都是不同的
Unity是按照z x y
的顺序进行旋转的
比如下图 x和z两个轴在同一个平面内 这样 无论旋转哪个角 都是绕着y轴转
如此 就丢掉了一个维度
万向节死锁在某些情况下 会导致动画不够流畅
若出现该情况 则必须同时修改两个旋转轴才行了Quaternion 四元数
四元数是一种表示旋转的方式
某些实现下比旋转矩阵的效率更高
而在代码里 为了避免万向节死锁问题 使用的是四元数
因此 在编辑器中看到的角度和代码中的角度是不一样的将四元数转换为欧拉角
eulerAngles
能返回四元数对应的欧拉角// Unity在代码中为了避免万向节死锁问题 使用四元数来存放一个旋转 // Unity编辑器中为了直观地显示旋转 显示的是欧拉角 // eulerAngles可以将四元素转换为欧拉角 Vector3 e_degree = cube_trans.rotation.eulerAngles; Debug.Log(e_degree);
将欧拉角转换为四元数
Euler()
函数 然后传入一个三维向量对象 可以将欧拉角转换为四元数// 将欧拉角转换为四元数 直接到了指定角度 cube_trans.rotation = Quaternion.Euler(new Vector3(0, 30, 60));
Rotate 欧拉角度
Rotate()
函数 然后传入一个三维向量对象 同样能够旋转指定的欧拉角度
是在当前的基础上再进行旋转的// 直接旋转欧拉角度 是在当前的基础上再进行旋转的 cube_trans.Rotate(new Vector3(0, 30, 60));
实现一直旋转
// 定义角速度 float w = 360; // 角度=角速度×时间 float degree = w * Time.deltaTime; // 旋转 // cube_trans.Rotate(0, degree, 0); // 将每个小变换组成一个大变换 因此不能用加法[+] 而是应该用乘法[*] cube_trans.rotation = cube_trans.rotation * Quaternion.Euler(new Vector3(0, degree, 0));
🚩其它常用旋转方法
初始位置和结束位置的角就是角度
方向 + 角度就能算出四元数 将四元数给物体 物体就能旋转
Rotate(欧拉角,空间)
Rotate(方向,角度)
private Transform cube = transform.FindChild("Cube"); // 欧拉角旋转 cube.Rotate(new Vector3(0, 45, 0)); // 旋转向量+角度 cube.Rotate(new Vector3(0, 1, 0), 45);
RotateAround()
绕着某个点旋转
语法:RotateAround(要围绕的点,方向,角度)
public class game_scene : MonoBehaviour { private Transform sphere; // Use this for initialization void Start () { sphere = transform.FindChild("Sphere"); } // Update is called once per frame void Update () { // 角度=时间*速度 float angle = Time.deltaTime * 180; // 要围绕的中心点 Vector3 pos = new Vector3(0, 0, 0); // 旋转 RotateAround(要围绕的点,方向,角度) sphere.RotateAround(pos, new Vector3(0, 1, 0), angle); } }
LookAt() ★
LookAt()
对准对应的方位(视线对准)
经常用与游戏的寻路 移动等功能
LookAt是跟着目标不停旋转 因此需要旋转角度和旋转向量
旋转向量在LookAt中 被称作是头顶方向
头顶方向 即为注视着目标点的时候 是绕着什么轴旋转的
默认以y轴(0,1,0)为旋转轴
有了头顶方向 能够指名按照哪个向量进行旋转void Update () { // 角度=时间*速度 float angle = Time.deltaTime * 180; // 要围绕的中心点 Vector3 pos = new Vector3(0, 0, 0); // 旋转 RotateAround(要围绕的点,方向,角度) sphere.RotateAround(pos, new Vector3(0, 1, 0), angle); // 锁定目光 cube.LookAt(sphere.position, new Vector3(0, 1, 0)); }
localEularAngles()
返回一个当前旋转相对于父节点的欧拉角🚩Quaternion四元素常用旋转方法
LookRotation()
根据自己的上方向盯着前方
用法和LookAt类似 但LookAt使用会更加多Quaternion rot= Quaternion.LookRotation(this.sphere.position,new Vector3(0,1,0)); cube.rotation = rot;
Angle(lhs,rhs)
计算两个旋转之间的夹角
用于计算两个角之间的差值
FromToRotation(from,to)
获得从初始向量旋转到目标向量的旋转四元数// 获得从初始向量旋转到目标向量的旋转四元数 Quaternion rot= Quaternion.FromToRotation(new Vector3(0, 0, 1), new Vector3(1, 0, 1)); cube.rotation = rot;
🚩Vector3
若表示向量 则表示从原点开始到结束点(x,y,z)的向量向量的加减法
比如:(x1,y1,z1)+(x2,y2,z2)=(x1+x2,y1+y2,z1+z2) (x1,y1,z1)-(x2,y2,z2)=(x1-x2,y1-y2,z1-z2)
向量的缩放
放大:(x1,y1,z1)*n=(x1n,y1n,z1n)(n>0)
缩小:(x1,y1,z1)*n=(x1n,y1n,z1n)(n<0)
同理 向量除以比例系数即可缩小向量的比较
若x1=y1,x2=y2,z1=z2那么这两个向量相等
只要有一个不等 那么这两个向量就不相等单位向量
根号(x^2+y^2+z^2)=1
的向量
Vector提供了一些单位向量:zero one forward right upDebug.Log(Vector3.zero); // (0.0,0.0,0.0) Debug.Log(Vector3.one); // (1.0,1.0,1.0) Debug.Log(Vector3.forward); // (0.0,0.0,1.0) Debug.Log(Vector3.right); // (1.0,0.0,0.0) Debug.Log(Vector3.up); // (0.0,1.0,0.0)
float speed = 10; float s = speed * Time.deltaTime; cube.transform.position += new Vector3(0,0,s);
float speed = 10; float s = speed * Time.deltaTime; cube.transform.position += Vector3.forward*s;
Lerp线性插值
from+(to-from)*t
若t=1 就在B点
若t=0.5 就在A点和B点的中间
所谓线性插值 这是一条直线// from (0,0,0) to (10,0,0) // Time.time为从开始到现在所有delteTime的累计之和 cube.transform.position = Vector3.Lerp(Vector3.zero, Vector3.right * 10,Time.time);
Slerp球面插值
由于球面的圆心是(0,0,0) 因此不能从(0,0,0)开始移动// 球面插值 // from (-10,0,0) to (10,0,0) cube.transform.position = Vector3.Slerp(Vector3.right * -10, Vector3.right * 10, Time.time);
distance向量的距离
Distance()
来求向量的距离
向量的距离就是两个点之差求模
// Distance向量的距离 float len = Vector3.Distance(Vector3.right, Vector3.right * -1); Debug.Log(len); // 2
Angle向量的角度
// Angle向量的角度 float degree = Vector3.Angle(Vector3.right, Vector3.right * -1); Debug.Log(degree); // 180
Min Max 比较向量的模的大小
Vector3 max= Vector3.Max(Vector3.right, Vector3.right * 2); Debug.Log(max); Vector3 min = Vector3.Min(Vector3.right, Vector3.right * 2); Debug.Log(min);
transform总共包括了四个逻辑
🚩获取组件实例
MonoBehavior组件也有一个transform指向gameObject
MonoBehavior还有一个数据成员gameObject指向gameObject
因此 围绕着gameObject有一个组件transform 除此之外 还有一些必有的组件1,2…
同时 每个组件都有一个transform变量指向节点所对应的transform组件 包括其自己也有一个transform变量指向它自己
同时 transform又是一个组件 因此也能拿到gameObject
gameObject
成员可以获得该组件实例所绑定的节点transform
成员可以获得该组件实例所绑定的transform组件transform
成员指向其所挂载的Transform组件的实例GetComponent() 获取节点上所挂载的transform组件实例
<>
里填入要获取的组件的类型即可
获取节点上所挂载的transform组件实例// 获取节点上所挂载的transform组件实例 // 会自动查找节点挂载的第一个Transform的组件实例 Transform t=gameObject.GetComponent<Transform>(); Debug.Log(t.name);
// 获取节点上所挂载的所有为该类型的组件 Transform[] tList = gameObject.GetComponents<Transform>(); for (int i=0;i<tList.Length;i++) { Debug.Log(tList[i].name); }
// 获取名为cube的组件实例 Debug.Log(cube.gameObject.GetComponent("cube"));
gameObject
开始查找的
其实只是封装了一层 本质还是通过组件找到节点 然后通过节点找指定组件的 就不需要通过gameObject了// 根据组件获取当前组件所挂载的节点的其它组件 // 其实只是封装了一层 本质还是通过组件找到节点 然后通过节点找指定组件的 就不需要通过gameObject了 this.GetComponent<Transform>();
将代码中的参数绑定到编辑器
比如:
public class game_scene : MonoBehaviour { public int speed=10; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } }
同样 在编辑器中进行修改 在代码中也能拿到对应的值 (类似于Vue的双向数据绑定…)
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算