Unity脚本(二)

时间:2023-01-01 16:53:22

视频教程:https://www.bilibili.com/video/BV12s411g7gU?p=122   

目录

Transform

GameObject

Object

GetComponentInParent

LookAt

GetSiblingIndex和SetSiblingIndex

Instantiate 


Transform

对象的位置、旋转和缩放

场景中的每个对象都有一个Transform,用于存储和操作对象的位置、旋转和缩放。 每个Transform都可以有一个父级,能够分层应用位置、旋转和缩放

Transform.position:相对于世界坐标系原点的位置 

Transform.localPosition:相对于父物体轴心点的位置,若没有父级,则其与Transform.position相同

Transform.localScale:相对于父物体的缩放比例

ps:Inspector面板中的Position、Rotation、 Scale均是相对于父物体的

将Inspector面板设置为debug

Unity脚本(二)  

Unity脚本(二)

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);
        }
    }
}

Unity脚本(二)

foreach--transform按钮:获取直接(第一代)子物体的物体名

有如下图的父子关系,child 1、child 2和child 3是父物体parent的直接(第一代)子物体,而_child 1、_child 2是其间接(第二代)子物体;将TransformDemo挂载至父物体parent上 

Unity脚本(二)

运行后点击foreach--transform按钮,可以观察到控制台输出第一代子物体的物体名

Unity脚本(二)

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) 

Unity脚本(二)

而在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)

Unity脚本(二)

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的子项

ps:可写成如下路径的格式代表父子层级 

transform. Find("LeftShoulder/Arm/Hand/Finger");

Transform.childCount:返回父级的直接(第一代)子项数 

Transform.GetChild:按索引返回对应的直接(第一代)子项

childCount按钮:与foreach--transform按钮功能类似但可以按索引返回对应的第一代子项;同样以foreach--transform中父子结构为例,为parent挂载该脚本,运行并点击childCount按钮,可以观察到控制台输出父级parent的第一代子项

Unity脚本(二)

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)

 关于自身坐标与世界坐的区别,如下图所示

Unity脚本(二)

Transform.Rotate:按世界坐标或者本地坐标旋转物体,通常以欧拉角而不是四元数提供旋转

Self.World--Rotate_X+1按钮与Space.World--Rotate_X+1按钮,两者的功能均是将物体绕X轴选择1度,而区别同样在于参考系不同

Transform.RotateAround:围绕穿过世界坐标中的一点的旋转轴旋转物体

Unity脚本(二)

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作为查找的目标

Unity脚本(二)

在parent上挂载脚本并进行参数设置后,运行场景点击Game面板中左上角的Recursion_Find按钮,可以观察控制台输出了子项target

Unity脚本(二)

GameObject

GameObject.activeInHierarchy:物体实际激活状态 

GameObject.activeSelf:物体自身激活状态(Inspector面板中的状态,且是只读的)

如下图,父级child 1被禁用导致子项_child 1被禁用,但实际上子项_child 1在Inspector面板中仍是启用状态

Unity脚本(二)  

Unity脚本(二)

 Unity脚本(二)

在上述情况下,子项_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的游戏对象 

 Unity脚本(二)

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

 Unity脚本(二)

 Unity脚本(二)

 Unity脚本(二)

编写脚本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);
        }
    }
}

Unity脚本(二)

查找距离最近的敌人  

分别将Enemy 1、Enemy 2、Enemy 3设置至不同位置

Unity脚本(二)  

Unity脚本(二)

Unity脚本(二)

 在脚本Find_Enemies中添加代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Find_Enemies : MonoBehaviour
{
    public Transform target;

    void OnGUI()
    {
        // 查找血量最低的敌人

        if (GUILayout.Button("查找距离最近的敌人"))
        {
            var enemy_list = Object.FindObjectsOfType<Enemy>();
            Enemy closer = enemy_list[0];
            float dist = Vector3.Distance(closer.transform.position, target.position);
            foreach (Enemy i in enemy_list)
            {
                if (Vector3.Distance(i.transform.position, target.position) < dist)
                {
                    closer = i;
                }
            }
            print(closer);
        }
    }
}

创建一个名为target空物体作为距离的参照物,即哪一个Enemy对象与target距离最近;运行场景并点击“查找距离最近的敌人”按钮

Unity脚本(二)  

Unity脚本(二)

Unity脚本(二)

Vector3.magnitude:返回该向量的模长的平方(只读)

ps:new Vector3(x,y,z).magnitude=x^2+y^2+z^2

Vector3.sqrMagnitude:返回该向量的模长(只读)

ps:new Vector3(x,y,z).sqrMagnitude=(x^2+y^2+z^2)^(1/2)

Vector3.Distance(Vector3 a, Vector3 b):返回a与 b间的距离,与(a-b).magnitude相同

GetComponentInParent

Component.GetComponentInParent<T>():从当前游戏对象开始查找T组件,若有直接返回,若无则向上遍历父级,直到找到为止

LookAt

Transform.LookAt:使当前物体向前矢量指向目标位置

GetSiblingIndex和SetSiblingIndex

Transform.GetSiblingIndex:获取同级(共享一个直接父级并且处于同一级别)索引

Unity脚本(二)  

Transform.SetSiblingIndex:设置/更改同级索引

Instantiate 

Object.Instantiate:克隆对象并返回