Unity UGUI Selectable部分源码浅析

private readonly List<CanvasGroup> m_CanvasGroupCache = new List<CanvasGroup>();protected override void OnCanvasGroupChanged(){//判断父节点中是否允许交互var groupAllowInteraction = true;Transform t = transform;while (t != null){t.GetComponents(m_CanvasGroupCache);bool shouldBreak = false;for (var i = 0; i < m_CanvasGroupCache.Count; i++){//如果父节点中的canvasgroup不允许交互,那么断开循环,设置falseif (!m_CanvasGroupCache[i].interactable){groupAllowInteraction = false;shouldBreak = true;}// 如果此节点设置了“忽略父设置”,那么也直接断开if (m_CanvasGroupCache[i].ignoreParentGroups)shouldBreak = true;}if (shouldBreak)break;t = t.parent;}if (groupAllowInteraction != m_GroupsAllowInteraction){m_GroupsAllowInteraction = groupAllowInteraction;OnSetProperty();}}

在canvasGroup属性改变时调用OnCanvasGroupChanged

public virtual bool IsInteractable(){return m_GroupsAllowInteraction && m_Interactable;}

物体的可交互属性需要一起判断m_GroupsAllowInteraction 和 m_Interactable,即自身或父物体上的canvasGroup是否允许交互,以及自身是否允许交互

protected override void OnEnable(){base.OnEnable();if (s_IsDirty)RemoveInvalidSelectables();  //如果标记为脏,就从可选择物体数组中移除m_WillRemove = false;if (s_SelectableCount == s_Selectables.Length)   //如果可选择物体数组满了,则扩容两倍{Selectable[] temp = new Selectable[s_Selectables.Length * 2];Array.Copy(s_Selectables, temp, s_Selectables.Length);s_Selectables = temp;}s_Selectables[s_SelectableCount++] = this;isPointerDown = false;DoStateTransition(currentSelectionState, true);  //设置初始状态}
protected override void OnTransformParentChanged(){base.OnTransformParentChanged();// 如果父物体有改变,需要判断自身和父物体的canvasGroup属性是否有改变OnCanvasGroupChanged();}
private void OnSetProperty(){
#if UNITY_EDITORif (!Application.isPlaying)DoStateTransition(currentSelectionState, true);else
#endifDoStateTransition(currentSelectionState, false);}

设置状态属性,如果是Editor模式,如果正在运行,那么立即改变,没有过渡,如果非Editor模式,那么有过渡

        protected override void OnDisable(){m_WillRemove = true;s_IsDirty = true;InstantClearState();  //重置各种状态base.OnDisable();}

取消激活时,将自身标记为脏

private static void RemoveInvalidSelectables(){for (int i = s_SelectableCount - 1; i >= 0; --i){// Swap last element in array with element to be removedif (s_Selectables[i] == null || s_Selectables[i].m_WillRemove)s_Selectables[i] = s_Selectables[--s_SelectableCount];}s_IsDirty = false;}

将元素从可选择物体数组列表中移除,同时标记为脏

protected SelectionState currentSelectionState{get{if (!IsInteractable())return SelectionState.Disabled;if (isPointerDown)return SelectionState.Pressed;if (hasSelection)return SelectionState.Selected;if (isPointerInside)return SelectionState.Highlighted;return SelectionState.Normal;}}

获取当前的选择状态

protected virtual void InstantClearState(){string triggerName = m_AnimationTriggers.normalTrigger;isPointerInside = false;isPointerDown = false;hasSelection = false;switch (m_Transition){case Transition.ColorTint:StartColorTween(Color.white, true);break;case Transition.SpriteSwap:DoSpriteSwap(null);break;case Transition.Animation:TriggerAnimation(triggerName);break;}}

即时清除状态,将Selectable的状态还原

protected virtual void DoStateTransition(SelectionState state, bool instant){if (!gameObject.activeInHierarchy)return;Color tintColor;Sprite transitionSprite;string triggerName;switch (state){case SelectionState.Normal:tintColor = m_Colors.normalColor;transitionSprite = null;triggerName = m_AnimationTriggers.normalTrigger;break;case SelectionState.Highlighted:tintColor = m_Colors.highlightedColor;transitionSprite = m_SpriteState.highlightedSprite;triggerName = m_AnimationTriggers.highlightedTrigger;break;case SelectionState.Pressed:tintColor = m_Colors.pressedColor;transitionSprite = m_SpriteState.pressedSprite;triggerName = m_AnimationTriggers.pressedTrigger;break;case SelectionState.Selected:tintColor = m_Colors.selectedColor;transitionSprite = m_SpriteState.selectedSprite;triggerName = m_AnimationTriggers.selectedTrigger;break;case SelectionState.Disabled:tintColor = m_Colors.disabledColor;transitionSprite = m_SpriteState.disabledSprite;triggerName = m_AnimationTriggers.disabledTrigger;break;default:tintColor = Color.black;transitionSprite = null;triggerName = string.Empty;break;}switch (m_Transition){case Transition.ColorTint:StartColorTween(tintColor * m_Colors.colorMultiplier, instant);break;case Transition.SpriteSwap:DoSpriteSwap(transitionSprite);break;case Transition.Animation:TriggerAnimation(triggerName);break;}}

状态切换方法

public Selectable FindSelectable(Vector3 dir){dir = dir.normalized;Vector3 localDir = Quaternion.Inverse(transform.rotation) * dir;Vector3 pos = transform.TransformPoint(GetPointOnRectEdge(transform as RectTransform, localDir));float maxScore = Mathf.NegativeInfinity;Selectable bestPick = null;if (s_IsDirty)RemoveInvalidSelectables();for (int i = 0; i < s_SelectableCount; ++i){Selectable sel = s_Selectables[i];if (sel == this)continue;if (!sel.IsInteractable() || sel.navigation.mode == Navigation.Mode.None)continue;#if UNITY_EDITOR除了运行时使用,FindSelectable被自定义编辑器用来在不同的可选项之间绘制箭头。对于场景视图摄像机,只考虑同一阶段的可选对象。if (Camera.current != null && !UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(sel.gameObject, Camera.current))continue;
#endifvar selRect = sel.transform as RectTransform;Vector3 selCenter = selRect != null ? (Vector3)selRect.rect.center : Vector3.zero;Vector3 myVector = sel.transform.TransformPoint(selCenter) - pos;//值就是沿着这个方向的距离float dot = Vector3.Dot(dir, myVector);//跳过方向错误或距离为0的元素这也确保了下面的评分公式不会有除数为零的误差if (dot <= 0)continue;// This scoring function has two priorities:// - Score higher for positions that are closer.// - Score higher for positions that are located in the right direction.// This scoring function combines both of these criteria.// It can be seen as this://   Dot (dir, myVector.normalized) / myVector.magnitude// The first part equals 1 if the direction of myVector is the same as dir, and 0 if it's orthogonal.// The second part scores lower the greater the distance is by dividing by the distance.// The formula below is equivalent but more optimized.//// If a given score is chosen, the positions that evaluate to that score will form a circle// that touches pos and whose center is located along dir. A way to visualize the resulting functionality is this:// From the position pos, blow up a circular balloon so it grows in the direction of dir.// The first Selectable whose center the circular balloon touches is the one that's chosen.float score = dot / myVector.sqrMagnitude;if (score > maxScore){maxScore = score;bestPick = sel;}}return bestPick;}

此方法用来寻找临近的可选择对象

public virtual void OnMove(AxisEventData eventData){switch (eventData.moveDir){case MoveDirection.Right:Navigate(eventData, FindSelectableOnRight());break;case MoveDirection.Up:Navigate(eventData, FindSelectableOnUp());break;case MoveDirection.Left:Navigate(eventData, FindSelectableOnLeft());break;case MoveDirection.Down:Navigate(eventData, FindSelectableOnDown());break;}}

当焦点移动到另一个可选择对象时,调用此方法,确定选择的对象

protected bool IsHighlighted(){if (!IsActive() || !IsInteractable())return false;return isPointerInside && !isPointerDown && !hasSelection;}

判断是否高亮,即鼠标移上去的时候,需判断三个状态,鼠标在UI范围内,没有点下,没有选择

protected bool IsPressed(){if (!IsActive() || !IsInteractable())return false;return isPointerDown;}

是否按下

private void EvaluateAndTransitionToSelectionState(){if (!IsActive() || !IsInteractable())return;DoStateTransition(currentSelectionState, false);}

执行状态改变

public virtual void OnPointerDown(PointerEventData eventData){if (eventData.button != PointerEventData.InputButton.Left)  //如果不是鼠标左键,returnreturn;//如果可以交互,导航模式不为空,且EventSystem存在,那么设置EventSystem的当前选择物体if (IsInteractable() && navigation.mode != Navigation.Mode.None && EventSystem.current != null)EventSystem.current.SetSelectedGameObject(gameObject, eventData);isPointerDown = true;EvaluateAndTransitionToSelectionState();}

鼠标按下回调

public virtual void OnPointerUp(PointerEventData eventData){if (eventData.button != PointerEventData.InputButton.Left)return;isPointerDown = false;EvaluateAndTransitionToSelectionState();}

鼠标抬起回调

public virtual void OnPointerEnter(PointerEventData eventData){isPointerInside = true;EvaluateAndTransitionToSelectionState();}

鼠标进入回调

public virtual void OnPointerExit(PointerEventData eventData){isPointerInside = false;EvaluateAndTransitionToSelectionState();}

鼠标离开回调

public virtual void OnSelect(BaseEventData eventData){hasSelection = true;EvaluateAndTransitionToSelectionState();}

选择回调

public virtual void OnDeselect(BaseEventData eventData){hasSelection = false;EvaluateAndTransitionToSelectionState();}

取消选择回调

public virtual void Select(){if (EventSystem.current == null || EventSystem.current.alreadySelecting)return;EventSystem.current.SetSelectedGameObject(gameObject);}

直接确定EventSystem的选择物体

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664369.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

互联网电商平台资金结算的合规处理方案是怎样的?

主要用于电商平台&#xff0c;对电商平台进行流量变现&#xff0c;并对其交易资金进行分账&#xff0c;来达到平台方获取盈利的目的。具体分为二大部分&#xff1a;第一部分&#xff0c;建立银行虚拟账户体系&#xff0c;开通电商平台店铺对应的银行虛拟账户账户&#xff0c;并…

一番赏盲盒小程序系统开发,提高商业价值的新模式

在我国&#xff0c;盲盒市场非常火爆&#xff0c;同时&#xff0c;作为经典玩法的一番赏也同样受到了大众的喜爱。一番赏中会不定时推出不同IP的系列赏品&#xff0c;用户根据概率在赏箱内进行抽赏。 在互联网的发展下&#xff0c;也给一番赏的发展创造了新的机遇。线下市场也…

C#拆分字符串,正则表达式Regex.Split 方法 vs String.Split 方法

目录 一、使用的方法 1.使用Split(String, String)方法 2.String.Split 方法 二、源代码 1.源码 2.生成效果 使用正则表达式可以拆分指定的字符串。同样地&#xff0c;使用字符串对象的Split方法也可以实现此功能。使用字符串对象的Split方法可以根据用户选择的拆分条件&…

jsp自助点餐管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 自助点餐管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

2024年【A特种设备相关管理(电梯)】考试总结及A特种设备相关管理(电梯)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 A特种设备相关管理&#xff08;电梯&#xff09;考试总结是安全生产模拟考试一点通生成的&#xff0c;A特种设备相关管理&#xff08;电梯&#xff09;证模拟考试题库是根据A特种设备相关管理&#xff08;电梯&#x…

【Web】CORS概念性描述

简言 描述CORS。 CORS CORS&#xff08;Cross-Origin Resource Sharing&#xff0c;跨源资源共享&#xff09; 是一个系统&#xff0c;它由一系列传输的 HTTP 标头组成&#xff0c;这些 HTTP 标头决定浏览器是否阻止前端 JavaScript 代码获取跨源请求的响应。 同源安全策略默…

Android Studio非UI线程修改控件——定时器软件

目录 一、UI界面设计 1、UI样式 2、XML代码 二、功能编写 1、定义 2、实现方法 3、功能实现 一、UI界面设计 1、UI样式 2、XML代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android…

LabVIEW叶片厚度远程监控

LabVIEW叶片厚度远程监控 随着网络技术的高速发展&#xff0c;远程监控广泛应用在各个领域。本文介绍了一种基于LabVIEW的植物叶片厚度远程监控系统&#xff0c;旨在实现对植物生长状况的精准监测和分析。 该系统利用LabVIEW软件开发工具&#xff0c;通过TCP网络协议实现数据…

Scrum敏捷开发企业培训-敏捷研发管理

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。 这是一个两天的实训课程&#xff0c;面向研发管理者、项目经理、产品经理、研发团队等&#xff0c;旨在帮助学员全面系统地学习Scrum和敏捷开发, 帮助企业快速启动敏…

11:按键

按键 1、按键的相关知识2、独立按键3、CPU如何处理按健4、编程测试&#xff08;用LED1作为指示&#xff09;5 、编程测试&#xff08;用8个LED作为指示&#xff09; 1、按键的相关知识 分为独立按键和矩阵按键 2、独立按键 由图得独立按键右边接地&#xff0c;左边独立连接到…

断电保持霍尔传感器

断电保持霍尔传感器的工作原理 断电保持霍尔传感器是一种利用变压器或共振电路的检测元件&#xff0c;通过检测物体与探头之间的物理距离控制电路的开关状态&#xff0c;从而实现对物体位置和状态的监测。该开关可以通过调试和校准以满足不同场合的要求。 断电保持霍尔传感器控…

jsp游戏网上商城系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 游戏网上商城系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

算法练习02——双指针

目录 283. 移动零11. 盛最多水的容器15. 三数之和42. 接雨水*(暴力&#xff0c;双指针优化暴力&#xff0c;单调栈)27. 移除元素344. 反转字符串54. 替换数字&#xff08;第八期模拟笔试&#xff09;151. 反转字符串中的单词206. 反转链表19. 删除链表的倒数第 N 个结点.面试题…

Electron开发的十大神级产品,vscode、atom、skype、figma等

Hi、我是贝格前端工场&#xff0c;今天分享一下基于Electron的十大著名产品&#xff0c;欢迎友友们补充。 Visual Studio Code 这是一款由微软开发的轻量级代码编辑器&#xff0c;它提供了丰富的功能和插件生态系统&#xff0c;支持多种编程语言和开发工具。Visual Studio Cod…

SpringBoot整理-安全(Spring Security)

在 Spring Boot 应用中实现安全性通常涉及到集成 Spring Security 框架。Spring Security 是一个功能强大且高度可定制的认证和访问控制框架,非常适合用于保护 Spring Boot 应用。 核心特性 认证: 认证是确认某个实体的身份,Spring Security 支持多种认证机制,如表单登录、L…

C++ | 部分和函数partial_sum的使用技巧

如果你需要处理一个数组的前缀和&#xff0c;或者数组中某一段元素的前缀和&#xff0c;你会怎么做呢&#xff1f; partial_sum函数是STL中的函数&#xff0c;用于计算范围的部分和&#xff0c;并从结果开始分配范围中的每个元素&#xff0c;range[first,last)中相应元素的部分…

爬虫工作量由小到大的思维转变---<第四十章 Scrapy Redis 的Queue问题>

前言: 对于scrapy-redis有一个特殊的地方,就是队列的进出关系,因为我们的url请求会从各个任务统一归纳到redis里面,因此,如何解决下载请求这个问题,也是scrapy-redis的一个关键点!!! 正文: 先讲解代码,讲它自带的3个队列方式; 然后,再讲讲如何自定义队列... 原文翻译: 1.Bas…

<网络安全>《14 日志审计系统》

1 概念 日志审计系统是用于全面收集企业IT系统中常见的安全设备、网络设备、数据库、服务器、应用系统、主机等设备所产生的日志&#xff08;包括运行、告警、操作、消息、状态等&#xff09;并进行存储、监控、审计、分析、报警、响应和报告的系统。 日志审计系统是一种用于…

投资更好的管理会计系统,探索全面预算管理的奥秘

目前&#xff0c;我国财政体制正值如火如荼的调整阶段&#xff0c;各级政府和部门响应国家号召&#xff0c;旨在加强管理会计系统建设&#xff0c;制定具有先导性和科学性的现代化全面预算管理制度&#xff0c;从而将我国财力推向一个新高度。其中&#xff0c;基于服务或产品的…

工程师 - headless模式

headless 英文释义&#xff1a; 在没有用户界面的情况下运行&#xff1b;具体地说&#xff0c;在没有显示器、键盘和鼠标的情况下运行。 Running without a user interface; specifically, running without a monitor, keyboard, and mouse. 说明 所谓的“无头系统”&#x…