简易A*自动寻路算法

using System.Collections.Generic;
using UnityEngine;
using Game.Map;

public class PathNode
{
    public Vector3 position;
    public MapNode mapNode;
    public int distance;
    public byte state;
    public PathNode progenitor;
    public PathNode rearguard;
    public List<PathNode> children;

    public PathNode(Vector3 position, MapNode mapNode)
    {
        this.position = position;
        this.mapNode = mapNode;
        children = new List<PathNode>();
    }

}
public class PathNodeManager {


    private static PathNodeManager _instance;
    public static PathNodeManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new PathNodeManager();
            }
            return _instance;
        }
    }

    private Dictionary<Vector3, PathNode> m_PathDic;

    private PathNodeManager()
    {
        m_PathDic = new Dictionary<Vector3, PathNode>();
    }

    public PathNode InstancePathNode(Vector3 pos, MapNode mapNode)
    {
        PathNode node = new PathNode(pos, mapNode);
        if (m_PathDic.ContainsKey(pos))
        {
            if (mapNode != null && m_PathDic[pos].mapNode != null)
            {
                m_PathDic[pos].mapNode = mapNode;
            }
        }
        else
        {
            m_PathDic.Add(pos, node);
        }
        return m_PathDic[pos];
    }

    public void InitPathNode()
    {
        List<MapNode> tempList = new List<MapNode>(MazeManager.Instance.MapNodeDic.Values);
        for (int i = 0; i < tempList.Count; i++)
        {

            Vector2 index = tempList[i].index;
            Vector3 p0 = (new Vector3(index.x, 0, index.y)) * MazeManager.unitSize;
            MapNode mapNode = tempList[i];

            if (tempList[i].roadType == RoadType.Room || tempList[i].roadType == RoadType.Hall)
            {
                PathNode node1 = InstancePathNode(p0 + new Vector3(-2, 0, -2), mapNode);
                PathNode node2 = InstancePathNode(p0 + new Vector3(-2, 0, -1), mapNode);
                PathNode node3 = InstancePathNode(p0 + new Vector3(-2, 0, 0), mapNode);
                PathNode node4 = InstancePathNode(p0 + new Vector3(-2, 0, 1), mapNode);
                PathNode node5 = InstancePathNode(p0 + new Vector3(-2, 0, 2), mapNode);
                PathNode node6 = InstancePathNode(p0 + new Vector3(-1, 0, -2), mapNode);
                PathNode node7 = InstancePathNode(p0 + new Vector3(-1, 0, -1), mapNode);
                PathNode node8 = InstancePathNode(p0 + new Vector3(-1, 0, 0), mapNode);
                PathNode node9 = InstancePathNode(p0 + new Vector3(-1, 0, 1), mapNode);
                PathNode node10 = InstancePathNode(p0 + new Vector3(-1, 0, 2), mapNode);
                PathNode node11 = InstancePathNode(p0 + new Vector3(0, 0, -2), mapNode);
                PathNode node12 = InstancePathNode(p0 + new Vector3(0, 0, -1), mapNode);
                PathNode node13 = InstancePathNode(p0, mapNode);
                PathNode node14 = InstancePathNode(p0 + new Vector3(0, 0, 1), mapNode);
                PathNode node15 = InstancePathNode(p0 + new Vector3(0, 0, 2), mapNode);
                PathNode node16 = InstancePathNode(p0 + new Vector3(1, 0, -2), mapNode);
                PathNode node17 = InstancePathNode(p0 + new Vector3(1, 0, -1), mapNode);
                PathNode node18 = InstancePathNode(p0 + new Vector3(1, 0, 0), mapNode);
                PathNode node19 = InstancePathNode(p0 + new Vector3(1, 0, 1), mapNode);
                PathNode node20 = InstancePathNode(p0 + new Vector3(1, 0, 2), mapNode);
                PathNode node21 = InstancePathNode(p0 + new Vector3(2, 0, -2), mapNode);
                PathNode node22 = InstancePathNode(p0 + new Vector3(2, 0, -1), mapNode);
                PathNode node23 = InstancePathNode(p0 + new Vector3(2, 0, 0), mapNode);
                PathNode node24 = InstancePathNode(p0 + new Vector3(2, 0, 1), mapNode);
                PathNode node25 = InstancePathNode(p0 + new Vector3(2, 0, 2), mapNode);
                node1.children.Add(node2); node1.children.Add(node6);
                node2.children.Add(node1); node2.children.Add(node3); node2.children.Add(node7);
                node3.children.Add(node2); node3.children.Add(node4); node3.children.Add(node8);
                node4.children.Add(node3); node4.children.Add(node5); node4.children.Add(node9);
                node5.children.Add(node4); node5.children.Add(node10);
                node6.children.Add(node1); node6.children.Add(node7); node6.children.Add(node11);
                node7.children.Add(node2); node7.children.Add(node6); node7.children.Add(node8); node7.children.Add(node12);
                node8.children.Add(node3); node8.children.Add(node7); node8.children.Add(node9); node8.children.Add(node13);
                node9.children.Add(node4); node9.children.Add(node8); node9.children.Add(node10); node9.children.Add(node14);
                node10.children.Add(node5); node10.children.Add(node9); node10.children.Add(node15);
                node11.children.Add(node6); node11.children.Add(node12); node11.children.Add(node16);
                node12.children.Add(node7); node12.children.Add(node11); node12.children.Add(node13); node12.children.Add(node17);
                node13.children.Add(node8); node13.children.Add(node12); node13.children.Add(node14); node13.children.Add(node18);
                node14.children.Add(node9); node14.children.Add(node13); node14.children.Add(node15); node14.children.Add(node19);
                node15.children.Add(node10); node15.children.Add(node14); node15.children.Add(node20);
                node16.children.Add(node11); node16.children.Add(node17); node16.children.Add(node21);
                node17.children.Add(node12); node17.children.Add(node16); node17.children.Add(node18); node17.children.Add(node22);
                node18.children.Add(node13); node18.children.Add(node17); node18.children.Add(node19); node18.children.Add(node23);
                node19.children.Add(node14); node19.children.Add(node18); node19.children.Add(node20); node19.children.Add(node24);
                node20.children.Add(node15); node20.children.Add(node19); node20.children.Add(node25);
                node21.children.Add(node16); node21.children.Add(node22);
                node22.children.Add(node17); node22.children.Add(node21); node22.children.Add(node23);
                node23.children.Add(node18); node23.children.Add(node22); node23.children.Add(node24);
                node24.children.Add(node19); node24.children.Add(node23); node24.children.Add(node25);
                node25.children.Add(node20); node25.children.Add(node24);

                if ((tempList[i].doors & 1) == 1 && tempList[i].place != 4)
                {
                    node23.children.Add(InstancePathNode(p0 + new Vector3(3, 0, 0), null));
                }
                if ((tempList[i].doors & 2) == 2 && tempList[i].place != 3)
                {
                    node3.children.Add(InstancePathNode(p0 + new Vector3(-3, 0, 0),null));
                }
                if ((tempList[i].doors & 4) == 4 && tempList[i].place != 2)
                {
                    node11.children.Add(InstancePathNode(p0 + new Vector3(0, 0, -3),null));
                }
                if ((tempList[i].doors & 8) == 8 && tempList[i].place != 1)
                {
                    node15.children.Add(InstancePathNode(p0 + new Vector3(0, 0, 3),null));
                }

            }
            else if (tempList[i].roadType == RoadType.Way)
            {
                PathNode node = InstancePathNode(p0, mapNode);
                if ((tempList[i].doors & 1) == 1)
                {
                    PathNode node1 = InstancePathNode(p0 + new Vector3(1, 0, 0), mapNode);
                    PathNode node2 = InstancePathNode(p0 + new Vector3(2, 0, 0), mapNode);
                    PathNode node3 = InstancePathNode(p0 + new Vector3(3, 0, 0),null);
                    node.children.Add(node1);
                    node1.children.Add(node); node1.children.Add(node2);
                    node2.children.Add(node1); node2.children.Add(node3);
                }
                if ((tempList[i].doors & 2) == 2)
                {
                    PathNode node1 = InstancePathNode(p0 + new Vector3(-1, 0, 0), mapNode);
                    PathNode node2 = InstancePathNode(p0 + new Vector3(-2, 0, 0), mapNode);
                    PathNode node3 = InstancePathNode(p0 + new Vector3(-3, 0, 0),null);
                    node.children.Add(node1);
                    node1.children.Add(node); node1.children.Add(node2);
                    node2.children.Add(node1); node2.children.Add(node3);
                }
                if ((tempList[i].doors & 4) == 4)
                {
                    PathNode node1 = InstancePathNode(p0 + new Vector3(0, 0, -1), mapNode);
                    PathNode node2 = InstancePathNode(p0 + new Vector3(0, 0, -2), mapNode);
                    PathNode node3 = InstancePathNode(p0 + new Vector3(0, 0, -3),null);
                    node.children.Add(node1);
                    node1.children.Add(node); node1.children.Add(node2);
                    node2.children.Add(node1); node2.children.Add(node3);
                }
                if ((tempList[i].doors & 8) == 8)
                {
                    PathNode node1 = InstancePathNode(p0 + new Vector3(0, 0, 1), mapNode);
                    PathNode node2 = InstancePathNode(p0 + new Vector3(0, 0, 2), mapNode);
                    PathNode node3 = InstancePathNode(p0 + new Vector3(0, 0, 3),null);
                    node.children.Add(node1);
                    node1.children.Add(node); node1.children.Add(node2);
                    node2.children.Add(node1); node2.children.Add(node3);
                }
            }
            else if (tempList[i].roadType == RoadType.Hall)
            {
                

            }
        }
    }

    public void SetPathNode(Vector3 pos)
    {
        if (m_PathDic.ContainsKey(pos))
        {
            m_PathDic.Remove(pos);
        }
        else
        {
            Debug.Log("!!!!!!!!!!!!!!!!!!!!不在路径节点字典里" + pos);
        }

        List<PathNode> temp = new List<PathNode>(m_PathDic.Values);
        for (int i = 0; i < temp.Count; i++)
        {
            for (int j = 0; j < temp[i].children.Count; j++)
            {
                if (temp[i].children[j].position == pos)
                {
                    temp[i].children.RemoveAt(j);
                }
            }
        }
    }

    public Vector3 GetPosInteger(Vector3 pos)
    {
        return new Vector3(Mathf.RoundToInt(pos.x), 0, Mathf.RoundToInt(pos.z));
    }

    public Stack<Vector3> GetShortestPath(Vector3 origin,Vector3 destination)
    {

        List<PathNode> PathNodeList = new List<PathNode>(m_PathDic.Values);
        Stack<Vector3> tempStack = new Stack<Vector3>();
        Queue<PathNode> tempQueue = new Queue<PathNode>();
        PathNode node = null;

        for (int i = 0; i < PathNodeList.Count; i++)
        {
            PathNodeList[i].distance = int.MaxValue;
            PathNodeList[i].state = 0;
            PathNodeList[i].progenitor = null;
            PathNodeList[i].rearguard = null;
        }

        PathNode startNode = null;
        if (m_PathDic.ContainsKey(origin))
        {
            startNode = m_PathDic[origin];
        }
        else
        {
            Debug.Log("!!!!!!!!!!!!!!!!!!!!!!不在PathNode字典" + origin);
        }
        
        startNode.distance = 0;
        startNode.state = 0;
        startNode.progenitor = null;
        startNode.rearguard = null;
        tempQueue.Enqueue(startNode);

        while (tempQueue.Count > 0 && node == null)
        {
            PathNode tempNode = tempQueue.Dequeue();
            foreach (PathNode item in tempNode.children)
            {
                if (item.state == 0)
                {
                    item.state = 1;
                    if (MazeManager.Instance.OccupyPosDic.ContainsValue(new Vector2(item.position.x,item.position.z))
                        && !VectorTool.ApproximatelyXZ(item.position, PlayerController.Instance.TargetPos, 0.1f))
                        continue;
                    item.distance = tempNode.distance + 1;
                    item.progenitor = tempNode;
                    if (VectorTool.ApproximatelyXZ(item.position, GetPosInteger(destination), 0.1f))
                    {
                        node = item;
                        break;
                    }
                    tempQueue.Enqueue(item);
                }
            }
            tempNode.state = 2;
        }

        while (node != null && node.progenitor != null)
        {
            tempStack.Push(node.position);
            node = node.progenitor;
        }

        return tempStack;
    }

    public List<Vector3> GetRoomPathNode(MapNode node)
    {
        List<PathNode> PathNodeList = new List<PathNode>(m_PathDic.Values);
        List<Vector2> OccupyPosList = new List<Vector2>(MazeManager.Instance.OccupyPosDic.Values);
        List<Vector3> CurrentPosList = new List<Vector3>();
        for (int i = 0; i < PathNodeList.Count; i++)
        {
            if (PathNodeList[i].mapNode == node)
            {
                CurrentPosList.Add(PathNodeList[i].position);
            }
        }

        return CurrentPosList;
    }

}

 

 

********************************

 

using System.Collections.Generic;
using UnityEngine;

namespace Game.Map
{
    public enum NodeType
    {
        Error,
        Empty,
        Boss,
        Path
    }

    public enum RoadType
    {
        Error = 0,
        
        /// <summary>
        /// 走廊
        /// </summary>
        Way = 65,
        /// <summary>
        /// 普通房间
        /// </summary>
        Room = 66,
        /// <summary>
        /// 大厅
        /// </summary>
        Hall = 67,
        /// <summary>
        /// Boss房
        /// </summary>
        Boss = 68,
    }

    public enum RoomType
    {
        Error,

        /// <summary>
        /// 被锁的房间
        /// </summary>
        Locked,
        /// <summary>
        /// 机关房
        /// </summary>
        OrganRoom,
        /// <summary>
        /// 宝藏
        /// </summary>
        TreasureRoom,
        /// <summary>
        /// 有一个宝箱的房间
        /// </summary>
        TreasureBox,
        /// <summary>
        /// 矿石房
        /// </summary>
        OreHeapRoom,
        /// <summary>
        /// 草药房
        /// </summary>
        HerbRoom,
    }


    /// <summary>
    /// 地图上的每个节点
    /// </summary>
    public class MapNode : MonoBehaviour
    {

        public string IconName;
        
        public Vector2 index;

        public Vector2 position;

        public GameObject build;

        /// <summary>
        /// 道路类型
        /// A:走廊,B:房间,C:大厅,D:Boss房
        /// </summary>
        public RoadType roadType;

        /// <summary>
        /// 房间类型,roadType必定为‘B’
        /// A:被锁,B:机关房,C:宝藏房,D,宝箱房
        /// </summary>
        public RoomType roomType;

        /// <summary>
        /// 正确的机关的下标
        /// 0,左上,顺时针旋转
        /// </summary>
        public int keyOrganIndex;

        public OrganBehaviour[] Organs;

        public MapNode parent;

        public List<MapNode> children;

        public int distance;

        public int doors;

        public byte place;
       
        public NodeType nodeType;

        /// <summary>
        /// 门
        /// </summary>
        public int[] doorsData;

        /// <summary>
        /// 带锁的门
        /// </summary>
        public GameObject[] lockDoors;

        /// <summary>
        /// 房间里的物品
        /// </summary>
        public List<TreasureBox> Goods; 

        /// <summary>
        /// 采集点
        /// </summary>
        public CollectionBehaviour[] Collection;

        /// <summary>
        /// 房间里的怪物
        /// </summary>
        public List<MonsterController> monsters;

        /// <summary>
        /// 地图房间
        /// </summary>
        public int MapRoom;
        public List<int> MapIcon;
        public List<int> MapMonster;

        /// <summary>
        /// 地图房间
        /// </summary>
        public int MiniMapRoom;
        public List<int> MiniMapIcon;
        public List<int> MiniMapMonster;

        private Vector3 m_startPos;

        public Vector3 StartPos { get { return m_startPos; } }

        public void Init(Vector2 pos)
        {
            this.index = pos;
            parent = null;
            roomType = 0;
            //children = new List<MapNode>();
            distance = 0;
            place = 0;
            this.nodeType = NodeType.Empty;
            doors = 0;
            doorsData = new int[4];
            lockDoors = new GameObject[4];
            Goods = new List<TreasureBox>();

            MapRoom = -1;
            MapIcon = new List<int>();
            MapMonster = new List<int>();

            MiniMapRoom = -1; 
            MiniMapIcon = new List<int>();
            MiniMapMonster = new List<int>();
        }

        private void Start()
        {
            m_startPos = transform.position;
            index = MazeManager.Instance.GetPosAsKey(transform.position);
            MazeManager.Instance.AddMapNode(this);
            MiniMap.Instance.NewCreateMiniMap(this);
            HideOnFar();
            //gameObject.SetActive(false);
        }

        private void SetRoadType()
        {
            if (name.Contains("A"))
            {
                roadType = RoadType.Way;
            }
            else if (name.Contains("B"))
            {
                roadType = RoadType.Room;
            }
            else if (name.Contains("C"))
            {
                roadType = RoadType.Hall;
            }
            else
            {
                roadType = RoadType.Boss;
            }
        }

        private void HideMonsters()
        {
            if (monsters == null) return;

            for (int i = 0; i < monsters.Count; i++)
            {
                monsters[i].gameObject.SetActive(false);
            }
        }

        private void MonstersActive()
        {
            if (monsters == null) return;

            for (int i = 0; i < monsters.Count; i++)
            {
                monsters[i].gameObject.SetActive(true);
                monsters[i].Init(true);
                MonsterManager.Instance.AddMonster(monsters[i]);
            }
        }

        /// <summary>
        /// 废弃代码
        /// </summary>
        private void TreasureBoxsActive()
        {
            if (Goods == null) return;

            for (int i = 0; i < Goods.Count; i++)
            {
                TreasureBox box = Goods[i];
                box.gameObject.SetActive(true);
                //box.Init(box.transform.position,transform.localEulerAngles,BoxType.Close);
                MiniMap.Instance.CreateBoxIcon(this, gameObject);
            }
        }

        public void Refresh()
        {
            SetRoadType();
            CreateWallPoster();
            CreateDoorframeOfRoom();
        }

        public void CreateWallPoster()
        {
            Transform room = transform;
            if (Random.Range(0, 10) < 3 ||
                roadType == RoadType.Way ||
                roadType == RoadType.Boss)
                return;

            int length = roadType == RoadType.Boss ?
                Random.Range(3, 10) : Random.Range(1, 3);

            for (int i = 0; i < length; i++)
            {
                string posterName = "LevelArt/" + MazeManager.SceneType + "/WallPoster" +
                    (Random.Range(0, 2) == 1 ? "" : "2");
                GameObject prefab = ResourcesManager.Instance.LoadResource(posterName) as GameObject;
                GameObject poster = Instantiate(prefab);
                poster.transform.SetParent(room);
                poster.transform.localPosition = Vector3.zero;

                int temp = Random.Range(0, 4);
                int dir = 1 << temp;

                switch (roadType)
                {
                    case RoadType.Way:
                        //node.PastePosterOnTheWay(poster.transform, dir);
                        break;
                    case RoadType.Room:
                        PastePosterOnTheRoom(poster.transform, dir);
                        break;
                    case RoadType.Hall:
                        PastePosterOnTheRoom(poster.transform, dir);
                        break;
                    default:
                        break;
                }
            }
        }

        private const float posterPos = 2.495f;

        /// <summary>
        /// 在房间内贴广告
        /// </summary>
        /// <param name="node"></param>
        /// <param name="poster"></param>
        /// <param name="dir"></param>
        public void PastePosterOnTheRoom(Transform poster, int dir)
        {
            float temp = 0;
            if ((doors & dir) == dir)//this wall has a door
            {
                if (roadType == RoadType.Hall && place == dir)
                {
                    temp = Random.Range(0, 2) == 1 ? 2 : -2;
                }
                else
                {
                    temp = Random.Range(0, 2) == 1 ? Random.Range(-2f, -1f) : Random.Range(1f, 2f);
                }
            }
            else
            {
                temp = Random.Range(-2, 2);
            }

            switch (dir)
            {
                case 1:
                    poster.localPosition = new Vector3(posterPos, 0, temp);
                    poster.localEulerAngles = new Vector3(0, 270, 0);
                    break;
                case 2:
                    poster.localPosition = new Vector3(-posterPos, 0, temp);
                    poster.localEulerAngles = new Vector3(0, 90, 0);
                    break;
                case 4:
                    poster.localPosition = new Vector3(temp, 0, -posterPos);
                    poster.localEulerAngles = Vector3.zero;
                    break;
                case 8:
                    poster.localPosition = new Vector3(temp, 0, posterPos);
                    poster.localEulerAngles = new Vector3(0, 180, 0);
                    break;
                default:
                    Debug.LogError("dir Error:" + dir);
                    break;
            }
        }



        /// <summary>
        /// 创建门框
        /// </summary>
        public void CreateDoorframeOfRoom()
        {
            Transform room = transform;

            /*
             * 只有走廊没有门框
             * 房间与房间相连时,父节点生成门框
            */
            if (roadType != RoadType.Way)
            {
                Vector3 pos;
                int angle;

                int actor = roadType == RoadType.Boss ? 3 : 1;

                if ((doors & 1) == 1 &&
                    (parent == null || parent.roadType == RoadType.Way ||
                        parent.index.x <= index.x))//right
                {
                    angle = 180;
                    pos = new Vector3(2.5f * actor, 0, 0);
                    CreateOneDoorframe(room, pos, angle, actor);
                }
                if ((doors & 2) == 2 &&
                    (parent == null || parent.roadType == RoadType.Way ||
                        parent.index.x >= index.x))//left
                {
                    angle = 0;
                    pos = new Vector3(-2.5f * actor, 0, 0);
                    CreateOneDoorframe(room, pos, angle, actor);
                }
                if ((doors & 4) == 4 &&
                    (parent == null || parent.roadType == RoadType.Way ||
                        parent.index.y >= index.y))//down
                {
                    angle = -90;
                    pos = new Vector3(0, 0, -2.5f * actor);
                    CreateOneDoorframe(room, pos, angle, actor);
                }
                if ((doors & 8) == 8 &&
                    (parent == null || parent.roadType == RoadType.Way ||
                        parent.index.y <= index.y))//up
                {
                    angle = 90;
                    pos = new Vector3(0, 0, 2.5f * actor);
                    CreateOneDoorframe(room, pos, angle, actor);
                }
            }
        }

        private void CreateOneDoorframe(Transform room, Vector3 pos, int angle, int actor)
        {
            GameObject prefab = ResourcesManager.Instance.
                LoadResource("LevelArt/" + MazeManager.SceneType + "/" + "Doorframe" + (actor == 3 ? "2" : "")) as GameObject;
            GameObject doorframe = Instantiate(prefab);
            doorframe.transform.SetParent(room);
            doorframe.transform.localPosition = pos;
            doorframe.transform.localEulerAngles = new Vector3(0, angle, 0);
        }

        public void SetStart(MapNode node)
        {

            List<MapNode> mapNodes = new List<MapNode>();

            for (int i = 0; i < children.Count; i++)
            {

                if (children[i] != null)
                {
                    mapNodes.Add(children[i]);
                }

                children[i] = null;
            }

            if (parent != null && parent != node) mapNodes.Add(parent);

            parent = node;

            if (node != null)
            {
                for (int i = 0; i < mapNodes.Count; i++)
                {
                    if (mapNodes[i] == node)
                    {
                        mapNodes.RemoveAt(i);
                    }
                }
            }

            for (int i = 0; i < mapNodes.Count; i++)
            {
                children[i] = mapNodes[i];
            }






            //for (int i = 0; i < children.Length; i++)
            //{

            //    MapNode mapNode = children[i];

            //    if (node == null && mapNode == null)
            //    {
            //        children[i] = parent;
            //        parent = null;
            //    }

            //    if (mapNode == null) continue;

            //    if (mapNode == node)
            //    {
            //        children[i] = parent;
            //        parent = node;
            //    }
            //}

            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    children[i].SetStart(this);
                }
            }
        }


        public void ShowOnStartPos()
        {
            transform.position = m_startPos;
        }

        public void HideOnFar()
        {
            transform.position = new Vector3(transform.position.x, transform.position.y + 1000, transform.position.z);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值