C#初级编程
https://learn.u3d.cn/tutorial/beginner-gameplay-scripting
8 Update 和 FixedUpdate
Update(不是按固定时间调用的) 经常用于
- 移动非物理特性的物体(不是物理对象)
- 简单定时器
- 接收输入
FixedUpdate(调用时间间隔相同)
- 进行任何必要的物理计算(任何物理对象)
- 最好使用力来定义移动
使用 IDE 的 Unity Event Functions 插入函数
9 点积、叉积
点积算出标量,如果点积为 0 则两个向量互相垂直,飞机模拟例子:
- 点积 = 0,飞机前向 Z 轴 与 Y 轴垂直,此时阻力最小
- 点积 > 0,飞机在爬升,此时阻力变大
- 点积 < 0,飞机在俯冲
叉积算出新向量。使用左手坐标系根据 A 、B 确定 C 的方向(中指)
- 为了确定围绕哪个轴施加扭矩 来转动坦克炮塔
- 如果知道炮塔目前朝向和目标朝向,则可以用叉积算出需要围绕的轴的方向
10 启用和禁用组件
private Light myLight; private void Start() { myLight = GetComponent<Light>(); } private void Update() { if (Input.GetKeyUp(KeyCode.Space)) myLight.enabled = !myLight.enabled; }
11 激活游戏对象
- 父节点无效后,子节点也会一同跟着无效,(不活跃节点在层次结构中依旧可见)
- 利用父节点保持对对象群的控制
- 子节点由于父节点被禁用而禁用时,只针对子节点
setActive不管用,想要重新激活子节点就必须重新激活父节点
- 要确认某个节点是否为活跃状态
- activeSelf 看节点本身
- activeInHierarchy 看父子关系(父节点关则false;根节点自身为父节点)
Debug.Log(myObject.activeSelf); Debug.Log(myObject.activeInHierarchy);
12 物体移动
- 默认移动,旋转都是 Space.self
- 移动一个有碰撞体的对象(带物理效果的物体),不能用 Translate 与 Rotate
public void Rotate(Vector3 axis, float angle) => this.Rotate(axis, angle, Space.Self);
13 LookAt
让摄像机看向某一物体
public Transform target; private void Update() { transform.LookAt(target); }
14 Lerp
线性插值会在两个给定值之间找到某个百分比的值。
float result = Mathf.Lerp (3f, 5f, 0.5f); // Color.Lerp 和 Vector3.Lerp Vector3 from = new Vector3 (1f, 2f, 3f); Vector3 to = new Vector3 (5f, 6f, 7f); // 此处 result = (4, 5, 6) Vector3 result = Vector3.Lerp (from, to, 0.75f);
在对值进行平滑时,通常情况下最好使用 SmoothDamp 函数。想要实现特定效果时,才应使用 Lerp 进行平滑。
Unity - Scripting API: Mathf.SmoothDamp (unity3d.com)
Need help understanding the Mathf.SmoothDamp function - Unity Forum
ref velocity 存在的必要性
如果目标距离较远,函数会尝试加速你的位置,如果目标越来越近,则会减速。为了加速/减速,你需要知道你的速度有多快,这就是速度参数
16 GetButton、GetKey
- GetKey 需要使用 KeyCode 类型参数
- KeyCode 只与特定键相关,建议使用 GetButton
- 参数是字符串,可以在 Project Settings | Input Manager 中设置,灵活性很大
- 两种方式都有三种状态:Down、状态、Up
private void Update() { if(Input.GetButtonDown("Jump")) Debug.Log("按下了空格键"); if(Input.GetButtonDown("Fire1")) Debug.Log("按下了鼠标左键"); }
17 GetAxis、GetAxisRaw
- GetButton、GetKey 只返回布尔值
- GetAxis 返回浮点值,介于-1到1之间
- GetAxisRaw 返回浮点值,仅返回 -1,0,1,不受平滑过滤参数影响
- 针对需要严格控制输入的2D游戏非常有用
- Gravity 按钮松开后归零的速度(越高归零越快)
- Sensitivity 按钮按下后到达1或-1的速度有多快(越高越快)
- Dead 值针对手柄盲区(LS、RS轻微转动不影响)(越大盲区越大)
private void Update() { float x = Input.GetAxis("Horizontal"); float v = Input.GetAxis("Vertical"); float x2 = Input.GetAxisRaw("Horizontal"); float v2 = Input.GetAxisRaw("Vertical"); Debug.Log($"{x} {v} {x2} {v2}"); }
void Movement () { float forwardMovement = Input.GetAxis("Vertical") * speed * Time.deltaTime; float turnMovement = Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime; transform.Translate(Vector3.forward * forwardMovement); transform.Rotate(Vector3.up * turnMovement); }
18 OnMouseDown
用于检测对 带碰撞体组件的物体节点 或 GUI元素 鼠标点击事件
以下代码针对一个物理物体,每次鼠标点击给予 forward 反方向的推力
private void OnMouseDown() { Debug.Log($"点击 {gameObject.name}"); rb.AddForce(-transform.forward * 500f); }
19 GetComponent
GetComponent 性能消耗大,应该尽量减少调用,最好是在 Awake,Start 调用
20 deltaTime
定时器功能与平滑移动(按速度移动)
public float speed = 8f; public float countdown = 3.0f; void Update () { countdown -= Time.deltaTime; if(countdown <= 0.0f) light.enabled = true; if(Input.GetKey(KeyCode.RightArrow)) transform.position += new Vector3(speed * Time.deltaTime, 0.0f, 0.0f); }
21 值、引用

- 值类型对应的值被改变,只会影响特定变量
- 引用类型指向的值被改变,所有包含相同存储地址的引用类型变量都会受到影响
void Start () { //值类型变量 Vector3 pos = transform.position; // 值拷贝 pos = new Vector3(0, 2, 0); //引用类型变量 Transform tran = transform; tran.position = new Vector3(0, 2, 0); }
22 类
- 拆分类的功能,不要全部写在一起(单一职责原则)
- 如射击类、移动类、库存类
- 多用代码段,比如 ctor 生成构造函数
- 先全面仔细设计脚本结构,再开始编写一个大类,将各种不同内容囊括其中
23 Instantiate
Instantiate 用于动态生成预制体对象(创建预制件的克隆体)
⭐动态实例化生成的子弹预制体节点被强制转型成了 RigidBody
public Rigidbody bulletPrefab; // 可以不是GameObject而是绑定的组件 public Transform firePosition; public float bulletSpeed; ... Rigidbody bulletInstance = Instantiate(bulletPrefab, firePosition.position, firePosition.rotation) as Rigidbody;
案例中用到了 as 关键字。《C# 8.0本质论》里没有写
- 按(Rigidbody)显式转换方式如果转换不成功会抛出异常
- as 运算符类似于强制转换操作;但是,如果转换不可行,as 会返回 null 而不是引发异常
24 数组
使用 FindGameObjectsWithTag 初始化查找所有 Tag 为 Player 的节点存储至数组中
C# 数组是从抽象的基类型Array派生的引用类型
public GameObject[] players; void Start() { players = GameObject.FindGameObjectsWithTag("Player"); foreach (var player in players) { Debug.Log($"{player.name}"); } }
25 Invoke
- Invoke 调用的函数必须 不包含参数,且无返回值
其他内容以前笔记有写,略过
26 enum
用整数描述方向不易读,可以建立 enum 类型(类内类外都可创建)
enum Direction : short { North, // 0 East, // 1 South = 100, // 100 West // 101 }; void Start() { Direction myDirection; myDirection = Direction.North; var newDirection = ReverseDirection(myDirection); } Direction ReverseDirection (Direction dir) { if(dir == Direction.North) dir = Direction.South; else if(dir == Direction.South) dir = Direction.North; else if(dir == Direction.East) dir = Direction.West; else if(dir == Direction.West) dir = Direction.East; return dir; }
27 switch
跟 C++ 差不多
public int intelligence = 5; void Start() { switch (intelligence) { case 1: break; case 2: break; default: break; } }