Unity代码笔记

作者:纸片

图片1 对游戏有了解的都知道,因为受场景渲染的复杂程度,还有输入的一系列事件等等各种原因影响,游戏画面的帧率是在不断变化的。 所以,在控制游戏逻辑的过程中,一般是需要按照每帧去处理的(使用Update )。而物理相关的处理,则需要根据时间的变化去处理(使用FixedUpdate )。 而当我们在Update 中,希望通过每隔一段时间去执行一些逻辑,比如最常见的修改GameObject的Transform,就需要使用Time.deltaTime来达到效果了。 根本原因,就是帧率在不断变化,Update 被调用的时间并不是线性的。 如下图,在时间轴上,渲染出的5帧画面Frame 1 Frame 5…

Update :每帧被调用一次 FixedUpdate :每隔Time.fixedDeltaTime被调用一次。 Time.fixedDeltaTime默认是0.02s,可以通过Edit ProjectSettings Time来设置 图片1 对游戏有了解的都知道,因为受场景渲染的复杂程度,还有输入的一系列事件等等各种原因影响,游戏画面的帧率是在不断变化的。 所以,在控制游戏逻辑的过程中,一般是需要按照每帧去处理的(使用Update )。而物理相关的处理,则需要根据时间的变化去处理(使用FixedUpdate )。 而当我们在Update 中,希望通过每隔一段时间去执行一些逻辑,比如最常见的修改GameObject的Transform,就需要使用Time.deltaTime来达到效果了。 根本原因,就是帧率在不断变化,Update 被调用的时间并不是线性的。 如下图,在时间轴上,渲染出的5帧画面Frame 1 Frame 5,以及每帧的时间间隔t1t4: 图片2 假如我们希望使GameObject每隔一段时间沿X轴正方向移动1个单位,可以在FixedUpdate 中这样写: transform.Translate Vector3.right 如果希望通过Update 来实现,把这句写到Update 中是不合适的,你会看到GameObject移动起来出现卡顿。 解决方法,是给移动的距离乘以Time.deltaTime: transform.Translate Vector3.right Time.deltaTime 这个时候,虽然不会出现卡顿,但是移动的速度会很慢。这个问题后面再解释,并给出解决办法。 为什么乘以Time.deltaTime之后就好了呢?要解释这个问题,要理解我们如何使GameObject产生了位移。 Transform的Translate方法接受的参数,实际上是一个位移,而不是速度。 在FixedUpdate 中,发生的情况是这样的: 图片3 因为FixedUpdate 的调用间隔就是0.02s=t1=t2=t3=t4,所以实际上,位移=速度 时间,transform.Translate Vector3.right == transform.Translate Vector3.right 1 1就代表了单位时间Time.fixedDeltaTime。 因为Update 并不是按照单位时间被调用的,所以要乘以每次的“帧间时间”,而这个时间就是Time.deltaTime。 这样的操作相当于一个“补偿”,将每次帧率的变化,通过时间的变化同步体现到执行逻辑上。 剩下一个问题,就是之前乘以Time.deltaTime之后速度变慢。 其实很好解决,在FixedUpdate 中,我们每次的执行间隔是0.02s,而单位时间体现的是1;同样我们在Update中,执行间隔是Time.deltaTime,为了与FixedUpdate一致,时间单位也需要是1。所以直接乘以FixedUpdate 中真实时间和单位时间的比例(1/0.02 = 50)即可,让Update中的时间也变成单位时间。 在Update 中需要依赖固定时间去执行的逻辑,都可以通过Time.deltaTime来进行“补偿”。道理是一样的。 if a==1 elee if a==2 Transform & GameObject 基础操作 Transform 属性 transform.position 世界坐标 Vector3 transform.localPosition 相对父节点坐标 transform.rotation/ transform.localRotation transform.eulerAngles 欧拉角,易读 transform.localScale 缩放 //Vector3 vs Vector2: 2D游戏尽量用 Vector2,减少不必要的Z轴干扰。 // 位置移动 transform.position = new Vector2 5, 3 ; // 设置位置 transform.Translate Vector2.right speed ; // 相对移动 transform.Translate 0, 1, 0 ; // 移动 x, y // 旋转 transform.rotation = Quaternion.Euler 0, 0, 45 ; // 设置旋转角度 transform.Rotate 0, 0, 90 ; // 旋转90度 // 缩放 transform.localScale = new Vector2 2, 2 ; // 设置缩放 // 查找 Transform child = transform.Find "ChildName" ; // 查找子物体 Transform parent = transform.parent; // 获取父物体 transform.SetParent newParent ; // 设置父物体 Vector2/Vector3 常用函数 // 距离 float distance = Vector2.Distance pos1, pos2 ; // 两点距离 float magnitude = velocity.magnitude; // 向量长度 float sqrMagnitude = velocity.sqrMagnitude; // 平方长度(性能更好) // 方向 Vector2 direction = target position .normalized; // 单位方向 Vector2 normalized = velocity.normalized; // 归一化 // 点积/叉积 float dot = Vector2.Dot dir1, dir2 ; // 点积 float angle = Vector2.Angle dir1, dir2 ; // 夹角 // 移动 Vector2 newPos = Vector2.MoveTowards current, target, speed Time.deltaTime ; Vector2 newPos = Vector2.Lerp start, end, t ; // 插值移动 // 特殊向量 Vector2 zero = Vector2.zero; // 0,0 Vector2 one = Vector2.one; // 1,1 Vector2 up = Vector2.up; // 0,1 Vector2 down = Vector2.down; // 0, 1 Vector2 left = Vector2.left; // 1,0 Vector2 right = Vector2.right; // 1,0 坐标转换 // 屏幕坐标 世界坐标 常用于鼠标点击 Vector3 worldPos = Camera.main.ScreenToWorldPoint Input.mousePosition ; worldPos.z = 0; // 2D游戏通常要把Z轴归零 // 世界坐标 屏幕坐标 Vector3 screenPos = Camera.main.WorldToScreenPoint transform.position ; 对象创建与销毁 // 1. 实例化预制体 最常用 Instantiate prefab, position, Quaternion.identity ; // 2. 克隆已有物体 GameObject clone = Instantiate existingObject ; GameObject go = Instantiate Object,Transform ; Instantiate sourceObject, transform.position, transform.rotation ; Destroy gameObject ; // 立即销毁 Destroy enemy, 2f ; // 2秒后销毁 //Destroy vs DestroyImmediate: 编辑器脚本用后者,运行时用前者。 // 创建/销毁 Destroy gameObject ; // 销毁物体 Destroy gameObject, 2f ; // 2秒后销毁 DestroyImmediate gameObject ; // 立即销毁 Instantiate prefab ; // 实例化 Instantiate prefab, position, rotation ; // 带位置旋转实例化 // 激活/禁用 gameObject.SetActive true ; // 激活物体 bool isActive = gameObject.activeSelf; // 是否激活 bool isActiveInHierarchy = gameObject.activeInHierarchy; // 层次中是否激活 // 查找 GameObject obj = GameObject.Find "ObjectName" ; // 按名称查找 GameObject obj = GameObject.FindWithTag "Player" ;// 按标签查找 GameObject enemies = GameObject.FindGameObjectsWithTag "Enemy" ; // 查找多个 // 组件操作 GetComponent<Rigidbody2D ; // 获取组件 GetComponentInChildren<SpriteRenderer ; // 获取子物体组件 GetComponentsInChildren<Collider2D ; // 获取所有子物体组件 AddComponent<Rigidbody2D ; // 添加组件 // 标签/层级 CompareTag "Player" ; // 比较标签 gameObject.tag = "Enemy"; // 设置标签 gameObject.layer = 8; // 设置层级 寻找对象 // 1. 直接查找 性能最差,Update中禁用 GameObject obj = GameObject.Find "Player" ; // 2. 通过标签查找 推荐 GameObject enemies = GameObject.FindGameObjectsWithTag "Enemy" ; GameObject player = GameObject.FindWithTag "Player" ; // 3. 通过层级路径查找 较快 Transform child = transform.Find "Weapon/Sword" ; // 4. 拖拽赋值 最佳实践,Inspector面板拖入 public GameObject targetObject; 组件获取类 if gameObject.TryGetComponent<怪物 脚本 out var 怪物 Debug.Log 怪物.生命 ; 怪物 脚本 怪物 = gameObject.GetComponent<怪物 脚本 ; Rigidbody2D rb = GetComponent<Rigidbody2D ; // 当前物体 BoxCollider2D col = GetComponentInChildren<BoxCollider2D ; // 自己或子物体 SpriteRenderer sr = GetComponentInParent<SpriteRenderer ; // 自己或父物体 组件开关 sr.enabled = false; // 关闭渲染 col.enabled = col.enabled; // 翻转碰撞体状态 数组&List<T &倒序删除 敌方.Add enemy…

#Unity代码笔记#Unity#Unity代码