unity--2d( A*寻路)

目录

一.网格式寻路

1.创建一个A*寻路脚本,命名为"AStarPathfinding.cs"。

2.创建一个人物控制的脚本,命名为"CharacterController2D.cs"。

3.创建一个游戏管理脚本,命名为"GameManager.cs"。

二.UGUI下的自动寻路

1.路径点脚本

示意图:

 代码:

2.A*寻路脚本

3.人物控制脚本

4.管理脚本


一.网格式寻路

1.创建一个A*寻路脚本,命名为"AStarPathfinding.cs"。
using UnityEngine;
using System.Collections.Generic;

public class AStarPathfinding : MonoBehaviour
{
    // 定义一个节点类来表示地图中的每个格子
    private class Node
    {
        public int x;
        public int y;
        public bool walkable;
        public int gCost;
        public int hCost;
        public Node parent;

        public Node(int _x, int _y, bool _walkable)
        {
            x = _x;
            y = _y;
            walkable = _walkable;
        }

        public int fCost
        {
            get { return gCost + hCost; }
        }
    }

    public LayerMask obstacleMask; // 障碍物层

    private Node[,] grid;
    private Vector2Int gridSize;

    public void InitializeGrid(Vector2Int size)
    {
        gridSize = size;
        CreateGrid();
    }

    private void CreateGrid()
    {
        grid = new Node[gridSize.x, gridSize.y];
        for (int x = 0; x < gridSize.x; x++)
        {
            for (int y = 0; y < gridSize.y; y++)
            {
                Vector3 worldPoint = new Vector3(x, y, 0);
                bool walkable = !Physics2D.OverlapCircle(worldPoint, 0.1f, obstacleMask); // 检测当前格子是否可行走
                grid[x, y] = new Node(x, y, walkable);
            }
        }
    }

    public List<Vector2Int> FindPath(Vector3 startPos, Vector3 targetPos)
    {
        Node startNode = GetNodeFromWorldPoint(startPos);
        Node targetNode = GetNodeFromWorldPoint(targetPos);

        List<Node> openSet = new List<Node>();
        HashSet<Node> closedSet = new HashSet<Node>();
        openSet.Add(startNode);

        while (openSet.Count > 0)
        {
            Node currentNode = openSet[0];
            for (int i = 1; i < openSet.Count; i++)
            {
                if (openSet[i].fCost < currentNode.fCost || openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost)
                {
                    currentNode = openSet[i];
                }
            }

            openSet.Remove(currentNode);
            closedSet.Add(currentNode);

            if (currentNode == targetNode)
            {
                return RetracePath(startNode, targetNode);
            }

            foreach (Node neighbor in GetNeighbors(currentNode))
            {
                if (!neighbor.walkable || closedSet.Contains(neighbor))
                {
                    continue;
                }

                int newCostToNeighbor = currentNode.gCost + GetDistance(currentNode, neighbor);
                if (newCostToNeighbor < neighbor.gCost || !openSet.Contains(neighbor))
                {
                    neighbor.gCost = newCostToNeighbor;
                    neighbor.hCost = GetDistance(neighbor, targetNode);
                    neighbor.parent = currentNode;

                    if (!openSet.Contains(neighbor))
                    {
                        openSet.Add(neighbor);
                    }
                }
            }
        }

        return null; // 如果找不到路径,返回空
    }

    private List<Vector2Int> RetracePath(Node startNode, Node endNode)
    {
        List<Vector2Int> path = new List<Vector2Int>();
        Node currentNode = endNode;

        while (currentNode != startNode)
        {
            path.Add(new Vector2Int(currentNode.x, currentNode.y));
            currentNode = currentNode.parent;
        }

        path.Reverse();
        return path;
    }

    private Node GetNodeFromWorldPoint(Vector3 worldPos)
    {
        int x = Mathf.RoundToInt(worldPos.x);
        int y = Mathf.RoundToInt(worldPos.y);
        return grid[x, y];
    }

    private List<Node> GetNeighbors(Node node)
    {
        List<Node> neighbors = new List<Node>();
        for (int x = -1; x <= 1; x++)
        {
            for (int y = -1; y <= 1; y++)
            {
                if (x == 0 && y == 0)
                    continue;

                int checkX = node.x + x;
                int checkY = node.y + y;

                if (checkX >= 0 && checkX < gridSize.x && checkY >= 0 && checkY < gridSize.y)
                {
                    neighbors.Add(grid[checkX, checkY]);
                }
            }
        }

        return neighbors;
    }

    private int GetDistance(Node nodeA, Node nodeB)
    {
        int distX = Mathf.Abs(nodeA.x - nodeB.x);
        int distY = Mathf.Abs(nodeA.y - nodeB.y);
        return distX + distY;
    }
}
2.创建一个人物控制的脚本,命名为"CharacterController2D.cs"。
using UnityEngine;

public class CharacterController2D : MonoBehaviour
{
    public float speed = 5f;
    public AStarPathfinding pathfinding;

    private Vector3 targetPosition;
    private bool isMoving = false;
    private int currentPathIndex = 0;
    private float pathfindingUpdateInterval = 0.5f;
    private float lastPathfindingUpdateTime;

    private void Start()
    {
        lastPathfindingUpdateTime = Time.time;
        targetPosition = transform.position;
    }

    private void Update()
    {
        HandleInput();

        if (isMoving)
        {
            Move();
        }
    }

    private void HandleInput()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            targetPosition = new Vector3(Mathf.Round(mousePosition.x), Mathf.Round(mousePosition.y), 0f);

            // 调用A*寻路
            if (Time.time - lastPathfindingUpdateTime > pathfindingUpdateInterval)
            {
                lastPathfindingUpdateTime = Time.time;
                var path = pathfinding.FindPath(transform.position, targetPosition);
                if (path != null && path.Count > 0)
                {
                    currentPathIndex = 0;
                    targetPosition = new Vector3(path[0].x, path[0].y, 0f);
                    isMoving = true;
                }
            }
        }
    }

    private void Move()
    {
        Vector3 direction = (targetPosition - transform.position).normalized;
        transform.position += direction * speed * Time.deltaTime;

        if (Vector3.Distance(transform.position, targetPosition) < 0.05f)
        {
            // 到达当前路径点,更新目标路径点
            currentPathIndex++;
            if (currentPathIndex >= path.Count)
            {
                isMoving = false;
            }
            else
            {
                targetPosition = new Vector3(path[currentPathIndex].x, path[currentPathIndex].y, 0f);
            }
        }
    }
}
3.创建一个游戏管理脚本,命名为"GameManager.cs"。
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public AStarPathfinding pathfinding;
    public CharacterController2D character;

    private void Start()
    {
        pathfinding.InitializeGrid(new Vector2Int(10, 10)); // 设置地图大小

        // 这里可以根据需求设置障碍物等
    }
}

在场景中创建一个空物体并将"GameManager.cs"脚本和其他脚本(A*寻路脚本、人物控制脚本)挂载到这个空物体上。然后创建一个2D人物(例如一个精灵或一个SpriteRenderer)并挂载"CharacterController2D.cs"脚本。配置好障碍物层和人物的移动速度等参数。

现在,当你运行游戏并点击鼠标左键在地图上选择目标点,人物就会使用A算法进行寻路,并沿着最短路径移动到目标点。

二.UGUI下的自动寻路

1.路径点脚本

示意图:

 代码:
using UnityEngine;

public class PathPoint : MonoBehaviour
{
    [HideInInspector]
    public RectTransform rect;

    //当前路径点 如:[0,0]
    public Vector2Int point;
    //层级
    public int sort = -9;

    private void Awake()
    {
        rect = GetComponent<RectTransform>();
    }


    [ContextMenu("SetPoint")]
    public void SetPoint()
    {
        point = new Vector2Int(int.Parse(gameObject.name.Split('-')[0]), int.Parse(gameObject.name.Split('-')[1]));
    }
}

2.A*寻路脚本

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

public class AStar
{
    private List<Point> list_open = new List<Point>();//开启列表
    private List<Point> list_close = new List<Point>();//关闭列表
    public Func<int, int, bool> IsBarAction;

    //定义一个路径数组
    private List<Vector2Int> way = new List<Vector2Int>();

    private int startX, startY, endX, endY;

    public void Init(int _startX, int _startY, int _endX, int _endY)
    {
        startX = _startX;
        startY = _startY;
        endX = _endX;
        endY = _endY;
    }

    //从开启列表中找到那个F值最小的格子
    private Point FindMinFInOpenList()
    {
        Point minPoint = null;

        foreach (var v in list_open)
        {
            if (minPoint == null || minPoint.GetF > v.GetF)
                minPoint = v;
        }
        return minPoint;
    }

    //从开启列表中找到格子
    private Point FindInOpenList(int x, int y)
    {

        foreach (var v in list_open)
        {
            if (v.x == x && v.y == y)
                return v;
        }
        return null;

    }

    //判断某点是否在开启列表中
    private bool IsInOpenList(int x, int y)
    {
        foreach (var v in list_open)
        {
            if (v.x == x && v.y == y)
                return true;
        }

        return false;
    }

    //判断某点是否在关闭列表中
    private bool IsInCloseList(int x, int y)
    {
        foreach (var v in list_close)
        {
            if (v.x == x && v.y == y)
                return true;
        }
        return false;
    }

    /// <summary>
    /// a星寻路
    /// </summary>
    /// <returns>寻到的路径</returns>
    /// <param name="starPoint">起点</param>
    /// <param name="targetPoint">终点</param>
    public List<Vector2Int> AStarFindWay(Vector2Int starPoint, Vector2Int targetPoint)
    {
        //Debug.LogError("寻路:" + starPoint.ToString() + "..." + targetPoint.ToString());
        //清空容器
        way.Clear();
        list_open.Clear();
        list_close.Clear();

        //初始化起点格子
        Point starMapPoint = new Point(starPoint.x, starPoint.y);

        //初始化终点格子
        Point targetMapPoint = new Point(targetPoint.x, targetPoint.y);

        //将起点格子添加到开启列表中
        list_open.Add(starMapPoint);

        //寻找最佳路径
        //当目标点不在打开路径中时或者打开列表为空时循环执行
        while (!IsInOpenList(targetMapPoint.x, targetMapPoint.y) || list_open.Count == 0)
        {
            //从开启列表中找到那个F值最小的格子
            Point minPoint = FindMinFInOpenList();

            if (minPoint == null)
                return null;

            //将该点从开启列表中删除,同时添加到关闭列表中
            list_open.Remove(minPoint);
            list_close.Add(minPoint);

            //检查该点周边的格子
            CheckPerPointWithMapFour(minPoint, targetMapPoint);
        }

        //在开启列表中找到终点
        Point endPoint = FindInOpenList(targetMapPoint.x, targetMapPoint.y);

        Vector2Int everyWay = new Vector2Int(endPoint.x, endPoint.y);//保存单个路径点

        way.Add(everyWay);//添加到路径数组中

        //遍历终点,找到每一个父节点:即寻到的路
        while (endPoint.fatherPoint != null)
        {
            everyWay.x = endPoint.fatherPoint.x;
            everyWay.y = endPoint.fatherPoint.y;

            way.Add(everyWay);

            endPoint = endPoint.fatherPoint;
        }

        //将路径从倒序变成正序并返回
        List<Vector2Int> ways = new List<Vector2Int>();
        for (int i = way.Count - 1; i >= 0; --i)
        {
            ways.Add(way[i]);
        }

        //清空容器
        way.Clear();
        list_open.Clear();
        list_close.Clear();

        //返回正序的路径数组
        return ways;
    }

    //判断地图上某个坐标点是不是障碍点
    private bool IsBar(int x, int y)
    {
        return IsBarAction(x, y);
    }

    //计算某方块的G值
    public int GetG(Point p)
    {
        if (p.fatherPoint == null)
            return 0;

        if (p.x == p.fatherPoint.x || p.y == p.fatherPoint.y)
            return p.fatherPoint.G + 10;
        else
            return p.fatherPoint.G + 14;
    }

    //计算某方块的H值
    public int GetH(Point p, Point targetPoint)
    {
        return (Mathf.Abs(targetPoint.x - p.x) + Mathf.Abs(targetPoint.y - p.y)) * 10;
    }

    //检查某点周边的格子 周围8个
    private void CheckPerPointWithMapEight(Point _point, Point targetPoint)
    {
        for (int i = _point.x - 1; i <= _point.x + 1; ++i)
        {
            for (int j = _point.y - 1; j <= _point.y + 1; ++j)
            {
                //剔除超过地图的点
                if (i < startX || i >= endX || j < startY || j >= endY)
                    continue;

                //剔除该点是障碍点:即周围有墙的点
                if (IsBar(i, j))
                    continue;

                //剔除已经存在关闭列表或者本身点
                if (IsInCloseList(i, j) || (i == _point.x && j == _point.y))
                    continue;

                //剩下的就是没有判断过的点了
                if (IsInOpenList(i, j))
                {
                    //如果该点在开启列表中
                    //找到该点
                    Point point = FindInOpenList(i, j);

                    int G = 0;
                    //计算出该点新的移动代价
                    if (point.x == _point.x || point.y == _point.y)
                        G = point.G + 10;
                    else
                        G = point.G + 14;

                    //如果该点的新G值比前一次小
                    if (G < point.G)
                    {
                        //更新新的G点
                        point.G = G;
                        point.fatherPoint = _point;

                    }
                }
                else
                {
                    //如果该点不在开启列表内
                    //初始化该点,并将该点添加到开启列表中
                    Point newPoint = new Point();
                    newPoint.x = i;
                    newPoint.y = j;
                    newPoint.fatherPoint = _point;

                    //计算该点的G值和H值并赋值
                    newPoint.G = GetG(newPoint);
                    newPoint.H = GetH(newPoint, targetPoint);

                    //将初始化完毕的格子添加到开启列表中
                    list_open.Add(newPoint);

                }

            }
        }
    }

    //检查某点周边的格子 上下左右4个
    private void CheckPerPointWithMapFour(Point _point, Point targetPoint)
    {
        for (int i = _point.x - 1; i <= _point.x + 1; ++i)
        {
            for (int j = _point.y - 1; j <= _point.y + 1; ++j)
            {
                //剔除超过地图的点
                if (i < startX || i > endX || j < startY || j > endY)
                    continue;

                //去除斜线方向上的点 
                if (Mathf.Abs(i - _point.x) + Mathf.Abs(j - _point.y) != 1)
                    continue;

                //去除该点是障碍点:即周围有墙的点
                if (IsBar(i, j))
                    continue;

                //去除已经存在关闭列表或者本身点
                if (IsInCloseList(i, j) || (i == _point.x && j == _point.y))
                    continue;

                //剩下的就是没有判断过的点了
                if (IsInOpenList(i, j))
                {
                    //如果该点在开启列表中
                    //找到该点
                    Point point = FindInOpenList(i, j);

                    int G = 0;
                    //计算出该点新的移动代价
                    if (point.x == _point.x || point.y == _point.y)
                        G = point.G + 10;
                    //else
                    //    G = point.G + 14;

                    //如果该点的新G值比前一次小
                    if (G < point.G)
                    {
                        //更新新的G点
                        point.G = G;
                        point.fatherPoint = _point;

                    }
                }
                else
                {
                    //如果该点不在开启列表内
                    //初始化该点,并将该点添加到开启列表中
                    Point newPoint = new Point();
                    newPoint.x = i;
                    newPoint.y = j;
                    newPoint.fatherPoint = _point;

                    //计算该点的G值和H值并赋值
                    newPoint.G = GetG(newPoint);
                    newPoint.H = GetH(newPoint, targetPoint);

                    //将初始化完毕的格子添加到开启列表中
                    list_open.Add(newPoint);

                }
            }
        }
    }
}

public class Point
{
    //F = G + H
    //G        从起点A移动到指定方格的移动代价,父格子到本格子代价:直线为10,斜线为14
    //H        使用 Manhattan 计算方法,    计算(当前方格到目标方格的横线上+竖线上所经过的方格数)* 10

    public int x;//格子的x坐标
    public int y;//格子的y坐标

    public int G;//G : 从开始到当前位置
    public int H;//H : 从当前位置到目标

    public int GetF
    {
        get
        {
            return G + H;
        }
    }

    public Point fatherPoint;//父格子

    public Point() { }

    public Point(int _x, int _y)
    {
        x = _x;
        y = _y;
    }

    public Point(int _x, int _y, int _G, int _H, Point _fatherPoint)
    {
        this.x = _x;
        this.y = _y;
        this.G = _G;
        this.H = _H;
        this.fatherPoint = _fatherPoint;
    }
}

3.人物控制脚本

 

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

/// <summary>
/// 移动
/// </summary>
public class Mover : MonoBehaviour
{
    private List<PathPoint> movePath;
    private int moveIndex;
    private Vector3 targetPos;
    private bool isMove = false;
    private Table target;
    private System.Action moveEnd;
    public System.Action<bool> moveAnim;
    private RectTransform rect;
    private Canvas canvas;
    public float speed = 200;
    public bool isOut = false;

    private void Awake()
    {
        rect = GetComponent<RectTransform>();
        canvas = GetComponent<Canvas>();
    }

    public bool IsMove
    {
        get => isMove; set
        {
            isMove = value;
            moveAnim?.Invoke(isMove);
        }
    }

    /// <summary>
    /// 移动到某一个桌子
    /// </summary>
    /// <param name="point"></param>
    public void MoveToServicePoint(Table table, System.Action action)
    {
        MoveToPoint(table.clothPathPoint, action);
        target = table;
    }

    //移动到某一路径点
    public void MoveToPoint(PathPoint point, System.Action action)
    {
        PathPoint cur = null;
        if (isOut)
        {
            cur = PathOutMgr.Inst.GetClosestPoint(transform.position);
            movePath = PathOutMgr.Inst.GetPath(cur.point, point.point);
        }
        else
        {
            try
            {
                cur = PathHouseMgr.Inst.GetClosestPoint(transform.position);
                movePath = PathHouseMgr.Inst.GetPath(cur.point, point.point);
            }
            catch (Exception e)
            {
                Debug.LogError("出错路径:" + cur.point.ToString() + "..." + point.point.ToString());
            }
        }
        //PathPoint cur = isOut ? PathOutMgr.Inst.GetClosestPoint(transform.position) : PathHouseMgr.Inst.GetClosestPoint(transform.position);
        //movePath = isOut ? PathOutMgr.Inst.GetPath(cur.point, point.point) : PathHouseMgr.Inst.GetPath(cur.point, point.point);
        if (movePath.Count > 1)
        {
            float angle = Vector2.Angle(movePath[0].rect.anchoredPosition - rect.anchoredPosition,
                movePath[0].rect.anchoredPosition - movePath[1].rect.anchoredPosition);
            if (angle < 90) movePath.RemoveAt(0);
            //Debug.Log(angle);
        }
        moveEnd = action;
        target = null;

        IsMove = true;
        MoveTo(0);
    }

    private void MoveTo(int index)
    {
        targetPos = index < movePath.Count ? movePath[index].rect.anchoredPosition : target.serviceTra.anchoredPosition;
        SetFace(targetPos.x <= rect.anchoredPosition.x);
        moveIndex = index;
        if (targetPos.x >= rect.anchoredPosition.x)
        {
            if (moveIndex - 1 >= 0)
                canvas.sortingOrder = movePath[moveIndex - 1].sort;
        }
        else
        {
            if (moveIndex < movePath.Count)
                canvas.sortingOrder = movePath[moveIndex].sort;
        }
    }

    private void FixedUpdate()
    {
        if (!IsMove) return;
        rect.anchoredPosition = Vector2.MoveTowards(rect.anchoredPosition, targetPos, speed * Time.fixedDeltaTime);
        if (Vector3.Distance(rect.anchoredPosition, targetPos) <= 1)
        {
            if (moveIndex + 1 <= (target != null ? movePath.Count : movePath.Count - 1))
            {

                MoveTo(moveIndex + 1);
            }
            else
            {
                MoveEnd();
            }
        }
    }

    //移动结束
    private void MoveEnd()
    {
        IsMove = false;
        //SetFace(target.FaceLeft);
        moveEnd?.Invoke();
    }

    //设置朝向
    public void SetFace(bool isLeft)
    {
        transform.localScale = new Vector3(isLeft ? 1 : -1, 1, 1);
    }
}

4.管理脚本

using System.Collections.Generic;
using UnityEngine;

public class PathHouseMgr : MonoBehaviour
{
    public static PathHouseMgr Inst { get; private set; }

    public Vector2Int max;
    public Vector2Int min = new Vector2Int(-1, 0);
    public PathPoint[] pathPoint;
    private Dictionary<Vector2Int, PathPoint> points;
    public PathPoint goOutPoint;//离开点
    public PathPoint takePoint;//取餐点
    private AStar aStar;

    private void Awake()
    {
        Inst = this;
    }

    private void Start()
    {
        points = new Dictionary<Vector2Int, PathPoint>();
        foreach (var v in pathPoint) points.Add(v.point, v);

        aStar = new AStar();
        aStar.Init(min.x, min.y, max.x, max.y);
        aStar.IsBarAction += IsNotMove;
    }

    public List<PathPoint> GetPath(Vector2Int cur, Vector2Int target)
    {
        List<PathPoint> path = new List<PathPoint>();
        var aStar = this.aStar.AStarFindWay(cur, target);
        foreach (var v in aStar)
        {
            path.Add(points[v]);
        }
        return path;
    }

    public PathPoint GetClosestPoint(Vector3 pos)
    {
        float min = float.MaxValue;
        float dis = 0;
        PathPoint p = null;
        foreach (var v in pathPoint)
        {
            dis = Vector3.Distance(pos, v.transform.position);
            if (dis <= min)
            {
                min = dis;
                p = v;
            }
        }
        return p;
    }

    //是否是不能移动的点
    public bool IsNotMove(int x, int y)
    {
        return !points.ContainsKey(new Vector2Int(x, y));
    }
}

5.移动目标脚本

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

public class Table : MonoBehaviour
{
    public RectTransform serviceTra;    //服务点
    public PathPoint clothPathPoint;//距离最近的移动点
    public string food = "can1";
    [SerializeField] private GameObject[] stateObjs;

    public State state = State.Empty;   //当前桌子状态
    private Ornament ornament;      //装饰物
    [HideInInspector] public BaseTable table;
    [SerializeField] private Image foodIcon;
    [SerializeField] private GameObject eatObj;
    private GuestGroup guest;
    private float timer;
    [HideInInspector] public GuestOrder order;

    private float eatBaseTime = 5;

    public bool FaceLeft { get => serviceTra.position.x > transform.position.x; }

    private void Awake()
    {
        ornament = GetComponent<Ornament>();
        table = GetComponent<BaseTable>();
        serviceTra.SetParent(transform.parent);
    }

    /// <summary>
    /// empty空桌、waitGuest等待客人、order等待点餐、cooking正在烹饪、
    /// MealFodd送餐、Eating正在用餐、Accoint等待结账、Clean等待清扫、Waiter服务员正在服务中
    /// </summary>
    public enum State
    {
        Empty = 0,      //空桌
        WaitGuest,  //等待客人
        Order,      //等待点餐
        Cooking,    //正在烹饪
        MealFood,   //送餐
        Eating,     //正在吃饭
        Account,    //等待结账
        Clean,      //等待清扫
        Waiter,     //服务员正在服务中
    }

    public bool IsUnlock { get => ornament.partData.IsUnlock; }

    public string TableName { get => ornament.partData.data.part; }

    public int PeopleNum { get => guest.guests.Count; }

    public float EatRate
    {
        get
        {
            return DataManager.GetModle<Decoration>().GetDecoration(ornament.partData.Decoration).data.funcValue;
        }
    }

    public void GuestSit(GuestGroup guest, Guest guest1)
    {
        this.guest = guest;
        table.Sit(guest1, guest1.index);
        //SetState(State.Order);
    }

    //设置当前状态
    public void SetState(State state)
    {
        this.state = state;
        int s = -1;

        switch (state)
        {
            case State.Order:
                s = 0;
                break;
            case State.MealFood:
                s = 1;
                break;
            case State.Account:
                s = 2;
                break;
            case State.Clean:
                s = 3;
                break;
        }

        for (int i = 0; i < stateObjs.Length; i++)
        {
            stateObjs[i].SetActive(i == s);
        }
    }

    private void Update()
    {
        if (state == State.Cooking)
        {
            timer -= Time.deltaTime;
            if (timer <= 0)
            {
                //等待送餐
                SetState(State.MealFood);
            }
        }
        else if (state == State.Eating)
        {
            timer -= Time.deltaTime;
            if (timer <= 0)
            {
                //结账
                foodIcon.gameObject.SetActive(false);
                eatObj.SetActive(true);
                guest.guests.ForEach((s) => s.SetState(Guest.State.Sit));
                SetState(State.Account);

                if (!DataManager.GetModle<Guide>().IsPass("Level") && GuideMgr.CurIndex == 16)
                {
                    GuideMgr.OnGuide("Level", 17);
                }

                if (DataManager.GetModle<Guide>().IsPass("Rubbish") && Random.value <= DataManager.GetModle<Restaurant>().curLevel.rubishRate)
                {
                    RubbishMgr.Inst.SpawnRubbish();
                }
            }
        }
    }

    //点餐
    public void Order()
    {
        order = new GuestOrder(guest.GetDishNum());

        //烹饪时间
        timer = order.CookTime * (1 - OrderMgr.Inst.GetFuncData(DecorationFunc.DownCookTime));
        SetState(State.Cooking);
    }

    //送餐
    public void MealFood()
    {
        foodIcon.sprite = GUtil.GetSprite($"{food}_{Random.Range(1, 5)}");
        foodIcon.gameObject.SetActive(true);
        guest.guests.ForEach((s) => s.SetState(Guest.State.Eating));
        timer = eatBaseTime * (1 - EatRate);
        SetState(State.Eating);
    }

    //结账
    public void Btn_Account()
    {
        Account(true);
        UIManager.OpenUIWindow<PanelBill>().ShowBill(this, order);
    }

    public void Account(bool isClick = false)
    {
        //客人离场
        SetState(State.Clean);
        guest.GoOut();

        var bill = order.Account();
        float rate = DataManager.GetModle<Restaurant>().curLevel.account - RubbishMgr.Inst.RubbishCount() * 0.05f;
        float earn = (bill[0] - bill[1]) * (1 + rate);
        PlayerInfo.Inst.CoinDeal((int)earn, Currency.Coin);
        DataManager.GetModle<D_Task>().CompleteTask(D_Task.TaskType.Service);

        FlurryScript.Instance.SendEvent(isClick ? Custom_Event.Table_Acount_Click.ToString() : Custom_Event.Table_Acount.ToString(),
            new Dictionary<string, string>()
            {
                {"收益",  ((int)((bill[0] - bill[1])  / (float)bill[1] * 100f)).ToString("d2")}
            });
    }

    public void Btn_Clean()
    {
        SetState(State.Empty);
        OrderMgr.Inst.OnEmpty();
        eatObj.SetActive(false);
        StaffMgr.Inst.OnWash();
    }
}

猜你喜欢

转载自blog.csdn.net/lalate/article/details/131835260
今日推荐