孙广东   2016.10.15
http://blog.csdn.net/u010019717

起这个标题完全是为了区分于 《Unity 关于UGUI不规则图片响应区域解决方法》

最近看到 《Unity 关于NGUI不规则图片响应区域解决方法》    之所以要记录这个也是多自己之前项目的一个总结, 看看那里不好, 该怎么解决!。  我们卡牌游戏就是 UGUI + spine

推荐  雨凇的(看一下评论)

UGUI研究院之不规则按钮的响应区域(十四)

来自 <http://www.xuanyusong.com/archives/3492>

非常巧妙 使用  Polygon Collider2D 作为区域编辑和判断, 但是不能跟随图片的分辨率变化!  这是硬伤!

而且代码可以简化使用  Collider2D.OverlapPoint    判断点在没在多边形碰撞体中

推荐  秦元培 的总结(多边形碰撞器<还是  雨凇  的> 和  精灵像素检测  <出处 http://m.manew.com/forum.php?mod=viewthread&tid=45046&highlight=uGUI%2B%E4%B8%8D%E8%A7%84%E5%88%99&mobile=2 >)

Unity3D游戏开发之在uGUI中使用不规则精灵制作按钮

来自 <http://blog.csdn.net/qinyuanpei/article/details/51868638>

首先指出雨凇的代码实现问题(判断一个点在没在多边形内的算法 http://geomalgorithms.com/a03-_inclusion.html )。     同时也说明了 Image.eventAlphaThreshold  的 意义用处!

 开始正题吧

扩展  UGUI组件呗!

1、自己设置多边形组件(判断一个点是否在一个多边形内)。  2、就是镂空精灵(透明度)。  首先为什么要有第一种需求, 我们游戏当时使用的是Spine动画, 不是精灵, 所以当时用的 2d碰撞体。 如果用镂空精灵作为检测区域的话,就会增加游戏无用的资源, 因为不参与显示(显示的是spine动画)。所以就有了需求1.               对于2、镂空精灵, 就是 秦元培  他们网上所说的方式!也是需要Sprite资源的!

主要是根据IsRaycastLocationValid这个方法的返回值来进行判断的,而这个方法用到的基本原理则是判断指定点对应像素的RGBA数值中的Alpha是否大于某个指定临界值。

而且

public override boolIsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)

{

//当透明度>=1.0时,表示点击在可响应区域返回true

if (m_EventAlphaThreshold >= 1)

return true;

//当没有指定精灵时为什么要返回true?

Debug.Log("射线检测");

Sprite sprite = overrideSprite;

if (sprite == null)      //  注意这个,如果要想像素检测这个不能为空!, 编辑器一定要赋值一个内容

return true;

1、自己设置多边形组件

参考 我之前的博客: 《Unity游戏选/创建角色界面中职业能力图六角形》     来自 <http://blog.csdn.net/u010019717/article/details/52279010>

中的   脚本  UIPolygon.cs

我的想法是错的,  我没有办法得到    最终显示的渲染状态(颜色表)。     也就没办法脱离  贴图  做判断!, 唉~

还好想到了           Mesh能得到顶点数,  能得到三角形,判断在没在多边形内, 所有三角形内就可以了!!!!!!!!     哈哈~

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Assertions.Must;
using UnityEngine.UI.Extensions;namespace SGD
{/// <summary>/// 描述:/// author: sunguangdong/// </summary>[AddComponentMenu("SGD/PolygonButtonWithPixel")]public class PolygonButtonWithPixel : UIPrimitiveBase, IPointerClickHandler{public bool fill = true;public float thickness = 5;[Range(3, 360)]public int sides = 3;[Range(0, 360)]public float rotation = 0;[Range(0, 1)]public float[] VerticesDistances = new float[3];private float size = 0;/// /       针对 多边形响应区域检测  startpublic bool _isShowUI;public UnityEvent _ClickEvent = new UnityEvent();public void Start(){useLegacyMeshGeneration = false;}public void OnPointerClick(PointerEventData eventData){Debug.LogError("点击到精灵");_ClickEvent.Invoke();}/ <summary>/ 只参与 点击响应, 不参与绘制   todo 但是在编辑器下也看不到了?????/ </summary>/ <param name="toFill"></param>//protected override void OnPopulateMesh(VertexHelper toFill)//{//    toFill.Clear();//}/// <summary>/// 自定义 多边形响应区域(根据Mesh内的顶点 和 三角形弄的)/// </summary>/// <param name="screenPoint"></param>/// <param name="eventCamera"></param>/// <returns></returns>public override bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera){Vector2 local;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local);try{return InPolygon(new Vector3(local.x, local.y, 0));}catch (UnityException e){Debug.LogError("Using clickAlphaThreshold lower than 1 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);return true;}}/// <summary>///  判断一个点  在没在多边形内!/// </summary>/// <param name="_target"></param>/// <returns></returns>protected bool InPolygon(Vector3 _target){Vector2 prevX = Vector2.zero;Vector2 prevY = Vector2.zero;Vector2 pos0;Vector2 pos1;Vector2 pos2;float degrees = 360f / sides;int vertices = sides + 1;if (VerticesDistances.Length != vertices){VerticesDistances = new float[vertices];for (int i = 0; i < vertices - 1; i++) VerticesDistances[i] = 1;}// last vertex is also the first!VerticesDistances[vertices - 1] = VerticesDistances[0];for (int i = 0; i < vertices; i++){float outer = -rectTransform.pivot.x * size * VerticesDistances[i];float inner = -rectTransform.pivot.x * size * VerticesDistances[i] + thickness;float rad = Mathf.Deg2Rad * (i * degrees + rotation);float c = Mathf.Cos(rad);float s = Mathf.Sin(rad);pos0 = prevX;pos1 = new Vector2(outer * c, outer * s);if (fill){pos2 = Vector2.zero;}else{pos2 = new Vector2(inner * c, inner * s);}prevX = pos1;prevY = pos2;if (InTrigon(_target, pos0, pos1, pos2)){return true;}}return false;}/// <summary>///  判断一个点  在没在三角形内!/// </summary>/// <param name="_target"></param>/// <param name="_center"></param>/// <param name="_left"></param>/// <param name="_right"></param>/// <returns></returns>public static bool InTrigon(Vector3 _target, Vector3 _center, Vector3 _left, Vector3 _right){Debug.Log(_target.ToString() + _center.ToString() + _left.ToString() + _right.ToString());Vector3 Ctl = _left - _center;Vector3 Ctr = _right - _center;Vector3 Ctt = _target - _center;Vector3 Ltr = _right - _left;Vector3 Ltc = _right - _center;Vector3 Ltt = _left - _target;Vector3 Rtl = _left - _right;Vector3 Rtc = _center - _right;Vector3 Rtt = _target - _right;if (Vector3.Dot(Vector3.Cross(Ctl, Ctr).normalized, Vector3.Cross(Ctl, Ctt).normalized) == 1 &&Vector3.Dot(Vector3.Cross(Ltr, Ltc).normalized, Vector3.Cross(Ltr, Ltt).normalized) == 1 &&Vector3.Dot(Vector3.Cross(Rtc, Rtl).normalized, Vector3.Cross(Rtc, Rtt).normalized) == 1)return true;elsereturn false;}///  /       针对 多边形响应区域检测  endpublic void DrawPolygon(int _sides){sides = _sides;VerticesDistances = new float[_sides + 1];for (int i = 0; i < _sides; i++) VerticesDistances[i] = 1; ;rotation = 0;}public void DrawPolygon(int _sides, float[] _VerticesDistances){sides = _sides;VerticesDistances = _VerticesDistances;rotation = 0;}public void DrawPolygon(int _sides, float[] _VerticesDistances, float _rotation){sides = _sides;VerticesDistances = _VerticesDistances;rotation = _rotation;}void Update(){size = rectTransform.rect.width;if (rectTransform.rect.width > rectTransform.rect.height)size = rectTransform.rect.height;elsesize = rectTransform.rect.width;thickness = (float)Mathf.Clamp(thickness, 0, size / 2);}protected override void OnPopulateMesh(VertexHelper vh){vh.Clear();if (_isShowUI){Vector2 prevX = Vector2.zero;Vector2 prevY = Vector2.zero;Vector2 uv0 = new Vector2(0, 0);Vector2 uv1 = new Vector2(0, 1);Vector2 uv2 = new Vector2(1, 1);Vector2 uv3 = new Vector2(1, 0);Vector2 pos0;Vector2 pos1;Vector2 pos2;Vector2 pos3;float degrees = 360f / sides;int vertices = sides + 1;if (VerticesDistances.Length != vertices){VerticesDistances = new float[vertices];for (int i = 0; i < vertices - 1; i++) VerticesDistances[i] = 1;}// last vertex is also the first!VerticesDistances[vertices - 1] = VerticesDistances[0];for (int i = 0; i < vertices; i++){float outer = -rectTransform.pivot.x * size * VerticesDistances[i];float inner = -rectTransform.pivot.x * size * VerticesDistances[i] + thickness;float rad = Mathf.Deg2Rad * (i * degrees + rotation);float c = Mathf.Cos(rad);float s = Mathf.Sin(rad);uv0 = new Vector2(0, 1);uv1 = new Vector2(1, 1);uv2 = new Vector2(1, 0);uv3 = new Vector2(0, 0);pos0 = prevX;pos1 = new Vector2(outer * c, outer * s);if (fill){pos2 = Vector2.zero;pos3 = Vector2.zero;}else{pos2 = new Vector2(inner * c, inner * s);pos3 = prevY;}prevX = pos1;prevY = pos2;vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));}}}}
}
using System;namespace UnityEngine.UI.Extensions
{public class UIPrimitiveBase : MaskableGraphic, ILayoutElement, ICanvasRaycastFilter{[SerializeField]private Sprite m_Sprite;public Sprite sprite { get { return m_Sprite; } set { if (SetPropertyUtility.SetClass(ref m_Sprite, value)) SetAllDirty(); } }[NonSerialized]private Sprite m_OverrideSprite;public Sprite overrideSprite { get { return m_OverrideSprite == null ? sprite : m_OverrideSprite; } set { if (SetPropertyUtility.SetClass(ref m_OverrideSprite, value)) SetAllDirty(); } }// Not serialized until we support read-enabled sprites better.internal float m_EventAlphaThreshold = 1;public float eventAlphaThreshold { get { return m_EventAlphaThreshold; } set { m_EventAlphaThreshold = value; } }/// <summary>/// Image's texture comes from the UnityEngine.Image./// </summary>public override Texture mainTexture{get{if (overrideSprite == null){if (material != null && material.mainTexture != null){return material.mainTexture;}return s_WhiteTexture;}return overrideSprite.texture;}}public float pixelsPerUnit{get{float spritePixelsPerUnit = 100;if (sprite)spritePixelsPerUnit = sprite.pixelsPerUnit;float referencePixelsPerUnit = 100;if (canvas)referencePixelsPerUnit = canvas.referencePixelsPerUnit;return spritePixelsPerUnit / referencePixelsPerUnit;}}protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs){UIVertex[] vbo = new UIVertex[4];for (int i = 0; i < vertices.Length; i++){var vert = UIVertex.simpleVert;vert.color = color;vert.position = vertices[i];vert.uv0 = uvs[i];vbo[i] = vert;}return vbo;}#region ILayoutElement Interfacepublic virtual void CalculateLayoutInputHorizontal() { }public virtual void CalculateLayoutInputVertical() { }public virtual float minWidth { get { return 0; } }public virtual float preferredWidth{get{if (overrideSprite == null)return 0;return overrideSprite.rect.size.x / pixelsPerUnit;}}public virtual float flexibleWidth { get { return -1; } }public virtual float minHeight { get { return 0; } }public virtual float preferredHeight{get{if (overrideSprite == null)return 0;return overrideSprite.rect.size.y / pixelsPerUnit;}}public virtual float flexibleHeight { get { return -1; } }public virtual int layoutPriority { get { return 0; } }#endregion#region ICanvasRaycastFilter Interfacepublic virtual bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera){if (m_EventAlphaThreshold >= 1)return true;Sprite sprite = overrideSprite;if (sprite == null)return true;Vector2 local;RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local);Rect rect = GetPixelAdjustedRect();// Convert to have lower left corner as reference point.local.x += rectTransform.pivot.x * rect.width;local.y += rectTransform.pivot.y * rect.height;local = MapCoordinate(local, rect);// Normalize local coordinates.Rect spriteRect = sprite.textureRect;Vector2 normalized = new Vector2(local.x / spriteRect.width, local.y / spriteRect.height);// Convert to texture space.float x = Mathf.Lerp(spriteRect.x, spriteRect.xMax, normalized.x) / sprite.texture.width;float y = Mathf.Lerp(spriteRect.y, spriteRect.yMax, normalized.y) / sprite.texture.height;try{return sprite.texture.GetPixelBilinear(x, y).a >= m_EventAlphaThreshold;}catch (UnityException e){Debug.LogError("Using clickAlphaThreshold lower than 1 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);return true;}}/// <summary>/// Return image adjusted position/// **Copied from Unity's Image component for now and simplified for UI Extensions primatives/// </summary>/// <param name="local"></param>/// <param name="rect"></param>/// <returns></returns>private Vector2 MapCoordinate(Vector2 local, Rect rect){Rect spriteRect = sprite.rect;return new Vector2(local.x * spriteRect.width / rect.width, local.y * spriteRect.height / rect.height);}Vector4 GetAdjustedBorders(Vector4 border, Rect rect){for (int axis = 0; axis <= 1; axis++){float combinedBorders = border[axis] + border[axis + 2];if (rect.size[axis] < combinedBorders && combinedBorders != 0){float borderScaleRatio = rect.size[axis] / combinedBorders;border[axis] *= borderScaleRatio;border[axis + 2] *= borderScaleRatio;}}return border;}#endregion}
}
其中要说明的    1、  是否参与绘制 _isShowUI  (只是接受检测,涉及到填充率, 在编辑器下编辑完多边形测试OK,就设置为false) 。   2、算法不涉及到  镂空精灵的算法,所以可以设置Sprite属性。

2、镂空精灵

镂空就是  透明的区域不接受检测,不透明区域接受检测。  透明不透明的指标自己定吧!

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Assertions.Must;namespace SGD
{/// <summary>/// 描述:/// author: sunguangdong/// </summary>[AddComponentMenu("SGD/UnregularButtonWithPixel ")][RequireComponent(typeof(Image))]public class UnregularButtonWithPixel : MonoBehaviour, IPointerClickHandler{/// <summary>/// Image组件/// </summary>private Image _image;/// <summary>/// 透明度临界值/// </summary>[Range(0.0f, 0.5f)]public float _Alpha;// 编辑器脚本 startvoid Reset(){_image = transform.GetComponent<Image>();}public void OnValidate(){MustExtensions.MustBeFalse(!_image , "UnregularButtonWithPixel 脚本的 Inspector 面板的赋值 不全!");}// 编辑器脚本 end public void Start(){//获取Image组件_image = transform.GetComponent<Image>();//设定透明度临界值_image.eventAlphaThreshold = _Alpha;}public void OnPointerClick(PointerEventData eventData){Debug.Log("点击到精灵");}}
}
Canvas 下的空对象上  添加这个组件  测试
提醒,  检测的开关还有  (这两种方式  都会受到  下面的开关影响!)

Unity 关于Spine不规则响应区域解决方法相关推荐

  1. 插入u盘计算机未响应,win7系统插入u盘死机怎么办|win7插入u盘无响应的解决方法...

    ‍‍ 最近有些win7旗舰版用户遇到u盘插入计算机后会出现未响应导致系统死机,虽然等一会儿就能恢复正常,但是每次插入u盘都要卡一下决对是有问题的.遇到在win7系统插入u盘死机怎么办呢?会出现插入u盘 ...

  2. 关于Qt Designer程序/UI文件打开未响应的解决方法

    关于Qt Designer程序/UI文件打开未响应的解决方法 参考文章: (1)关于Qt Designer程序/UI文件打开未响应的解决方法 (2)https://www.cnblogs.com/ys ...

  3. win10 mysql5.5无响应_Win10安装mysql5.5安装最后一步停住卡死未响应的解决方法

    在win10系统中安装了Mysql5.5,不过在配置到最后一步的时候,就会出现停止卡死未响应的现象,尝试修改了Mysql端口号和修改了Mysql服务名之后,都不能解决该问题,还使用管理员身份启动Mys ...

  4. dnf服务器未响应win7,win7dnf未响应怎么解决|分享win7系统dnf总是未响应的解决方法...

    收到反馈win7dnf未响应怎么解决|分享win7系统dnf总是未响应的解决方法,相信dnf的忠实用户们一定会遇到dnf未响应的问题吧,有些小伙伴们还是经常性的会遇到这种问题,就来求助小编给出解决方法 ...

  5. wdns服务器未响应,Win7系统​网络诊断提示DNS服务器未响应的解决方法

    Win7系统​网络诊断提示DNS服务器未响应的解决方法 昨天小编的朋友Win7系统​网络诊断提示DNS服务器未响应的解决方法说,她win7系统电脑在开机的过程中,怎么都连接不上网络了,并且出现dns服 ...

  6. 路由器wan口认证断开服务器无响应,路由器WAN口设置已断开(服务器无响应)的解决方法...

    越洋帮路由网原创:文章是关于"路由器WAN口设置已断开(服务器无响应)的解决方法"的相关知识分享,希望可以帮到大家. - 素材来源网络 编辑:小易. 路由器WAN口设置的地方显示: ...

  7. DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法

    DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法 参考文章: (1)DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法 (2)https://www.cnblogs.co ...

  8. Endnote 导入enw文件无响应及解决方法

    Endnote 导入enw文件无响应及解决方法 参考文章: (1)Endnote 导入enw文件无响应及解决方法 (2)https://www.cnblogs.com/shuaihe/p/114701 ...

  9. dns远程服务器未响应,dns服务器未响应的解决方法

    <dns服务器未响应的解决方法>由会员分享,可在线阅读,更多相关<dns服务器未响应的解决方法(3页珍藏版)>请在人人文库网上搜索. 1.dns服务器未响应的解决方法网络连接显 ...

最新文章

  1. Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数
  2. Android加载大图片(压缩)
  3. 高通android新建项目
  4. buu [BJDCTF 2nd]rsa1
  5. pythorch基本信息查询
  6. 为什么6lowpan 要有四个地址_大型监控网络系统如何规划ip地址
  7. 141.Linked List Cycle
  8. Upload-Labs(11-15)
  9. ae 地理坐标与投影坐标转换 [转]
  10. Android Studio 创建aar包与引用
  11. java网页内容不能复制_win7系统禁用Java小程序脚本网页内容复制不了的解决方法...
  12. 转载: 找不到MSVCR90.dll、Debug vs Release及cppLapack相关
  13. C#MessageBox 自动关闭窗口
  14. Bolt: Anonymous Payment Channels for Decentralized Currencies 学习笔记
  15. C# (1)点击菜单跳出新窗体,(2)在主窗体中切换子窗体(pannel控件的使用)
  16. 异常:java.lang.ArithmeticException
  17. SEM扫描电镜知识点扫盲,请收好
  18. Jenkins里的Crumb
  19. 什么是buffer?
  20. zabbix触发器通过钉钉发送警报

热门文章

  1. [转载]modbus通讯协议详解和几张modbus图解 力求通俗易懂
  2. java设计模式之—OO面向对象思维 Object Oriented(农场一头小母牛,每年生头小母牛,母牛5岁产母牛,20年上多少牛?)
  3. (gMLP)Pay Attention to MLPs
  4. 互联网的女性主义特征
  5. nms,soft nms算法理解
  6. 巧用 @JvmName 解决 Kotlin 函数签名冲突
  7. 干货 | 在线查你的个人数据有没有泄露
  8. 以下是一些提供技术专利申请模板的中文网站,供您参考
  9. 南京烽火星空——企业移动信息化的“大白”
  10. 「镁客·请讲」易瞳科技梁剑泓艾韬:未来MR会把VR和AR融合在一起