先上效果图

可能大家都已经对Polygon Collider 2D这个组件已经非常的熟悉,就是一个判断多边形碰撞的组件,我们可以通过编辑形状大小来实现对不同多边形的碰撞检测。
但是如果遇到较为复杂的多边形,我们在调节时就可能会相对困难,例如下边这个复杂的多边形

在这里分享一个脚本,可以去识别多边形最边缘的边,把最边缘的边赋值给Polygon Collider 2D,就可以使得Polygon Collider 2D的大小完美贴合多边形的边缘。

查找边缘的主要算法就是取到多边形内不共用的边(可以发现只有边缘的边是不被三角形共用的,被三角形公用的边都在内部)

代码:

using UnityEngine;
using System.Collections.Generic;
using UnityEditor;[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(PolygonCollider2D))]
[ExecuteInEditMode]
public class Mesh2DColliderMaker : MonoBehaviour {/// <summary>/// 定义一个结构体,用来表示边/// </summary>struct Edge2D{public Vector2 a;public Vector2 b;public override bool Equals(object obj){if (obj is Edge2D){var edge = (Edge2D)obj;//An edge is equal regardless of which order it's points are inreturn (edge.a == a && edge.b == b) || (edge.b == a && edge.a == b);}return false;}public override int GetHashCode(){return a.GetHashCode() ^ b.GetHashCode();}public override string ToString(){return string.Format("[" + a.x + "," + a.y + "->" + b.x + "," + b.y + "]");}}MeshFilter filter;PolygonCollider2D polyCollider;void Start() {filter = GetComponent<MeshFilter>();polyCollider = GetComponent<PolygonCollider2D>();CreatePolygon2DColliderPoints();}void Update(){        }public void CreatePolygon2DColliderPoints(){var edges = BuildEdgesFromMesh();var paths = BuildColliderPaths(edges);ApplyPathsToPolygonCollider(paths);}/// <summary>/// 对多边形碰撞体设置路径/// </summary>/// <param name="paths"></param>private void ApplyPathsToPolygonCollider(List<Vector2[]> paths) {if (paths == null)return;polyCollider.pathCount = paths.Count;for (int i = 0; i < paths.Count; i++) {var path = paths [i];polyCollider.SetPath(i, path);}}/// <summary>/// 通过mesh去找所有的边,存到一个字典里/// 如果 int = 1 则证明是边缘的边,如果 int = 2 则证明则是公用的(不是边缘)/// </summary>/// <returns>返回存Edge2D的字典</returns>private Dictionary<Edge2D, int> BuildEdgesFromMesh() {var mesh = filter.sharedMesh;if (mesh == null)return null;var verts = mesh.vertices;var tris = mesh.triangles;var edges = new Dictionary<Edge2D, int>();for (int i = 0; i < tris.Length - 2; i += 3) {var faceVert1 = verts[tris[i]];var faceVert2 = verts[tris[i + 1]];var faceVert3 = verts[tris[i + 2]];Edge2D[] faceEdges;faceEdges = new Edge2D[] {new Edge2D{ a = faceVert1, b = faceVert2 },new Edge2D{ a = faceVert2, b = faceVert3 },new Edge2D{ a = faceVert3, b = faceVert1 },};foreach(var edge in faceEdges) {if (edges.ContainsKey(edge))edges[edge]++;elseedges[edge] = 1;}}return edges;}private List<Vector2[]> BuildColliderPaths(Dictionary<Edge2D, int> allEdges) {if (allEdges == null)return null;  var outerEdges = GetOuterEdges(allEdges);var paths = new List<List<Edge2D>>();List<Edge2D> path = null;while (outerEdges.Count > 0) {if (path == null) {path = new List<Edge2D>();path.Add (outerEdges[0]);paths.Add (path);outerEdges.RemoveAt(0);}bool foundAtLeastOneEdge = false;int i = 0;while (i < outerEdges.Count) {var edge = outerEdges [i];bool removeEdgeFromOuter = false;if (edge.b == path[0].a) {path.Insert (0, edge);removeEdgeFromOuter = true;}else if (edge.a == path[path.Count - 1].b) {path.Add(edge);removeEdgeFromOuter = true;}if (removeEdgeFromOuter) {foundAtLeastOneEdge = true;outerEdges.RemoveAt(i);} elsei++;}if (!foundAtLeastOneEdge)path = null;}var cleanedPaths = new List<Vector2[]>();foreach(var builtPath in paths) {var coords = new List<Vector2>();foreach(var edge in builtPath)coords.Add (edge.a);cleanedPaths.Add (CoordinatesCleaned(coords));}        return cleanedPaths;}/// <summary>/// 取到边缘的边(即字典中int = 1的值)/// </summary>/// <param name="allEdges"></param>/// <returns>边缘的边</returns>private List<Edge2D> GetOuterEdges(Dictionary<Edge2D, int> allEdges){var outerEdges = new List<Edge2D>();foreach (var edge in allEdges.Keys){var numSharedFaces = allEdges[edge];if (numSharedFaces == 1)outerEdges.Add(edge);}return outerEdges;}private bool CoordinatesFormLine(Vector2 a, Vector2 b, Vector2 c){//If the area of a triangle created from three points is zero, they must be in a line.float area = a.x * ( b.y - c.y ) + b.x * ( c.y - a.y ) + c.x * ( a.y - b.y );return Mathf.Approximately(area, 0f);}private Vector2[] CoordinatesCleaned(List<Vector2> coordinates) {List<Vector2> coordinatesCleaned = new List<Vector2> ();coordinatesCleaned.Add (coordinates [0]);var lastAddedIndex = 0;for (int i = 1; i < coordinates.Count; i++) {var coordinate = coordinates [i];Vector2 lastAddedCoordinate = coordinates [lastAddedIndex];Vector2 nextCoordinate = (i + 1 >= coordinates.Count) ? coordinates[0] : coordinates [i + 1];if (!CoordinatesFormLine(lastAddedCoordinate, coordinate, nextCoordinate)) {coordinatesCleaned.Add (coordinate);lastAddedIndex = i;                           }}return coordinatesCleaned.ToArray ();}}

Unity通过脚本实现不规则多边形的碰撞检测相关推荐

  1. Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理

    Unity UGUI 效果 之 UI 元素 多边形UI (例如雷达图,圆形,不规则多边形 UI等)显示 的简单实现的几种方法整理 目录 Unity UGUI 效果 之 UI 元素 多边形UI (例如雷 ...

  2. 聊聊在博客园写博客的这两年《Unity 3D脚本编程:使用C#语言开发跨平台游戏》正式出版...

    版本状态: 2016.9 第一次印刷 (2016.11 输出到台湾) 2017.1 第二次印刷 2017.5 第三次印刷 2017.5 电子书上线:Unity 3D脚本编程--使用C#语言开发跨平台游 ...

  3. Unity Mono脚本 加密

    加密环境 引擎版本:Unity3D 5.3.4 及更高版本 (使用Mono而并非IL2CPP) 操作系统:CentOS 6.2(Final) 加密环境:Android.IOS(暂定) 加密对象:C#源 ...

  4. unity中脚本编辑器UnIDE

    引言 unity默认脚本编辑器是MonoDevelop,随着unity4.3面世,MonoDevelop (4.0.1)版本也随之而来,更新为界面更改和bug自动修复功能等,具体还未使用. 点击uni ...

  5. 不规则多边形重心求解

    文章目录 一.不规则多边形重心求解 1.1 三角形重心计算方法 1.2 三角形面积计算方法 1.3 多边形面积的计算方法 1.4 不规则多边形的重心计算方法 一.不规则多边形重心求解 1.1 三角形重 ...

  6. 【opencv-python不规则多边形 ROI提取】

    opencv-python不规则多边形 ROI提取 import cv2import numpy as np import joblibpts = [] # 用于存放点# 统一的:mouse call ...

  7. Unity游戏脚本简单学习

    Unity游戏脚本 1.脚本操作游戏对象 1.1.创建游戏对象 创建一个空的游戏对象 GameObject obj = new GameObject("obj1"); 用该方法创建 ...

  8. 《Unity 3D脚本编程:使用C#语言开发跨平台游戏》序言

    本文是7月受陈嘉栋的委托为他的新书<Unity 3D脚本编程:使用C#语言开发跨平台游戏>所写的序言,借助序言告诉大家.NET平台有着一个广阔的使用场景. 序言 Unity3D 是由两个具 ...

  9. 不规则多边形区域的面积计算算法

    不规则多边形区域的面积计算算法 最近在写一个显微图像分析处理方面的程序,里面有一个功能是计算一个不规则的多边形区域的面积.因此花了点时间研究这个算法该如何写.研究了一番之后,算是找到了个比较靠谱的算法 ...

最新文章

  1. 近年来霸屏CNS封面的领域,值得关注
  2. TP获取服务器mysql版本
  3. Android 如何抓取开机Log
  4. 2019,别进大厂了!
  5. windows server 2008 远程桌面(授权、普通用户登录)
  6. 俄罗斯方块代码 java_俄罗斯方块java代码-java编写俄罗斯方块代码详解分享
  7. MSDN for VC 6.0 MSDN下载地址
  8. 项目日报模板_速看!贵港这个年产值近100亿元项目即将正式投产
  9. 【UML】构件图(Component Diagram)
  10. 语法分析——自顶向下分析方法
  11. 方差分解分析 (VPA):定量不同环境因子对群落变化的解释比例
  12. javaswing,JAVA中国象棋网上对弈
  13. 手把手教你搭建Windows环境微信小程序的本地测试服务器
  14. 根据原厂uboot进行移植
  15. 一种基于时间滑动窗口的黑产团伙挖掘算法
  16. 虚拟服务器鼠标左键被锁了,鼠标在网页里左键被锁怎么办
  17. Mybatis常见错误 Could not find resource com/mybatis/mapper/UserInfoMapper.xml
  18. 2、Terraform-安装
  19. 01.Windows系统安装
  20. mui报错:[Intervention] Unable to preventDefault inside passive event listener due to target being

热门文章

  1. 系统之美 作者:德内拉梅多斯
  2. 【Android】使用后端云Bmob实现登录、注册
  3. PDF - 使用 Adobe Acrobat 压缩 PDF 大小
  4. 不提杨元庆,先看看联想该如何让Moto复活
  5. linux程序设计项目报告,Linux程序设计实验报告大作业
  6. chrome打开网页很慢,别的浏览器打开相同的网页很快
  7. 微软bing搜索好强大
  8. Exp8 web基础 20164323段钊阳
  9. 量子计算机解泊松方程,学界 | 从泊松方程的解法,聊到泊松图像融合
  10. Apple开启双重认证过程