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.让鬼可以按照单条路径巡逻
首先添加路径点
然后给鬼添加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();
}
private void FixedUpdate()
{
if (transform.position != wayPoints[index].position)
{
Vector2 temp = Vector2.MoveTowards(transform.position, wayPoints[index].position, speed);
GetComponent().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 wayPoints = new List();
private void Awake()
{
anim = GetComponent();
}
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().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 wayPoints = new List();
private Vector3 startPos;
private void Awake()
{
anim = GetComponent();
}
private void Start()
{
startPos = transform.position + new Vector3(0, 3, 0);
//初始化路径
LoadAPath(wayPointsGos[GameManager._instance.usingIndex[GetComponent().sortingOrder - 2]]);
}
private void FixedUpdate()
{
if (transform.position != wayPoints[index])
{
Vector2 temp = Vector2.MoveTowards(transform.position, wayPoints[index], speed);
GetComponent().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().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().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().isSuperPacdot = true;
}
private void FreezeEnemy()
{
binky.GetComponent().enabled = false;
clyde.GetComponent().enabled = false;
inky.GetComponent().enabled = false;
pinky.GetComponent().enabled = false;
binky.GetComponent().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
clyde.GetComponent().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
inky.GetComponent().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
pinky.GetComponent().color = new Color(0.7f, 0.7f, 0.7f, 0.7f);
}
private void DisFreezeEnemy()
{
binky.GetComponent().enabled = true;
clyde.GetComponent().enabled = true;
inky.GetComponent().enabled = true;
pinky.GetComponent().enabled = true;
binky.GetComponent().color = new Color(1, 1, 1, 1);
clyde.GetComponent().color = new Color(1, 1, 1, 1);
inky.GetComponent().color = new Color(1, 1, 1, 1);
pinky.GetComponent().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().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().enabled = state;
binky.GetComponent().enabled = state;
clyde.GetComponent().enabled = state;
inky.GetComponent().enabled = state;
pinky.GetComponent().enabled = state;
}
12.UI逻辑的完善与计分面板的显示
private int pacdotNum = 0;
private int nowEat = 0;
public int score = 0;
//更新显示
private void Update()
{
if(nowEat == pacdotNum && pacman.GetComponent().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.发布游戏