目录
1.世界坐标系
2.视野中心框显所选
3.出生点
4.透视与正交
5.透视、广角设定
6.旋转与缩放
7.右键点导航器的中间小方块
8.网格
9.材质|颜色
10.纹理
11.外部模型
12.正面、背面
13.FBX文件
14.资源文件
15.资源包的导入
16.轴心的位置是在建模软件中指定的
17.父子关系
18.相对坐标
19.空物体(EmptyObject)
20.Global 与 Local
21.pivot 与 center
22.Mesh Filter 与 Mesh Render
23.Audio Source组件
24.调整摄像机的角度
25.脚本
26.物体的坐标
27.帧更新 Update()
28.运动的方向
29.物体的旋转
30.相对旋转
31.自转与公转
32.脚本的运行
33.消息函数
34.脚本优先级
35.主控脚本
36.脚本的参数
(1)参数用法
(2)参数的赋值
(3)值类型
(4)引用类型
(5)运行时调试
37.组件
(1)组件的调用
38.获取物体
1.按名称/路径获取(不推荐)
2.引用获取(推荐)
39.父子物体
1.获取父级
2.获取子级
3.transform.Find() ,按名称查找子项
40.物体的操作
设置新的父级
GameObject.setActive(),显示/隐藏
transform.Find("/222"); 其中/表示在根下查找物体
41.资源的使用
42.资源数组
43.定时调用
44.定时与线程
45.向量
a.向量运算
b.向量测距
c.向量的使用
46.预制体
a.预制体的创建
b.预制体的实例
c.预制体的编辑
d.多级节点
47.动态创建实例
a.实例的初始化
b.实例的销毁
48.物理系统
a.物理碰撞
b.反弹与摩擦
c.MeshCollider 网格碰撞体
49.天空盒子
游戏中的方向感:一般来说,Y轴代表上下,X/Z代表东南西北。
选中一个物体,按F键,置于视野中心/双击物体,此时旋转视图,似是绕着物体旋转。
添加一个新物体,物体位于视图中心
注:出生点不是在(0,0,0),而是在当前视图中心
透视视图Perspective,近大远小
正交视图 Orthographic,又称等距视图 Isometric (物体的显示与距离无关)
正交视图常用于物体的布局、对齐操作如:正交顶视图、正交右视图、正交前视图
摄像机的广角Field,默认为60°,广角越大,透视畸变越厉害。可视为30~40度
(1)逆时针为正,顺时针为负
(2)可在Inspector里精确指定
(3)按住CTRL键时,角度增量为15度
W键对应移动工具 E键对应旋转 R键对应缩放
Top顶视图
Back正视图(从后往前)
Right右视图(从右往左)
在Unity中观察模型的网格
(1)shaded着色模式,显示表面材质
(2)wireframe 线框模式,仅显示网格
(3)shaded Wireframe 线框着色模式
显然,任何物体的表面都是由若干三角面围城的
金属|非金属
光滑|粗糙
透明|半透明|不透明
凹陷|凸起
纹理 Texture,也称贴图,用一张图定义物体的表面颜色
标准模型格式:FBX
在Unity中,1)一个平面是没有厚度的
2)正面可见,背面透明
或者说,平面的背面不会被渲染
FBX模型文件,一般包含
Mesh网格,定义物体的形状
Material材质,定义表面的光学特性
Texture贴图,定义表面的像素颜色
(1)FBX材质替换(重映射)
a.选中*.fbx资源文件
b.在Inspector中切换到Materials属性
Use Embeded Materials
On Demand Remap: 映射新的材质
c.点Apply应用设置
(2)FBX使用外部材质
选中fbx文件
Location :Use External Materials 使用外部材质 点Apply应用,则将内嵌材质解压缩到Materials 目录,直接修改Materials 目录下的材质文件
(3)FBX第三种使用方式:分解重组
选择fbx中的网格
选择fbx中的材质,或者自定义一个材质
如果存在贴图,则使用fbx配套的贴图文件
Assets目录下的文件,成为资源。
常见类型:
导入资源包,直接把*.unitypackage拖到project窗口
轴心 pivot 指一个物体的操作基准点(移动,旋转)
父子关系指两个物体之间的关系
在Hierarchy窗口中
相对坐标:子物体的坐标是相对于父物体的
即空对象、空节点
(1)Global即世界坐标系
以世界中心为轴,6个方向代表:上下 东西 南北
(2)Local即本地坐标系
以物体自身为轴,6个方向代表:上下 前后 左右
y轴称之为up,Z轴称为forward ,X轴称为right
一般地,要求模型的正脸与Z轴方向一致
pivot:轴心
center:几何中心
一般来说,物体的轴心并不咋几何中心处
Audio Source 组件,用于播放音乐/音效
(1)添加一个音乐文件,*.mp3 / wav / aiff
(2)创建一个物体
Add Component , Audio/Audio Source
将音乐文件拖动Audio Source.AudioClip 属性
在3D窗口上方,选Toggle AudioOn播放
(1)手工移动、旋转摄像机对准目标
(2)Align with view 与 3D 视图对齐
先在3D视图里摆好角度,此为观察着角度,然后选中Main Camera , 执行 Align with view 。
此时,摄像机角度与观察着角度完全相同
选中摄像机 -> GameObject -> Align with view
在.cs中,获取当前物体
this.gameObjet,当前物体
this.gameObject.name , 当前物体的名字
this.gameObject.transform , 当前物体的Transform 组件 ,为了简化书写,也可写作 this.transform 效果相同。
transform.position , 世界坐标
transform.localposition , 本地坐标
一般常使用的是localposition 与 Inspector中的值一致。
设置物体的坐标:
this.transform.localPosition = new Vector3(1.5f,0,2.0f);
帧率观察:
Time.time:游戏时间
Time.deltaTime , 距离上次更新的时间差
(1)unity不支持固定帧率,但可以设定一个近似帧率
Application.targetFrameRate = 60; (设定1秒更新的次数)
其中指示unity尽量以FPS = 60 的帧频率更新游戏
(2)使用deltaTime,让物体做匀速运动
float speed= 3;
float distance = speed * Time.deltaTime;
(3)一般使用transform.Translate(dx,dy,dz,....),实现相对运动,其中dx,dy,dz是坐标增量
例如:transform.Translate(0,0,distance); //z方向增加distance
transform.Translate(dx,dy,dz,space)
其中第4个参数
Space.World,相对于世界坐标系
Space.Self,相对于自身坐标系(本地坐标系)其中,Space.Self更常用沿自己的坐标轴,前后左右移动。
(1)获取目标物体
GameObject flag = GameObject.Find("红旗"); //可以根据名字或者路径查找
(2)转向目标
this.transform.LookAt(flag.transform); //使物体的Z轴指向物体
(3)向前运动 forward +Z方向
this.transform.Translate(0,0,dz,Space.Self);
欧拉角 EulerAngle
transform.enlerAngles = new Vector(0,45,0);
transform.localEulerAngles = new Vector3(0,45,0);
void update()
{
Vector3 angles = this.transform.localEulerAngles;
angles.y += 0.5f;
this.transform.localEulerAngles = angles;
}
Rotate(),旋转一个相对角度
transform.Rotate(dx,dy,dz,space);
自转:绕着自身轴旋转
公转:围绕另一个物体旋转
当父物体转动时,带动子物体一并旋转
(1)创建节点
GameObject node = new GameObject();
(2)实例化组件
MeshRender comp = new MeshRender();
(3)实例化脚本组件
SimpleLogic script = new SimpleLogic()
(4)调用事件函数
初始化 script.start()
帧更新 script.update()
Awake,初始化,仅执行一次
Start , 初始化,仅执行一次
Update,帧更新, 每帧调用一次
OnEnable, 每当组件启用时调用
OnDisable,每当组件禁用时调用
其中Awake先于start调用
Awake总是调用,即使组件被禁用
Start只执行一次,第一次启用时调用
已禁用的组件,其消息函数Start / Update 不会被调用
Awake/Start 都只会执行一次
一般地,并不需要设置,默认即可
默认地所有脚本的执行优先级为0
优先级的设定:
即游戏的主控逻辑(全局性的设置,全局性的逻辑可以设置脚本的优先级)
用于控制脚本组件的功能
1.参数必须为public,才可以再检查器中显示
2.参数的名称,即变量名
rotateSpeed --> Rotate Speed
3.参数的默认值,即变量的默认值
可以Reset菜单重置
4.参数的工具提示,可以用 [Tooltip()] 指定
[Tooltip("旋转角速度")]
public float rotateSpeed = 30f;
this.rotateSpeed = 100f;
结构体赋值
public Vector3 rotateSpeed = new Vector3(1,1,1);
节点 GameObject
组件如 Transform、MeshRender、AudioSource
资源如Material、Texture、AudioClip
数组类型
显然在运行模式下,所有参数不能保存到现场
保存参数的办法:
在 Play Mode下,组件Copy Component
在 Edit Mode 下,组件 Paste Component Values
AudioSource可用于播放音乐,音效
其中,play on Awake 表示自动播放
用API来使其播放音乐
1.获取Audio Source组件
AudioSource audio = this.GetComponent();
2.播放
audio.play();
其中,<>表示泛型,即获取
(2)引用别的组件
最常用的方法,直接引用就,在检查器中赋值
public AudioSource bgm;
小结:获取当前物体下的组件
comp = this.getComponent
获取别的物体下的组件
comp = otherNode.getComponent
游戏物体GameObject,也可以叫节点
若不重名,可以按名称获取
GameObject node = GameObject.Find("旋翼");
最好指定全路径
GameObject node = GameObject.Find("无人机/旋翼");
添加一个变量,在检查器引用目标
public GameObject wingNode;
场景中的层级关系/父子关系,是由Transform维持的
查看文档,找到Transform类的说明
Transform parent = this.transform.parent;
获取父级节点
GameObject parentNode = this.transform.parent.gameObject;
foreach(Transform child in transform)
{
Debug.Log("*子物体:"+child.name);
}
获取第0个子项
Transform aa = this.transform.getChild(0);
Transform aa = this.transform.find("aa");
Transform bb = this.transform.find("bb");
Transform cc = this.transform.find("bb/cc");
其中二级子级应该指定路径,如bb/cc
this.transform.setParent(other);
this.transform.setParent(null); 其中parent为null表示为一级节点(没有父级)
Transform child = this.transform.Find("aa");
if(child.gameObject.activeSelf)
{
child.gameObject.setActive(false);
}
else
{
child.gameObject.setActive(true);
}
在脚本中添加变量
public AudioClip audio;
引用音频资源
使用API播放音频
AudioSource.playOneShot(clip),用于播放音效
在脚本中也可以定义一个数组变量
比如一个音乐盒,存了多首歌曲
public AudioClip[] songs;
//随机播放
int index = Random.Range(0,songs.Length);
AudioSource ac = GetComponent();
ac.clip = this.songs[index];
ac.play();
index = Random.Range(min,max); 用于在[min,max)中随机抽取一个数,不含max
定时调用invoke,即一般所谓的‘定时器’;
继承自 MonoBehavior:
Invoke(func,delay),只调用一次,在几秒后调用func方法
InvokeRepeating(func,delay,interval),循环调用
IsInvoking(func); 是否正在调度中
CancelInvoke(func);取消调度,从调度队列中移除,取消该MonoBehavior上的所有Invoke调用
使用this.Invoke("DoSomething",1);在1秒后调用DoSomething()方法
unity引擎的核心是单线程的
InvokeRepeating定时调用,并没有创建新的线程
获取当前线程号: using System.Threading;
int threading = Thread.CurrentThread.ManagedThreadId;
Unity是单线程核心,不必考虑线程、并发、互斥
在Invoke时,一般要避免重复调用
形如:
if(!IsInvoking(func))
{
Invoking(func,delay,interval);
}
例子
[Tooltip("红、绿、黄按顺序指定")]
public Material[] colors;
void start()
{
changeColor();
}
void changeColor()
{
Material color = this.colors[m_index];
MeshRenderer renderer = GetComponent();
renderer.materal = color;
if(m_index == 0)
{
Invoke("changeColor",4); //红--> 绿
}
else if(m_index == 1)
{
Invoke("changeColor",4); //绿--> 黄
}
else if(m_index == 2)
{
Invoke("changeColor",1); //黄--> 红
}
m_index++;
if(m_index >= 3)
{
m_index = 0;
}
}
旋转实例:
//最大转速
public float maxRotateSpeed = 720;
float m_speed = 0; //当前转速
bool m_speedUp = false; //true:加速 false:减速
void Start()
{
InvokeRepeating("AdjustSpeed",0.1f,0.1f);
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
m_speedUp = !m_speedUp;
}
if(m_speed >0)
{
this.transform.Rotate(0,m_speed*Time.deltaTime,0,Space.Self);
}
}
private void AdjustSpeed()
{
if(m_speedUp)
{
if(m_speed < maxRotateSpeed)
{
m_speed+=10;
}
else
{
m_speed-=10;
if(m_speed < 0)
m_speed = 0;
}
}
}
有方向的量
1.向量的长度:√x^2+y^2+z^2
API: Vector3 v = new Vectors(3,0,4);
float len = v.magnitude;
2.单位向量,即长度为1的向量
3.标准化 Normalize :缩放一个向量,使其长度为1
API: Vector3 v1 = new Vector3(2,2,0);
Vector3 v2 = v1.normalized;
4.几个常量
Vector3.zero 即 (0,0,0)
Vector3.up 即 (0,1,0)
Vector3.right 即 (1,0,0)
Vector3.forward 即 (0,0,1)
1.向量的加法,即xyz三个向量分别相加
例:
Vector3 a = new Vector3(1,3,0);
Vector3 b = new Vector3(4,1,3);
Vector3 c = a+b; //(5,4,0)
2.向量的减法,即xyz三个向量分别相减
Vector3 a = new Vector3(5,4,0);
Vector3 b = new Vector3(1,3,0);
Vector3 c = a-b; //(4,1,0)
3.向量乘法分3种
(1)标量乘法 b= a*2;
(2)点积 c = Vector3.Dot(a,b);
(3)差积 c = Vector3.Cross(a,b);
其中只要求掌握标量乘法,即对每一个分量相乘
4.Vector3是值类型,可以直接赋值
Vector3 a = new Vector(1,1,0);
Vector3 b = a;
//注:不能设为null
用于求两个物体间的距离
Vector3 p1 = this.transform.position; //自己位置
Vector3 p2 = this.transform.position; //目标位置
Vector3 direction = p2-p1;//方向向量
float distance = direction.magnitude; //距离
Vector3.Distance(a,b); //也可以求距离
物体间的距离,确切的说是轴心点之间的距离
Vector3可以直接作为脚本的参数
public Vector3 speed;
this.transform.Translate(speed*Time.deltaTime,Space.Self);
预制体Prefab,即预先制作好的物体
使用预制体可以提高开发效率
1.先制作好一个样本节点
2.做好以后,直接拖到Assets窗口,则自动生成一个*.prefab资源
3.原始物体不再需要,可以删除
在导出prefab资源时,应该将依赖文件一并导出
prefab只记录了节点的信息
prefab文件不包含材质、贴图数据,仅包含引用
prefab Instance,由预制体创建得到的对象
特征:
在Hierarchy中,节点图标不同
在Hierarchy中,右键菜单 | prefab
在Inspector中,上下文工具 | prefab
prefab Instance 和原prefab之间存在关联
右键菜单 Prefab | Unpack,则解除关联,成为普通物体
*.prefab 相当于一个模板,可以再次编辑
第1种方式:
双击Prefab,进入单独编辑模式,编辑节点和组件
第2种方式:原位编辑
-选择Prefab Instance
-在检查器中 Open
-Context显示:Normal | Gray | Hidden
-此时,仅选中的物体被编辑,其余物体时陪衬
-编辑节点
-退出,完成编辑
第3种方式:覆盖编辑
-选择Prefab Instance
-直接在场景中编辑
-编辑完后
Override | Apply , 应用编辑
Override | Revert ,取消编辑
prefab中,多级节点 | 父子关系,也是常见的情况
创建Prefab之后,用API动态创建实例
API: Object.Instance(original,parent); //(要复制的对象,新对象的父对象)
实例
1.准备子弹prefab
2.添加火控脚本 FireLogic
//添加变量
Public GameObject bulletPrefab;
//克隆实例
GameObject node = Object.Instance(bulletPrefab,null);
node.transform.position = Vector3.zero;
node.transform.localEulerAngles = Vector3.zero;
创建Prefab Instance之后,应做初始化:
-parent,父节点
-position | localPosition , 位置
-eulerAngles | localEulerAngles , 旋转
-script , 自带的控脚本
GameObject node = Object.Instantiate(bulletPrefab,bulletFolder);
node.transform.position = this.firePoint.position;
node.transform.eulerAngles = this.cannon.eulerAngles;
(1)一般引用Transform,而GameObject是没有存在感的
(2)可以使用空物体,标记一个空间坐标
一般的,创建实例之后,也要负责销毁
对于子弹来说:
--当飞出屏幕时销毁
--按射程/飞行时间
--当击中目标时销毁
Object.Destory(Object obj,float t); //要销毁的对象,销毁对象前的延迟(可选)
Object.Destory(this.gameObject);
Destory()不会立即执行,而是在本轮Update之后执行
物理系统Physics,即由物理规律起作用的系统
确切的说,是牛顿运动定律(力、质量、速度)
刚体组件Rigidbody,物理学中的物体
physics | Rigidbody
当添加Rigidbody后,由物体引擎负责缸体的运动
碰撞体Collider,描述了物体的碰撞范围
其中,BoxCollider,长方碰撞体
Sphere Collider,球形碰撞体
刚体的反弹与摩擦,也归物理系统负责
(1)新建physic Material
(2)设置Friction Bounciness
如果想让两个MeshCollider发生碰撞。那就必须勾选convex(凸面)属性
勾选Is Trigger 和Convex选项框,从而将Mesh Collider设置为触发器
天空盒子 Skybox,即游戏的背景
Environment | skybox Material 天空盒子材质
window | Rendering | Lighting , 光照设置