1-3 Unity零基础入门 古迹探险
任务1/2:资料下载
链接:https://pan.baidu.com/s/1jHVymNk 密码:rbob
任务3:工程的创建和打开
Project:古迹探险
任务4:工程目录
任务5:资源的导入方式
方法1a. 在window->Asset Store->搜索
方法1b. 在Project面板上的搜索框内直接搜索想要资源的关键字即可,可以指定搜索范围
可以选为Asset Store(前提是在Edit->Preferences->General->勾选Show Asset Store search hits)
方法2. 从第三方.unitypackage中导入
将.unitypackage拖入工程面板即可
或是在工程面板右键Import Package->Custom Package,选择.unitypackage即可
方法3. 导入unity自带的资源(指的是安装unity自带的Standard Assets资源)
在工程面板右键Import Package->除了Custom Package之外的都是自带资源
如果在安装unity的时候没有勾选Standard Assets,则不会显示
Standard Assets里面的资源挺优质的
任务6:3D物体
1. 自带的简单3D几何体
cube/ sphere/ capsule/ cylinder/ Plane(单面显示,多用作地板)/ Quad面片(单面显示,小)/ Terrain/ Tree/ WindZone(风区,制造随风摇摆的效果)/ 3D Text等
2. 复杂的3D模型
Mesh Filter:网格,模型的形状
Mesh Renderer中的Materials:模型的特点,光滑度/透明等等
Texture:使用贴图
任务7:菜单栏
Mobile Input是Standard Assets中扩展出来的一个菜单,用来表示是否启动移动端的控制
GameObject菜单下方有一些有用的工具
Align With View:当想要把Camera的视角设置成当前Scene的视角的时候
任务8:工具栏
Center/ Pivot的区别
Center:中心点 有子物体的时候会计算平均的中心位置,可能会变化
Pivot:原点/ 坐标点 Position,在建模的时候一般就确定了
中间三个键:运行/ 暂停/ 逐帧运行
右上角Layers:每个GameObject都属于一个层,可以设定成锁定/不可见
任务9:窗口操作
任务10:Scene窗口下视野控制
飞行模式:按住鼠标右键进入飞行模式
鼠标移动进行视野旋转
WASD进行前进后退左右的控制
QE进行垂直上下的控制
任务11:Transform组件
任务12:控制物体移动的小技巧
Ctrl:
之前提到了按住ctrl移动物体的时候会一米一米地移动,那么步长可以修改吗?
Edit->Snap Settings->默认的move x/y/z 为1,可以修改
按住ctrl后也可以进行单位化的scale和rotate
v:
选定一个物体,按住v键,鼠标会自动吸附物体的顶点
可以将物体按照该顶点进行移动/ 旋转/ 缩放
移动时会将该顶点与其他物体的顶点进行吸附
任务13:导入资源,Prefab预制体
Prefab的instance中的Inspector上有Select/ Revert/ Apply
Select:会跳转到该instance对应的prefab上
Revert:
(如果instance的某些属性修改成和Prefab不同时,会以粗体显示,并且不会受到prefab的修改而改变)
Apply:点击某个instance里的Apply,会将该instance的属性值赋值给prefab(修改了prefab的属性)
如果有一个instance的prefab被删除了而仍需要保留该instance,但是instance会显示missing,在GameObject中选中break prefab instance即可;如果有某一个instance想脱离prefab的关联,也是选中break prefab instance即可
任务14&15:地形设计
作为开发,了解就好,团队里的美工会设计好的
3D Object->Terrain
选中pivot,从原点进行聚焦观察
创建一个Terrain后会在Project中自动创建一个New Terrain的文件,该文件保存了具体的地形数据,可以新建文件夹Terrains并命名为Terrain Data
组件:
Terrain Collider 地形的碰撞体
Terrain 设置地形的形状
第一个按钮为Raise/Lower the Terrain Height:笔刷粉刷地形的时候地形会升高/(按住Shift)降低(最低值为0)
第二个按钮为Set the Terrain Height:升高地形,有一个height的值,升高的时候不会超过这个height,如果原地形的高度已经超过,则会慢慢降低地形直至该height;height旁边有一个flatten的按钮,会使整个地形的高度变为相同(flat),但不会超过maximun height
第三个按钮为Smooth the Terrain Height:将地形变化变得平缓
第四个按钮为Paint Texture:绘制贴图
Edit Texture->Add Texture,select texture: 分为Albedo Smoothness和Normal,Normal不是必要的。Normal选择后会将凹凸不平的细节显示地更好
可以添加多张贴图,第一张被添加的贴图会覆盖整个Tarrain,第二张被添加的时候不会有任何效果,需要通过鼠标进行粉刷
添加贴图的时候下面有一个size的选择:表示一张贴图的大小(需要粉刷多张贴图到整个terrain)
第五个按钮为Place Trees:放置植被
Edit Trees->Add Tree->选择Tree的prefab->add
之后用笔刷粉刷即可,按住shift粉刷为减少树;
可以设置brush size/ tree density/ tree height (random)/ Lock width to height/ color variation等
第六个按钮为Paint Details:一般用来粉饰小草/植被的细节
Edit details->Add grass texture->选择贴图->笔刷粉刷即可(Opacity为密度)
草是贴图,而树是模型,草会随着你的视野方向改变而面向你
第七个按钮可以设置大小等(默认长宽为500m,一个大格为100m);这里设置成50*50*height(此时一个大格为10m);高度height为地形的最大高度,设置成50
可以设置笔刷的形状/ 大小size/ 影响地形的快慢opacity
在修改地形属性的时候右下角会有一个Clustering的处理光照进度条,如果不想要这个处理的话(耗费性能),Window->Lighting->Setting->Scene->uncheck Auto Generate
任务16/17/18:古迹探险地形设计
1. 放置人物 Meshes->dwarf_hero
2. 如何知道hero的大小呢?
创建一个cube,大小对比;调节hero高度在1-2m之间即可
3. 创建Terrain;width:20,length:20,height:20
4. 将自动生成的Terrain数据命名并放入Terrains文件夹
5 将hero放在(10, 0, 0)的位置
6. 地形粉刷
思路:三面环山,中间略微有起伏
size 100 opacity 30 粉刷山脉
size 100 opacity 5 粉刷中间空旷地区起伏
使用smooth height将地形变得平滑
7. 添加贴图Texture:选择GrassRockyAlbedo
将size改为20, 20
8. 实现群山环绕的效果
Prefabs->Rock_Large, scale为0.3
环绕三面摆放,并将每一块石头手动随机旋转/调节大小等
9. 既然为古迹探险,加入Ruin元素
Prefabs里的石头/ruin随意加
10. 添加草/植被
Meshes->Vegetation->Low有多种草的模型
Meshes->Vegetation->Bushes有树的模型
手动调整大小位置旋转
11. 将所有环境有关的GameObject(树/石/Ruin)放入empty gameobject Env
总体效果:
任务19:刚体
Mass 质量,可以控制惯性
Drag 摩擦力(移动时的阻力)
Angular Drag 旋转时的摩擦力
Constraints:冻结某个属性(刚体效果不改变某个属性)
任务20:碰撞器
Box collider是最节约性能的,越复杂的collider越耗费性能,Mesh collider最耗费性能
Mesh Collider:需要assign一个mesh,选择和Mesh Filter相同的mesh即可
比如想要给Rock_Large添加一个Mesh Collider,需要展开Rock_Large,选中里面的Group1,添加一个mesh collider,把mesh选择为Group1即可(会自动选择)
NB: 不需要太精细的情况下,没必要选择mesh collider,因为太耗费性能;如果你的mesh比较简单,那么选择mesh collider是可行的
任务21/22:碰撞检测函数/ 碰撞信息取得
void OnCollisionEnter/Exit/Stay(Collision collision);
碰撞检测是基于刚体的,也就是说即使有collider但是没有rigidbody,碰撞检测是不可用的
碰撞检测的条件:https://docs.unity3d.com/Manual/CollidersOverview.html
任务23:触发检测
勾选collider的is trigger,使得该collider成为一个触发器,其他物体可以进入该collider内部
void OnTriggerEnter/Exit/Stay(Collider other);
任务24:Unity中的四种灯光
Create->Light->Directional Light/ Point Light/ Spotlight/ Area Light
Directional Light:直射光/ 平行光/ 太阳,它的position是没有影响的,只有rotation是有影响的;在天空盒子里可以看到一个太阳,太阳是位于直射光的后面的,当直射光旋转的时候,太阳的位置也会随之改变
Point Light:点光源/ 灯泡,属性Range,Intensity
SpotLight:手电筒/ 从一点发射一个锥形范围的光,锥形的大小和长度是可调节的
Area Light:区域光,主要用于烘培,实际环境的光照设置不会使用它
任务25:给场景添加火堆
古墓探险不需要太强烈的光,将directional light调成日出的状态(180, 90, 0), indensity 0.3
创建一个空物体Light,将Direcitional light放在其下,并添加一个Point light
调成暗紫色,intensity调弱一点,分别放几个在山上
调成弱黄色,放几个在空地上
创建火堆Bonfire:
Prefabs->*_01 火堆头
Prefabs->Barrier_02 火堆底
在Bonfire中创建一个point light,放置在火堆的正中间,颜色偏黄,intensity调强
制作成Prefab方便日后修改
任务26/27:Lightmapping
Lightmapping 光照贴图
如果不使用光照贴图的话,光在游戏运行时对场景的影响是需要实时计算的,耗费性能
如果使用lightmapping的话,会提前将光照计算好,烘培成贴图,将贴图贴在环境模型上,实际运行时就不需要实时进行计算了,能够很大提高性能
将Terrain,Env及其孩子勾选成static的;再将所有灯光也勾选成static
将所有灯光的mode选择成baked
Window->Lighting->Settings
Scene中的Debug Settings中点击Generate Lighting
会发现整个环境亮了许多,将直射光改为Rotation的x值改为191.2;点光源的range调小,重新烘焙
此时若是禁用了灯光,会发现环境下的灯光效果不变(不再是real time了)
但是这样的话火堆的效果就没有了,火焰需要一闪一闪的效果
火堆光的进一步改进:
将火堆光的mode改为mixed,表示即可以实时计算,又可以烘培
并将其的Shadow Type改为Hard Shadows或Soft Shadows(hard烘培时间会慢一点)
任务28:使用粒子系统创建火焰
在Bonfire下创建Effects->Particle System
Shape:修改成火堆的大小
Start Lifetime:生命时间改小一点 1.5
Start Speed:速度设置为Random between two constants 1~1.5
粒子样子:FX->Fire->flame 4x4,这是一个4*4的动画效果
在Fire中创建material flame,shader选择Particles->Additive;texture选择flame 4x4;颜色设置成白色
将该material指定给粒子系统
改变粒子系统的Renderer中的material即可
但是这时候texture的动画效果没有展示
勾选粒子系统的Texture Sheet Animation,将Tiles设置成4*4(4行4列的动画)
现在已经有火焰的效果了,但是粒子太大了
修改粒子系统的Start Size即可
粒子应该越来越小:
Size over Lifetime:修改成一个曲线
也可以修改粒子数量
Emission中的Rate over time可以修改成1-20
任务29: 创建动画(火光闪烁)
通过动画系统实现灯光的闪烁
1. 选中Bonfire的点光源
2. Window->Animation->Create->将新建的Flicker.anim放在文件夹Animations中
会自动在Bonfire的点光源里创建一个Animator的组件,用来控制动画的播放;和在Animations文件夹下创建一个动画文件Flicker.anim和一个叫Point light的动画状态机
3. 编辑Flicker动画
Window->Animation,以打开animation窗口,并选中Flicker或点光源
Add Property->Light->Intensity 火光亮度
经过不同时间,调整intensity数值(火焰效果需要intensity的变化很大)
Add Property->Transform->Position 火光左右摇摆
把sample设为25,减慢动画播放速度
任务30:导航系统-导航网格生成
导航系统(寻路系统):角色朝某个地方运动时,通过导航系统寻找最短路径,并沿着最短路径到达指定位置,并会自动进行避障
进行导航网格的烘焙:
确保Env和Terrain的navigation static是勾选状态
生成导航网格
Window->Navigation->Bake
点击bake生成蓝色区域,为可行走区域
Agent Radius:控制不可行走区域的半径,修改成0.1
Agent Height:
因为草是可以穿越的,所以把草的Navigation static取消勾选
发现一些石头/树的上方也是可行走的,选中石头的Mesh renderer组件(Group1),Navigation->Object->Navigation Area->Not Walkable(树也类似)
控制Hero在导航网格上行走
给Hero添加导航组件Nav Mesh Agent后会自动生成一个圆柱体,用于计算某个区域是否可以穿过的参照,需要保证圆柱体和Hero模型大小保持一致:Radius/ Height
之后需要代码来告诉Hero要去的目的地(下个任务)
任务31:通过导航系统控制英雄的移动
思路:通过鼠标在地面上点击的点作为目的地,让导航系统控制英雄向目的地移动
创建Hero.cs并attach到Hero
1. 获取目标位置:鼠标按下的时候,向鼠标点击的位置发射一道射线,判断射线和Terrain的哪一个位置发生碰撞,获取该位置
Input.GetMouseButtonDown(0); // 鼠标左键按下
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // main camera中的ScreenPointToRay()将屏幕坐标转换为一道射线;Input.mousePosition为屏幕坐标
RaycastHit hit; // 用来保存碰撞信息
Physics.Raycast(ray, out hit); // 如果与任意碰撞器发生碰撞,返回true;out参数hit为碰撞信息
hit.point; // 碰撞的地面位置(x,y,z)
2. 控制角色到达位置:将hit.point的点赋值给Nav Mesh Agent
using UnityEngine.AI;
public navMeshAgent agent; // 得到Nav Mesh Agent;
agent.SetDestination(hit.point); // 设置Nav Mesh Agent的目的地点
3. 成功,但是角色转向太慢了
Nav Mesh Agent->Angular Speed=360
public class Hero : MonoBehaviour { public NavMeshAgent agent; // Update is called once per frame
void Update () {
if(Input.GetMouseButtonDown()) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit)) {
agent.SetDestination(hit.point);
}
}
}
}
任务32:控制摄像机的跟随
调整相机的跟随位置(12.22, 7.27, -5) (39.3, 0, 0) (Hero位置(12.078, 1.363, 0))
创建FollowTarget.cs并attach到Main Camera上
public Transform hero; // 跟随目标的Transform(Transform组件就够用了)
private Vector3 offset; offset = transform.position - hero.position; // 偏移量
transform.position = hero.position + offset; // 相机位置的跟随
public class FollowTarget : MonoBehaviour { public Transform hero;
private Vector3 offset; // Use this for initialization
void Start () {
offset = transform.position - hero.position;
} // Update is called once per frame
void Update () {
transform.position = hero.position + offset;
}
}
任务33:控制角色的动画播放
动画效果为Animations中的四个动画文件,我们这里需要的是idle/ walk和run
通过动画状态机进行动画的控制
Hero->Animator中需要动画状态机
在Animation文件夹中创建Animation Controller,叫做HeroController,并赋值到Hero
编辑动画状态机:
选中Hero,Window->Animator
设置默认状态Entry,将idle动画拖到Entry
状态切换:
idle->walk; // 通过速度的检测来切换状态
如何获得Nav Mesh Agent中的Speed呢
在Animator窗口左侧Parameter中添加一个float speed
将walk动画拖到Animator窗口中
右键idle状态,make transition,指向walk状态
点击transition的线
在Inspector中添加一个condition:speed greater than 0
取消勾选Has Exit Time,因为动画的切换会随时发生
在Hero.cs中
public Animator anim; // 获取Animator组件
anim.setFloat("speed", agent.velocity.magnitude); // 赋值给speed
public class Hero : MonoBehaviour { public NavMeshAgent agent;
public Animator anim; // Update is called once per frame
void Update () {
if(Input.GetMouseButtonDown()) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit)) {
agent.SetDestination(hit.point);
}
} anim.SetFloat("speed", agent.velocity.magnitude);
}
}
walk->run; // speed>2时
run->walk; //类似
walk->idle; // 类似
完成