unity2D:添加敌人AI——移动、动画、消灭、hurt效果

注:该文为学习笔记,具体请看b站upMichael-Studio的unity教程2D入门:13敌人Enemy!

环境:unity2020.3

敌人效果:若玩家碰到敌人会掉血,若玩家踩到敌人的头上,则可以将敌人消灭,平时敌人会左右移动

准备工作

1.将素材导入

2.将素材尺寸调整好——Pixels Per Unit

即每个小格代表多大的像素

开始

 3.创建2Dsprite

4.给该sprite添加图片,一般默认是最常用的一张图——Sprite属性

另外如果不显示,则需要调整sorting layer

添加重力效果和碰撞组件

5.添加Rigidbody2D 和 collider

如果是tile碰撞体记得锁定RigidBody的z轴

添加动画效果

6.添加animator

7.在asset中创建一个新的animator controller,并赋值给animator的Controller属性

 具体添加动画的内容不再赘述

消灭敌人

该函数为内置的函数,意为:当碰到2D碰撞体时执行

为了实现“踩到敌人将敌人消灭”我的判断条件是当Player的动画状态是falling时...判断条件不唯一,根据需要来

如果不是falling的状态则做出另外的反应(代码省略)

 如果想要游戏有更好的体验,可以在消灭敌人后有一些小反馈,比如反作用力向上起跳一小段

这里有个小bug,如果“下落”不是“弹起-->下落",而是自由落体,那么不仅Player的动画不会切换到falling,而且踩在enemy头上也不会将它消灭,反而会掉血,改正方法如下

        //下落切换fall效果
        if(rb.velocity.y<0.1f&&!Coll.IsTouchingLayers(Groud))
        {
            Anim.SetBool("falling",true);
        }

受伤Hurt效果

首先hurt动画需要读者自己给Player添加好

 Plyer:  被撞到后往后弹一段距离,切换Hurt动画并掉血

首先,这部分代码写在刚才else的括号中,如果想要有回弹的效果,本质上是改变了velocity,但是在update中不断的调用左右移动的函数,在该函数中的velocity改变值没来得及实现就被盖过去了,为了防止这种情况出现,我们需要这样做。

首先,else部分添加如下代码

 注:ishurt为一个bool值,可以帮助我们在hurt期间先停止左右移动的刷新,只需在update中如下写

什么时候才可以让ishurt重归为false呢?

移动一段距离、经历一段时间、又或是velocity的速度减小为0

这里用的是最后一个方法,请注意,最后一个方法默认的是有摩擦力,也就是速度确实是在不断减小的,我们可以把Player-->Rigidbody-->linear Drag改大一些

然后写下面的代码:↓

至于这几行代码该写在哪里?写在update中或者update调用的任意一个函数中,这里我写在了统一改变Player状态的函数中

 接下来,Player切换受伤效果动画

1.需要添加一个bool参数hurt

2.动画间的关系如下,idle、run、jump都可能切换到hurt状态

3.切换时的参数调整记得注意

 最后hurt应该能回到状态idle 条件为 hurt==false&&idle==true

其他地方不用改,此处改几行代码即可

 PlayerControler代码如下,需要自取

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//控制角色的移动
//控制物品的收集

public class PlayerControler : MonoBehaviour
{
    //获取刚体
    private  Rigidbody2D rb;//物理
    private  Animator  Anim;//动画
    private bool getCherry=false;
    private bool ishurt=false;


    public float speed;
    public float  Jumpforce;
    public LayerMask Groud;//LayerMask是获得图层的
    public Collider2D Coll;//player's colliderBox
    public int Cherry=0;//吃到的cherry的个数

    //UI
    public Text Cherrynumber;



    // Start is called before the first frame update
    void Start()
    {
        rb=GetComponent<Rigidbody2D>();
        Anim=GetComponent<Animator>();
    }

    // Update is called once per frame
    void FixedUpdate()//
    {
        if(ishurt==false)
            Movement();
        SwitchAnim();
        if(getCherry)
        {
            Cherry+=1;
            getCherry=false;
            Cherrynumber.text=Cherry.ToString();
        }
    }

    void Movement()
    {
        float Horizontalmove=Input.GetAxis("Horizontal");//获得玩家横向的输入 -1:left 0:static 1:right 是有-1--1的小数的
        float FaceDirection=Input.GetAxisRaw("Horizontal");//Row可以直接获得-1.0.1的整数
        //角色移动
        if(Horizontalmove!=0)
        {
            rb.velocity=new Vector2(Horizontalmove*speed*Time.deltaTime,rb.velocity.y);//Time.deltaTime单位时间
            Anim.SetFloat("running",Mathf.Abs(Horizontalmove));//调用动画的代码  改动相应的 参数
        }else
        {
            Anim.SetFloat("running",0);//如果不回复的话,running的值会一直在
        }
        //根据 向左向右移动反转身体
        if(FaceDirection!=0)
        {
            transform.localScale=new Vector3(FaceDirection,1,1);//直接用的transform 就是挂脚本的组件的
        }
        //跳跃
        if(Input.GetButtonDown("Jump"))
        {
            if(Coll.IsTouchingLayers(Groud))
            {
                rb.velocity=new Vector2(rb.velocity.x,Jumpforce*Time.deltaTime);
                Anim .SetBool("jumping",true);
                Anim .SetBool("idle",false);
            }
        }
        
    }

    void SwitchAnim()
    {
        if(Anim.GetBool("jumping"))
        {
            if(rb.velocity.y<0)
            { 
                Anim .SetBool ("jumping",false);
                Anim .SetBool ("falling",true);
            }
        }
        else if(ishurt)
        {
            Anim.SetBool("hurt",true);
            if(Mathf.Abs(rb.velocity.x)<0.1f)
            {
                Anim.SetBool("hurt",false);
                Anim.SetBool("idle",true);
                ishurt=false;
            }
        }
        else if(Coll.IsTouchingLayers(Groud ))
        {
            Anim.SetBool("falling",false);
            Anim.SetBool ("idle",true);
        }
    }

    //捡起樱桃
    private void OnTriggerEnter2D(Collider2D obj) 
    {
        if(obj.tag=="Collection")
        {
            Destroy(obj.gameObject);
            getCherry=true;
        }
    }

    //消灭敌人
    private void OnCollisionEnter2D(Collision2D other) 
    {
        
        if(other.gameObject.tag=="enemy")
        {
            //只有掉落的时候才会消失
            if(Anim.GetBool("falling"))
            {
                Destroy(other.gameObject);
                rb.velocity=new Vector2(rb.velocity.x,Jumpforce*Time.deltaTime);
                Anim.SetBool("jumping",true);
            }
            //enemy在左侧 向左后退
            else if(transform.position.x<other.gameObject.transform.position.x)
            {
                rb.velocity=new Vector2(-5,rb.velocity.y);
                ishurt=true;            
            }
            //同理
            else if(transform.position.x>other.gameObject.transform.position.x)
            {
                rb.velocity=new Vector2(5,rb.velocity.y);
                ishurt=true;
            }
        }
    }
}

移动AI

上面都是Player对Enemy反应的部分,下面写一下Enemy在平时自己来回走动的代码,当然了,也可能走着走着跳一下啥的,不过,我还不会~

思路:给enemy设一个左右的限制,判断enemy的位置,假如超过了左侧界限则向右转并向右走,反之亦然,这一部分只需要比较transform.position,并适时改变rigidbody.velocity和transform.localscale

代码如下:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Enemy_Frog : MonoBehaviour

{

    private Rigidbody2D rb;

    public float Speed;

    private float leftPoint,rightPoint;//左右终止点

    private bool faceleft=true;


 

    void Start()

    {

        rb=GetComponent<Rigidbody2D>();

        leftPoint=transform.position.x-2;

        rightPoint=transform.position.x+2;

        //transform.DetachChildren();//改变该节点的transform时,该节点的孩子不受影响

    }


 

    void Update()

    {

        Movement();

    }

    void Movement()

    {

        if(faceleft)

        {

            rb.velocity=new Vector2(-Speed,rb.velocity.y);

            if(transform.position.x<leftPoint)

            {

                transform.localScale=new Vector3(-1,1,1);

                faceleft=false;

            }

        }else

        {

            rb.velocity=new Vector2(Speed,rb.velocity.y);

            if(transform.position.x>rightPoint)

            {

                transform.localScale=new Vector3(1,1,1);

                faceleft=true;

            }

        }

    }

}

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Karon_NeverAlone

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值