有使用到的教程:
M_Studio : Unity2020 3DRPG游戏开发教程
使用的软件:
Unity hub 3.3.0-c1
Unity 2020.3.24f1c1 (64-bit)
Visual Studio 2019
平台:Windows 11 64-bit
前言:
这次一定 这次一定不放弃
Unity2020 3DRPG游戏开发
M_Studio
01:Create Project 创建项目导入素材
使用 Unity2020.2 创建新 3D 项目
安装 Universal RP 并将整个项目升级到URP
使用Unity版本:2020.2
创建3D项目,package manager中安装unversal RP,
右键创建Rendering=>Universal Render PipeLine=>Pipeline Asset(urp的设置文件)
菜单的Edit中选择Project Settings,切到Graphic选单,将刚才创建的设置文件拖到那个显眼的框框里面
支线:可以在Quality(质量)选单中为不同的渲染质量选择不同的渲染设置文件.
因为版本问题(Unity2020后不能在软件内使用资源商店),无法在软件内部访问Asset Store,需要在网页端进行资源导入.
回到Unity,打开Package Manager,切换Package到My Asset,选择你想要导入的素材,右下角download,再import
(选素材之前记得确认素材对渲染管线的支持情况)
在Edit=>Render Pipeline=>Universal Render Pipeline=>中可以升级当前场景或者当前项目的素材的渲染管线.
本节所使用的素材:
[场景]Low-Poly Simple Nature Pack
[角色]Dog Knight PBR Polyart
02:Build Level 尝试熟悉基本工具
还是要注意素材需要支持通用渲染管线
添加SkyBox:Windows-Rendering-Lighting-Envirinment-SkyboxMaterial
修改SkyBox在光照-环境-天空盒材质里
直接将项目素材从Assets拖拽到hierarchy(图层?)窗口,可以保留其初始的位置值
URP改变人物影子:
Max Distance:离镜头多少米开始渲染阴影
CascadeCount:分层级来渲染
Shadow Resolution:
开启HDR:后期Post Processing处理时会用到
Anti Aliasing(MAAA):抗锯齿
Soft Shadows:虚阴影
Normal Bias:调节阴影缝隙
场景LightingSetting
新版本需要自行创建Lighting Setting
Windows-Rendering-Lighting
LightMode:Baked Indirect
Lightmapper:GPU
颜色没有改变
在Environment内的Lighting Source改为Color;也可自己设置颜色
铺设&简单摆放技巧
V:定点自动吸附
选中摄像机,按下 Ctrl+Shift+F
可以将摄像机位置固定在当前位置下
收纳归类好习惯
用空的Object来分栏
摆放prefeb,完成简单场景
03:PolyBrush 发挥创意构建场景
PolyBrush:
Pack Manager中安装Poly Brush,并在它的页面中点开Samples,根据渲染管线导入对应 Shader
安装完成之后,菜单会多出一个Tool,选择Polybrush=> Polybrush Window打开Polybrush的悬浮窗
Polybrush窗口顶部的几个图标功能分别是:
地形高矮,地形柔化,地形颜色,刷预制体,刷图片
高矮:
左键上升,按住Ctrl再点击则是下降
Shift+滚轮是内圈大小,Ctrl+滚轮调整外圈大小
Direction可以选择变化方向,默认的Normal是法线方向,其他的建议自己尝试
柔化:
比较类似,大家动手试一试吧
颜色:
需要先用之前导入的shader创建对应的Material,拖拽至地面,刷的颜色才能生效
刷预制体:
可以将想要刷的预制体拖拽至调色盘(Current Palette)中,
选择想要刷的预制体,在Brush Loadout中可以调整出现的概率
按住Ctrl再点击便是删除
Hit Surface is Parent选项可以将刷进去的预制体变为地面的子物体,方便整理
ProBuilder:
安装ProBuilder,Samples中导入URP支持
Tool=>ProBuilder打开菜单,右上角三个点可以将文字描述更改为图标描述,按住Shift再移动鼠标可以看到功能介绍
有齿轮的则可以按住Alt或者Option点击出菜单
创建一个物体,形状选择Plane,下面的Width Segments和Length Segments可以设置长款的顶点数量
默认创建出的物体,锚点是在边角,在ProBuilder的菜单中选择中心点按钮(具体看视频)可以将锚点设置为中心
(可选)打开Project Settings=>Package Manager选项中开启Enable Preview Package,安装ProGrids
安装完成后场景左上角便会多一个图标,点击启动,可以增加参考线,以及移动吸附功能
因为ProBuilder创建的物体默认是正方形顶点,可以在ProBuilder菜单中找到那个长得像折纸的图标,将对应物体的顶点改为三角形连接
来自麦扣的作业:做一个地图!!!物体记得分类!!!
本节所使用的素材:
[SkyBox]FREE Skybox Extended Shader
04:Navigation 智能导航地图烘焙
polybrush的其他设置:
给材质球更改为Polybrush材质,使其可以用Polybrush上色

移动的时候,按住Ctrl+Shift
可以吸附在表面上
在polybrush刷树的时候,按住V好像就能直接吸附了
调整可移动区域(设置导航)
给地板设置为静态(两种方法都可以):


然后就可以将地板设置为可行走的区域

然后可以选中所有的树,将其设置为 Not walkable

烘焙之后,将可以看到可移动区域。
给角色添加导航:



同时将烘焙代理的大小调整为角色大小

可攀爬角度一般是30°— 45°
添加导航的障碍:

胶囊为给物体描边,box为方形,以此来设置不可行走的范围
切割选项选中后,将会在地面上实时切割区域,将其设置为不可行走

05:MouseManager 鼠标控制人物移动
创建空对象,创建新的C#脚本并绑定上去
使用Enents:
1 |
using UnityEngine.Events; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; //Class EnentVector3 并非继承于MonoBehaviour,需要序列化 [System.Serializable] //继承UnityEvent<Vector3> public class EnentVector3 : UnityEvent<Vector3> { } public class mousemanager : MonoBehaviour { //用于保存鼠标点击的坐标点 public EnentVector3 OnMouseClicked; } |

destination是导航的目标点
接下来使用的是:Camera.ScreenPointToRay
返回从摄像机通过屏幕点的光线。
另一个:Physics.Raycast
1 |
public static bool Raycast (Vector3 origin, Vector3 direction, out RaycastHit hitInfo, float maxDistance, int layerMask, QueryTriggerInteraction queryTriggerInteraction); |
这个方法会返回一个RaycastHit类型的值,所以我们需要先创建一个RaycastHit类型的变量
1 2 |
//用于保存Physics.Raycast的RaycastHit类型的返回值 RaycastHit hitInfo; |
为了让鼠标在触碰到不同东西时有鼠标指针的变化,同样需要用到射线碰撞返回碰撞信息
1 2 3 4 5 |
//使用Physics.Raycast画ray这条射线,碰撞点输出到hitInfo if(Physics.Raycast(ray, out hitInfo)) { //鼠标光标切换 } |
Physics.Raycast的定义:public static bool Raycast(Ray ray, out RaycastHit hitInfo);
在Update中执行SetCursorTexture();
使其实时的检测这条射线的相关信息,并且实时的将hitInfo的信息返回
接下来是鼠标控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void MouseControl() { //如果鼠标按键0(左键)按下,并且hitInfo获取到的碰撞体不是null if(Input.GetMouseButtonDown(0) && hitInfo.collider != null) { //如果点击的碰撞体上的标签是Ground(鼠标点击地面) if (hitInfo.collider.gameObject.CompareTag("Ground")) { //?.的意思是判断前面的OnMouseClicked是否为空,不为空时执行Invoke将其启动 OnMouseClicked?.Invoke(hitInfo.point); //每次鼠标点击地面,都会将那个点的坐标传回OnMouseClicked这个事件,OnMouseClicked这个事件可以将人物的NavMeshAgent的destination设置到这个点 } } } |
到此为止鼠标控制.cs的全部代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; //Class EnentVector3 并非继承于MonoBehaviour,需要序列化 [System.Serializable] //继承UnityEvent<Vector3> public class EnentVector3 : UnityEvent<Vector3> { } public class mousemanager : MonoBehaviour { //用于保存Physics.Raycast的RaycastHit类型的返回值 RaycastHit hitInfo; //用于保存鼠标点击的坐标点,在Unity界面显示 public EnentVector3 OnMouseClicked; private void Update() { SetCursorTexture(); MouseControl(); } //设置指针贴图 void SetCursorTexture() { //创建射线ray来自Camera:主摄像机获取点 来自鼠标 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //使用Physics.Raycast画ray这条射线,碰撞点输出到hitInfo if (Physics.Raycast(ray, out hitInfo)) { //切换鼠标贴图 } } void MouseControl() { //如果鼠标按键0(左键)按下,并且hitInfo获取到的碰撞体不是null if(Input.GetMouseButtonDown(0) && hitInfo.collider != null) { //如果点击的碰撞体上的标签是Ground(鼠标点击地面) if (hitInfo.collider.gameObject.CompareTag("Ground")) { //?.的意思是判断前面的OnMouseClicked是否为空,不为空时执行Invoke将其启动 OnMouseClicked?.Invoke(hitInfo.point); //每次鼠标点击地面,都会将那个点的坐标传回OnMouseClicked这个事件,OnMouseClicked这个事件可以将人物的NavMeshAgent的destination设置到这个点 } } } } |
记得要将地面的Tag设置:


设置人物的转向速度、加速、停止距离:

在人物手持不同武器时,执行攻击敌人的指令会有不同的停止距离,例如大剑就会远一些,空手时会更贴近一些。
06:SetCursor 设置鼠标指针
为了不每一个角色、关卡都需要拖拽设置移动方法,需要进行改造:
将mousemanager设置为单例模式
1 2 3 4 5 6 7 8 9 10 |
//创建单例模式的mousemanager自身变量 public static mousemanager Instance; void Awake() { if (Instance != null) Destroy(gameObject);//删掉多余的 Instance = this; } |
因为已经将mousemanager设置为单例模式,现在创建新的脚本后可以直接访问其中的方法
创建event事件
1 2 3 4 5 6 |
//Class EnentVector3 并非继承于MonoBehaviour,需要序列化 //[System.Serializable] //继承UnityEvent<Vector3> //public class EnentVector3 : UnityEvent<Vector3> { } |
1 2 3 |
//用于保存鼠标点击的坐标点,在Unity界面显示 //public EnentVector3 OnMouseClicked; public event Action<Vector3> OnMouseClicked; |
Action是返回值为void的内置委托类型,如果遇到这类委托可以直接使用而无需自己定义
于是 在鼠标点击地面的那部分,触发启用了OnMouseClicked
时,所有订阅了这个事件,添加进去的方法都会被执行。
目前playercontroller.cs如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class playercontroller : MonoBehaviour { private NavMeshAgent agent; //Awake会在游戏执行的最开始调用 void Awake() { agent = GetComponent<NavMeshAgent>(); } //用于学习 注册暂时写到start void Start() { //事件添加订阅的方式是+= //想要添加订阅,要保证函数的命名方式定义方式与源完全一样,例中是Vector3 mousemanager.Instance.OnMouseClicked += MoveToTarget; } //角色移动函数,注册自OnMouseClicked public void MoveToTarget(Vector3 target) { agent.destination = target; } } |
在本次更新,OnMouseClicked的作用从unity的拖拽改成了订阅事件,从触发unity内的NavMeshAgent变成了触发所有的订阅事件
记得把playercontroller拖拽到狗子身上
PNG格式图片导入后仍有背景:
将其全选,可直接设置为鼠标的Cursor

因图片质量不高,将其设置为

为图片设置变量;
1 2 |
public Texture2D 点击, 传送, 攻击, 目标, 光标; |

使用switch来更改图标:
更改图标使用Cursor.SetCursor(某图片);
SetCursor()
方法是将一个Texture2D的图片更改为光标,同时有一个Vector2 hotspot的值用于记录偏移量,因为光标一般只有左上角起作用,设置偏移量以保证如圆圈这种的光标能变得合理。
后面会将光标设置为像素32*32,因此偏移量是16,16
其他光标偏移量为0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
if (Physics.Raycast(ray, out hitInfo)) { //切换鼠标贴图 switch (hitInfo.collider.gameObject.tag) { case "Ground": Cursor.SetCursor(目标, new Vector2(16, 16), CursorMode.Auto); break; case "敌人": Cursor.SetCursor(攻击, new Vector2(0,0), CursorMode.Auto); break; case "传送门": Cursor.SetCursor(传送, new Vector2(16, 16), CursorMode.Auto); break; case "交互": Cursor.SetCursor(点击, new Vector2(0, 0), CursorMode.Auto); break; default: Cursor.SetCursor(光标, new Vector2(0, 0), CursorMode.Auto); break; } } |
07:Cinemachine & Post Processing 摄像机跟踪和后处理
导入包:Cinemachine,添加Virtual Camera。
此时MainCamera会被Virtual Camera操控
