- 官方文档 unity.cn/中文文档
- 本地路径 Editor/Data/Documentation/en/Manual/index.html
设置脚本默认打开方式: Edit/Preferences/External Tools/ Exteral Script Editor
Helloworld
添加一个脚本
- 右键 Create/C# Script
- 文件名必须规范, 文件名即类名 如SimpleLogic
- 双击在vs中打开脚本,检查类名与文件名是否一致
在vs中编辑代码
- 添加一行打印输出
void Start(){ Debug.Log("Hello World") }
- 其中Debug是Unity API中的一个工具类
- Ctrl+S 保存代码,关闭vs
编译
- 保存会自动编译
挂载脚本
- 点Add Component,选Scripts/Simple Logic
- 或者,直接将脚本拖到Inspector窗口的最下方
运行游戏
- 点play按钮,运行
帧
- Frame 一个游戏帧
- FrameRate 帧率|刷新率
- FPS Frames Per Second 每秒更新多少帧
Update() 帧更 新此方法会被游戏引擎定时调用,以更新游戏的状态
帧更新
- Time.time 游戏时间
- Time.deltaTime 距离上次更新的时间差
- 显然,帧率是不固定的,Unity会尽量较快地更新
Unity不支持固定的帧率,但可以设定一个近似帧率
Application.targetFameRate=60
其中,指示Unity尽量以FPS=60的帧率更新游戏物体
基本属性
- this 当前脚本组件
- this.gameObject 当前物体
- this.gameObjecet.name 当前物体的名字
- this.gameObject.transform 当前物体下的transform组件
为了简化书写 也可写作this.transform 效果相同
GameObject obj = this.gameObject; string name = obj.name; Transform tr = obj.transform;
API中的大部分类型,来自于UnityEngine
using UnityEngine;
- 基类 MonoBehaviour
- 游戏物体 GameObject
- 变换组件 Transform
三维向量 Vector3
坐标
物体的坐标
- transform.position 世界坐标
transform.localPosition 本地坐标
一般用localPosition 与Inspector窗口中的一致Vector3 pos = tr.position; Vector3 pos1 = tr.localPosition; tr.localPosition = new Vector3(1.2f, 1.2f, 1.2f);
移动
float speed = 3; float distance=speed * Time.deltaTime; Vector3 pos=this.transform.localPosotion; pos.x+=distance; this.transform.localPosotion=pos;
相对运动
一般使用
trasform.Translate(dx,dy,dz,space)
实现相对运动
其中dx,dy,dz是坐标增量
- 例如
transform.Translate(0,0,distance)
Z方向增加distance
float speed = 3;
float distance=speed * Time.deltaTime;
this.transform.Translate(0,0,distance);
其space:
- Space.World 相对于世界坐标系
- Space.Self 相对于自身坐标系(本地坐标系)
运动方向
获取目标物体(根据名字|路径来查找物体)
- GameObject flag=GameObject.Find("红旗")
转向目标(使物体的z轴指向物体)
- this.trnsform.LookAt(flag.transform);
向前运动,forward,+z方向(沿物体自身坐标系的轴向运动)
- this.transform.Translate(0,0,dz,Space.Self)
- 若目标在空中,则物体也向空中运动
向量测距
- p1=火车.transform.position
- p2=红旗.transform.position
- p=p1-p2
- distance=p.magnitude
play时观察跟随
旋转
给物体转一个旋转角度
Quanternion 四元组(x,y,z,w)
- transform.rotaion=... 不便操作,官方不建议使用
欧拉角 Euler Angle
- transform.eulerAngles=new Vector3(0,45,0);
- transform.localEulerAngles=new Vector(0,45,0); 一般使用这个
float rotateSpeed=30;
Vector3 angles=this.transform.localEulerAngles;
angles.y+=rotateSpeed*Time.deltaTime;
this.transform.localEulerAngles=angles;
相对旋转
Rotate() 旋转一个相对的角度transform.Rotate(dx,dy,dz,space)
float rotateSpeed=30;
this.transform.Rotate(0,rotateSpeed*Time.deltaTime,0.Space.Self);
当父物体转动时,带动子物体一并旋转。
生命周期
常见的生命周期消息函数
- Awake 初始化,仅仅执行一次
- Start 初始化,仅仅执行一次(script被禁用则不触发)
- Update 帧更新,每帧调用一次
- OnEnable 每当组件启用时调用
- OnDisable 每当组件禁用时调用
优先级
默认单个周期内物体没有优先级,都是0
Awake
- script1.Awake(),scirpt2.Awake()
Start
- script1.Start(),scirpt2.Start()
Update
- script1.Update(),scirpt2.Update()
优先级设定:
- 选中一个物体,打开Execution Order
- 点+,添加一个脚本
指定优先级,值越小,优先级越高
- 或者直接拖动调节顺序
主控脚本
游戏的主控逻辑
添加MainLogic.cs到新建的空物体上,设置优先级
脚本参数
- 参数必须为public,才可以在检查器中显示
参数的名称,即变量名
- rotateSpeed->Roate Speed
参数的默认值|初始值,即变量的默认值
- 可以Reset菜单重置
参数的工具提示,可以用Tooltip()指定
[Tooltip("旋转角速度")]
脚本参数的赋值(以下按时间顺序)
定义默认值
- Public float rotateSpeed=30f
在检查器中赋值
- script.rotateSpeed=180f //由unity框架对参数赋值
- 在awake中初始化
在start中初始化
值类型
参数的类型,分为值类型、引用类型
值类型(struct):如Vector3,Color
- 本身是一个值,可直接复制
- 若为赋值,则默认0
- 不能为null
引用类型(class):如GameObject,Transform,MeshRenderer
- 节点 GameObject
- 组件 Transform,MeshRenderer,AudioSource
- 资源 Material, Texture, AudioClip
- 数组类型
其实在c#里面 int float 本质也是struct类型
String 原则上属于class类型参数的保存
- 在Play Mode 下,组件Copy Component
在Edit Mode 下,组件Pate Component Values
鼠标键盘输入
if(Input.GetMouseButtonDown(0)){ //点击鼠标左键 } if(Input.GetKeyDown(KeyCode.W)){ //按W键 } if(Input.GetKeyDown(KeyCode.Space)){ //按空格 }
音乐播放
- Play On Wake
代码
获取AudioSource组件
AudioSource audio = this.GetComponent<AudioSource>();
播放
- audio.Play();
void PlayMusic(){ AudioSource audio = this.GetComponent<AudioSource>(); if(audio.isPlaying){ audio.Stop(); //audio.loop //audio.mute }else{ audio.Play(); } }
组件参数
- AudioClip 音频资源
- Mute 是否静音
- Loop 是否循环播放
- Volume 音量
引用别的组件
第一种
public GameObject node;
AudioSource audio = node.getComponent<AudioSource>();
第二种
public AudioSource bgm
消息调用
SendMessage 以‘消息’的形式来调用另一个组件
//找到目标节点 public GameObject target; //向目标节点发送消息 target.SendMessage(methodName,value);
SendMessage内部执行(反射)
- 找到target下所有组件
在组件下寻找methodName函数
- 若存在,则调用
- 若无法匹配,则报错获
取物体
按名称、路径获取(不推荐)
- GameObject flag=GameObject.Find("旋翼")
- 最好指定全路径"无人机/旋翼"
引用获取
- 添加一个变量,在检查器引用目标
- public GameObject node;
父子物体
获取父
Transform parent=this.transform.parent;
获取父节点
GameObject parentNode=this.transform.parent.gameObject;
获取子
foreach(Transform child in transform{ Debug.Log(chid.name); }
Transform child= this.transform.GetChild(0);
Transform chikld=this.transform.Find("aa"); Transform chikld=this.transform.Find("bb/cc"); Transform chikld=this.transform.Find("/dd");//表示根下
设置父
- this.transform.SetParent(other)
设为一级节点 - this.transform.SetParent(null);
其中,parent为null表示一级节点(没父)
显示隐藏
child.gameObject.SetActive(false)
资源使用
脚本中使用资源
- 添加变量public AudioClip audioSuccess
- 引用音频资源
AudioSource audioSource=GetComponent<AudioSource>();
使用audioSource.PlayOneShot(audioSuccess) 播放
资源数组
public AudioClip[] songs; songs.Length; Random.Range(min,max);//用于在[min,max)中随机抽取一个数,不含max
public class SimpleLogic:MonoBeHaviour{ public Material[] colors; int m_index=0; void Start(){ } void Update(){ if(Input.GetMouseButtonDown(0)){ ChangeColor(); } } private void ChangeColor(){ m_index+=1; if(m_index>=this.colros.Length){ m_index=0; } Material selected = this.colors[m_index]; MeshRenderer rd=GetComponent<MeshRenderer>(); rd.material=selected; } }
定时调用
定时调用Invoke*,即定时器
继承自MonoBehaviour:
- Invoke(func,delay)在delay之后执行,只调用一次
- InvokeRepeating(func,delay,interval)在delay之后执行,每interval执行一次
- IsInvoking(func)是否正在调度中
- CancelInvoke(func)取消调用、从调度队列中移除
Unity引擎核心是单线程的 获取当前线程号
using System.Threading; int threadId=Thread.CurrentThread.ManagedThreadId
向量
Vector3 (x,y,z)
- 单位向量: 长度为1
标准化 Normalize: 缩放一个向量,使其长度为1
Vector3 v1=new Vector3(2,2,0); Vector3 v2=v1.normalized; Debug.log(v2.ToString("f3"));
几个常量
- Vector3.zero (0,0,0)
- Vector3.up (0,1,0)
- Vector3.right (1,0,0)
- Vector3.forward (0,0,1)
向量运算: - 加法 a+b
- 减法 a-b
- 标量乘法 b=a*2
- 点积 c=Vector3.Dot(a,b)
- 差积 c=Vector3.Cross(a,b)
不能设null,默认是(0,0,0)
向量测距:Vector3.Distance(a,b) 轴心点距离Vector3 p1=this.transform.position; Vector3 p2=target.transform.position; Vector3 direction=p2-p1; float distance=direction.magnitude
预制体
Prefab, 预先制作好的物体,可以提高开发效率
创建
- 先制作好一个样本节点
- 做好后直接拖到Assets窗口,则自动生成一个prefab资源
原始物体不再需要,可删
导出
实例
Prefab Instance 和原始Prefab之间存在关联
特征:- 在层级窗口中,节点图标不同
- 在层级窗口中,右键菜单/Prefab
- 在检查窗口中,上下文工具/Prefab
解除关联: 在层级窗口中,右键菜单 Prefab/Unpack
编辑
prefab 相当于一个模板,可以再次编辑
单独编辑:
- 双击Prefab进入单独编辑模式
- 编辑节点和组件
- 退出,完成编辑
原位编辑 - 选择Prefab Instance
- 在检查器中Open
Content显示Normal/Gray/Hidden
- 此时,仅选中的物体被编辑,其余物体是陪衬
- 编辑节点
退出,完成编辑
动态创建实例
Object.Instantiate(original,parent)
演示:- 准备prefab,添加脚本
- 添加变量 public GameObject bulletPrefab;
克隆实例
GameObject node= Instantiate(bulletPrefab,null); node.transform.position = Vector3.zero; node.transform.localEulerAngles = Vector3.zero;
初始化
创建Prefab Instance之后,应做初始化:
- Parent 父节点
- position/localPosition 位置
- eulerAngles/localEulerAngles 旋转
Script 自带的控制脚本
销毁
object.Destroy(obj)用于销毁一个实例
对于子弹来说
- 当飞出屏幕时,销毁
- 按射程 / 飞行时间
当击中目标时,销毁
碰撞检测
private void OnTriggerEnter(Collider other){
if(other.name.StartsWith("xxx"){
Destory(this.gameObject);
Destory(other.gameObject);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。