目录

声明

6:SetCursor 设置鼠标指针

7:Cinemachine & Post Processing 摄像机跟踪和后处理

8:Animator 动画控制器

9:Shader Graph 遮挡剔除

10:Enemy Set States 设置敌人的基本属性和状态


声明

本教程学习均来自U3D中文课堂麦扣老师

6:SetCursor 设置鼠标指针

如果使用拖拽的方式来控制人物移动的话,在未来后面的游戏设计和开发的时候都不适用,所以我们要舍弃这样的方式,更改MouseManager,为了希望不拖拽的方式就可以调用里面的一些方法,就要把它写成一个单例模式,

先创建一个static的自身变量

public static MouseManager Instance;

然后再Awake中判断

    private void Awake()
    {
        if(Instance != null)
        {
            Destroy(gameObject);
        }
        Instance = this;
    }

创建第二个代码来调用:

想要使用NavMeshAgent需要使用using UnityEngine.AI;命名空间,初始化NavMeshAgent变量

在MouseManager中舍弃UnityEvent方法,使用unity自带的event:添加命名空间using System;

创建event事件:public event Action<Vector3> onMouseClicked;

Player接收鼠标点击发送的Vector3的值,创建方法MoveToTarget,onMouseClicked事件一起用就会调用这个函数

代码如下:

PlayerController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class PlayerController : MonoBehaviour
{
    private NavMeshAgent agent;

    private void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    private void Start()
    {
        MouseManager.Instance.onMouseClicked += MoveToTarget; //onMouseClicked事件添加注册 MoveToTarget()方法
    }
    public void MoveToTarget(Vector3 target) //必须包含参数Vector3,保证函数命名方式定义方式是和onMouseClicked完全一致
    {
        agent.destination = target;
    }
}

MouseManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class MouseManager : MonoBehaviour
{
    public static MouseManager Instance;

    RaycastHit hitInfo; //保存射线碰撞到的物体的相关信息

    public event Action<Vector3> onMouseClicked;

    private void Awake()
    {
        if(Instance != null)
        {
            Destroy(gameObject);
        }
        Instance = this;
    }
    private void Update()
    {
        SetCursorTexture();//设置指针的贴图
        MouseControl();//返回鼠标左键点击返回值
    }

    void SetCursorTexture() //设置指针的贴图
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if(Physics.Raycast(ray,out hitInfo))
        {
            //切换鼠标贴图
        }
    }

    void MouseControl()//返回鼠标左键点击返回值
    {
        if(Input.GetMouseButtonDown(0)&&hitInfo.collider != null)
        {
            if(hitInfo.collider.gameObject.CompareTag("Ground"))
            {
                onMouseClicked?.Invoke(hitInfo.point); //当前onMouseClicked事件如果不为空,将点击到地面上的坐标传回给这个事件(执行所有加入到onMouseClicked的函数方法)
            }
        }
    }
}

 这样就实现了没有用拖拽的方式就将人物添加到MouseManager中去控制了

下面设置鼠标指针:

指针有 :手指、传送门、攻击、目标、箭头;

创建5个Texture2D贴图变量:public Texture2D point, doorway, attack, target, arrow;

补充SetCursorTexture() 方法:

void SetCursorTexture() //设置指针的贴图
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if(Physics.Raycast(ray,out hitInfo))
        {
            //切换鼠标贴图
            switch(hitInfo.collider.gameObject.tag)
            {
                case "Ground":
                    Cursor.SetCursor(target, new Vector2(16, 16),CursorMode.Auto); 
                    break;
            }
        }
    }

 这样鼠标指向地面贴图就变为target了

7:Cinemachine & Post Processing 摄像机跟踪和后处理

安装Cinemachine做摄像机跟随,

Unity ui遮罩3d物体_unity

 创建虚拟相机

Unity ui遮罩3d物体_System_02

 调整摄像机属性

Unity ui遮罩3d物体_Unity ui遮罩3d物体_03

 这样就能跟随人物移动了

为远处设置迷雾效果会更好,选择Lighting,勾选Environment中的迷雾Fog,

调整属性,画面就有迷雾效果了

Unity ui遮罩3d物体_游戏引擎_04

Unity ui遮罩3d物体_游戏引擎_05

 Post Processing 后处理提升画质,创建GlobalVolume

Unity ui遮罩3d物体_System_06

在MainCamera中勾选 Post Processing

Unity ui遮罩3d物体_System_07

 添加属性:

Unity ui遮罩3d物体_unity_08

8:Animator 动画控制器

创建PlayerController 

Unity ui遮罩3d物体_Unity ui遮罩3d物体_09

PlayerController 中建立BlendTree,编辑BlendTree,创建一个Parameters名为Speed,Float类型,来根据人物移动速度切换走路和跑步的状态,BlendTree中添加3个Motion动画

Unity ui遮罩3d物体_3d_10

 下面用脚本来给Animator中的Speed变量赋值:先获取Player的Animator组件,接下来写一个方法来实时切换动画,

private void SwitchAnimation()//实时切换动画
    {

        anim.SetFloat("Speed", agent.velocity.sqrMagnitude);   
        //sqrMagnitude将velocity转换为浮点数值
    }

这样角色移动就有动作了

9:Shader Graph 遮挡剔除

新建一个Shader Graph

Unity ui遮罩3d物体_Unity ui遮罩3d物体_11

 

Unity ui遮罩3d物体_游戏引擎_12

并基于Shader创建一个材质 

Unity ui遮罩3d物体_游戏引擎_13

点开Shader Graph,新建一个Fresnel Effect

Unity ui遮罩3d物体_Unity ui遮罩3d物体_14

Unity ui遮罩3d物体_游戏引擎_15

应用费尼尔现象,为了后面能修改颜色,新建一个Color,设置颜色,然后拖入面板,进行乘法运算,输出到Base Color.

Unity ui遮罩3d物体_3d_16

Unity ui遮罩3d物体_System_17

Unity ui遮罩3d物体_3d_18

 添加噪点效果:新建一个Dither,

Unity ui遮罩3d物体_游戏引擎_19

 新建一个Float型变量

Unity ui遮罩3d物体_System_20

进行输入,输出到Alpha值

Unity ui遮罩3d物体_System_21

 Save保存,这样就可以在材质外面更改了

Unity ui遮罩3d物体_游戏引擎_22

 现在需要创建一个阈值来控制alpha。在创建一个Float变量AlphaThreshold

Unity ui遮罩3d物体_游戏引擎_23

 Save保存,返回游戏,

要将人物移动到遮挡物后面的时候,就让它应用这个材质,那样的话就只显示一个轮廓了,这就涉及到我们的pipeline的setting了,urp就是可编辑的渲染管线,所以我们要在渲染管线当中进行编辑了,找到pipeline settings,找到UniversalRenderPipelineAsset_Renderer,新建RenderObjects,因为人物在后面和在前面的时候是2种不同的方式显示的,将第一个命名为CharacterBehind

Unity ui遮罩3d物体_System_24

 应用depth判断人物是在后面还是前面,将第一个RenderObject命名为CharacterBehind,将Player图层设置为Player图层,选择Player进行剔除

Unity ui遮罩3d物体_Unity ui遮罩3d物体_25

 

Unity ui遮罩3d物体_Unity ui遮罩3d物体_26

 在添加一个Render Objects,取名为CharacterInFront,选择应用Player图层

Unity ui遮罩3d物体_Unity ui遮罩3d物体_27

 这样只有在人物被其它物品挡住的时候,它才会应用上面的材质,没有遮挡的情况下就保持不变

 解决问题:由于树木遮挡了鼠标的射线导致人物没法移动到树的位置,第一种方法是可以将所有的树忽略射线,就直接解决这个问题了,第二种方法是将所有的树的MeshCollider关闭掉

Unity ui遮罩3d物体_Unity ui遮罩3d物体_28

 

Unity ui遮罩3d物体_Unity ui遮罩3d物体_29

10:Enemy Set States 设置敌人的基本属性和状态

下载资源

Unity ui遮罩3d物体_System_30

导入素材

Unity ui遮罩3d物体_Unity ui遮罩3d物体_31

将所有材质升级到URP材质,

Unity ui遮罩3d物体_3d_32

 将史莱姆放置到场景中

Unity ui遮罩3d物体_3d_33

 创建一个EnemyController脚本:因为很多敌人都会挂载Enemy的脚本,希望这个脚本里获取的所有变量都能够让它能够自动添加到我们物体上,先写这个代码:

EnemyController:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

[RequireComponent(typeof(NavMeshAgent))]    //确保NavMeshAgent组件一定存在
public class EnemyController : MonoBehaviour
{
    private NavMeshAgent agent;

    private void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
    }
}

为史莱姆添加BoxCollider组件,调整各组件的属性值

Unity ui遮罩3d物体_System_34

 为了切换敌人不同的状态,我们要先想我们的敌人可能会有哪几种状态,首先是Guard(站桩)的状态,它是一个站桩的敌人,当我们的player接近的时候它才会追击我们的player,另外一种它是一个(PATROL)巡逻的敌人,他会按照自己巡逻的点不断移动,一旦发现我们的玩家就会追击,那么顺理成章我们也有一个(CHASE)追击的状态,然后他还有一个(DEAD)死亡的状态。

我们用一个enum枚举来切换控制它的状态,

声明枚举变量:public enum EnemyStates { GUARD,PATROL,CHASE,DEAD}

生成变量: public EnemyStates ememyStates;

现在代码中就有一个下拉菜单选择是那种怪物了,先选择为站桩怪

Unity ui遮罩3d物体_游戏引擎_35

接下来写一个函数方法来切换它的不同状态:

void SwitchStates() //切换状态
    {
        switch(ememyStates)
        {
            case EnemyStates.GUARD:
                break;
            case EnemyStates.PATROL:
                break;
            case EnemyStates.CHASE:
                break;
            case EnemyStates.DEAD:
                break;
        }
    }

并在Update方法中调用它

EnemyController:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public enum EnemyStates { GUARD,PATROL,CHASE,DEAD}  //站桩,巡逻,追击,死亡

[RequireComponent(typeof(NavMeshAgent))]    //确保NavMeshAgent组件一定存在
public class EnemyController : MonoBehaviour
{
    public EnemyStates ememyStates;

    private NavMeshAgent agent;

    private void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    private void Update()
    {
        SwitchStates();//切换状态
    }

    void SwitchStates() //切换状态
    {
        switch(ememyStates)
        {
            case EnemyStates.GUARD:
                break;
            case EnemyStates.PATROL:
                break;
            case EnemyStates.CHASE:
                break;
            case EnemyStates.DEAD:
                break;
        }
    }
}

这样敌人基本的框架就有了

下面让鼠标指向敌人可以切换鼠标的样子,为敌人添加一个Layer和Tag,取名都为Enemy

留意:我们的敌人也是希望和Player一样可以发生遮挡剔除的,不然它们跑到树林当中我们无法看见它们并且选中它们产生攻击效果的,所以我们回到pipeline settings当中将Enemy图层也选上

Unity ui遮罩3d物体_游戏引擎_36

 返回到MouseManager当中,修改我们的Cursor:

void SetCursorTexture() //设置指针的贴图
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if(Physics.Raycast(ray,out hitInfo))
        {
            //切换鼠标贴图
            switch(hitInfo.collider.gameObject.tag)
            {
                case "Ground":
                    Cursor.SetCursor(target, new Vector2(16, 16),CursorMode.Auto); //偏移(16,16)
                    break;
                case "Enemy":
                    Cursor.SetCursor(attack, new Vector2(16, 16), CursorMode.Auto); //偏移(16,16)
                    break;
            }
        }
    }

下期将会实现敌人的所有功能了,赶紧操作起来吧!