✅ 古迹探险环境搭建
直接运用之前搭建好的地形。然后找到主角Hero
的模型,拖到场景当中:
这里每个方格大小都是【1米乘1米】。
image.png调整下主角的起始点
image.png接着给场景添加一些【石头和灯光】,把石头模型Rock_Large
直接拖到场景,调整大小
给石头添加【 Mesh Collider
碰撞器】,勾上Convex
能优化性能
其实在地形里没必要添加这么精细的碰撞器 Mesh Collider
,改成一个Box Collider
完全可以。
接着,选中【石头节点】,并把Mesh Renderer
勾选上 | 禁掉光照:
看下禁掉光照的效果:
image.png复制一些石头,其实可以把石头做成【预制体】 。适当调整下石头的位置,旋转角度:
image.png自己随意设计去摆放:
image.png
可以把【光重新禁掉】,看下整体效果:
image.png然后把【所有石头节点】选中 | 右键 | Create Empty Parent
, 名字改为Env
,意味和环境有关的节点
我们可以把【环境光】再整体调暗一些:Window | Rendering | Lighting | Environment
:
然后添加一些灯光
,再最外层和内层都添加一些灯光,添加【点光源】,稍微放大一些,外出设置为有点神秘色彩的紫色,内层设置为偏绿色:
这些灯光其实都是作为一些环境光存在的。 把所有灯光都选中,也放在一个叫Light的父节点下:
image.png整体看下效果:
image.png✅ 废墟环境搭建
放置一些废墟古迹 Prefab
比如:
image.png
可以放大一些
image.png可以【手动摆放】一些树木和火堆,放在我们想要的位置。因为直接通过笔刷刷上去的有时候位置一般不精准,如果想精准把树木摆在某个地方,就可以手动摆放
一下。
火堆上的火焰,后面通过粒子效果实现。
把火堆支架和火堆,做成一个整体,创建一个公共父类,叫 Bonefire,然后把这个Bonefire也做成一个预制体,方便后期的修改。
image.png➡️ 生成光照贴图
选择上面创建的所有点光源,把它们的Mode改为 Backed。
然后选择 window | rendering | lighting | Generate Lighting
✅ Unity 粒子系统(Particle System)
在Bonefire节点下,创建一个 空节点(Create Empty) | 在改节点下 Add Component | Particle System
粒子默认是从左到右发射,我们要让它从下往上发射,需要让它围绕x轴旋转-90度。
image.png关于这个粒子系统它里面东西还是挺多的,挺复杂的:
image.png我们可以粒子系统创建很多特效。
image.png可以通过这个选项,把粒子外的边框去掉。
这里为什么粒子显示成紫色,是因为在下面Renderer这里我们没有制定材质,我们可以给它指定一个系统自带的材质试一下:
image.png这下就粒子就有了材质:
image.png看下一些相关参数:
image.png- Duration:粒子动画一次持续的时间
- Loop:是否循环播放
- Prewarm :是否预先生成一些粒子
- Start Lifttime:单个粒子的存活时间
- Start Speed:每个粒子的速度
Emission只要是用来控制发射的。有两种模式,第一是通过时间来发射,第二是通过距离来发射。
Rate over time:10 。表示每秒发射10个。
Rate over distance: 10。表示随着粒子系统的移动,它才会发射粒子。比如,移动Fire节点时,才会发射粒子。比如赛车时尾气拖尾。
✅ Unity 粒子系统创建火焰
image.png素材是4x4的一张贴图。
首先,创建材质: 右键 |Create | Material:
image.png接着,选择一下它的shader | Particles | Standard Unit:
image.png然后把火焰贴图拖到 Albedo那里。
然后把粒子系统Renderer下的材质,替换成我们刚创建的材质球:
image.png我们发现它是播放一整张贴图:
image.png去掉黑色背景:
image.png然后设置火焰帧动画的播放:
image.png因为贴图是4x4的,所以tile设置为4x4
这里Time mode 默认是根据每个粒子的生命周期Lifttime来播放的,这样可能有点慢,我们可以改成根据FPS帧率播放,然后调整FPS的数值来控制让它播放的更快或更慢一些。
接着,调整下粒子的形状:
image.pngStart Size 让他随机一些:
image.png
都调整好之后,因为Bonefire是个 预制体,所以需要点下 Apply All:
image.png然后,在场景里多复制几个 Bonefire。
➡️ 给 Bonefire 添加灯光特效 - 闪烁动画
在 Bonefire 下创建一个 Light物体 | 设置为 Point类型 | 颜色偏橙红色:
image.png image.png下面添加一下动画。选择 window | Animation | Animation:
image.png然后选中 Bonefire节点,点击Create:
image.png接着,去录制一下这个动画。 点击录制按钮:
image.png接着,去修改一下这个Point Light 身上的 Indensity:
第0帧是让它稍微暗一些:比如 Indensity:1
第15帧时稍微亮一些:比如 Indensity:1.9
第25帧时稍微暗一些:比如 Indensity:1.5
第35帧时稍微更亮一些:比如 Indensity:2.5
第50帧时回到最初:比如 Indensity:1
通过修改这个帧率,来调节下火光播放的快慢。
火光在播放动画时,火光时左右移动的,所以需要修改下位置:
第0帧是一个位置
第15帧一个位置
第25帧一个位置
第35帧一个位置
第50帧一个位置
运行预览没问题后,回到 Bonefire 预制体,点下 Apply All。
✅ 导航系统基本使用
创建一个新的Scene
来测试导航系统的使用。
在场景中创建一些物体:
-
胶囊代表我们要控制的玩家角色。
image.png
当Unity中导入了 AI Navigation,在Scene的右下角就多了这样一个面板:
image.png当然我们可以通过 overlay menu 控制这个 AI Navigation 面板的显示或隐藏
image.pngimage.png
➡️ 制作导航网格
在大纲窗口右键 | AI | NavMesh Surface:
image.png
这个 NavMesh Surface
就是用来烘培导航网格的。可以创建多个 NavMesh Surface
就可以创建多个导航网格。因为不同的导航网格适合不同的物体进行导航
。
点击右下角的Bake,就可以生成一个导航网格了:
image.png- 蓝色的是可以行走的部分
- 白色的是不可以行走的部分
为什么我们的玩家角色也被当成障碍物了?你需要告诉导航系统,它是玩家角色不需要烘焙。
有两种方式:
第一种是把不需要烘焙的物体,单独禁掉后,再点击Bake。如果有很多这种物体,一个一个单独单独禁的话比较麻烦。
第二种就是,选中所有不需要烘焙的物体。点击 Add Components,给它们添加 NavMeshModifier 组件:
image.png把组件的mode改为Remove object:
image.png然后再回到 NavMesh Surface
点击Bake
,玩家就不会被当成障碍物去计算了:
导航网格生成好后,就可以进行导航了。导航的话,我们需要另外一个组件:NavMeshAgent
。接着,在Player身上添加 NavMeshAgent
组件,用这个组件来控制Player的移动。
要让Player移动,我们需要告诉NavMeshAgent
组件一个目标位置。
新建一个 Empty节点,命名为TargetPosition。
image.png接着创建一个脚本 TestPlayerNav,挂载到Player节点上。
image.png给两个属性拖拽赋值:
image.png此时运行起来,Player就会追着目标位置 TargetPosition
走了:
➡️ 导航系统使用总结
第一步,使用 NavMesh Surface
生成导航网格。
第二步,使用 NavMesh Modifier
移除掉不需要作为障碍物的物体。
第三步,通过 NavMesh Agent
导航代理组件来控制我们要进行导航的角色。 但我们不一定非要使用 NavMesh Agent
来控制角色的移动,移动控制也可以通过刚体、或Transform动画来控制。
-
Show Only Selected
: 场景当中可能存在多个导航网格, 不方便查看,可以勾选这个选项,这样就只会展示你选择的那个NavMesh Surface
,不勾选的话所有的导航网格都会显示出来。
✅ 导航系统相关设置
image.png-
Agent Type
: Agent 代表要导航的角色,它可能是一个人物,也可能是一个NPC, 可能是个怪物或物件,总之就是可以移动的游戏物体。 Type 代表游戏物体的类型,Humanoid 表示人物类型, 可以通过open agent setting
来增加Agent Type
:
因为它会根据这个宽高来判断某些路能不能过的去。
比如,新建一个Monster模型,x、y、z都是Player的2倍:
image.png image.png把 Monster
的 Agent Type
改为 Monsterid:
再复制一份 NavMesh Surface
:
然后运行发现,小的会通过中间的路,大的就绕道走了:
image.png✅ 古迹探险 - 制作导航系统
首先添加一个 NavMesh Surface
,然后设置好Agent Type:
点击Bake
生成导航网格:
通过鼠标点击控制人物的目标位置,然后进行导航。要导航的话,需要给 Hero 身上添加一个 NavMesh Agent
组件:
这个Agent 圆柱体的大小,基本和人物的大小吻合:
image.png接着,我们需要让相机找到一个合适的视野,照到人物身上:
接着,我们添加一个聚光灯,从上到下照到人物身上:
接着要控制人物移动,就需要用到射线检测(Raycast)
➡️ 什么是射线检测?
其实,就是从一个点,发射一条射线。在发射的过程中,有没有碰撞到其他的Collider。
射线检测的核心就是: 发射一条射线
。
新建一个测试场景:
射线的位置不方便观察,我们可以选择一个icon方便观察:
再创建一个Cube作为障碍物。
返回一个布尔值,表示是否碰撞到了其他物体。
image.png我们发现射线和Cube已经不挨在一起了,射线检测依然返回true。这是因为默认只绘制1米的射线,但是射线检测是不限长度的。
如果要限制射线检测的长度,可以加上一个距离: maxDistance,用来控制射线检测的最大距离。
image.png当然也可以控制绘制射线的颜色:
image.png这一次,当射线和Cube不相交时就返回false了:
image.png检测碰没碰到物体返回布尔值。具体和哪些物体发射了碰撞怎么获取?
image.png需要注意一点,射线虽然从视觉上穿过了2个物体,但是它只会返回第一个和它碰撞的物体。
image.png➡️ 控制人物移动
在Hero身上添加一个脚本来控制人物移动,控制人物的移动分两步:
- 第一步用
射线检测
,来判断鼠标点击的点 - 第二步通过
NavMeshAgent
让 Hero移动到鼠标点击的点
如果想把屏幕上某个点转换成一条射线的话,需要用到Camera
:
➡️ 摄像机跟随主角移动
可以获得到相机的位置和主角的位置,相减得到一个位置差,然后在update里面让【相机的位置 = 主角位置 + 位置差】 。
创建一个脚本挂载到Main Camera上
image.png
- 首先要有一个跟随的目标 target
- offset 就是位置差
➡️ 给Hero添加动画
这里制作idle和walk两个动画,让着两个动画进行一个切换就可以了。
image.pngHero身上的Animator组件就是用来控制动画播放的:
image.png- controller是用来制定Hero的动画状态机的
在Animation文件夹下创建一个新的 Animator Controller
命名为Hero, 拖拽到Animator
的Controller
下 :
双击打开Hero的Animator状态机 ,Idle动画先拖进来,第一个动画,就是idle动画就成了hero的默认动画,再把walk动画也拖进来,角色可以从idle动画切换到walk,也可以从walk切换到idle。
image.png添加动画之间的过渡(右键 | Make Transition)
两个动画怎么切换那,我们可以通过速度进行判定。 添加一个参数叫 IsWalking 来判断动画是否切换
image.png然后选中下面的线,来看从idle切换到walk应该怎么设置
image.png image.pngwalk到idle的设置同理。
Conditions 中 true时就会从idle切换到walk
Conditions 中 false时就会从walk切换到idle
运行起来,通过勾选isWalking,就可以查看Hero的状态切换动画了
image.png image.png
这个Transition Durations 如果设置0,就是直接切换,相对生硬。
这个Transition Durations 如果设置为0.25,有一个过渡时间,显得切换更加丝滑。接着回到Hero脚本,我们需要通过代码来控制 isWalking 这个参数。
Angular Speed 控制Hero转向速度
image.png
保存场景。运行,Hero就可以做动画了,摄像机可以跟随了。
image.png✅ 添加音效
找到石头,添加背景音效
找到火炬,可以添加一些火燃烧的音效
网友评论