视频教程:https://www.bilibili.com/video/BV12s411g7gU/?share_source=copy_web
Transform
对象的位置、旋转和缩放
场景中的每个对象都有一个Transform,用于存储和操作对象的位置、旋转和缩放。 每个Transform都可以有一个父级,能够分层应用位置、旋转和缩放
Transform.position:相对于世界坐标系原点的位置
Transform.localPosition:相对于父物体轴心点的位置,若没有父级,则其与Transform.position相同
Transform.localScale:相对于父物体的缩放比例
ps:Inspector面板中的Position、Rotation、 Scale均是相对于父物体的
将Inspector面板设置为debug
Transform.lossyScale: 物体的全局缩放比例(只读)
ps:lossyScale=自身缩放比例*父物体缩放比例;假设父物体localScale为2,子物体localScale为3,则其lossyScale为6
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TransformDemo : MonoBehaviour
{
public Transform root;
void OnGUI()
{
if (GUILayout.Button("foreach--transform"))
{
foreach (Transform child in this.transform)
{
print(child.name);
}
}
if (GUILayout.Button("root"))
{
print(this.transform.parent);
}
if (GUILayout.Button("Space.World--setParent"))
{
//当前物体的位置视为世界坐标
this.transform.SetParent(root);
}
if (GUILayout.Button("Self.World--setParent"))
{
//当前物体的位置视为localScale
this.transform.SetParent(root, false);
}
if (GUILayout.Button("DetachChildren"))
{
this.transform.DetachChildren();
}
if (GUILayout.Button("Find"))
{
print(this.transform.Find("Cube"));
}
if (GUILayout.Button("childCount"))
{
int count = this.transform.childCount;
for (int i = 0; i < count; i++)
{
print(transform.GetChild(i));
}
}
if (GUILayout.Button("Self.World--Z+1"))
{
this.transform.Translate(0, 0, 1);
}
if (GUILayout.Button("Space.World--Z+1"))
{
this.transform.Translate(0, 0, 1, Space.World);
}
if (GUILayout.Button("Self.World--Rotate_X+1"))
{
this.transform.Rotate(10, 0, 0);
}
if (GUILayout.Button("Space.World--Rotate_X+1"))
{
this.transform.Rotate(10, 0, 0, Space.World);
}
if (GUILayout.RepeatButton("RotateAround"))
{
this.transform.RotateAround(Vector3.zero, Vector3.up, 1);
}
}
}
foreach--transform按钮:获取直接(第一代)子物体的物体名
有如下图的父子关系,child 1、child 2和child 3是父物体parent的直接(第一代)子物体,而_child 1、_child 2是其间接(第二代)子物体;将TransformDemo挂载至父物体parent上
运行后点击foreach--transform按钮,可以观察到控制台输出第一代子物体的物体名
Transform.parent:获取根物体的Transform组件
root按钮:输出根物体的物体名(类似树中的根节点);如同样有上文中的父子关系图,分别将脚本挂载至child 1和_child 1并点击root按钮,可以观察到控制台输出的均是parent
Transform.SetParent:设置当前Transform的父级
Space.World--setParent按钮与Self.World--setParent按钮:两者的功能都是将当前游戏对象设置为另一游戏对象的子物体(设置父级),区别在于设置父子关系后的位置
在Space.World--setParent按钮中
this.transform.SetParent(root)
等价于
this.transform.SetParent(root,true)
上述代码的含义为将当前物体设置为root的子物体后,将当前物体相对于世界坐标系原点的位置转换为相对于root的localPosition,即当前物体在世界坐标系中的位置不发生改变
如下图root(15,0,0),Cube(15,0,5),执行后Cube中世界坐标的位置仍为(15,0,5),而相对于root的localPosition为(0,0,5)
而在Self.World--setParent按钮中
this.transform.SetParent(root, false)
该代码的含义为将当前物体设置为root的子物体后,将当前物体相对于世界坐标系原点的位置作为相对于root的localPosition,即当前物体在世界坐标系中的位置等于父物体在世界坐标中的位置+当前物体此前在世界坐标中的位置(两者的向量和)
如下图root(15,0,0),Cube(15,0,5),执行后Cube中世界坐标的位置为(30,0,5),而相对于root的localPosition为(15,0,5)
Transform.DetachChildren:解除父级的所有直接(第一代)子项(子物体)
DetachChildren按钮: 若有如foreach--transform中父子结构,同样为parent挂载该脚本,运行后点击DetachChildren按钮,则parent的所有直接子项解除与父级parent的关系;即分离出了child 1、child 2、child 3,而_child 1和_child 2仍分别作为child 1和child 2的子项
Transform.Find:寻找并返回对应名称的子项
Find按钮:在所有直接子项中寻找并返回名为Cube的子项
Transform.childCount:返回父级的直接(第一代)子项数
Transform.GetChild:按索引返回对应的直接(第一代)子项
childCount按钮:与foreach--transform按钮功能类似但可以按索引返回对应的第一代子项;同样以foreach--transform中父子结构为例,为parent挂载该脚本,运行并点击childCount按钮,可以观察到控制台输出父级parent的第一代子项
Transform.Translate:按世界坐标或者本地坐标移动物体
Self.World--Z+1按钮与Space.World--Z+1:两者的功能都是使物体的Z轴+1,但参考系不同,Self.World--Z+1参考的是物体的自身坐标而Space.World--Z+1参考的是世界坐标
在Self.World--Z+1中
this.transform.Translate(0, 0, 1)
等同于
this.transform.Translate(0, 0, 1, Space.Self)
关于自身坐标与世界坐的区别,如下图所示
Transform.Rotate:按世界坐标或者本地坐标旋转物体,通常以欧拉角而不是四元数提供旋转
Self.World--Rotate_X+1按钮与Space.World--Rotate_X+1按钮,两者的功能均是将物体绕X轴选择1度,而区别同样在于参考系不同
Transform.RotateAround:围绕穿过世界坐标中的一点的旋转轴旋转物体
RotateAround按钮:使物体围绕穿过坐标原点方向向量为(0,1,0)的旋转轴进行旋转
使用递归在层级未知的情况下查找子项
编写脚本TransformHelper
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TransformHelper : MonoBehaviour
{
public string target;
void OnGUI()
{
if (GUILayout.Button("Recursion_Find"))
{
print(Recursion_Find(this.transform, target));
}
}
Transform Recursion_Find(Transform root, string name)
{
Transform target = root.transform.Find(name);
if (target) return target;
if (root.transform.childCount == 0) return null;
foreach (Transform child in root.transform)
{
if (Recursion_Find(child, name) != null)
{
return Recursion_Find(child, name);
}
}
return null;
}
}
更改foreach--transform中展示父子结构,在child 3添加一个名为target的Cube作为查找的目标
在parent上挂载脚本并进行参数设置后,运行场景点击Game面板中左上角的Recursion_Find按钮,可以观察控制台输出了子项target
GameObject
GameObject.activeInHierarchy:物体实际激活状态
GameObject.activeSelf:物体自身激活状态(Inspector面板中的状态,且是只读的)
如下图,父级child 1被禁用导致子项_child 1被禁用,但实际上子项_child 1在Inspector面板中仍是启用状态
在上述情况下,子项_child 1的activeInHierarchy为fales,而activeSelf为true
GameObject.SetActive:启用/禁用物体
GameObject.AddComponent<T>():将组件T添加到游戏对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameObjectDemo : MonoBehaviour
{
void OnGUI()
{
if (GUILayout.Button("添加光源"))
{
GameObject lightGO = new GameObject();
Light light = lightGO.AddComponent<Light>();
light.color=Color.red;
light.type=LightType.Point;
}
}
}
ps:在脚本中挂载组件时无需使用new关键字创建对象,因为执行AddComponent方法以包含了使用new进行构造的过程
为某一游戏对象挂载该脚本,运行后点击Game面板中左上角的“添加光源”按钮,即可发现创建中新增了一个挂载light组件且名为New Game Object的游戏对象
GameObject.Find("游戏对象名称"):在场景中根据名字查找物体(慎用,该方法将会尝试遍历场景中的每一个游戏对象)
GameObject.FindGameObjectWithTag("标签名称"):返回第一使用该标签的物体(单个)
GameObject.FindGameObjectsWithTag("标签名称"):返回所有使用该标签的物体(数组)
Object
Object.Destroy(Object obj, float delay= 0.0F):移除GameObject、组件或资源
obj | 要销毁的对象 |
delay | (可选)销毁对象前的延迟时间 |
Object.DestroyImmediate:立即销毁游戏对象(建议改用 Destroy)
Object.DontDestroyOnLoad:在加载新的Scene时,不销毁Object
Object.FindObjectOfType<T>():返回第一个类型为T的激活对象(单个)
Object.FindObjectsOfType<T>():返回所有类型为T的对象(数组)
查找血量最低的敌人
编写脚本Enemy
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float hp;
}
在场景中创建三个游戏物体分别命名为Enemy 1、 Enemy 2、Enemy 3,为其挂载脚本Enemy并设置不同的Hp
编写脚本Find_Enemies并将其挂载至某一游戏物体后,运行场景并点击“查找血量最低的敌人”按钮
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Find_Enemies : MonoBehaviour
{
void OnGUI() {
if(GUILayout.Button("查找血量最低的敌人")){
var enemy_list=Object.FindObjectsOfType<Enemy>();
Enemy target=enemy_list[0];
foreach(Enemy i in enemy_list){
if(target.hp>i.hp){
target=i;
}
}
print(target);
}
}
}
getcomponentinparent
lookat
GetSiblingIndex
Time
time
deltaTime 每帧的间隔 完成一帧的时间
unscaletime