? 99久久精品99999久久,精品国精品国产自在久国产AV,日韩性爱无码
聯(lián)系我們

給我們留言

聯(lián)系我們

地址:福建省晉江市青陽街道洪山路國際工業(yè)設(shè)計園納金網(wǎng)

郵箱:info@narkii.com

電話:0595-82682267

(周一到周五, 周六周日休息)

當前位置:主頁 > 3D教程 > 圖文教程

Unity實用小工具或腳本—自制2D碰撞體

來源: 未知 | 責任編輯:六月芳菲 | 發(fā)布時間: 2018-03-05 15:17 | 瀏覽量:

更多精彩unity教程:http://m.594ljc.cn/resource/



一、 前言
看到標題其實有人就要問了,自制2D的碰撞體。樓主你這是在炫技嗎,Unity不是有自帶的碰撞體和剛體可以用嗎,為什么要吃飽了自己寫一個?無奈!職場生活,裝逼必死無疑。Unity的碰撞體和剛體只能在TmeScale!=0的時候使用。但是,那么在TimeScale=0的時候我們還需要這個功能怎么辦呢?有人要說了,這不是要搞事情自己作死嗎?沒辦法,需求擺在那,明知是坑也要去填啊于是乎,我就自己寫了一個可以在TimeScale=0的情況下執(zhí)行的碰撞。

更多精彩unity教程:http://m.594ljc.cn/resource/


二、 說明
1、盡管TimeScale=0了,但是在Update()函數(shù)里的腳本還是可以執(zhí)行的,不能執(zhí)行的是FixedUpdate()函數(shù)的腳本。因此,我的邏輯腳本都是在Update里寫的。
2、這個碰撞體只實現(xiàn)了帶三個點以上的多邊形,比如長方形、棱形、不規(guī)則多邊形等。對于沒有點和邊的形狀,如圓形、橢圓等還不能實現(xiàn)碰撞。
3、僅僅是實現(xiàn)了2D的碰撞體。

更多精彩unity教程:http://m.594ljc.cn/resource/


三、 實現(xiàn)
1、判斷點是否在線段上:
假設(shè)點的坐標為P(x1,y1),線段上的直線方程為Ax+By+C=0;將P點帶入方程中得到的值如果等于0表示P在線段上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UI2DPointToLine : MonoBehaviour {
 
    public Image imagePoint;
    public Image imageStartPoint;
    public Image imageEndPoint;
    public float value;
    // Use this for initialization
    void Start () {
    }
    // Update is called once per frame
    void Update () {
        value = Intersect();
        Debug.Log(value);
    }
    private float Intersect()
    {
        Vector3 startScreenPos = Camera.main.WorldToScreenPoint(imageStartPoint.transform.position);
        Vector3 endScreenPos = Camera.main.WorldToScreenPoint(imageEndPoint.transform.position);
        Vector3 pointSceenPos = Camera.main.WorldToScreenPoint(imagePoint.transform.position);
        //線段1的直線方程
        float A1 = endScreenPos.y - startScreenPos.y;
        float B1 = startScreenPos.x - endScreenPos.x;
        float C1 = endScreenPos.x * startScreenPos.y - startScreenPos.x * endScreenPos.y;
        float v11 = A1 * pointSceenPos.x + B1 * pointSceenPos.y + C1;
        return v11;
    }
}
2、判斷兩個線段是否相交:
假設(shè)線段P1O1的直線方程為A1x+B1y+C1;P2O2的直線方程為A2x+B2y+C2=0;
1>將P1O1的兩個點帶入到P2O2的直線方程中,得到的值相反或者有一個至少為零則P1O1線段和P2O2所在的直線方程相交;
2>同樣,將P2O2帶入P1O1的直線方程,判斷的結(jié)果和1>一樣;
3>如果1>和2>都滿足則表示兩個線段是相交的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UI2DLineIntersect : MonoBehaviour {
 
    public Text resultText;
    public UI2DImageLine line1;
    public UI2DImageLine line2;
    public Vector3 line1StartInScreenPos;
    public Vector3 line1EndInScreenPos;
    public Vector3 line2StartInScreenPos;
    public Vector3 line2EndInScreenPos;
 
    // Use this for initialization
    void Start()
    {
    }
    // Update is called once per frame
    void Update()
    {
        bool isCollision = Intersect();
        resultText.text = isCollision.ToString();
        Debug.Log(isCollision);
    }
    private bool Intersect()
    {
        bool isIntersect = false;
        bool yes1 = false;
        bool yes2 = false;
 
        line1StartInScreenPos = Camera.main.WorldToScreenPoint(line1.imageStartPoint.transform.position);
        line1EndInScreenPos = Camera.main.WorldToScreenPoint(line1.imageEndPoint.transform.position);
        line2StartInScreenPos = Camera.main.WorldToScreenPoint(line2.imageStartPoint.transform.position);
        line2EndInScreenPos = Camera.main.WorldToScreenPoint(line2.imageEndPoint.transform.position);
        //線段1的直線方程
        float A1 = line1EndInScreenPos.y - line1StartInScreenPos.y;
        float B1 = line1StartInScreenPos.x - line1EndInScreenPos.x;
        float C1 = line1EndInScreenPos.x * line1StartInScreenPos.y - line1StartInScreenPos.x * line1EndInScreenPos.y;
        //線段2的開始點在線段1直線方程的值
        float v11 = A1 * line2StartInScreenPos.x + B1 * line2StartInScreenPos.y + C1;
        float v12 = A1 * line2EndInScreenPos.x + B1 * line2EndInScreenPos.y + C1;
        //線段2的直線方程
        float A2 = line2EndInScreenPos.y - line2StartInScreenPos.y;
        float B2 = line2StartInScreenPos.x - line2EndInScreenPos.x;
        float C2 = line2EndInScreenPos.x * line2StartInScreenPos.y - line2StartInScreenPos.x * line2EndInScreenPos.y;
        //線段1的開始點在線段2直線方程的值
        float v21 = A2 * line1StartInScreenPos.x + B2 * line1StartInScreenPos.y + C2;
        float v22 = A2 * line1EndInScreenPos.x + B2 * line1EndInScreenPos.y + C2;
        Debug.Log("v11:" + v11 + "v12:" + v12 + "v21:" + v21 + "v22:" + v22+"...." +Mathf.Round(v11));
        if(Mathf.Round(v11)==0|| Mathf.Round(v12) == 0 || Mathf.Round(v21) == 0 || Mathf.Round(v22) == 0)
        {
            return true;
        }
        if((v11>0&&v12<0)||(v11<0&&v12>0))
        {
            yes1 = true;
        }
        if((v21>0&&v22<0)||(v21<0&&v22>0))
        {
            yes2 = true;
        }
        isIntersect = yes1 && yes2;
        return isIntersect;
    }
}
3、判斷兩個Box是否碰撞:有了2的判斷剩下的就是將兩個Box的每一個邊進行相交判斷;遍歷比較就可以了。碰撞發(fā)生之后,兩個物體要分別向位置向量的相反方向運動。代碼如下:
先定義邊:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class UI2DEdge : MonoBehaviour {
 
    public EDGE_TYPE edgeType;
    public Vector3 StartPointInScreenPos;
    public Vector3 endPointInScreenPos;
    [SerializeField]
    private Image imageStartPoint;
    [SerializeField]
    private Image imageEndPoint;
//    [SerializeField]
    private Image imageParent;
    [SerializeField]
    private Image imageCurLine;
    private Vector3 startPointPos;
    private Vector3 endPointPos;
    // Use this for initialization
    void Start () {
 
        imageParent = transform.parent.GetComponent<Image>();
    }
     
    // Update is called once per frame
    void Update () {
 
        float halfWidth = imageParent.rectTransform.sizeDelta.x / 2.0f;
        float halfHeight = imageParent.rectTransform.sizeDelta.y / 2.0f;
 
        Canvas canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
 
        switch (edgeType)
        {
            case EDGE_TYPE.TOP:
                {
                    startPointPos = new Vector3(-halfWidth, halfHeight, 0);
                    endPointPos = new Vector3(halfWidth, halfHeight, 0);
                    imageCurLine.rectTransform.sizeDelta = new Vector2(halfWidth * 2.0f, 1.0f);
                }
                break;
            case EDGE_TYPE.RIGHT:
                {
                    startPointPos = new Vector3(halfWidth, halfHeight, 0);
                    endPointPos = new Vector3(halfWidth, -halfHeight, 0);
                    imageCurLine.rectTransform.sizeDelta = new Vector2(1.0f, halfHeight * 2.0f);
                }
                break;
            case EDGE_TYPE.DOWN:
                {
                    startPointPos = new Vector3(halfWidth, -halfHeight, 0);
                    endPointPos = new Vector3(-halfWidth, -halfHeight, 0);
                    imageCurLine.rectTransform.sizeDelta = new Vector2(halfWidth * 2.0f, 1.0f);
                }
                break;
            case EDGE_TYPE.LEFT:
                {
                    startPointPos = new Vector3(-halfWidth, -halfHeight, 0);
                    endPointPos = new Vector3(-halfWidth, halfHeight, 0);
                    imageCurLine.rectTransform.sizeDelta = new Vector2(1.0f, halfHeight * 2.0f);
                }
                break;
        }
        imageStartPoint.transform.localPosition = startPointPos;
        imageEndPoint.transform.localPosition = endPointPos;
        imageCurLine.transform.localPosition = (endPointPos + startPointPos) / 2.0f;
        StartPointInScreenPos = Camera.main.WorldToScreenPoint(imageStartPoint.transform.position);
        endPointInScreenPos = Camera.main.WorldToScreenPoint(imageEndPoint.transform.position);
    }
    public bool Is_Intersect(UI2DEdge otherEdge)
    {
        bool isIntersect = false;
        bool yes1 = false;
        bool yes2 = false;
        //線段1的直線方程
        float A1 = endPointInScreenPos.y - StartPointInScreenPos.y;
        float B1 = StartPointInScreenPos.x - endPointInScreenPos.x;
        float C1 = endPointInScreenPos.x * StartPointInScreenPos.y - StartPointInScreenPos.x * endPointInScreenPos.y;
        //線段2的開始點在線段1直線方程的值
        float v11 = A1 * otherEdge.StartPointInScreenPos.x + B1 * otherEdge.StartPointInScreenPos.y + C1;
        float v12 = A1 * otherEdge.endPointInScreenPos.x + B1 * otherEdge.endPointInScreenPos.y + C1;
        //線段2的直線方程
        float A2 = otherEdge.endPointInScreenPos.y - otherEdge.StartPointInScreenPos.y;
        float B2 = otherEdge.StartPointInScreenPos.x - otherEdge.endPointInScreenPos.x;
        float C2 = otherEdge.endPointInScreenPos.x * otherEdge.StartPointInScreenPos.y - otherEdge.StartPointInScreenPos.x * otherEdge.endPointInScreenPos.y;
        //線段1的開始點在線段2直線方程的值
        float v21 = A2 * StartPointInScreenPos.x + B2 * StartPointInScreenPos.y + C2;
        float v22 = A2 * endPointInScreenPos.x + B2 * endPointInScreenPos.y + C2;
      //     Debug.Log("v11:" + v11 + "v12:" + v12 + "v21:" + v21 + "v22:" + v22);
        if (Mathf.Round(v11) == 0 || Mathf.Round(v12) == 0 || Mathf.Round(v21) == 0 || Mathf.Round(v22) == 0)
        {
            return true;
        }
        if ((v11 > 0 && v12 < 0) || (v11 < 0 && v12 > 0))
        {
            yes1 = true;
        }
        if ((v21 > 0 && v22 < 0) || (v21 < 0 && v22 > 0))
        {
            yes2 = true;
        }
        isIntersect = yes1 && yes2;
        return isIntersect;
    }
}
public enum EDGE_TYPE
{
    TOP,RIGHT,DOWN,LEFT
}
實現(xiàn)碰撞:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class UI2DCollisionBox : MonoBehaviour {
 
    public const float MoveSpeed = 1.1f;
    public int ID;
    private UI2DEdge[] edges;
    private bool isInit = false;
    private List<UI2DCollisionBox> listOtherCollisionBox;
    // Use this for initialization
    void Start () {
        edges = GetComponentsInChildren<UI2DEdge>();
    }
   
    // Update is called once per frame
    void Update () {
 
        if (!isInit) return;
        Collision_Move();
 
    }
    private void Collision_Move()
    {
        if (null == listOtherCollisionBox) return;
        for (int i = 0; i < listOtherCollisionBox.Count; i++)
        {
            bool isCollision = Collision(listOtherCollisionBox[i]);
            if (isCollision)
            {
                float dis = Vector3.Distance(transform.position, listOtherCollisionBox[i].transform.position);
                Vector3 dir;
                if (Mathf.Round(dis) == 0)
                {
                    dir = Vector2.one;
                }
                else
                {
                    dir = listOtherCollisionBox[i].transform.position - transform.position;
                }
                transform.position -= dir.normalized * MoveSpeed;
            }
        }
    }
    private bool Collision(UI2DCollisionBox other)
    {
        bool isCollision = false;
        for (int i = 0; i <edges.Length; i++)
        {
            for (int j = 0; j < other.edges.Length; j++)
            {
                if(edges[i].Is_Intersect(other.edges[j]))
                {
                    return true;
                }
            }
        }
        return isCollision;
    }
    internal void Init(List<UI2DCollisionBox> listAllCollsionBox)
    {
        listOtherCollisionBox = listAllCollsionBox.FindAll(p => p.ID != ID);
        isInit = true;
    }
}
四、 總結(jié)
其實都是數(shù)學問題,而且用到的都是非常簡單的數(shù)學原理。而用代碼實現(xiàn)的過程才是我們程序員能力價值所在。
 
 

更多精彩unity教程:http://m.594ljc.cn/resource/


相關(guān)文章
網(wǎng)友評論

您需要登錄后才可以發(fā)帖 登錄 | 立即注冊

關(guān)閉

全部評論:0條

推薦
熱門