Unity之射线检测和导航系统

目录

📕一、射线检测原理

📕1.2、实现实例 

📕二、导航

📕2.1 导航网格的使用

📕2.2 创建角色,在地形上移动

📕2.3 动态障碍物 

📕2.4 网格链接 

📕2.5 自定义网格链接 

📕2.6 区域


不知道大家有没有玩过红色警戒 —— 一款即时战略游戏,和罪恶都市一样小编小学的时候就开始玩了,这款游戏控制单位角色移动是通过鼠标的点击来实现。

同样的操作方法还有英雄联盟等很多游戏,那本篇文章小编就通过简单小实例来讲解这种操作在Unity中是如何实现的。

小编先展示一下实例的演示动图:红色球体表示我们控制的角色,鼠标左键点击小球就会到相应的坐标位置并打印坐标。

进阶版:添加了导航功能

一、射线检测原理

先来讲一下这种操作方式的原理:它其实是从摄像机发射出的一条射线。当鼠标点击的时候,射线就从摄像机发射打到你点击的位置,通过检测射线获取到位置坐标,角色就向这个坐标移动。

 注:射线发射后碰到的游戏物体必须要有碰撞组件才会被检测到,演示动图中点击平面区域以外的地方是没有任何反应的。

1.2、实现实例 

创建射线的两种方法:该实例是通过摄像机创建射线

//创建射线的两种方法:
//方式一 通过向量创建
Ray ray1 = new Ray(Vector3.zero , Vector3.up);
//方式二 通过摄像机创建
Ray ray2 = Camera.main.ScreenPointToRay(Input.mousePosition);

新建一个平面一个球体,球体挂载上红色的材质方便我们观察,新建RayTest脚本用来检测射线并挂载到球体上。

public class RayTest : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        //当点击鼠标左键时执行
        if(Input.GetMouseButtonDown(0))
        {
            //按下鼠标左键发射射线  射线发射后碰到的游戏物体必须要有碰撞组件才会被检测到
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            //声明一个碰撞信息类
            RaycastHit hit;
            //碰撞检测用布尔类型表示
            bool res = Physics.Raycast(ray,out hit);
            //如果碰撞到的情况下,hit就有内容了
            if (res == true)
            {
                //打印出碰撞信息的坐标
                Debug.Log(hit.point);
                //把坐标赋值给球体,球体位置就会直接闪现到射线检测点
                transform.position = hit.point;
            }
            
            //多检测
            //RaycastHit[] hits = Physics.RaycastAll(ray, 100, 1 << 10);
        }
    }
}

点击运行就是动图的演示效果了,很简单的一个实例,接下来我们升级点难度来讲导航

二、导航

2.1 导航网格的使用

依然拿红色警戒来举例:我们都知道普通士兵只能在陆地上行走不能下水;而海豹突击队既可以在陆地上行走也可以下水游泳。

这是通过导航来区分的,导航的作用就是实现按照最优路线移动、哪些地方可以移动、哪些地方不能移动。


我们来看看怎么生成导航网格,先手动搭建一个类似城墙的障碍物,不过有斜坡和楼梯可以上去,如下图所示:就是拿立方体来搭积木嘛,相信大家都可以。把立方体都放进平面里形成一个整体。

给这个地形设置一个静态导航 :

设置为静态导航意思是告诉Unity的导航系统可以通过这些物体计算来生成导航网格

然后我们把导航窗口打开: 选中平面  ——> 窗口  ——> ai  ——> 导航

打开导航窗口后进入到烘焙,这里面有很多属性。 

代理半径代理高度,可以把它想象成一个人的胖瘦和身高。比如一个人要钻进桥洞,导航系统就会根据这个人的胖瘦和身高和桥洞大小做对比判断他能不能钻进去。

最大坡度步高就是一个人能爬坡度的大小和台阶的高度 ,比如我说我能爬90°的坡和三米高的台阶(doge.jpg)

了解了这几个简单属性我们点击Bake按钮生成导航网格,然后我们来看一下:

图中生成的蓝色区域就是导航系统判断可以移动的地方。那为什么边界是灰色的不能走呢?

我们要知道导航系统是根据物体中心判断的,假如说中心是我们的心脏的话那我们就算贴紧墙面心脏也贴紧不了,就是这个道理。

2.2 创建角色,在地形上移动

创建一个胶囊来表示我们控制的玩家,给它挂载上导航代理组件Nav Mesh Agent

上边说过代理半径代理高度可以看成一个人,如果游戏中有体型不同的人呢?比如有胖子、正常体型、瘦子,那就到代理类型发挥它的作用了:

这样我们就可以创建不同的类型给它归类了

另外添加上导航代理组件后我们胶囊就会多出一个绿色圆柱体线框,这个是代理半径和高度产生的和胶囊本身的碰撞器是不一样的

接下来我们编写脚本控制胶囊的移动 ,并把脚本挂载到胶囊上

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

public class PlayerControl3 : MonoBehaviour
{
    //声明导航代理组件
    private NavMeshAgent agent;
    // Start is called before the first frame update
    void Start()
    {
        //获取代理组件
        agent = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        //如果按下鼠标
        if (Input.GetMouseButtonDown(0))
        {
            //通过射线获取点击位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            //判断射线是否碰到物体
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                //拿到射线点击位置
                Vector3 point = hit.point;
                //设置该位置为导航目标点
                agent.SetDestination(point);
            }
        }
    }
}

选中胶囊,改成局部,蓝色箭头就会是胶囊移动的方向了,我们来运行一下

2.3 动态障碍物 

接下来介绍另外一个导航组件NavMeshObstacle,这个组件一般用在动态的障碍物上比如说自动开关门。门打开了我们导航就可以通过,门关闭就通过不了。

我们这里给动图中的立方体看做门取名为Door、把它的静态导航关掉并挂载NavMeshObstacle组件。

注意看蓝色导航区域,当我们移动门的时候蓝色导航区域也会进行动态的改变,这就是NavMeshObstacle组件的作用

2.4 网格链接 

上面我们在看烘焙那一栏时除了代理半径代理高度等属性外还有一个生成分离网格链接,我们通过实例来看看网格链接是干嘛的。

网格链接下面还有两个属性值为掉落高度跳跃距离

 掉落高度是指从一个高度为xxx的地方落下去,跳跃距离是在xxx范围内从一个地方跳到另一个地方。


 我们来设置一下,点击选中两个立方体(是两个)并给红框中的属性画上勾,网络链接就可以使用了。我们给掉落高度跳跃距离都赋值为10,重新烘焙运行看一下:

 效果一目了然

2.5 自定义网格链接 

哆啦A梦o((=゚♀゚=))o的传送门大家都知道吧,我们来做个简陋版的。胶囊可以通过这两个立方体来回传送越过城墙:

我们创建两个立方体放在上图中你想传送的位置,其中一个立方体挂载OffMeshLink组件

起始和结束位置把两个立方体放进去,双向就是可以双向传送,我们看下效果:

 可以看到胶囊通过链接随便游走在城墙两边了

2.6 区域

Unity的导航并不是按照最短距离来计算的

假如小编要去一个地方,但是我和目的地中间隔了一座小山,直线走的话就需要爬山了。假如走爬山的路线一共要消耗5点体力,绕路走一共要消耗3点体力,那小编肯定要绕路走。


 对应到Unity中这叫区域。小编新添一个区域叫做Mountain来模仿山,后边的数值就相当于要消耗的体力点。

新建一个立方体Mountain,把它设置为Mountain区域。

我们来运行一下看看胶囊是怎么走的: 有一段可以发现它绕路了

可以看到加上“山”区域胶囊就开始“权衡利弊”了(doge.jpg),它会选择最优路线来走 。

回头再来说红色警戒中普通士兵不能游泳和海豹突击队可以游泳,他们之间导航的区别。

点击选中胶囊,在胶囊的组件中我们之前挂载了NavMeshAgent,组件中有一个属性叫区域遮罩,下拉菜单里罗列了我们的导航区域(包括我们自定义的),取消勾选的区域胶囊无论怎样都不可以涉足了。

这样大家就知道普通士兵和海豹突击队他们的导航是怎么区分的了吧,拜拜┏(^0^)┛ 

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值