Unity導(dǎo)出地形給服務(wù)器做尋路與AI實(shí)現(xiàn)

轉(zhuǎn)載請注明出處:
http://www.itdecent.cn/p/63b66c4a2cf9

說明

本文主要針對MMORPG這種、unity前端做好地形、如何給后端讀取并實(shí)現(xiàn)尋路等算法的使用。
因后端有可能采用各種語言,如C++也好、C#也好。。所以本文尋路這里、算法我直接寫在前端了,作為一個Unity導(dǎo)出工具使用。
因?yàn)橹饕壿媽懺诤蠖?,前端代碼沒有做優(yōu)化整理,只是急忙實(shí)現(xiàn)了下算法,所以會比較難看,只為說明思路用。(不過別擔(dān)心,有看到本文的放心copy+C使用即可,也歡迎留言提問)

具體思路

1目的:

image.png

2具體思路:

  1. 烘培出Navigation網(wǎng)格
  2. 讀取網(wǎng)格信息生成文件。
  3. --------傳給服務(wù)器--------
  4. 讀取文件生成地形
  5. 剔除不可行走部分。
  6. 計(jì)算網(wǎng)格間距(三角形之間)作為初步的A*尋路的G值(兩個相鄰格子移動消耗代價)使用。
  7. 尋路算法

2-1 我可以省略上面的1步驟嗎??
Yes,you can~~。If any萬 有 what 疑問, please 留言。
2-2 讀取網(wǎng)格信息生成文件
UnityEngine.AI.NavMesh.CalculateTriangulation();
這個函數(shù)會讀取地形,返回如下結(jié)構(gòu)體NavMeshTriangulation。
我們只關(guān)心結(jié)構(gòu)體中的vertices和areas變量。
vertices: 儲存了bake后的地形網(wǎng)格的所有點(diǎn)
areas: 儲存了由點(diǎn)生成三角網(wǎng)格的字典。
什么意思呢???????如下圖

image.png

這樣就清晰明了了。上圖共2個三角形,分別是ABC和ACD。
2-3--------傳給服務(wù)器--------
這個也略吧。。。就傳唄。。。Linux的話用FTP,電腦下載個FileZilla一拖。。。就到服務(wù)器了。。。(具體需要配置下)。不知道咋配置的也百度不到的。。。給我留言吧先。。。
2-4讀取文件生成地形
既然已知全地形所有三角形的點(diǎn)了,就可在字典中,如上圖三個一組讀取一次,這樣就會獲取到所有的三角形。
然后遍歷所有三角形,發(fā)現(xiàn)只要有2個點(diǎn)重合的,那么這兩個三角形就相鄰。(判斷重合最好不要用等號,最好是兩點(diǎn)間距離小于某個值。。。)
2-5剔除不可行走部分
那么畫說回來,這么多三角形,如何剔除不可行走部分呢???
image.png

image.png

如上圖,藍(lán)色劃掉的部分那個溝壑(嘿嘿嘿。。)明顯是地形之外的。那么如何去除呢???我們可以返回再看2-4讀取文件生成地形這一步,判斷三角形重合點(diǎn)。。那么問題來啦,第一個三角形和誰去重合?最起碼有個基礎(chǔ)三角形吧?。?!所以我們只需要指定一個基礎(chǔ)三角形,這個指定的三角形在你設(shè)計(jì)的可行走范圍內(nèi)隨便選一個即可,然后計(jì)算三角形重合時候會不斷的鋪開。生成的就是可行走區(qū)域。如下圖
image.png

我指定的是紅線黃線包圍的三角形。
2-6計(jì)算尋路代價
這里其實(shí)只需要計(jì)算相鄰三角形的中心距離即可。距離即為代價(除非你有分什么沙漠地形、泥巴地形之類的行走速度會受影響,需要重新定制)。
2-7尋路算法
1首先判斷角色屬于某個三角形
2判斷目標(biāo)屬于某個三角形
3根據(jù)A*計(jì)算尋路算法生成三角形上的行走路徑
4優(yōu)化行走路徑

A算法計(jì)算路徑就不再多說了,網(wǎng)上有很多講解的。這里主要講解A算法計(jì)算尋路后,路徑只是一排三角形中點(diǎn)的行進(jìn)路線,那么如何找出最優(yōu)路線呢???

image.png

首先我們想象人眼睛只要能目測到的地方(沒有被墻體阻擋視線)即可直線直接到達(dá))。
那么假設(shè)人眼能發(fā)射探照燈。第一次探照的結(jié)果如下圖:
image.png

黃色地方全都可以通過
再次探照如下圖
image.png

最后一次探照如下圖:
image.png

發(fā)現(xiàn)敵軍就在視野范圍內(nèi)?。?!在視野范圍內(nèi)說明啥??請往上翻,看到的第一個黑加粗字體。。。就是可直線直接到達(dá)的?。。?!于是??!我們直接過去?。】乘?!刀他!?。∫坏?99!??!極品屠龍,綠毒屠龍!紫毒屠龍!!哇!?。敲线_(dá)來收裝備啦?。?!就這樣。。。

那么我們一眼看不到呢???

image.png

很常見思路。。哪里擋住你視線了,走過去!!再看!!不就完了???如下圖。。。這個就是多邊形尋路。
(首先我們要明確再優(yōu)化路徑之前我們已經(jīng)找到大致的路線了如上圖黃點(diǎn))
image.png

移動到遮擋部分,重新進(jìn)行觀測即可。
所以具體思路:

  1. 從起點(diǎn)進(jìn)行觀測,每次根據(jù)A*的路徑移動一次,每次根據(jù)路徑取出“視野最小的”觀測范圍(如上圖第二次觀測)
  2. 如果觀測遇到障礙物徹底阻擋了視線,則阻擋的位置即為第一個目標(biāo)目的地,我們先走過去,然后重新進(jìn)行上一步的操作,不斷進(jìn)行觀測,知道發(fā)現(xiàn)敵人。

其他注意點(diǎn):
可能遇到如下路徑


image.png

當(dāng)剛好之后某些路徑計(jì)算的時候,遇到拐點(diǎn),并且拐點(diǎn)在下一個路徑的一條邊上。因?yàn)槲覀円暰€觀測判斷阻擋,從眼睛射出的射線是要分左右的,但是此時你站在拐點(diǎn)處,是無法區(qū)分左右的(因?yàn)楹鸵粋€點(diǎn)重合了,此時判斷射線左右需要首先找到當(dāng)前你所屬的三角形,通過三角形的中點(diǎn)計(jì)算左右。

代碼:

代碼我混合導(dǎo)出地形和尋路計(jì)算到了一起,尋路等是為了先在前端演示一下效果,然后再移動到服務(wù)器的。
懶得理解了可以直接復(fù)制
但是服務(wù)器尋路還是要參照下的。
(我的是linuxC++,因?yàn)闆]有界面不直觀,所以先在前端寫了一下大致算法,就是下面的,然后再到服務(wù)器寫)

using UnityEditor;
using System.IO;
using UnityEngine;
using System.Text;
using UnityEngine.AI;
using System.Collections.Generic;
using ServerTools;

public class ExportNavMeshPathGround
{
    private static string outFilePath = "path_ground.dat";
    private static List<Triangle> listTriangle = new List<Triangle>();
    private static int baseTag = 0;
    private static float dis = 0.05f;
    private static int startI = 0;
    private static int endI = 113;
    [MenuItem("Zhbd_Tools/Export_NavMeshData_Path_Ground")]
    static void Export_NavMeshData_Path_Ground()
    {
        StringBuilder str = new StringBuilder();
        FileStream outFile = new FileStream(Application.dataPath + "/" + outFilePath, FileMode.Create, FileAccess.ReadWrite);

        listTriangle.Clear();
        ServerPath.getInstance().listDraw.Clear();

        NavMeshTriangulation nmt = UnityEngine.AI.NavMesh.CalculateTriangulation();
        for (int i = 0; i < nmt.vertices.Length; ++i)
        {
            str.Append("x: " + nmt.vertices[i].x + ",y: " + nmt.vertices[i].y + ",z: " + nmt.vertices[i].z + "\n");
        }
        str.Append("\nindices:");
        for (int i = 0; i < nmt.indices.Length; ++i)
        {
            str.Append(nmt.indices[i] + ",");
        }
        str.Append("\nareas:");
        for (int i = 0; i < nmt.areas.Length; ++i)
        {
            str.Append(nmt.areas[i] + ",");
        }
        Debug.Log(str.ToString());
        byte[] bytes = Encoding.UTF8.GetBytes(str.ToString());
        outFile.Write(bytes, 0, bytes.Length);
        outFile.Close();
        for (int i = 0; i < nmt.indices.Length; i += 3)
        {
            Triangle t = new Triangle();
            t.A = nmt.vertices[nmt.indices[i]];
            t.B = nmt.vertices[nmt.indices[i + 1]];
            t.C = nmt.vertices[nmt.indices[i + 2]];
            listTriangle.Add(t);
        }
        ServerPath.getInstance().listDraw.Add(listTriangle[baseTag]);
        listTriangle.RemoveAt(baseTag);
        for (int i = 0; i < ServerPath.getInstance().listDraw.Count; ++i)
        {
            for (int j = 0; j < listTriangle.Count; ++j)
            {
                if ((ServerPath.getInstance().listDraw[i].A - listTriangle[j].A).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].A - listTriangle[j].B).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].A - listTriangle[j].C).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].B - listTriangle[j].A).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].B - listTriangle[j].B).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].B - listTriangle[j].C).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].C - listTriangle[j].A).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].C - listTriangle[j].B).magnitude < dis ||
                   (ServerPath.getInstance().listDraw[i].C - listTriangle[j].C).magnitude < dis)
                {
                    ServerPath.getInstance().listDraw.Add(listTriangle[j]);
                    listTriangle.RemoveAt(j);
                    --j;
                }
            }
        }
        for (int i = 0; i < ServerPath.getInstance().listDraw.Count; ++i)
        {
            Debug.DrawLine(ServerPath.getInstance().listDraw[i].A, ServerPath.getInstance().listDraw[i].B, Color.green, 5);
            Debug.DrawLine(ServerPath.getInstance().listDraw[i].A, ServerPath.getInstance().listDraw[i].C, Color.green, 5);
            Debug.DrawLine(ServerPath.getInstance().listDraw[i].C, ServerPath.getInstance().listDraw[i].B, Color.green, 5);
            
        }
        Debug.DrawLine(ServerPath.getInstance().listDraw[0].A, ServerPath.getInstance().listDraw[0].B, Color.red, 5);
        Debug.DrawLine(ServerPath.getInstance().listDraw[0].A, ServerPath.getInstance().listDraw[0].C, Color.red, 5);
        Debug.DrawLine(ServerPath.getInstance().listDraw[0].C, ServerPath.getInstance().listDraw[0].B, Color.yellow, 5);
        Debug.Log("AB和AC的夾角: " + Vector3.Angle((ServerPath.getInstance().listDraw[0].B - ServerPath.getInstance().listDraw[0].A),
            (ServerPath.getInstance().listDraw[0].C - ServerPath.getInstance().listDraw[0].A)));
        Debug.Log("AC和AB的夾角: " + Vector3.Angle((ServerPath.getInstance().listDraw[0].C - ServerPath.getInstance().listDraw[0].A),
            (ServerPath.getInstance().listDraw[0].B - ServerPath.getInstance().listDraw[0].A)));
        Debug.Log("AB和CA的夾角: " + Vector3.Angle((ServerPath.getInstance().listDraw[0].B - ServerPath.getInstance().listDraw[0].A),
            (ServerPath.getInstance().listDraw[0].A - ServerPath.getInstance().listDraw[0].C)));
        
        countG(ServerPath.getInstance().listDraw[startI]);
        countG(ServerPath.getInstance().listDraw[endI]);
        Debug.Log("listDraw.Count: " + ServerPath.getInstance().listDraw.Count);
        ServerPath.getInstance().initNeighbour();
        ServerPath.getInstance().countPath(0, endI);
    }
    public static void countG(Triangle t)
    {
        float my_a = (t.B - t.C).magnitude;
        float my_b = (t.B - t.C).magnitude;
        float my_c = (t.B - t.C).magnitude;

        Vector3 myCenter = new Vector3((my_a * t.A.x + my_b * t.B.x + my_c * t.C.x) / (my_a + my_b + my_c),
            (my_a * t.A.y + my_b * t.B.y + my_c * t.C.y) / (my_a + my_b + my_c),
            (my_a * t.A.z + my_b * t.B.z + my_c * t.C.z) / (my_a + my_b + my_c));
        Debug.DrawRay(myCenter, Vector3.up * 5, Color.red, 5);
    }
}

using System.Collections.Generic;
using UnityEngine;

namespace ServerTools
{
    public class Triangle
    {
        public Vector3 A;
        public Vector3 B;
        public Vector3 C;
        public Triangle neighborA = null;
        public Triangle neighborB = null;
        public Triangle neighborC = null;
        public int id;
        public Triangle father = null;
        public Triangle next = null;
        public float F = 0f;
        public float H = 0f;
        public float G = 0f;
        public bool finished = false;
        public void reset()
        {
            F = 0f;
            H = 0f;
            G = 0f;
            neighborA = null;
            neighborB = null;
            neighborC = null;
            father = null;
            next = null;
            finished = false;
        }
        public Vector3 getCenterPosition()
        {
            float a = (B - C).magnitude;
            float b = (B - C).magnitude;
            float c = (B - C).magnitude;

            Vector3 Center = new Vector3((a * A.x + b * B.x + c * C.x) / (a + b + c),
                (a * A.y + b * B.y + c * C.y) / (a + b + c),
                (a * A.z + b * B.z + c * C.z) / (a + b + c));
            return Center;
        }
    }
    
    public class ServerPath
    {
        private float countDis(Triangle TA, Triangle TB)
        {
            Vector3 ACenter = TA.getCenterPosition();
            Vector3 BCenter = TB.getCenterPosition();
            return (ACenter - BCenter).magnitude;
        }
        private ServerPath()
        {

        }
        private static ServerPath instance = null;
        public static ServerPath getInstance()
        {
            if(instance == null)
            {
                instance = new ServerPath();
            }
            return instance;
        }
        public List<Triangle> listDraw = new List<Triangle>();
        private List<Triangle> listcheck = new List<Triangle>();
        private List<Triangle> listfinish = new List<Triangle>();
        public void initNeighbour()
        {
            for (int i = 0; i < listDraw.Count; ++i)
            {
                listDraw[i].reset();
            }
            for (int i = 0; i < listDraw.Count; ++i)
            {
                for (int j = 0; j < listDraw.Count; ++j)
                {
                    if(i == j)
                    {
                        continue;
                    }
                    int bingleCount = 0;
                    bool hitA = false;
                    bool hitB = false;
                    bool hitC = false;
                    if ((listDraw[i].A - listDraw[j].A).magnitude < 0.05 ||
                        (listDraw[i].A - listDraw[j].B).magnitude < 0.05 ||
                        (listDraw[i].A - listDraw[j].C).magnitude < 0.05)
                    {
                        ++bingleCount;
                        hitA = true;
                    }
                    if ((listDraw[i].B - listDraw[j].A).magnitude < 0.05 ||
                        (listDraw[i].B - listDraw[j].B).magnitude < 0.05 ||
                        (listDraw[i].B - listDraw[j].C).magnitude < 0.05)
                    {
                        ++bingleCount;
                        hitB = true;
                    }
                    if ((listDraw[i].C - listDraw[j].A).magnitude < 0.05 ||
                        (listDraw[i].C - listDraw[j].B).magnitude < 0.05 ||
                        (listDraw[i].C - listDraw[j].C).magnitude < 0.05)
                    {
                        ++bingleCount;
                        hitC = true;
                    }
                    if(bingleCount > 1)
                    {
                        tryToAddNeighbour(listDraw[i], listDraw[j], hitA, hitB, hitC);
                    }
                }
            }
        }
        public void countPath(int start, int end)
        {
            if(start >= listDraw.Count || end >= listDraw.Count)
            {
                return;
            }
            listcheck.Clear();
            listfinish.Clear();
            for(int i = 0; i < listDraw.Count; ++i)
            {
                listDraw[i].id = i;
            }
            Triangle nowTriangle;
            tryToAddToListcheck(listDraw[start]);
            int ci = 0;
            while((nowTriangle = getPbByMinF()) != null)
            {
                ++ci;
                //Debug.Log(ci);
                if(nowTriangle.neighborA == listDraw[end] ||
                    nowTriangle.neighborB == listDraw[end] ||
                    nowTriangle.neighborC == listDraw[end])
                {
                    Triangle pbend = listDraw[end];
                    listfinish.Add(pbend);
                    pbend.father = nowTriangle;
                    while(pbend.father != null)
                    {
                        Debug.DrawLine(pbend.getCenterPosition(), pbend.father.getCenterPosition());
                        pbend.father.next = pbend;
                        pbend = pbend.father;
                    }
                    optimizationPath(pbend);
                    break;
                }
                if(countNeighbourF(nowTriangle, nowTriangle.neighborA))
                {
                    nowTriangle.neighborA.H = (nowTriangle.neighborA.getCenterPosition() - listDraw[end].getCenterPosition()).magnitude;
                    nowTriangle.neighborA.F = nowTriangle.neighborA.H + nowTriangle.neighborA.G;
                }
                if(countNeighbourF(nowTriangle, nowTriangle.neighborB))
                {
                    nowTriangle.neighborB.H = (nowTriangle.neighborB.getCenterPosition() - listDraw[end].getCenterPosition()).magnitude;
                    nowTriangle.neighborB.F = nowTriangle.neighborB.H + nowTriangle.neighborB.G;
                }
                if(countNeighbourF(nowTriangle, nowTriangle.neighborC))
                {
                    nowTriangle.neighborC.H = (nowTriangle.neighborC.getCenterPosition() - listDraw[end].getCenterPosition()).magnitude;
                    nowTriangle.neighborC.F = nowTriangle.neighborC.H + nowTriangle.neighborC.G;
                }
                addToFinish(nowTriangle);
            }
        }
        private Triangle getPbByMinF()
        {
            Triangle pb = null;
            for (int i = 0; i < listcheck.Count; ++i)
            {
                if(pb == null || pb.F > listcheck[i].F)
                {
                    pb = listcheck[i];
                }
            }
            return pb;
        }
        private void tryToAddToListcheck(Triangle t)
        {
            for (int i = 0; i < listfinish.Count; ++i)
            {
                if (t.id == listfinish[i].id)
                {
                    return;
                }
            }
            for (int i = 0; i < listcheck.Count; ++i)
            {
                if(t.id == listcheck[i].id)
                {
                    return;
                }
            }
            listcheck.Add(t);
        }
        private void addToFinish(Triangle t)
        {
            t.finished = true;
            listfinish.Add(t);
            listcheck.Remove(t);
        }
        private bool countNeighbourF(Triangle A, Triangle Neighbour)
        {
            if(Neighbour == null || Neighbour.finished)
            {
                return false;
            }
            float G = countDis(A, Neighbour);
            if (Neighbour.G == 0f || (A.G + G) < Neighbour.G)
            {
                Neighbour.G = A.G + G;
                Neighbour.father = A;
                tryToAddToListcheck(Neighbour);
                return true;
            }
            return false;
        }
        private void tryToAddNeighbour(Triangle baseTriangle, Triangle neighbour, bool hitA, bool hitB, bool hitC)
        {
            if(hitA && hitB)
            {
                baseTriangle.neighborC = neighbour;
            }
            else if (hitA && hitC)
            {
                baseTriangle.neighborB = neighbour;
            }
            else if (hitC && hitB)
            {
                baseTriangle.neighborA = neighbour;
            }
        }
        private void optimizationPath(Triangle start)
        {
            Vector3 v1 = new Vector3();
            Vector3 v2 = new Vector3();
            Vector3 v3 = new Vector3();
            Vector3 v4 = new Vector3();

            Vector3 p1 = new Vector3();
            Vector3 p2 = new Vector3();
            Vector3 p3 = new Vector3();
            Vector3 p4 = new Vector3();
            Triangle g1 = start;
            Triangle g2 = start;
            List<Vector3> listpath = new List<Vector3>();
            Vector3 startPosition = start.getCenterPosition();
            listpath.Add(startPosition);
            Triangle tCount = start.next;
            caculateV(startPosition, start, ref v1, ref v2, ref p1, ref p2);
            int testi = 0;
            while (tCount != null)
            {
                ++testi;
                caculateV(startPosition, tCount, ref v3, ref v4, ref p3, ref p4);

                if (testi == 999)
                {
                    Debug.DrawRay(startPosition + Vector3.up * 0.5f, v1, Color.cyan, 5);
                    Debug.DrawRay(startPosition + Vector3.up * 0.5f, v2, Color.cyan, 5);
                    Debug.DrawRay(startPosition, v3, Color.black, 5);
                    Debug.DrawRay(startPosition, v4, Color.black, 5);
                    tCount = null;
                    continue;
                }


                //左手坐標(biāo)系,所以小于等于
                if (Vector3.Cross(new Vector3(v3.x, 0, v3.z), new Vector3(v2.x, 0, v2.z)).y <= 0)
                {
                    Debug.DrawRay(p2, Vector3.up * 10, Color.yellow, 5);
                    startPosition = p2;
                    tCount = g2;
                    g2 = tCount.next;
                    caculateV(startPosition, tCount, ref v1, ref v2, ref p1, ref p2);
                    listpath.Add(startPosition);
                    this.countNext(ref listpath, ref tCount);
                    continue;
                }
                //左手坐標(biāo)系,所以大于等于
                if (Vector3.Cross(new Vector3(v4.x, 0, v4.z), new Vector3(v1.x, 0, v1.z)).y >= 0)
                {
                    Debug.DrawRay(p1, Vector3.up * 10, Color.yellow, 5);
                    startPosition = p1;
                    tCount = g1;
                    g1 = tCount.next;
                    caculateV(startPosition, tCount, ref v1, ref v2, ref p1, ref p2);
                    listpath.Add(startPosition);
                    this.countNext(ref listpath, ref tCount);
                    continue;
                }
                //左手坐標(biāo)系,所以小于等于
                if (Vector3.Cross(new Vector3(v3.x, 0, v3.z), new Vector3(v1.x, 0, v1.z)).y <= 0)
                {
                    v1 = v3;
                    p1 = p3;
                    g1 = tCount.next;
                }
                //左手坐標(biāo)系,所以小于等于
                if (Vector3.Cross(new Vector3(v4.x, 0, v4.z), new Vector3(v2.x, 0, v2.z)).y >= 0)
                {
                    v2 = v4;
                    p2 = p4;
                    g2 = tCount.next;
                }
                this.countNext(ref listpath, ref tCount);
            }
            for(int i = 0; i < listpath.Count - 1; ++i)
            {
                Debug.DrawLine(listpath[i], listpath[i + 1], Color.blue, 5);
            }
        }
        private void countNext(ref List<Vector3> listpath, ref Triangle t)
        {
            if (t.next == null)
            {
                listpath.Add(t.getCenterPosition());
            }
            t = t.next;
        }
        private void caculateV(Vector3 startPosition, Triangle tCount, ref Vector3 v1, ref Vector3 v2, ref Vector3 p1, ref Vector3 p2)
        {
            if(tCount == null)
            {
                return;
            }
            if(tCount.next != null)
            {
                if (tCount.next == tCount.neighborA)
                {
                    v1 = tCount.B - startPosition;
                    v2 = tCount.C - startPosition;
                    p1 = tCount.B;
                    p2 = tCount.C;
                }
                else if (tCount.next == tCount.neighborB)
                {
                    v1 = tCount.A - startPosition;
                    v2 = tCount.C - startPosition;
                    p1 = tCount.A;
                    p2 = tCount.C;
                }
                else if (tCount.next == tCount.neighborC)
                {
                    v1 = tCount.B - startPosition;
                    v2 = tCount.A - startPosition;
                    p1 = tCount.B;
                    p2 = tCount.A;
                }
                //start Position和另一個V,在同一個邊上則邊就確定了,從這個三角形中心找左右
                if (Vector3.Cross(new Vector3(v1.x, 0, v1.z), new Vector3(v2.x, 0, v2.z)).y == 0)
                {
                    Vector3 vcp_1 = p1 - tCount.getCenterPosition();
                    Vector3 vcp_2 = p2 - tCount.getCenterPosition();

                    if (Vector3.Cross(new Vector3(vcp_1.x, 0, vcp_1.z), new Vector3(vcp_2.x, 0, vcp_2.z)).y < 0)
                    {
                        v1 = p2 - startPosition;
                        v2 = p1 - startPosition;
                        Vector3 pswitch = p1;
                        p1 = p2;
                        p2 = pswitch;
                    }
                    else
                    {
                        v1 = p1 - startPosition;
                        v2 = p2 - startPosition;
                    }
                }
                //左手坐標(biāo)系,所以小于等于
                else if (Vector3.Cross(new Vector3(v1.x, 0, v1.z), new Vector3(v2.x, 0, v2.z)).y < 0)
                {
                    Vector3 vswitch = v1;
                    Vector3 pswitch = p1;
                    v1 = v2;
                    v2 = vswitch;
                    p1 = p2;
                    p2 = pswitch;
                }
            }
            else
            {
                v1 = v2 = tCount.getCenterPosition() - startPosition;
                p1 = p2 = tCount.getCenterPosition();
            }
        }
    }

}

大致的注解(因?yàn)樽约河茫僖粋€很多代碼只是服務(wù)器代碼的一個預(yù)演,湊合寫下,所以注釋基本沒有,有幾個變量的設(shè)置直接隨意的放到里面,下圖我大約注解一下。。。


image.png

代碼Copy之后,如下圖


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容