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)友評論
全部評論:0條
推薦
熱門