自学内容网 自学内容网

“敌人野猪”撞墙判定和等候计时

我们来实现可以判断我们的人物Player和Boar都可以判断有墙壁。判断墙壁,我们之前有写过一个代码,在physicsCheck代码当中,我们检测了地面,那我们同样在这个代码当中去检测我们的墙壁,我们也可以让我们的敌人同样挂载PlysicsCheck这个代码

我们先在Boar当中添加一下

添加好了之后,现在我们的敌人也可以检测我们的地面和我们的墙壁

设置一下在这里同样检测地面,因为后续设置敌人很可能走到悬崖边上,也希望它可以掉头,Ground Layer选择Ground;

也还有检测的范围,我们输入0.1,可以看到当前Scene当中的白色圆圈,如果我希望它检测前方有没有地面,通过修正Bottom Offset来调整白色小圈的位置。将他设置可以检测野猪面前的部分有没有地面(野猪走到悬崖边,前方位置显示没有Ground,野猪停下)

既然地面可以找一个这样的点来进行检测,撞墙就是需要左右两边各添加一个检测点

打开PhysicsCheck代码

我们先来添加一些新的状态的bool值touchLeftWall和touchRightWall

[Header("状态")]
public bool isGround;
public bool touchLeftWall;
public bool touchRightWall;

我们再来看看地面检测的时候,我们找了一个起始的点来检测。所以我们现在也要来找一个起始的点来进行检测,起始的点应该是左侧和右侧,我们同样也要定义一下我们的左右位置的偏移,方便我们来进行调整和设置leftOffset,rightOffset

[Header("检测参数")]
public Vector2 bottomOffset;
public float checkRaduis;//检测范围
public LayerMask groundLayer;//地面碰撞筛选器
public Vector2 leftOffset;//左侧位置偏移
public Vector2 rightOffset;//右侧位置偏移

设置好偏移之后,我们在下边写一下墙体的判断,用和地面检测相同的方法

注意后边我们所检测的图层LayerMask,我们现在墙壁绘制的图层仍然是platform这一层,platfomr被标记为Ground,那我们还是用Ground Layer就可以了

左侧写完写上右侧

 public void Check()
 {
     //检测地面
     isGround = Physics2D.OverlapCircle((Vector2)transform.position+bottomOffset, checkRaduis, groundLayer);
     //墙体判断
     touchLeftWall = Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, checkRaduis, groundLayer);
     touchRightWall = Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, checkRaduis, groundLayer);
 }

同样我们也希望在画面当中把它绘制出来,把UnityEngine.Gizmos中的命令修改一下再执行两次

 private void OnDrawGizmosSelected()
 {
     Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, checkRaduis);
     Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, checkRaduis);
     Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, checkRaduis);
 }

保存代码,返回unity

现在我们就重新绘制出了新的圆圈,我们调整一下左侧和右侧的位置

这样我们就成功检测了碰撞体左右的位置是不是撞墙了

然后我们留意一下人物,点击Player,按住键盘F键来集中一下人物,人物也同样绘制出了左右两个位置,我们也来手动进行一下调整。

如果他能自动判断我碰撞体的左右就更方便了,所以我们动手来写一下

打开physcisCheck代码,我们来创建一个变量,如果一旦勾选了,我们就让他自动去调整,找到我的这个碰撞体的左右的位置,(如果不是自动的,那就是手动的,那我们手动一个一个来设置就好了)我们先在上面创建一个变量起名为manual(手动)

 [Header("检测参数")]
 public bool manual;//手动
 public Vector2 bottomOffset;
 public float checkRaduis;//检测范围
 public LayerMask groundLayer;//地面碰撞筛选器
 public Vector2 leftOffset;//左侧位置偏移
 public Vector2 rightOffset;//右侧位置偏移

那我想要获得我的碰撞体,一开始我也要获得对应的组件,但目前我们的敌人和Player都使用的是CapsuleCollider,所以我创建这个变量CapsuleCollider2D;

在Awake当中我们也要赋值

赋值好了之后呢,我们来判断一下,如果是手动的,或者换个角度来写如果是自动的非手动的,那么我就让这个值一开始等于一个固定的值

我们先来写右侧的,然后左侧只需要改一下x就可以了

右侧x的值应该等于我的碰撞体整体size的一半,那我们要用的就是碰撞体,然后这里面我们要用到的变量叫做bounce(世界坐标)碰撞范围,在Scene的窗口种看见的绿色的框,他的尺寸的x,我们还有位移,我们只获得了这个x只是他的尺寸(比如说1.5宽,2.0宽,但是我们除以一半之前还要调整相加一下他的位移,

我们再回到unity当中,我们来看一下这个变量组件,我们看一下这个Capsule Collider2D,我现在这个胶囊型能画在这个位置,不光取决于他的宽度,也留意他的Offset;如果这个Offset有添加或者减少的话,它整体的这个胶囊都会向左向右移动,所以我们除了用这个尺寸以外,也要加上他的位移

所以我们加上他的位移的x,然后在这个基础之上,我们把它除2(因为我们从这个胶囊的中心点开始,我们现在计算的是右侧,我们加完了位移之后,我们要挪到右侧这个点的位置)所以我们要把这个部分除以2

y的值,直接就可以用我们整体的size,这个高度除以2

 private void Awake()
 {
     coll = GetComponent<CapsuleCollider2D>();

     if(!manual)
     {
         rightOffset = new Vector2((coll.bounds.size.x + coll.offset.x)/2,coll.bounds.size.y/2);
     }
 }

接下来写左侧等于x方向右侧位移差的负值,高度是一样的,只有x的位置不一样

private void Awake()
{
    coll = GetComponent<CapsuleCollider2D>();

    if(!manual)
    {
        rightOffset = new Vector2((coll.bounds.size.x + coll.offset.x)/2,coll.bounds.size.y/2);
        leftOffset = new Vector2(-rightOffset.x, rightOffset.y);
    }
}

保存代码,返回unity

我们记住一下我们的人物的大概位置,我们先点击暂停之后,再运行游戏

我们现在没有勾选我们的manual也就是非手动的,也就是全自动的,我们点击运行来测试一下

可以看到,目前我们的这个左右检测的点调整了一下位置,原因就是因为awake当中,我们执行了先获得我们的整体的碰撞体,然后加上位移,获得了左右的这个判断,

同样我们来看一下我们的野猪,野猪也是在位移的基础上,加上了左右的这个判断

这个点并不在我的碰撞体的这个边缘的位置,我们检测的基准点,是根据我们整个的当前的这个物体,也就是这张图片的中心点,我们是在中心点的基础之上来加上左右的offset,来进行绘制和检测的,

所以这张野猪图片的中心点可以看到,在Scene的场景当中,在脚底中心有应该蓝色的圈,所以这条为中线的话,然后左右对称的这个位置我们做了这个检测,但是实际我们的胶囊碰撞的这个偏移,还是有的,所以大家可以根据自己的需要来调整。

想要调整偏移,我们可以通过修改图片的中心点,这个方式来进行修改或者给他加上一些位移的差也没问题,那也可以直接把它勾选为手动的,我们就按照之前我们手动设置的方式就可以了

停止游戏,我们勾选manual,也就是我们手动来设置一下。野猪我们勾选手动,然后Player我们希望它自动获取我们的碰撞体。

我们点击运行,测试一下野猪走到墙壁会不会有检测碰撞到了墙;或者我们Player跑到墙边也可以进行检测

我们让野猪走到左侧,人物撞到右侧

我们先来看一下Player的PhysicsCheck--Touch Right Wall勾选

再来看一下野猪的PhysicsCheck--Touch Left Wall,野猪走到墙壁,并没有检测到墙壁

我们来修改一下我们的platform,刚才我们已经通过修改碰撞体,把他改为方块了,野猪还是检测不到。

原因是我们还没有修改我们Platform的Composite Collider2D合并的这个状态,因为我们合并之后呢,他的Geometry Type现在是Outlines,也就代表只有外框的这个位置,他才是这个碰撞的检测,一旦快速通过穿模了,那就没有办法检测这个碰撞了

我们要把这个Geometry Type改为Polygons,这样的话,他现在就是一个完整的一个检测的范围了,

我们再来点击play测试一下

当前我们的野猪可以检测到左侧的墙面

这样我们就成功实现了检测墙壁

接下来我们来实现一下,先让这个野猪可以左右走,好像有一种巡逻的状态

保存项目,打开Enemy代码

我们想获得PhysicsCheck当中的撞墙检测,在上面我们来获得一下这个组件

这个检测要放到Update当中去持续不断的判断。一旦碰墙了,就转身

我们先来获取一下physicsCheck这个变量,获得组件

所以在Update当中来写一下,如果touchLeftWall或者touchRightWall,要进行翻转,localScale等于我们设置的检测的faceDir(faceDir本身就等于负的localScale),y轴z轴都为1,保持不变

public class Enemy : MonoBehaviour
{
    Rigidbody2D rb;
    protected Animator anim;
    PhysicsCheck physicsCheck;

    [Header("基本参数")]
    public float normalSpeed;//普通速度
    public float chaseSpeed;//加速冲
    public float currentSpeed;//当前速度
    public Vector3 faceDir;//面朝方向

    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        physicsCheck = GetComponent<PhysicsCheck>();
        currentSpeed = normalSpeed;//初始速度=普通速度
    }

    private void Update()
    {
        faceDir = new Vector3(-transform.localScale.x, 0, 0);

        if(physicsCheck.touchLeftWall||physicsCheck.touchRightWall)
        {
            transform.localScale = new Vector3(faceDir.x, 1, 1);
        }
    }

保存代码,返回unity,测试一下,运行

当前就可以看到我们的野猪可以进行左右移动,碰到墙的时候就翻转

我们写好了这个内容,接下来我希望它碰到墙的时候,可以等待一会儿,等待之后呢,我们倒计时,计时过了之后再翻转

打开Enemy代码来写一下,首先我需要有等待这个部分,我们要再添加一个计时器(通过一个布尔值来判断,然后进行数值的减少,一旦小于了就重新赋值或者修改一下状态)

我们在Enemy当中创建一个新的Header取名为计时器,我们来创建一些变量。计时器要有他的等候时间waitTime;还要有计数的waitTimeCounter,记录当前的值;还要有记录当前状态的wait。

[Header("计时器")]
public float waitTime;
public float waitTimeCounter;
public bool wait;

接下来我们要写这个计时器,计时器也要写在Update当中;我们先在下方写一个函数方法TimeCounter,然后放入Update当中。

所有和敌人相关的计数,我们都放在这个位置(后面还要敌人丢失了Player玩家之后,也需要一段等待的时间,也需要一个计数器)

如果我们进入等待时间,我们的Counter减去我们时间的修正;如果等待时间的计数器小于等于零了,那么等候结束,我们重新修正时间,重新赋值,也要做一个转身。

  public void TimeCounter()
  {
      if(wait)
      {
          waitTimeCounter -= Time.deltaTime;
          if(waitTimeCounter<=0)
          {
              wait = false;
              waitTimeCounter = waitTime;
              transform.localScale = new Vector3(faceDir.x, 1, 1);
          }
      }
  }

我们不用撞墙之后马上转身了,修改一下上面的代码。在撞墙的时候把wait=true

 private void Update()
 {
     faceDir = new Vector3(-transform.localScale.x, 0, 0);

     if (physicsCheck.touchLeftWall || physicsCheck.touchRightWall)
     {
         wait = true;
     }
 }

将TimeCounter函数在Update当中调用

  private void Update()
  {
      faceDir = new Vector3(-transform.localScale.x, 0, 0);

      if (physicsCheck.touchLeftWall || physicsCheck.touchRightWall)
      {
          wait = true;
      }

      TimeCounter();
  }

保存代码,返回unity

找到野猪的Boar中的Wait Time设置为2;我们希望等待两秒之后,野猪转身

运行一下,看能否时间撞墙后的等待

在游戏一开始的时候撞到左侧的墙,他没有进行计数,原因就是Wait Time Counter最开始没有赋值,应该让他等于Wait Time;第二点撞到右侧墙,虽然等待了,可是转身之后马上又转回来了,原因就是因为当野猪转身的时候,这个野猪的后半部分的检测点撞墙了,所以再次进入了时间检测,我们需要来判断一下,我们只有面朝方向的那一侧的检测撞墙了才算,所以这时候我们要优化一下我们检测撞墙的条件

打开Enemy代码,来写一下

目前我们只简单的检测了左墙或右墙,我们也要同时判断一下下一个条件,就是撞左墙的前提是面朝方向为左侧faceDir<0,同样右侧我们也要加上相应的条件。我们用他的面朝方向来做一个约束,来进入这个等待时间

 private void Update()
 {
     faceDir = new Vector3(-transform.localScale.x, 0, 0);

     if (physicsCheck.touchLeftWall && faceDir.x<0 || physicsCheck.touchRightWall && faceDir.x>0)
     {
         wait = true;
     }

     TimeCounter();
 }

然后我们的waitTimeCounter需要在Awake当中初始化

 private void Awake()
 {
     rb = GetComponent<Rigidbody2D>();
     anim = GetComponent<Animator>();
     physicsCheck = GetComponent<PhysicsCheck>();
     currentSpeed = normalSpeed;//初始速度=普通速度
     waitTimeCounter = waitTime;
 }

保存代码,返回unity,再来测试一下

为了方便测试我们现在Platform当中绘制一个台阶,将Player放上去,点击运行

可以看到转身之后我们的时间重置,实现了野猪的左右巡逻

我们继续修改一下,希望野猪撞墙,进入等候的时候,可以站着不动,而不是播放走路的动画

打开Enemy代码

Update当中,进入到wait=true时,我们设置它走路的状态变为false

  private void Update()
  {
      faceDir = new Vector3(-transform.localScale.x, 0, 0);

      if (physicsCheck.touchLeftWall && faceDir.x<0 || physicsCheck.touchRightWall && faceDir.x>0)
      {
          wait = true;
          anim.SetBool("walk",false);
      }

      TimeCounter();
  }

保存代码,返回unity测试一下

这样我们就成功实现了我们野猪的巡逻状态


原文地址:https://blog.csdn.net/zhaokuangkuang_/article/details/142980076

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!