Unity 关于Spine不规则响应区域解决方法
起这个标题完全是为了区分于 《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;
![](/assets/blank.gif)
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}
}
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("点击到精灵");}}
}
![](/assets/blank.gif)
![](/assets/blank.gif)
![](/assets/blank.gif)
Unity 关于Spine不规则响应区域解决方法相关推荐
- 插入u盘计算机未响应,win7系统插入u盘死机怎么办|win7插入u盘无响应的解决方法...
最近有些win7旗舰版用户遇到u盘插入计算机后会出现未响应导致系统死机,虽然等一会儿就能恢复正常,但是每次插入u盘都要卡一下决对是有问题的.遇到在win7系统插入u盘死机怎么办呢?会出现插入u盘 ...
- 关于Qt Designer程序/UI文件打开未响应的解决方法
关于Qt Designer程序/UI文件打开未响应的解决方法 参考文章: (1)关于Qt Designer程序/UI文件打开未响应的解决方法 (2)https://www.cnblogs.com/ys ...
- win10 mysql5.5无响应_Win10安装mysql5.5安装最后一步停住卡死未响应的解决方法
在win10系统中安装了Mysql5.5,不过在配置到最后一步的时候,就会出现停止卡死未响应的现象,尝试修改了Mysql端口号和修改了Mysql服务名之后,都不能解决该问题,还使用管理员身份启动Mys ...
- dnf服务器未响应win7,win7dnf未响应怎么解决|分享win7系统dnf总是未响应的解决方法...
收到反馈win7dnf未响应怎么解决|分享win7系统dnf总是未响应的解决方法,相信dnf的忠实用户们一定会遇到dnf未响应的问题吧,有些小伙伴们还是经常性的会遇到这种问题,就来求助小编给出解决方法 ...
- wdns服务器未响应,Win7系统网络诊断提示DNS服务器未响应的解决方法
Win7系统网络诊断提示DNS服务器未响应的解决方法 昨天小编的朋友Win7系统网络诊断提示DNS服务器未响应的解决方法说,她win7系统电脑在开机的过程中,怎么都连接不上网络了,并且出现dns服 ...
- 路由器wan口认证断开服务器无响应,路由器WAN口设置已断开(服务器无响应)的解决方法...
越洋帮路由网原创:文章是关于"路由器WAN口设置已断开(服务器无响应)的解决方法"的相关知识分享,希望可以帮到大家. - 素材来源网络 编辑:小易. 路由器WAN口设置的地方显示: ...
- DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法
DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法 参考文章: (1)DEDECMS织梦后台更新网站栏目无反应一键更新无响应的解决方法 (2)https://www.cnblogs.co ...
- Endnote 导入enw文件无响应及解决方法
Endnote 导入enw文件无响应及解决方法 参考文章: (1)Endnote 导入enw文件无响应及解决方法 (2)https://www.cnblogs.com/shuaihe/p/114701 ...
- dns远程服务器未响应,dns服务器未响应的解决方法
<dns服务器未响应的解决方法>由会员分享,可在线阅读,更多相关<dns服务器未响应的解决方法(3页珍藏版)>请在人人文库网上搜索. 1.dns服务器未响应的解决方法网络连接显 ...
最新文章
- Python函数01/函数的初识/函数的定义/函数调用/函数的返回值/函数的参数
- Android加载大图片(压缩)
- 高通android新建项目
- buu [BJDCTF 2nd]rsa1
- pythorch基本信息查询
- 为什么6lowpan 要有四个地址_大型监控网络系统如何规划ip地址
- 141.Linked List Cycle
- Upload-Labs(11-15)
- ae 地理坐标与投影坐标转换 [转]
- Android Studio 创建aar包与引用
- java网页内容不能复制_win7系统禁用Java小程序脚本网页内容复制不了的解决方法...
- 转载: 找不到MSVCR90.dll、Debug vs Release及cppLapack相关
- C#MessageBox 自动关闭窗口
- Bolt: Anonymous Payment Channels for Decentralized Currencies 学习笔记
- C# (1)点击菜单跳出新窗体,(2)在主窗体中切换子窗体(pannel控件的使用)
- 异常:java.lang.ArithmeticException
- SEM扫描电镜知识点扫盲,请收好
- Jenkins里的Crumb
- 什么是buffer?
- zabbix触发器通过钉钉发送警报
热门文章
- [转载]modbus通讯协议详解和几张modbus图解 力求通俗易懂
- java设计模式之—OO面向对象思维 Object Oriented(农场一头小母牛,每年生头小母牛,母牛5岁产母牛,20年上多少牛?)
- (gMLP)Pay Attention to MLPs
- 互联网的女性主义特征
- nms,soft nms算法理解
- 巧用 @JvmName 解决 Kotlin 函数签名冲突
- 干货 | 在线查你的个人数据有没有泄露
- 以下是一些提供技术专利申请模板的中文网站,供您参考
- 南京烽火星空——企业移动信息化的“大白”
- 「镁客·请讲」易瞳科技梁剑泓艾韬:未来MR会把VR和AR融合在一起