碰撞检测(上篇)
游戏中的每个3D对象在世界坐标系里都有坐标。
技能的作用范围可能是圆形,矩形,扇形,三角形等。
那可不可以直接拿 “点”直接与这些形状进行碰撞检测呢!
如果你要的效果不是那么精确,可以允许一点点瑕疵,那么是可行的。
那么这个瑕疵是什么呢?
因为3D物体都有体积,当你肉眼都能看到你的3D模型已经在范围里面,但是为什么技能作用不到它呢?
因为实际取的是3D物体的中心点。当这个中心点真正进入技能范围内,技能才真正作用到他。
如图:中心点还在范围外
如果你不能允许,那这种方式就不适合了。我会在下篇整理更精确的方式。
这里有本书:Real-Time Collision Dectection 中文版
我上传到网盘了:
链接:http://pan.baidu.com/s/1o63VtqE 密码:d5vt
如果你能允许,那么请往下看。
1.点在三角形内
using UnityEngine; using System.Collections; /// <summary> /// 点在三角形里面 /// </summary> public class PointInTriangle : MonoBehaviour { public Transform PointTrans; public float distance = 5f; public float angle = 30f; void Update() { Quaternion r = this.transform.rotation; Vector3 f0 = transform.position + (r * Vector3.forward) * distance; //Debug.DrawLine(transform.position, f0, Color.red);//正前方 Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z); Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance; Debug.DrawLine(transform.position, f1, Color.red);//左30度方向 Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z); Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向 Debug.DrawLine(transform.position, f2, Color.red); Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形 Vector3 point = PointTrans.position; //点是否在一个三角形内 if (MyTool.isINTriangle(point, transform.position, f1, f2)) { Debug.Log("in"); } else { Debug.Log("not in"); } } }
2.点在扇形内
using UnityEngine; using System.Collections; /// <summary> /// 点在扇形里面 /// </summary> public class PointInSector : MonoBehaviour { public Transform pointTransform; public float distance = 5f; public float angle = 30f; void Update() { Quaternion r = this.transform.rotation; Vector3 f0 = transform.position + (r * Vector3.forward) * distance; Debug.DrawLine(transform.position, f0, Color.red);//正前方 Quaternion r0 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - angle, transform.rotation.eulerAngles.z); Vector3 f1 = transform.position + (r0 * Vector3.forward) * distance; Debug.DrawLine(transform.position, f1, Color.red);//左30度方向 Quaternion r1 = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + angle, transform.rotation.eulerAngles.z); Vector3 f2 = transform.position + (r1 * Vector3.forward) * distance;//右30度方向 Debug.DrawLine(transform.position, f2, Color.red); Debug.DrawLine(f1, f2, Color.red);//连接成一个三角形 Vector3 point = pointTransform.position; Vector3 selfVec = (f0 - this.transform.position).normalized; Vector3 targetVec = (pointTransform.position - this.transform.position).normalized; Debug.DrawLine(pointTransform.position, this.transform.position, Color.yellow); //在左右30度以内 if (Vector3.Dot(selfVec, targetVec) > Mathf.Cos(Mathf.PI / 6.0f)) { //且在周围distance范围以内,等价于在这个扇形区域! if ((pointTransform.position - this.transform.position).sqrMagnitude < distance * distance) { Debug.Log("in"); } else { Debug.Log("not in"); } } else { Debug.Log("out of angle"); } } }
3.点在矩形内
using UnityEngine; using System.Collections; /// <summary> /// 点在矩形里面 /// </summary> public class PointInRectangle : MonoBehaviour { public Transform pointTransform; public float length = 5f; public float width = 5f; private float half_length; private float half_width; void Start() { this.half_length = this.length / 2.0f; this.half_width = this.width / 2.0f; } void Update() { Quaternion r = transform.rotation; Vector3 left = (transform.position + (r * Vector3.left) * this.half_length); Debug.DrawLine(transform.position, left, Color.red); Vector3 right = (transform.position + (r * Vector3.right) * this.half_length); Debug.DrawLine(transform.position, right, Color.red); Vector3 leftEnd = (left + (r * Vector3.forward) * this.width); Debug.DrawLine(left, leftEnd, Color.red); Vector3 rightEnd = (right + (r * Vector3.forward) * this.width); Debug.DrawLine(right, rightEnd, Color.red); Debug.DrawLine(leftEnd, rightEnd, Color.red); Vector3 point = pointTransform.position; //是否在矩形内 if (MyTool.isINRect(point, leftEnd, rightEnd, right, left)) { Debug.Log("in"); } else { Debug.Log("not in"); } } }
工具类:
using UnityEngine; public class MyTool { private static float triangleArea(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y) { return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y - v1x * v0y - v2x * v1y - v0x * v2y) / 2f); } public static bool isINTriangle(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2) { float x = point.x; float y = point.z; float v0x = v0.x; float v0y = v0.z; float v1x = v1.x; float v1y = v1.z; float v2x = v2.x; float v2y = v2.z; float t = triangleArea(v0x, v0y, v1x, v1y, v2x, v2y); float a = triangleArea(v0x, v0y, v1x, v1y, x, y) + triangleArea(v0x, v0y, x, y, v2x, v2y) + triangleArea(x, y, v1x, v1y, v2x, v2y); if (Mathf.Abs(t - a) <= 0.01f) { return true; } else { return false; } } private static float Multiply(float p1x, float p1y, float p2x, float p2y, float p0x, float p0y) { return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y)); } public static bool isINRect(Vector3 point, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3) { float x = point.x; float y = point.z; float v0x = v0.x; float v0y = v0.z; float v1x = v1.x; float v1y = v1.z; float v2x = v2.x; float v2y = v2.z; float v3x = v3.x; float v3y = v3.z; if (Multiply(x, y, v0x, v0y, v1x, v1y) * Multiply(x, y, v3x, v3y, v2x, v2y) <= 0 && Multiply(x, y, v3x, v3y, v0x, v0y) * Multiply(x, y, v2x, v2y, v1x, v1y) <= 0) return true; else return false; } }
- 本文固定链接: http://www.shihuanjue.com/?p=139
- 转载请注明: 乔 2015年10月09日 于 是幻觉 发表