Unity初级案例 - 吃豆人(Unity2017.2.0)Day 2

1.用代码控制动画状态机及设置渲染顺序

            //获取移动方向
            Vector2 dir = dest - (Vector2)transform.position;
            //把获取到的移动方向设置给动画状态机
            anim.SetFloat("DirX", dir.x);
            anim.SetFloat("DirY", dir.y);

2.为迷宫加入可以被吃掉的豆点

创建豆点Pacdot,添加碰撞体,并且添加Pacdot脚本

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

public class Pacdot : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.name == "Pacman")
        {
            Destroy(gameObject);
        }
    }
}

运行程序,结果如下

3.创建四个敌人并采用重写状态机控制动画

4.用现有的知识模拟AI的思路讲解

使用A*寻路和感知系统来完成鬼的寻路。

5.让鬼可以按照单条路径巡逻

首先添加路径点

扫描二维码关注公众号,回复: 5720391 查看本文章

然后给鬼添加GhostMove脚本,让它移动

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

public class GhostMove : MonoBehaviour
{
    //储存所有路径点的Transform组件
    public Transform[] wayPoints;
    public float speed = 0.2f;
    //当前在前往哪个路径点的途中
    private int index = 0;
    private Animator anim;

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    private void FixedUpdate()
    {
        if (transform.position != wayPoints[index].position)
        {
            Vector2 temp = Vector2.MoveTowards(transform.position, wayPoints[index].position, speed);
            GetComponent<Rigidbody2D>().MovePosition(temp);
        }
        else
        {
            index = (index + 1) % wayPoints.Length;
        }
        Vector2 dir = (Vector2)wayPoints[index].position - (Vector2)transform.position;
        anim.SetFloat("DirX", dir.x);
        anim.SetFloat("DirY", dir.y);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            Destroy(collision.gameObject);
        }
    }
}

运行程序,结果如下

6.改进巡逻系统使鬼可以随机选择一条路径巡逻

重新编写巡逻系统

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

public class GhostMove : MonoBehaviour
{
    public GameObject[] wayPointsGos;
    public float speed = 0.2f;
    //当前在前往哪个路径点的途中
    private int index = 0;
    private Animator anim;
    private List<Vector3> wayPoints = new List<Vector3>();

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    private void Start()
    {
        LoadAPath(wayPointsGos[Random.Range(0, 2)]);
    }

    private void FixedUpdate()
    {
        if (transform.position != wayPoints[index])
        {
            Vector2 temp = Vector2.MoveTowards(transform.position, wayPoints[index], speed);
            GetComponent<Rigidbody2D>().MovePosition(temp);
        }
        else
        {
            index++;
            if(index >= wayPoints.Count)
            {
                index = 0;
                LoadAPath(wayPointsGos[Random.Range(0, 2)]);
            }
        }
        Vector2 dir = (Vector2)wayPoints[index] - (Vector2)transform.position;
        anim.SetFloat("DirX", dir.x);
        anim.SetFloat("DirY", dir.y);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            Destroy(collision.gameObject);
        }
    }

    private void LoadAPath(GameObject go)
    {
        wayPoints.Clear();
        foreach (Transform t in go.transform)
        {
            wayPoints.Add(t.position);
        }
    }
}

运行程序结果如下

7.完善用巡逻来模拟AI的逻辑

添加GameManager脚本,让鬼的初始路径各不相同

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

public class GhostMove : MonoBehaviour
{
    public GameObject[] wayPointsGos;
    public float speed = 0.2f;
    //当前在前往哪个路径点的途中
    private int index = 0;
    private Animator anim;
    private List<Vector3> wayPoints = new List<Vector3>();
    private Vector3 startPos;

    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    private void Start()
    {
        startPos = transform.position + new Vector3(0, 3, 0);
        //初始化路径
        LoadAPath(wayPointsGos[GameManager._instance.usingIndex[GetComponent<SpriteRenderer>().sortingOrder - 2]]);
    }

    private void FixedUpdate()
    {
        if (transform.position != wayPoints[index])
        {
            Vector2 temp = Vector2.MoveTowards(transform.position, wayPoints[index], speed);
            GetComponent<Rigidbody2D>().MovePosition(temp);
        }
        else
        {
            index++;
            if(index >= wayPoints.Count)
            {
                index = 0;
                LoadAPath(wayPointsGos[Random.Range(0, wayPointsGos.Length)]);
            }
        }
        Vector2 dir = (Vector2)wayPoints[index] - (Vector2)transform.position;
        anim.SetFloat("DirX", dir.x);
        anim.SetFloat("DirY", dir.y);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            Destroy(collision.gameObject);
        }
    }

    private void LoadAPath(GameObject go)
    {
        wayPoints.Clear();
        foreach (Transform t in go.transform)
        {
            wayPoints.Add(t.position);
        }
        wayPoints.Insert(0, startPos);
        wayPoints.Add(startPos);
    }
}

然后在GhostMove中初始化路径

 //初始化路径
        LoadAPath(wayPointsGos[GameManager._instance.usingIndex[GetComponent<SpriteRenderer>().sortingOrder - 2]]);

运行程序结果如下

8.引入超级豆点奖励道具

在GameManager中添加生成超级豆点的代码

    private void CreateSuperPacdot()
    {
        int tempIndex = Random.Range(0, pacdotGos.Count);
        pacdotGos[tempIndex].transform.localScale = new Vector3(3, 3, 3);
        pacdotGos[tempIndex].GetComponent<Pacdot>().isSuperPacdot = true;
    }

在Pacdot中添加吃豆人碰到超级豆点的方法

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.name == "Pacman")
        {
            if (isSuperPacdot)
            {
                //TODO
                //告诉GameManager我是超级豆子而且还被吃了
                //让吃豆人变成超级吃豆人,可以吃鬼
            }
            Destroy(gameObject);
        }
    }

在GhostMove中添加吃了超级豆点的吃豆人碰到鬼的方法

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            if (GameManager._instance.isSuperPacman)
            {
                //TODO
                //真倒霉,碰到了超级吃豆人,我要回家躲躲
            }
            Destroy(collision.gameObject);
        }
    }

9.完善超级豆点的功能

在GameManager中添加有关超级豆的一些代码

    private void Start()
    {
        Invoke("CreateSuperPacdot", 10f);
    }

    public void OnEatPacdot(GameObject go)
    {
        pacdotGos.Remove(go);
    }

    public void OnEatSuperPacdot()
    {
        Invoke("CreateSuperPacdot", 10f);
        isSuperPacman = true;
        FreezeEnemy();
        StartCoroutine("RecoverEnemy");
    }

    IEnumerator RecoverEnemy()
    {
        yield return new WaitForSeconds(3f);
        DisFreezeEnemy();
        isSuperPacman = false;
    }

    private void CreateSuperPacdot()
    {
        int tempIndex = Random.Range(0, pacdotGos.Count);
        pacdotGos[tempIndex].transform.localScale = new Vector3(3, 3, 3);
        pacdotGos[tempIndex].GetComponent<Pacdot>().isSuperPacdot = true;
    }

    private void FreezeEnemy()
    {
        binky.GetComponent<GhostMove>().enabled = false;
        clyde.GetComponent<GhostMove>().enabled = false;
        inky.GetComponent<GhostMove>().enabled = false;
        pinky.GetComponent<GhostMove>().enabled = false;
        binky.GetComponent<SpriteRenderer>().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
        clyde.GetComponent<SpriteRenderer>().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
        inky.GetComponent<SpriteRenderer>().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);        
        pinky.GetComponent<SpriteRenderer>().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
    }

    private void DisFreezeEnemy()
    {
        binky.GetComponent<GhostMove>().enabled = true;
        clyde.GetComponent<GhostMove>().enabled = true;
        inky.GetComponent<GhostMove>().enabled = true;
        pinky.GetComponent<GhostMove>().enabled = true;
        binky.GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 1);
        clyde.GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 1);
        inky.GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 1);
        pinky.GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 1);
    }

在 Pacdot中修改碰撞代码

 private void OnTriggerEnter2D(Collider2D collision)
    {
        if(collision.gameObject.name == "Pacman")
        {
            if (isSuperPacdot)
            {
                GameManager._instance.OnEatPacdot(gameObject);
                GameManager._instance.OnEatSuperPacdot();
                Destroy(gameObject);
            }
            else
            {
                GameManager._instance.OnEatPacdot(gameObject);
                Destroy(gameObject);
            }
        }
    }

在 GhostMove中修改碰撞代码

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            if (GameManager._instance.isSuperPacman)
            {
                transform.position = startPos - new Vector3(0, 3, 0);
                index = 0;
            }
            else
            {
                Destroy(collision.gameObject);
            }      
        }
    }

运行程序,结果如下 

10.设计UI界面

11.处理准备时的倒计时动画

在GameManager中添加游戏逻辑处理

    public GameObject startpanel;
    public GameObject gamePanel;
    public GameObject startCountDonwPrefab;
    public GameObject gameoverPrefab;
    public GameObject winPrefab;
    public AudioClip startClip;
    private void Start()
    {
        SetGameState(false);   
    }

    public void OnStartButton()
    {
        StartCoroutine(PlayerStartCountDown());
        AudioSource.PlayClipAtPoint(startClip, Vector3.zero);
        startpanel.SetActive(false);
    }

    public void OnExitButton()
    {
        Application.Quit();
    }

    IEnumerator  PlayerStartCountDown()
    {
        GameObject go = Instantiate(startCountDonwPrefab);
        yield return new WaitForSeconds(4f);
        Destroy(go);
        SetGameState(true);
        Invoke("CreateSuperPacdot", 10f);
        gamePanel.SetActive(true);
        GetComponent<AudioSource>().Play();
    }

    public void OnEatPacdot(GameObject go)
    {
        pacdotGos.Remove(go);
    }

    public void OnEatSuperPacdot()
    {
        Invoke("CreateSuperPacdot", 10f);
        isSuperPacman = true;
        FreezeEnemy();
        StartCoroutine("RecoverEnemy");
    }
    private void SetGameState(bool state)
    {
        pacman.GetComponent<PacmanMove>().enabled = state;
        binky.GetComponent<GhostMove>().enabled = state;
        clyde.GetComponent<GhostMove>().enabled = state;
        inky.GetComponent<GhostMove>().enabled = state;
        pinky.GetComponent<GhostMove>().enabled = state;
    }

12.UI逻辑的完善与计分面板的显示

    private int pacdotNum = 0;
    private int nowEat = 0;
    public int score = 0;
    //更新显示
    private void Update()
    {
        if(nowEat == pacdotNum && pacman.GetComponent<PacmanMove>().enabled != false)
        {
            gamePanel.SetActive(false);
            Instantiate(winPrefab);
            StopAllCoroutines();
            SetGameState(false);
        }
        if(nowEat == pacdotNum)
        {
            if (Input.anyKeyDown)
            {
                SceneManager.LoadScene(0);
            }
        }
        if (gamePanel.activeInHierarchy)
        {
            remainText.text = "Remain:\n\n" + (pacdotNum - nowEat);
            nowText.text = "Eaten:\n\n" + nowEat;
            remainText.text = "Remain:\n\n" + score;
        }
    }

在合适的地方对三个参数进行添加

在GhostMove中完善游戏结束的代码

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.name == "Pacman")
        {
            if (GameManager._instance.isSuperPacman)
            {
                transform.position = startPos - new Vector3(0, 3, 0);
                index = 0;
                GameManager._instance.score += 500;
            }
            else
            {
                collision.gameObject.SetActive(false);
                GameManager._instance.gamePanel.SetActive(false);
                Instantiate(GameManager._instance.gameoverPrefab);
                Invoke("ReStart", 3f);
            }      
        }
    }
    private void ReStart()
    {
        SceneManager.LoadScene(0);
    }

运行程序结果如下

13.发布游戏

猜你喜欢

转载自blog.csdn.net/kouzhuanjing1849/article/details/84979918