MonoBehavior/GameObject/Time/Transform/位移/角度旋转/缩放看向/坐标转换

MonoBehavior相关内容

复制代码
using UnityEngine;

public class Lesson3 : MonoBehaviour
{

    void Start()
    {
        //2.获取依附的GameObject的位置信息
        print(this.transform.position);
        print(this.transform.eulerAngles);
        print(this.transform.lossyScale);
       
    }
}

对应这三个参数

从当前物体通过脚本获取其他物体

通过在当前物体中声明一个类,然后将挂载该类的物体拖拽到这个窗口中,便可以获取该类物体相关信息(例如Transform/挂载组件之类)

获取脚本

获取物体单个脚本

第一种不常用,一般用泛型获取

复制代码
// 1. 获取脚本的方法
// 如果获取失败,就是没有对应的脚本,会默认返回空
Lesson3_Test t = this.GetComponent("Lesson3_Test") as Lesson3_Test;
print(t);

// 根据 Type 获取
t = this.GetComponent(typeof(Lesson3_Test)) as Lesson3_Test;
print(t);

// 根据泛型获取,建议使用泛型获取,因为不用二次转换
t = this.GetComponent<Lesson3_Test>();
if(t!=null){print(t);}

只要你能得到场景中的对象或者对象依附的脚本
那你就可以获取到它的所有信息

获取自己的多个脚本

一般不会同个脚本放在一个物体上

cs 复制代码
// 2. 得到自己挂载的多个脚本
//将当前物体中的Lesson3脚本返回到list存储起来
Lesson3[] array = this.GetComponents<Lesson3>();
print(array.Length);
List<Lesson3> list = new List<Lesson3>();
this.GetComponents<Lesson3>(list);

获取自己的子物体的单个脚本/多个脚本

这里也是找脚本Lesson3_Test

cs 复制代码
// 3. 得到子对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
// 函数是有一个参数的,默认不传是 false,意思就是:如果子对象失活,是不会去找这个对象上是否有某个脚本的
// 如果传 true,及时失活,也会找
t = this.GetComponentInChildren<Lesson3_Test>(true);
print(t);

// 得到子对象挂载脚本(单个)
Lesson3_Test[] lts = this.GetComponentsInChildren<Lesson3_Test>(true);
print(lts.Length);

// 得到子对象挂载脚本(多个)
List<Lesson3_Test> list2 = new List<Lesson3_Test>();
this.GetComponentsInChildren<Lesson3_Test>(true, list2);
print(list2.Count);

获取自己的父物体的单个脚本/多个脚本

这里不用像子对象一样------需要用true进行判断,因为父对象失活,自身也会失效

cs 复制代码
// 4. 得到父对象挂载的脚本(它默认也会找自己身上是否挂载该脚本)
t = this.GetComponentInParent<Lesson3_Test>();
print(t);

lts = this.GetComponentsInParent<Lesson3_Test>();
print(lts.Length);

// 它也有list的,省略不写了,和上面是一样的套路

GameObject相关内容

**核心概念:**GameObject是Unity场景中的最小单位,所有脚本都依附在GameObject上

基本属性

cs 复制代码
// 一些属性:
     // 脚本的激活
     this.enabled = true;

     // gameobj对象的激活
     bool isActive = this.gameObject.activeSelf;

     // 获取是否静态
     bool isStatic = this.gameObject.isStatic;

     // 获取标签
     string tag = this.gameObject.tag;

     // 获取层级
     int layer = this.gameObject.layer;

注意:这个Gameobject类也可以用transform

  • 物体位置信息有两种获取方式:
    • 通过MonoBehaviour:this.transform
    • 通过GameObject:this.gameObject.transform
  • 等效性: 两种方式获取的是同一个Transform组件
  • 位置信息: 可通过.position获取位置坐标,打印时会自动四舍五入显示

静态方法

cs 复制代码
// 静态方法:
	// 创建几何体
	    GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
	
	// 查找对象
	// 只能找激活对象,存在多个同名随机找出一个
	    GameObject obj1=GameObject.Find("otherTest"); // 对象名查找
	    GameObject obj2=GameObject.FindGameObjectWithTag("Player"); // 标签名查找
        if(obj1!=null){}//防止对象没有而报错



	    // 利用标签名找多个对象(找多个对象只能通过Tag来)
	    GameObject[] objs = GameObject.FindGameObjectsWithTag("Player");
	
	

// 实例化对象(空对象)
	    GameObject instObj = GameObject.Instantiate(testOBJ);
	
	
// 删除对象
	    GameObject.Destroy(instObj); // 删除实例化对象
	    GameObject.Destroy(instObj,5); // 延迟删除
	    GameObject.Destroy(this); // 删除脚本,这里是删除自身这个脚本
	    GameObject.DontDestroyOnLoad(this.gameObject);//场景切换时,物体会默认移除,所以会使用该方法保留不想切换场景摧毁的物体

Destory相关知识点

  • 异步移除:Destroy不会立即移除对象,只是添加移除标识
    • 执行时机:一般情况下先标记,然后通常在下一帧才会真正从内存移除
    • 设计目的:避免卡顿,统一处理内存释放
  • 内存管理:对象移除包含从场景和内存中双重移除
    • 该方法是异步的

**方法对比:**DestroyImmediate会立即移除对象并释放内存

  • 使用建议:除非特殊需求,否则建议使用普通Destroy
  • 性能考量:立即删除可能引起卡顿,特别是在批量操作时
  • 应用场景:编辑器扩展等需要即时反馈的特殊情况

Unity中的Object与C#中的Object区别

  • 命名空间区别:
    • Unity中的Object类位于UnityEngine命名空间
    • C#中的Object(万物之父)位于System命名空间
  • 继承关系:
    • Unity的Object是继承自C#万物之父的自定义类
    • 虽然继承但功能不同,Unity的Object特指游戏对象相关功能

成员方法

cs 复制代码
// 成员方法:
	// 创建空对象
	GameObject gameObject = new GameObject();
	GameObject gameObject2 = new GameObject("Test"); // 初始化对象名
	GameObject gameObject3 = new GameObject("TestAddComponent",typeof(otherTest)); // 初始化对象名,并且添加脚本(变长
	
	// 为对象添加脚本------ot是这个脚本实例化的名字
	otherTest ot = this.AddComponent<otherTest>();

    //得到脚本------Monobeahavior静态方法含有得到脚本相关方法
	
	// 标签比较
	if( this.CompareTag("Player"); )
    if(this.gameObject.tag == "Player")
	
	// gameobj的激活失活
	bool isActive  = this.gameObject.activeSelf; // 获得激活还是失活状态
	this.gameObject.SetActive(true); // 设置激活还是失活

比较次要的成员方法

了解即可------可能协作时有人会用这段代码,但是这个代码效果非常低下,自己最好不用

cs 复制代码
// 通知自己 执行什么行为
// 命令自己 去执行这个TestFun这个函数 会在自己身上挂在的所有脚本去找这个名字的函数
// 它会去找到 自己身上所有的脚本 有这个名字的函数去执行
this.gameObject.SendMessage("TestFun");
this.gameObject.SendMessage("TestFun2", 199);

// 广播行为 让自己和自己的子对象执行
// this.gameObject.BroadcastMessage("函数名");

// 向父对象和自己发送消息 并执行
// this.gameObject.SendMessageUpwards("函数名");

Time相关

核心概念: 通过Time类的timeScale属性控制游戏时间流速

cs 复制代码
 // 时间缩放
    Time.timeScale = 0; // 0倍 
    Time.timeScale = 2; // 2倍

帧时间间隔

  • 概念: 帧间隔时间指最近一帧完成所用的时间(单位:秒)
  • 本质: Unity游戏循环中一次完整循环的耗时
    • 60帧游戏的标准帧间隔时间约为16.67ms(1/60秒)
    • 120帧游戏约为8.33ms(1/120秒)

后续会学习如何将帧时间间隔控制到16ms------因为太低对Cpu压力也很大

cs 复制代码
    // 帧间隔时间
    float deltaTime = Time.deltaTime; // 受scale影响
    float unscaleDelatTime = Time.unscaledDeltaTime; // 不受scale影响

当timeScale=0时, Time.deltaTime=0而Time.unscaledDeltaTime依旧有值

帧间隔时间主要用于计算位移------核心公式: 位移 = 时间 × 速度

  • 选择原则:
    • 常规移动(游戏暂停时不移动的话)使用deltaTime
    • 需要无视暂停的效果使用unscaledDeltaTime

游戏开始到现在的时间

cs 复制代码
// 游戏开始到现在的时间
float time = Time.time; // 受scale影响
float unscaledTime = Time.unscaledTime; //不受scale影响

应用场景

  • 单机计时:主要用于单机游戏计时
  • 网络游戏限制:网络游戏应使用服务器时间而非本地时间

物理帧间隔

默认值:0.02秒(对应50FPS)------具体配置方法可在生命函数FixedUpdate() 中翻阅

cs 复制代码
private void FixedUpdate() 
{
    // 物理帧间隔时间
    float fixedDeltaTime = Time.fixedDeltaTime; // 受scale影响
    float fixedUnscaledDelateTime = Time.fixedUnscaledDeltaTime; // 受scale影响
}

帧数

本质:帧数表示游戏循环执行的次数,通过Time.frameCount获取

cs 复制代码
// 游戏开始到现在跑了多少帧
 float frameCount = Time.frameCount;

Transform相关

Unity 中的坐标系与 UE 不同,垂直屏幕向里面是 z轴,向上是y轴

Vector相关

cs 复制代码
// Vector3 可以表示点 或者 向量
Vector3 v1 = new Vector3(1, 2); // 缺省为0
Vector3 v2 = new Vector3(1, 5, 3);

// Vector3的基本计算
Vector3 v1 = new Vector3(1, 1, 1);
Vector3 v2 = new Vector3(2, 2, 2);

// 对应用x+或者-x......
print(v1 + v2); // (3, 3, 3)
print(v1 - v2); // (-1, -1, -1)

print(v1 * 10); // (10, 10, 10)
print(v2 / 2);  // (1, 1, 1)


// 零向量 单位向量
Vector3 zero = Vector3.zero; // 零向量
Vector3 right = Vector3.right; // 1 0 0
Vector3 left = Vector3.left; // -1 0 0
Vector3 forward = Vector3.forward; // 0 0 1 (面朝向)
Vector3 back = Vector3.back; // 0 0 -1
Vector3 up = Vector3.up; // 0 1 0
Vector3 down = Vector3.down; // 0 -1 0

// 两点距离
float distance = Vector3.Distance(v1, v2);

美术应在建模软件中将角色正面朝向其软件的'前方向'(通常是 Z+ 或 -Y),而不是强行对齐 Unity 的 Z 轴。

软件 默认朝上轴 默认朝前轴
Maya Y Z
3ds Max Z Y
Blender Z -Y
Cinema 4D Y -Z

Position相关

cs 复制代码
// 位置 position
Vector3 postiontion = this.transform.position; // 是世界坐标系下的坐标
Vector3 localPosition = this.transform.localPosition; // 本地坐标,相对于父对象的坐标,与面板显示一致
this.transform.position = new Vector3(1, 2, 3); // 不能单独改变position的 x,y,z


修改position
// 如果只想改一个值 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;

对象朝向

cs 复制代码
// 本地向量
Vector3 myForward = this.transform.forward;

对象朝向是基于当前旋转状态计算的,如下是俯视图

位移相关

位移 = 速度矢量(速度*方向) × 时间

额外注意点:这种帧变化相关的操作都放在Update函数中

复制代码
void Update()
{
    // 位移 
    // 三个等价:朝着自己的面朝向前进

    //1、自己计算------目标位置=当前位置+在指定方向的位移
    //(这里默认速度为1,实际是速度*方向*帧时间间隔,即帧位移)
    this.transform.position += this.transform.forward * Time.deltaTime;


    //调用Unity自带 API
    第一个参数:表示位移多少
    第二个参数:参考坐标系,默认该参数是相对自身的坐标系
    this.transform.Translate(Vector3.forward *1*Time.deltaTime); // 参考本地坐标系
    //如下指的是在世界坐标系下,沿着物体面朝向移动
    this.transform.Translate(this.transform.forward * Time.deltaTime, Space.World); // 参考世界坐标系
}

两种坐标系的都是物体面朝向,底层逻辑不同

复制代码
this.transform.Translate(Vector3.forward * Time.deltaTime);
// 等价于:
this.transform.Translate(Vector3.forward * Time.deltaTime, Space.Self);
  • Vector3.forward(0,0,1) ------ 这是一个固定的世界向量
  • 但因为用了 Space.Self(本地坐标系),Unity 会 把这个向量解释为"本地 Z 轴方向"
  • 所以实际上:不管 Vector3.forward 原本是什么,在本地坐标系下它就代表"物体自己的前方"
    • ✅ 效果:物体沿自身朝向移动。

💡 这就像你说:"我向前走一步"------这个"前"是相对于你自己身体的方向。

复制代码
this.transform.Translate(this.transform.forward * Time.deltaTime, Space.World);
  • transform.forward 是一个 动态计算出来的世界向量,表示"该物体局部 Z 轴在世界空间中的方向"。
  • 例如:如果物体旋转了 90° 向右,transform.forward 可能是 (1, 0, 0)(世界 X 轴方向)。
  • 然后你在 Space.World 下使用这个向量,就是直接在世界空间中沿那个方向移动。
    • ✅ 效果:同样沿自身朝向移动。

💡 这就像别人看着你说:"他现在面朝东,就让他向东走"------这是从外部观察者的视角描述。

如果想控制 相对于物体自身的运动,就用自身坐标系就够了。

角度和旋转

获取方法: 使用this.transform.eulerAngles获取对象相对于世界坐标系的欧拉角

**返回值类型:**返回Vector3类型,对应Inspector面板上显示的X/Y/Z角度值

**注意事项:**不能直接使用rotation属性,因为其返回的是四元数(Quaternion),与界面显示值不一致

cs 复制代码
Vector3 eulerAngles = this.transform.eulerAngles; // 世界坐标系
Vector3 localEulerAngles = this.transform.localEulerAngles; // 本地坐标系(即受父物体影响的旋转)

// 注意:设置角度和设置位置一样,不能单独设置xyz,要一起设置
this.transform.localEulerAngles = new Vector3(10, 10, 10);
this.transform.eulerAngles = new Vector3(10, 10, 10);
print(this.transform.localEulerAngles);

旋转运动

自转

cs 复制代码
// API计算
// 自转
// 每个轴(手动写入,这里的10感觉是速度) 具体每帧转多少度
// 第一个参数 相当于是旋转的角度 每一帧
// 第二个参数 默认不填 就是相对于自己坐标系 进行的旋转
this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime);
 this.transform.Rotate(new Vector3(0, 10, 0) * Time.deltaTime, Space.World);

// 相对于某个轴 转多少度
// 参数一:是相对哪个轴进行转动
// 参数二:是转动的角度 是多少
// 参数三:默认不填 就是相对于自己的坐标系 进行旋转
// 如果填 可以填写相对于世界坐标系进行旋转
// this.transform.Rotate(Vector3.right, 10 * Time.deltaTime);
this.transform.Rotate(Vector3.right, 10 * Time.deltaTime, Space.World);

公转

cs 复制代码
// 相对于某个轴 转多少度
// 参数一:是相对哪个轴进行转动
// 参数二:是转动的角度 是多少
// 参数三:默认不填 就是相对于自己的坐标系 进行旋转
// 如果填 可以填写相对于世界坐标系进行旋转
// this.transform.Rotate(Vector3.right, 10 * Time.deltaTime);
this.transform.Rotate(Vector3.right, 10 * Time.deltaTime, Space.World);

缩放相关

一般改localScale,相对于父对象的缩放,即相对缩放

cs 复制代码
 // 缩放
//不能单独修改xyz分量,必须同时修改
//特性: 相对世界坐标系大小只能获取不能修改,与位置和旋转不同(位置旋转可修改)
Vector3 lossyScale = this.transform.lossyScale; // 世界坐标系
Vector3 localScale = this.transform.localScale; // 本地坐标系

帧动态缩放

cs 复制代码
void Update()
{
    // 2. Unity没有提供关于缩放的API
    // 之前的旋转、位移都提供了对应的API,但是缩放并没有
    // 如果你想要让缩放发生变化,只能自己去写(自己算)

    this.transform.localScale += Vector3.one * Time.deltaTime;//这里Vector3.one是(1,1,1)

看向

cs 复制代码
//物体的正前方(z轴)将指向目标点
public Transform lookObject;
void Start()
{
    //看向一个点
    this.transform.LookAt(Vector3.zero);
    //看向一个对象
    this.transform.LookAt(lookObject);
}

父子相关API

添加父对象

cs 复制代码
void Start()
{
	// 父对象
	print(this.transform.parent); // 获取
	this.transform.parent = null; // 取消父对象
	this.transform.parent = GameObject.Find("Cube").transform; // 设置父对象

	this.transform.SetParent(null); // API的方法修改父对象

    // true 会保留世界坐标下的状态 和 父对象 进行计算 得到本地坐标系的信息
    // false 不会保留 会直接把世界坐标系下的 位置角度缩放 直接赋值到 本地坐标系下
	this.transform.SetParent(GameObject.Find("Cube").transform, true); // 保留面板上的参数
	this.transform.SetParent(GameObject.Find("Cube").transform, false); // 保持原本的世界坐标系状态,面板参数根据父对象修改

}
------------------------------------------------

子对象相关操作

cs 复制代码
	// 子对象
	this.transform.DetachChildren(); // 取消所有子对象
	this.transform.Find("Cube"); // 根据名字查找子对象,失活也可以查找,区别Gameobject
	
	for(int i = 0; i < this.transform.childCount; i++) 
	{
	    print(this.transform.GetChild(i)); // 索引号获得子对象
	}
	
	son.IsChildOf(this.transform); // 是子对象返回true 否则false
	son.GetSiblingIndex(); // 子对象编号
	son.SetAsFirstSibling(); // 设置为第一个子对象
	son.SetAsLastSibling(); // 设置为最后一个子对象
	son.SetSiblingIndex(2); // 自定义编号------如果填的数值超出范围也不会报错

坐标转换

世界坐标转换成本地坐标系

点的坐标系转换

cs 复制代码
// 世界坐标系的点 转化为 本地坐标系的点
// 受到target缩放大小影响
var pos = target.InverseTransformPoint(Vector.forward);

这就是坐标转换的具体细节

收到缩放影响:当cube放大2倍,转换后的坐标变为(-0.4,0,-0.4)

方向的坐标系转换

cs 复制代码
// 世界坐标系的方向 转化为 本地坐标系的方向
// 受到target缩放大小影响
var dic = target.InverseTransformDirection(new Vector3(0, 0, 1));
Debug.Log(dic);
// 不受到target缩放大小影响
dic = target.InverseTransformVector(new Vector3(0, 0, 1)); 

本地坐标系转换成世界坐标系

这个比较常用

cs 复制代码
// 本地坐标系的点 转化为 世界坐标系的点
print(this.transform.TransformPoint(Vector3.forward)); // 受自身缩放影响
// 本地坐标系的方向 转化为 世界坐标系的方向
print(this.transform.TransformDirection(Vector3.forward)); // 不受自身缩放影响
print(this.transform.TransformVector(Vector3.forward)); // 受自身缩放影响

本地坐标的点转换成世界坐标

本地坐标向量转换成世界坐标向量

相关推荐
凯子坚持 c2 小时前
Qt常用控件指南(4)
开发语言·qt
代码无bug抓狂人2 小时前
C语言之切蛋糕(运用前缀和算法和单调队列算法)
c语言·开发语言
量子炒饭大师2 小时前
【C++入门】Cyber骇客构造器的核心六元组 —— 【类的默认成员函数】明明没写构造函数也能跑?保姆级带你掌握六大类的默认成员函数(上:函数篇)
开发语言·c++·dubbo·默认成员函数
漫漫求2 小时前
Go的panic、defer、recover的关系
开发语言·后端·golang
曲幽2 小时前
FastAPI实战:Redis缓存与分布式锁的深度解析
redis·python·cache·fastapi·web·lock
Tony Bai2 小时前
2025 Go 官方调查解读:91% 满意度背后的隐忧与 AI 时代的“双刃剑”
开发语言·后端·golang
沐知全栈开发2 小时前
R 绘图 - 饼图
开发语言
charlie1145141912 小时前
嵌入式C++开发——RAII 在驱动 / 外设管理中的应用
开发语言·c++·笔记·嵌入式开发·工程实践
Fcy6482 小时前
C++11 新增特性(中)
开发语言·c++·c++11·可变参数模版·c++11 类的新增功能·c++11slt新增特性