第三个项目——PacMan(1)

简介
这是我的第二个项目,与之前第一项目不同,这个项目涉及的专业知识要求更高一些,这个项目的重点在于A*算法的使用AI状态机的使用,因此学习难度也比较好。所以我将这个项目分成几个部分。

第一步 场景搭建

与第一个项目相类似,这里就不多重复。这里查看我的第一个项目

第二步 动画的创建

第三个项目——PacMan(1)_第1张图片
一个动画控制器,四个方向的动画片段。

因为动画有上下左右四个动画,所以要相互转换,因此由Any State 向四个不同动画状态转换
第三个项目——PacMan(1)_第2张图片

在设置转换条件的时候,将Parameters 添加Float类型,因为当玩家操控角色进行上下左右移动时,总的来说就是控制物体进行坐标位置的增减。例如 右移一个单位就是DirX+1 ,而左移动一个单位就是 DirX-1。
注意:不能将float的判断条件设置为零,因为对于计算机来说,一个非常小的数也会被默认为零,会造成不准确。所以尽可能设置为0.1 、-0.1 …这样的数。
第三个项目——PacMan(1)_第3张图片

第三步 主角的移动控制

具体代码

public class PacmanMove : MonoBehaviour
{
    public float speed = 4f;
    public Vector2 dest;//PacMan行走的目标位置
 

    private void Start()
    {
        dest = this.transform.position;
    }
    public void FixedUpdate()//物理上每一帧,有物理组件时就要用FixedUpdate,Update控制的移动仅仅是图片上的移动
    {
        //1、控制角色朝着目标方向移动
        Vector2 p = Vector2.MoveTowards(this.transform.position, dest, speed * Time.fixedDeltaTime);//从当前位置向目标位置移动,每秒移动speed个单位

        this.gameObject.GetComponent<Rigidbody2D>().MovePosition(p);//移动位置

        //2、如果角色移动到目标点了,则检测玩家按键,通过上下左右控制角色


        if ((Vector2)this.transform.position == dest)//二维不能与三维直接判断,但是可以赋值
        {
            Vector2 dir = Vector2.zero;
            if (Input.GetKey(KeyCode.DownArrow) && CanGo(Vector2.down))
            {
                dir = Vector2.down;
            }
            if (Input.GetKey(KeyCode.UpArrow) && CanGo(Vector2.up))
            {
                dir = Vector2.up;
            }
            if (Input.GetKey(KeyCode.RightArrow) && CanGo(Vector2.right))
            {
                dir = Vector2.right;
            }
            if (Input.GetKey(KeyCode.LeftArrow) && CanGo(Vector2.left))
            {
                dir = Vector2.left;
            }
     

            GetComponent<Animator>().SetFloat("DirX",dir.x);//按键来控制动画
            GetComponent<Animator>().SetFloat("DirY", dir.y);

            dest += dir;
        }
    
    }

    private bool CanGo(Vector2 dir)
    {
        RaycastHit2D hit = Physics2D.Linecast(this.transform.position, (Vector2)this.transform.position + dir, 1 << LayerMask.NameToLayer("Map"));//发出射线,由pacman发出射线,射线的层由1位移到Map层,当碰到墙后,反映到hit上,有碰撞物就返回true,没有就返回flase
        //return hit != true;//=>hit.operator bool

        return hit!=true;//相当于ture!=ture 返回flase

    }
}

这一部分代码虽然不长,但是知识点十分密集。

  1. 主角移动的步骤
    1、控制角色朝着目标方向移动
    2、如果角色移动到了目标端,则检测玩家按键,通过上下左右控制

  2. 逻辑分析
    第三个项目——PacMan(1)_第4张图片
    1、先定义一个位置(dest),
    2、在开始时将当前的位置赋值给dest
    3、在按键后给当前位置增加一个单位
    4、调用MoveTowards方法使用一个dest数值,进行让角色向目标方向移动
    5、角色实现移动

  3. 角色移动的实现
    第三个项目——PacMan(1)_第5张图片
    Vector2.MoveTowards(位置1,位置2,每秒移动x个单位)
    位置1:this.transform.position 现有位置
    位置2: dest 即将要抵达的位置
    每秒移动x个单位:speed * Time.fixedDeltaTime 每秒按speed个单位移动
    效果:就是让游戏物体不会直接移动到目标位置,而是有一个过程

 this.gameObject.GetComponent<Rigidbody2D>().MovePosition(p)

调用MovePosition()方法,使带有刚体的游戏物体移动到p的位置

注意
这里的游戏物体的移动是建立在具有刚体组件的条件上的,这里就要区分FixedUpdate()与Update()方法的区别了。
FixedUpdate()方法在unity中是比Upadte更早被执行。
FixedUpdate()方法是游戏物体物理的上的移动
Update()方法则是游戏图片的移动
因此如果游戏物体上有物理组件,那么一定要使用FixedUpdate()方法

  1. 判断角色是否可以移动
    第三个项目——PacMan(1)_第6张图片
    原理:通过射线检测前方是否有碰撞体
    第三个项目——PacMan(1)_第7张图片
    Vector2 dir 输入按键参数,以确认是否为可以走。
    RaycastHit2D 射线类型
    Physic2D.Linecast 发出射线
    return 一个bool值。

方法分析
Linecast(位置1、位置2、掩码)
位置1 this.transform.postion 当前位置
位置2 this.transform.postion+dir 射线到到达的位置
掩码 1<从图层1到为"Map"的图层
返回值:如果有碰撞就返回true,如果没有碰撞就返回flase
第三个项目——PacMan(1)_第8张图片

注意 RaycastHit2D类型的值是一个重载bool值。在进行按键控制时,会调用这个方法,一定要注意返回者,前面有碰撞时要返回的是true,所以需要返回一个flase来控制不能让角色继续移动。这是就需要使用 true!=true 来返回一个flase(这里我就绕了很旧)。

还有一点,一定要注意角色的碰撞器与障碍的距离,如果角色的碰撞器过大,射线判断就会让角色一直处于碰撞的状态,让角色一直无法移动,或者发生可以左右移动,但是上下的距离不够,造成无法上下移动。

第四步 吃豆子功能

首先为豆子添加碰撞器,并且改为触发器模式
第三个项目——PacMan(1)_第9张图片
再添加一个脚本Pacdot

public class Pacdot : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "pacman")//当碰撞体的name为pacman时摧毁,当前游戏物体
        {
            Destroy(this.gameObject);
        }

    }
}

你可能感兴趣的:(unity)