[HideInInspector] [Obsolete ]

本文详细介绍了Unity中三种重要的特性:[HideInInspector]用于隐藏编辑器中的公共变量;[Obsolete]标记过时的方法或属性;sealed关键字用于阻止类的继承或方法的重写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 [HideInInspector]

看代码时看到了这个 [HideInInspector]

由于在unity中,public的变量是公开的,在编辑器中便可以修改,加上这个之后在inspector面板就不可见了,只能由代码来修改。


二、[Obsolete]

哇,听说一般在逼格比较高的程序员代码中常见此特性手法,他们因为某些原因不详注释掉原有的代码,用[Obsolete xxxxxxx]


三、sealed

1,当sealed用来修饰类时,可防止该类被其他类继承。

例如 

sealed Class A
{
}
Class B:A
{
}
这会报错。

2,当sealed用来修饰方法和属性时,能够允许类从基类继承,并防止它们重写特定的虚方法或虚属性。

例如

Class A
{
	public virtual void  A1(){}
}
Class B : A
{
	public sealed override  void A1(){}
}
Class C : A
{
	public sealed override  void A1(){}       //报错

}





using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; public class DialogueManager : MonoBehaviour { public Image backgroundPanel; public Image avatarImage; public Text nameText; public Text messageText; public Transform optionsPanel; public Button continueButton; public GameObject optionButtonPrefab; private Dictionary<int, DialogueNode> nodeDict = new Dictionary<int, DialogueNode>(); private DialogueNode currentNode; private bool isTyping = false; private string fullMessage; private string currentDialoguePath; public delegate void DialogueEvent(int nodeId); public event DialogueEvent OnNodeStart; public event DialogueEvent OnDialogueEnd; void Start() { continueButton.onClick.RemoveAllListeners(); continueButton.onClick.AddListener(OnContinueClicked); if (continueButton == null) { Debug.LogError("继续按钮未绑定!"); } } public void OpenDialogue(string dialoguePath, int startId = 1) { currentDialoguePath = dialoguePath; LoadDialogue(dialoguePath); gameObject.SetActive(true); StartCoroutine(StartDialogueRoutine(startId)); } IEnumerator StartDialogueRoutine(int startId) { yield return new WaitForEndOfFrame(); // 确保UI已激活 StartDialogueNode(startId); } void LoadDialogue(string path) { nodeDict.Clear(); TextAsset jsonFile = Resources.Load<TextAsset>(path); if (jsonFile == null) { Debug.LogError("对话文件未找到: " + path); return; } DialogueTree tree = JsonUtility.FromJson<DialogueTree>( "{ \"nodes\": " + jsonFile.text + "}" ); foreach (var node in tree.nodes) { nodeDict.Add(node.id, node); } } void StartDialogueNode(int nodeId) { if (!nodeDict.ContainsKey(nodeId)) { EndDialogue(); return; } currentNode = nodeDict[nodeId]; OnNodeStart?.Invoke(nodeId); UpdateUI(); } void UpdateUI() { // 清空选项区域 if (optionsPanel != null) { for (int i = optionsPanel.childCount - 1; i >= 0; i--) { Destroy(optionsPanel.GetChild(i).gameObject); } } foreach (Transform child in optionsPanel) { Destroy(child.gameObject); } nameText.text = string.IsNullOrEmpty(currentNode.name) ? "" : currentNode.name; fullMessage = currentNode.msg; if (!string.IsNullOrEmpty(currentNode.avatar)) { Sprite avatarSprite = Resources.Load<Sprite>(currentNode.avatar); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; avatarImage.gameObject.SetActive(true); } else { Debug.LogWarning("头像未找到: " + currentNode.avatar); avatarImage.gameObject.SetActive(false); } } else { avatarImage.gameObject.SetActive(false); } StartCoroutine(TypewriterEffect()); if (currentNode.opts != null && currentNode.opts.Length > 0) { continueButton.gameObject.SetActive(false); for (int i = 0; i < currentNode.opts.Length; i++) { if (currentNode.opts[i] != null) // 空检查 { CreateOptionButton(currentNode.opts[i]); } } } else if (currentNode.nextid > 0) { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "继续"; } else { continueButton.gameObject.SetActive(true); continueButton.GetComponentInChildren<Text>().text = "结束"; } } IEnumerator TypewriterEffect() { isTyping = true; messageText.text = ""; foreach (char c in fullMessage.ToCharArray()) { messageText.text += c; yield return new WaitForSeconds(0.03f); // 调整显示速度 } isTyping = false; } void CreateOptionButton(DialogueOption option) { if (optionButtonPrefab == null) { Debug.LogError("选项按钮预制体未分配!"); return; } GameObject buttonObj = Instantiate(optionButtonPrefab, optionsPanel); buttonObj.SetActive(true); Button primaryButton = buttonObj.GetComponentInChildren<Button>(true); Text primaryText = buttonObj.GetComponentInChildren<Text>(true); primaryText.text = option.msg; primaryButton.onClick.RemoveAllListeners(); primaryButton.onClick.AddListener(() => HandleOptionSelection(option)); } void HandleOptionSelection(DialogueOption option) { int targetId = option.toId != 0 ? option.toId : option.nextid; if (nodeDict.ContainsKey(targetId)) { StartDialogueNode(targetId); } else if (targetId > 0) { Debug.LogWarning($"目标节点不存在: {targetId}"); EndDialogue(); } else { EndDialogue(); // 结束对话 } } void OnContinueClicked() { if (currentNode == null) // 添加空值检查 { CloseDialogue(); return; } if (isTyping) { messageText.text = fullMessage; isTyping = false; return; } if (currentNode.nextid > 0 && nodeDict.ContainsKey(currentNode.nextid)) { StartDialogueNode(currentNode.nextid); } else { EndDialogue(); } } public void CloseDialogue() { continueButton.onClick.RemoveAllListeners(); foreach (Transform child in optionsPanel) { Button btn = child.GetComponent<Button>(); if (btn != null) btn.onClick.RemoveAllListeners(); } gameObject.SetActive(false); OnDialogueEnd?.Invoke(currentNode != null ? currentNode.id : -1); } void EndDialogue() { CloseDialogue(); OnDialogueEnd?.Invoke(currentNode.id); Debug.Log("对话结束"); } public void ChangeBackground(string bgPath) { Sprite bgSprite = Resources.Load<Sprite>(bgPath); if (bgSprite != null) { backgroundPanel.sprite = bgSprite; } else { Debug.LogWarning("背景未找到: " + bgPath); } } public void ChangeAvatar(string avatarPath) { Sprite avatarSprite = Resources.Load<Sprite>(avatarPath); if (avatarSprite != null) { avatarImage.sprite = avatarSprite; } else { Debug.LogWarning("立绘未找到: " + avatarPath); } } } using System; using UnityEngine; using UnityEngine.Serialization; namespace UnityEngine.EventSystems { [AddComponentMenu("Event/Standalone Input Module")] /// <summary> /// A BaseInputModule designed for mouse / keyboard / controller input. /// </summary> /// <remarks> /// Input module for working with, mouse, keyboard, or controller. /// </remarks> public class StandaloneInputModule : PointerInputModule { private float m_PrevActionTime; private Vector2 m_LastMoveVector; private int m_ConsecutiveMoveCount = 0; private Vector2 m_LastMousePosition; private Vector2 m_MousePosition; private GameObject m_CurrentFocusedGameObject; private PointerEventData m_InputPointerEvent; private const float doubleClickTime = 0.3f; protected StandaloneInputModule() { } [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)] public enum InputMode { Mouse, Buttons } [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)] public InputMode inputMode { get { return InputMode.Mouse; } } [SerializeField] private string m_HorizontalAxis = "Horizontal"; /// <summary> /// Name of the vertical axis for movement (if axis events are used). /// </summary> [SerializeField] private string m_VerticalAxis = "Vertical"; /// <summary> /// Name of the submit button. /// </summary> [SerializeField] private string m_SubmitButton = "Submit"; /// <summary> /// Name of the submit button. /// </summary> [SerializeField] private string m_CancelButton = "Cancel"; [SerializeField] private float m_InputActionsPerSecond = 10; [SerializeField] private float m_RepeatDelay = 0.5f; [SerializeField] [FormerlySerializedAs("m_AllowActivationOnMobileDevice")] [HideInInspector] private bool m_ForceModuleActive; [Obsolete("allowActivationOnMobileDevice has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")] public bool allowActivationOnMobileDevice { get { return m_ForceModuleActive; } set { m_ForceModuleActive = value; } } /// <summary> /// Force this module to be active. /// </summary> /// <remarks> /// If there is no module active with higher priority (ordered in the inspector) this module will be forced active even if valid enabling conditions are not met. /// </remarks> [Obsolete("forceModuleActive has been deprecated. There is no need to force the module awake as StandaloneInputModule works for all platforms")] public bool forceModuleActive { get { return m_ForceModuleActive; } set { m_ForceModuleActive = value; } } /// <summary> /// Number of keyboard / controller inputs allowed per second. /// </summary> public float inputActionsPerSecond { get { return m_InputActionsPerSecond; } set { m_InputActionsPerSecond = value; } } /// <summary> /// Delay in seconds before the input actions per second repeat rate takes effect. /// </summary> /// <remarks> /// If the same direction is sustained, the inputActionsPerSecond property can be used to control the rate at which events are fired. However, it can be desirable that the first repetition is delayed, so the user doesn't get repeated actions by accident. /// </remarks> public float repeatDelay { get { return m_RepeatDelay; } set { m_RepeatDelay = value; } } /// <summary> /// Name of the horizontal axis for movement (if axis events are used). /// </summary> public string horizontalAxis { get { return m_HorizontalAxis; } set { m_HorizontalAxis = value; } } /// <summary> /// Name of the vertical axis for movement (if axis events are used). /// </summary> public string verticalAxis { get { return m_VerticalAxis; } set { m_VerticalAxis = value; } } /// <summary> /// Maximum number of input events handled per second. /// </summary> public string submitButton { get { return m_SubmitButton; } set { m_SubmitButton = value; } } /// <summary> /// Input manager name for the 'cancel' button. /// </summary> public string cancelButton { get { return m_CancelButton; } set { m_CancelButton = value; } } private bool ShouldIgnoreEventsOnNoFocus() { #if UNITY_EDITOR return !UnityEditor.EditorApplication.isRemoteConnected; #else return true; #endif } public override void UpdateModule() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) { if (m_InputPointerEvent != null && m_InputPointerEvent.pointerDrag != null && m_InputPointerEvent.dragging) { ReleaseMouse(m_InputPointerEvent, m_InputPointerEvent.pointerCurrentRaycast.gameObject); } m_InputPointerEvent = null; return; } m_LastMousePosition = m_MousePosition; m_MousePosition = input.mousePosition; } private void ReleaseMouse(PointerEventData pointerEvent, GameObject currentOverGo) { ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); var pointerClickHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // PointerClick and Drop events if (pointerEvent.pointerClick == pointerClickHandler && pointerEvent.eligibleForClick) { ExecuteEvents.Execute(pointerEvent.pointerClick, pointerEvent, ExecuteEvents.pointerClickHandler); } if (pointerEvent.pointerDrag != null && pointerEvent.dragging) { ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler); } pointerEvent.eligibleForClick = false; pointerEvent.pointerPress = null; pointerEvent.rawPointerPress = null; pointerEvent.pointerClick = null; if (pointerEvent.pointerDrag != null && pointerEvent.dragging) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler); pointerEvent.dragging = false; pointerEvent.pointerDrag = null; // redo pointer enter / exit to refresh state // so that if we moused over something that ignored it before // due to having pressed on something else // it now gets it. if (currentOverGo != pointerEvent.pointerEnter) { HandlePointerExitAndEnter(pointerEvent, null); HandlePointerExitAndEnter(pointerEvent, currentOverGo); } m_InputPointerEvent = pointerEvent; } public override bool ShouldActivateModule() { if (!base.ShouldActivateModule()) return false; var shouldActivate = m_ForceModuleActive; shouldActivate |= input.GetButtonDown(m_SubmitButton); shouldActivate |= input.GetButtonDown(m_CancelButton); shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_HorizontalAxis), 0.0f); shouldActivate |= !Mathf.Approximately(input.GetAxisRaw(m_VerticalAxis), 0.0f); shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f; shouldActivate |= input.GetMouseButtonDown(0); if (input.touchCount > 0) shouldActivate = true; return shouldActivate; } /// <summary> /// See BaseInputModule. /// </summary> public override void ActivateModule() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) return; base.ActivateModule(); m_MousePosition = input.mousePosition; m_LastMousePosition = input.mousePosition; var toSelect = eventSystem.currentSelectedGameObject; if (toSelect == null) toSelect = eventSystem.firstSelectedGameObject; eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData()); } /// <summary> /// See BaseInputModule. /// </summary> public override void DeactivateModule() { base.DeactivateModule(); ClearSelection(); } public override void Process() { if (!eventSystem.isFocused && ShouldIgnoreEventsOnNoFocus()) return; bool usedEvent = SendUpdateEventToSelectedObject(); // case 1004066 - touch / mouse events should be processed before navigation events in case // they change the current selected gameobject and the submit button is a touch / mouse button. // touch needs to take precedence because of the mouse emulation layer if (!ProcessTouchEvents() && input.mousePresent) ProcessMouseEvent(); if (eventSystem.sendNavigationEvents) { if (!usedEvent) usedEvent |= SendMoveEventToSelectedObject(); if (!usedEvent) SendSubmitEventToSelectedObject(); } } private bool ProcessTouchEvents() { for (int i = 0; i < input.touchCount; ++i) { Touch touch = input.GetTouch(i); if (touch.type == TouchType.Indirect) continue; bool released; bool pressed; var pointer = GetTouchPointerEventData(touch, out pressed, out released); ProcessTouchPress(pointer, pressed, released); if (!released) { ProcessMove(pointer); ProcessDrag(pointer); } else RemovePointerData(pointer); } return input.touchCount > 0; } /// <summary> /// This method is called by Unity whenever a touch event is processed. Override this method with a custom implementation to process touch events yourself. /// </summary> /// <param name="pointerEvent">Event data relating to the touch event, such as position and ID to be passed to the touch event destination object.</param> /// <param name="pressed">This is true for the first frame of a touch event, and false thereafter. This can therefore be used to determine the instant a touch event occurred.</param> /// <param name="released">This is true only for the last frame of a touch event.</param> /// <remarks> /// This method can be overridden in derived classes to change how touch press events are handled. /// </remarks> protected void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released) { var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject; // PointerDown notification if (pressed) { pointerEvent.eligibleForClick = true; pointerEvent.delta = Vector2.zero; pointerEvent.dragging = false; pointerEvent.useDragThreshold = true; pointerEvent.pressPosition = pointerEvent.position; pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast; DeselectIfSelectionChanged(currentOverGo, pointerEvent); if (pointerEvent.pointerEnter != currentOverGo) { // send a pointer enter to the touched element if it isn't the one to select... HandlePointerExitAndEnter(pointerEvent, currentOverGo); pointerEvent.pointerEnter = currentOverGo; } var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime; if (resetDiffTime >= doubleClickTime) { pointerEvent.clickCount = 0; } // search for the control that will receive the press // if we can't find a press handler set the press // handler to be what would receive a click. var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler); var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // didnt find a press handler... search for a click handler if (newPressed == null) newPressed = newClick; // Debug.Log("Pressed: " + newPressed); float time = Time.unscaledTime; if (newPressed == pointerEvent.lastPress) { var diffTime = time - pointerEvent.clickTime; if (diffTime < doubleClickTime) ++pointerEvent.clickCount; else pointerEvent.clickCount = 1; pointerEvent.clickTime = time; } else { pointerEvent.clickCount = 1; } pointerEvent.pointerPress = newPressed; pointerEvent.rawPointerPress = currentOverGo; pointerEvent.pointerClick = newClick; pointerEvent.clickTime = time; // Save the drag handler as well pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo); if (pointerEvent.pointerDrag != null) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag); } // PointerUp notification if (released) { // Debug.Log("Executing pressup on: " + pointer.pointerPress); ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler); // Debug.Log("KeyCode: " + pointer.eventData.keyCode); // see if we mouse up on the same element that we clicked on... var pointerClickHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // PointerClick and Drop events if (pointerEvent.pointerClick == pointerClickHandler && pointerEvent.eligibleForClick) { ExecuteEvents.Execute(pointerEvent.pointerClick, pointerEvent, ExecuteEvents.pointerClickHandler); } if (pointerEvent.pointerDrag != null && pointerEvent.dragging) { ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler); } pointerEvent.eligibleForClick = false; pointerEvent.pointerPress = null; pointerEvent.rawPointerPress = null; pointerEvent.pointerClick = null; if (pointerEvent.pointerDrag != null && pointerEvent.dragging) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler); pointerEvent.dragging = false; pointerEvent.pointerDrag = null; // send exit events as we need to simulate this on touch up on touch device ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler); pointerEvent.pointerEnter = null; } m_InputPointerEvent = pointerEvent; } /// <summary> /// Calculate and send a submit event to the current selected object. /// </summary> /// <returns>If the submit event was used by the selected object.</returns> protected bool SendSubmitEventToSelectedObject() { if (eventSystem.currentSelectedGameObject == null) return false; var data = GetBaseEventData(); if (input.GetButtonDown(m_SubmitButton)) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler); if (input.GetButtonDown(m_CancelButton)) ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler); return data.used; } private Vector2 GetRawMoveVector() { Vector2 move = Vector2.zero; move.x = input.GetAxisRaw(m_HorizontalAxis); move.y = input.GetAxisRaw(m_VerticalAxis); if (input.GetButtonDown(m_HorizontalAxis)) { if (move.x < 0) move.x = -1f; if (move.x > 0) move.x = 1f; } if (input.GetButtonDown(m_VerticalAxis)) { if (move.y < 0) move.y = -1f; if (move.y > 0) move.y = 1f; } return move; } /// <summary> /// Calculate and send a move event to the current selected object. /// </summary> /// <returns>If the move event was used by the selected object.</returns> protected bool SendMoveEventToSelectedObject() { float time = Time.unscaledTime; Vector2 movement = GetRawMoveVector(); if (Mathf.Approximately(movement.x, 0f) && Mathf.Approximately(movement.y, 0f)) { m_ConsecutiveMoveCount = 0; return false; } bool similarDir = (Vector2.Dot(movement, m_LastMoveVector) > 0); // If direction didn't change at least 90 degrees, wait for delay before allowing consequtive event. if (similarDir && m_ConsecutiveMoveCount == 1) { if (time <= m_PrevActionTime + m_RepeatDelay) return false; } // If direction changed at least 90 degree, or we already had the delay, repeat at repeat rate. else { if (time <= m_PrevActionTime + 1f / m_InputActionsPerSecond) return false; } var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f); if (axisEventData.moveDir != MoveDirection.None) { ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler); if (!similarDir) m_ConsecutiveMoveCount = 0; m_ConsecutiveMoveCount++; m_PrevActionTime = time; m_LastMoveVector = movement; } else { m_ConsecutiveMoveCount = 0; } return axisEventData.used; } protected void ProcessMouseEvent() { ProcessMouseEvent(0); } [Obsolete("This method is no longer checked, overriding it with return true does nothing!")] protected virtual bool ForceAutoSelect() { return false; } /// <summary> /// Process all mouse events. /// </summary> protected void ProcessMouseEvent(int id) { var mouseData = GetMousePointerEventData(id); var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData; m_CurrentFocusedGameObject = leftButtonData.buttonData.pointerCurrentRaycast.gameObject; // Process the first mouse button fully ProcessMousePress(leftButtonData); ProcessMove(leftButtonData.buttonData); ProcessDrag(leftButtonData.buttonData); // Now process right / middle clicks ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData); ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData); ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData); ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData); if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f)) { var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject); ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler); } } protected bool SendUpdateEventToSelectedObject() { if (eventSystem.currentSelectedGameObject == null) return false; var data = GetBaseEventData(); ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler); return data.used; } /// <summary> /// Calculate and process any mouse button state changes. /// </summary> protected void ProcessMousePress(MouseButtonEventData data) { var pointerEvent = data.buttonData; var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject; // PointerDown notification if (data.PressedThisFrame()) { pointerEvent.eligibleForClick = true; pointerEvent.delta = Vector2.zero; pointerEvent.dragging = false; pointerEvent.useDragThreshold = true; pointerEvent.pressPosition = pointerEvent.position; pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast; DeselectIfSelectionChanged(currentOverGo, pointerEvent); var resetDiffTime = Time.unscaledTime - pointerEvent.clickTime; if (resetDiffTime >= doubleClickTime) { pointerEvent.clickCount = 0; } // search for the control that will receive the press // if we can't find a press handler set the press // handler to be what would receive a click. var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler); var newClick = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo); // didnt find a press handler... search for a click handler if (newPressed == null) newPressed = newClick; // Debug.Log("Pressed: " + newPressed); float time = Time.unscaledTime; if (newPressed == pointerEvent.lastPress) { var diffTime = time - pointerEvent.clickTime; if (diffTime < doubleClickTime) ++pointerEvent.clickCount; else pointerEvent.clickCount = 1; pointerEvent.clickTime = time; } else { pointerEvent.clickCount = 1; } pointerEvent.pointerPress = newPressed; pointerEvent.rawPointerPress = currentOverGo; pointerEvent.pointerClick = newClick; pointerEvent.clickTime = time; // Save the drag handler as well pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo); if (pointerEvent.pointerDrag != null) ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag); m_InputPointerEvent = pointerEvent; } // PointerUp notification if (data.ReleasedThisFrame()) { ReleaseMouse(pointerEvent, currentOverGo); } } protected GameObject GetCurrentFocusedGameObject() { return m_CurrentFocusedGameObject; } } } [ { "id":1, "msg":"帝帝帝大王正指挥瓦多迪建造'苹果能量塔',突然发现核心能源——星光苹果被偷。", "nextid":2 }, { "id": 2, "name": "DDD", "avatar": "Avatars/DDD", "msg": "(暴跳如雷)我的超级苹果!没有它能量塔就是废铁!等等…这粉色绒毛!(捡起沙滩上的绒毛)卡比——!!", "nextid":3 }, { "id":3, "msg": "(星之卡比从礁石后探头,抱着发光的苹果啃得正欢)", "nextid":4 }, { "id": 4, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": " Poyo?(无辜眨眼,苹果汁滴在沙子上泛起星光)", "opts": [ { "msg": "主动归还苹果,但要求交换条件", "toId": 8 }, { "msg": "转身逃跑引发追逐战", "toId": 5 } ] }, { "id": 5, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 可恶的粉球,给我站住不许跑!!!", "nextid":6 }, { "id": 6, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": "Poyo!Poyo!", "nextid":7 }, { "id": 7, "msg": "就这样两人一直追逐下去........但是最终还是选择和解", "nextid":8 }, { "id": 8, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": " Poyo-poyo!(指向远方迷雾海域)", "nextid":9 }, { "id": 9, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 什么?你说海妖偷走了其他苹果?(狐疑)哼!本大王才不会被骗…(突然巨浪袭来)", "nextid":10 }, { "id": 10, "msg": " 巨型海妖现身,触手卷走苹果能量塔的核心部件,两人被困在腐朽的船舱,海水不断渗入。", "nextid":11 }, { "id": 11, "name": "DDD", "avatar": "Avatars/DDD", "msg": " 锤子卡在木梁里)可恶!粉球球,现在我们是一根绳上的蚂蚱了!", "nextid":12 }, { "id": 12, "name": "Kriby", "avatar": "Avatars/Kirby", "msg": "(变身潜水卡比,照亮黑暗)Poyo! ", "nextid":13 }, { "id": 13, "msg": " 逃生途中发现古代石板,记载着苹果能量的秘密。", "nextid":14 }, { "id": 14, "name": "MetaKnight‌", "avatar": "Avatars/MetaKnight‌", "msg": "(突然从天而降)停下!那石板会唤醒古代灾厄!(剑指帝帝帝)你又在谋划什么? ", "nextid":15 }, { "id": 15, "name": "DDD", "avatar": "Avatars/DDD", "msg": "( 本大王需要苹果救妹妹蒂芙!她的石化病…(罕见露出脆弱) ", "nextid":16 }, { "id":16, "name":"Kriby", "msg":"Poyo?(那我现在应该怎么做呢?)", "opts": [ { "msg":"卡比调和冲突,提议三方合作", "nextid":17 }, { "msg":"卡比独自吞下石板引发能量暴走", "nextid":22 } ] }, { "id":17, "msg":"三人抵达星云神殿,发现苹果能量可治愈石化病,但会毁灭梦幻岛生态。", "nextid":18 }, { "id":18, "name":"DDD", "avatar":"Avatars/DDD", "msg":"(颤抖握锤)蒂芙还是岛屿…靠你了(为卡比提供能量)", "nextid":19 }, { "id":19, "name":"MetaKnight‌", "avatar":"Avatars/MetaKnight‌", "msg":"(收剑入鞘)或许是时候该发力了(为卡比提供能量)", "nextid":20 }, { "id":20, "name":"Kriby", "avatar":"Avatars/Kirby", "msg":"(跳到祭坛中央,全身发光)POYO——!", "nextid":21 }, { "id":21, "msg":"能量不断被吸入卡比体内,在短暂光芒之后,卡比稳定下来后让帝帝帝将苹果带回,蒂芙苏醒,帝帝帝含泪道谢" }, { "id":22, "msg":"卡比吸收过量能量裂变成暗黑卡比,引发新危机" } ]仔细检查代码是否有问题为什么会是NULL
最新发布
08-19
//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 Tasharen Entertainment //---------------------------------------------- using UnityEngine; using System.Collections.Generic; /// <summary> /// UI Panel is responsible for collecting, sorting and updating widgets in addition to generating widgets' geometry. /// </summary> [ExecuteInEditMode] [AddComponentMenu("NGUI/UI/NGUI Panel")] public class UIPanel : UIRect { /// <summary> /// List of active panels. /// </summary> static public List<UIPanel> list = new List<UIPanel>(); public enum RenderQueue { Automatic, StartAt, Explicit, } public delegate void OnGeometryUpdated (); /// <summary> /// Notification triggered when the panel's geometry get rebuilt. It's mainly here for debugging purposes. /// </summary> public OnGeometryUpdated onGeometryUpdated; /// <summary> /// Whether this panel will show up in the panel tool (set this to 'false' for dynamically created temporary panels) /// </summary> public bool showInPanelTool = true; /// <summary> /// Whether normals and tangents will be generated for all meshes /// </summary> public bool generateNormals = false; /// <summary> /// Whether widgets drawn by this panel are static (won't move). This will improve performance. /// </summary> public bool widgetsAreStatic = false; /// <summary> /// Whether widgets will be culled while the panel is being dragged. /// Having this on improves performance, but turning it off will reduce garbage collection. /// </summary> public bool cullWhileDragging = true; /// <summary> /// Optimization flag. Makes the assumption that the panel's geometry /// will always be on screen and the bounds don't need to be re-calculated. /// </summary> public bool alwaysOnScreen = false; /// <summary> /// By default, non-clipped panels use the camera's bounds, and the panel's position has no effect. /// If you want the panel's position to actually be used with anchors, set this field to 'true'. /// </summary> public bool anchorOffset = false; /// <summary> /// Whether the soft border will be used as padding. /// </summary> public bool softBorderPadding = true; /// <summary> /// By default all panels manage render queues of their draw calls themselves by incrementing them /// so that the geometry is drawn in the proper order. You can alter this behaviour. /// </summary> public RenderQueue renderQueue = RenderQueue.Automatic; /// <summary> /// Render queue used by the panel. The default value of '3000' is the equivalent of "Transparent". /// This property is only used if 'renderQueue' is set to something other than "Automatic". /// </summary> public int startingRenderQueue = 3000; /// <summary> /// List of widgets managed by this panel. Do not attempt to modify this list yourself. /// </summary> [System.NonSerialized] public List<UIWidget> widgets = new List<UIWidget>(); /// <summary> /// List of draw calls created by this panel. Do not attempt to modify this list yourself. /// </summary> [System.NonSerialized] public List<UIDrawCall> drawCalls = new List<UIDrawCall>(); /// <summary> /// Matrix that will transform the specified world coordinates to relative-to-panel coordinates. /// </summary> [System.NonSerialized] public Matrix4x4 worldToLocal = Matrix4x4.identity; /// <summary> /// Cached clip range passed to the draw call's shader. /// </summary> [System.NonSerialized] public Vector4 drawCallClipRange = new Vector4(0f, 0f, 1f, 1f); public delegate void OnClippingMoved (UIPanel panel); /// <summary> /// Event callback that's triggered when the panel's clip region gets moved. /// </summary> public OnClippingMoved onClipMove; // Clip texture feature contributed by the community: http://www.tasharen.com/forum/index.php?topic=9268.0 [HideInInspector][SerializeField] Texture2D mClipTexture = null; // Panel's alpha (affects the alpha of all widgets) [HideInInspector][SerializeField] float mAlpha = 1f; // Clipping rectangle [HideInInspector][SerializeField] UIDrawCall.Clipping mClipping = UIDrawCall.Clipping.None; [HideInInspector][SerializeField] Vector4 mClipRange = new Vector4(0f, 0f, 300f, 200f); [HideInInspector][SerializeField] Vector2 mClipSoftness = new Vector2(4f, 4f); [HideInInspector][SerializeField] int mDepth = 0; [HideInInspector][SerializeField] int mSortingOrder = 0; // Whether a full rebuild of geometry buffers is required bool mRebuild = false; bool mResized = false; [SerializeField] Vector2 mClipOffset = Vector2.zero; float mCullTime = 0f; float mUpdateTime = 0f; int mMatrixFrame = -1; int mAlphaFrameID = 0; int mLayer = -1; // Values used for visibility checks static float[] mTemp = new float[4]; Vector2 mMin = Vector2.zero; Vector2 mMax = Vector2.zero; bool mHalfPixelOffset = false; bool mSortWidgets = false; bool mUpdateScroll = false; /// <summary> /// Helper property that returns the first unused depth value. /// </summary> static public int nextUnusedDepth { get { int highest = int.MinValue; for (int i = 0, imax = list.Count; i < imax; ++i) highest = Mathf.Max(highest, list[i].depth); return (highest == int.MinValue) ? 0 : highest + 1; } } /// <summary> /// Whether the rectangle can be anchored. /// </summary> public override bool canBeAnchored { get { return mClipping != UIDrawCall.Clipping.None; } } /// <summary> /// Panel's alpha affects everything drawn by the panel. /// </summary> public override float alpha { get { return mAlpha; } set { float val = Mathf.Clamp01(value); if (mAlpha != val) { mAlphaFrameID = -1; mResized = true; mAlpha = val; SetDirty(); } } } /// <summary> /// Panels can have their own depth value that will change the order with which everything they manage gets drawn. /// </summary> public int depth { get { return mDepth; } set { if (mDepth != value) { mDepth = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif list.Sort(CompareFunc); } } } /// <summary> /// Sorting order value for the panel's draw calls, to be used with Unity's 2D system. /// </summary> public int sortingOrder { get { return mSortingOrder; } set { if (mSortingOrder != value) { mSortingOrder = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif UpdateDrawCalls(); } } } /// <summary> /// Function that can be used to depth-sort panels. /// </summary> static public int CompareFunc (UIPanel a, UIPanel b) { if (a != b && a != null && b != null) { if (a.mDepth < b.mDepth) return -1; if (a.mDepth > b.mDepth) return 1; return (a.GetInstanceID() < b.GetInstanceID()) ? -1 : 1; } return 0; } /// <summary> /// Panel's width in pixels. /// </summary> public float width { get { return GetViewSize().x; } } /// <summary> /// Panel's height in pixels. /// </summary> public float height { get { return GetViewSize().y; } } /// <summary> /// Whether the panel's drawn geometry needs to be offset by a half-pixel. /// </summary> public bool halfPixelOffset { get { return mHalfPixelOffset; } } /// <summary> /// Whether the camera is used to draw UI geometry. /// </summary> #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 public bool usedForUI { get { return (anchorCamera != null && mCam.isOrthoGraphic); } } #else public bool usedForUI { get { return (anchorCamera != null && mCam.orthographic); } } #endif /// <summary> /// Directx9 pixel offset, used for drawing. /// </summary> public Vector3 drawCallOffset { get { #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (anchorCamera != null && mCam.isOrthoGraphic) #else if (anchorCamera != null && mCam.orthographic) #endif { Vector2 size = GetWindowSize(); float pixelSize = (root != null) ? root.pixelSizeAdjustment : 1f; float mod = (pixelSize / size.y) / mCam.orthographicSize; bool x = mHalfPixelOffset; bool y = mHalfPixelOffset; if ((Mathf.RoundToInt(size.x) & 1) == 1) x = !x; if ((Mathf.RoundToInt(size.y) & 1) == 1) y = !y; return new Vector3(x ? -mod : 0f, y ? mod : 0f); } return Vector3.zero; } } /// <summary> /// Clipping method used by all draw calls. /// </summary> public UIDrawCall.Clipping clipping { get { return mClipping; } set { if (mClipping != value) { mResized = true; mClipping = value; mMatrixFrame = -1; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } UIPanel mParentPanel = null; /// <summary> /// Reference to the parent panel, if any. /// </summary> public UIPanel parentPanel { get { return mParentPanel; } } /// <summary> /// Number of times the panel's contents get clipped. /// </summary> public int clipCount { get { int count = 0; UIPanel p = this; while (p != null) { if (p.mClipping == UIDrawCall.Clipping.SoftClip || p.mClipping == UIDrawCall.Clipping.TextureMask) ++count; p = p.mParentPanel; } return count; } } /// <summary> /// Whether the panel will actually perform clipping of children. /// </summary> public bool hasClipping { get { return mClipping == UIDrawCall.Clipping.SoftClip || mClipping == UIDrawCall.Clipping.TextureMask; } } /// <summary> /// Whether the panel will actually perform clipping of children. /// </summary> public bool hasCumulativeClipping { get { return clipCount != 0; } } [System.Obsolete("Use 'hasClipping' or 'hasCumulativeClipping' instead")] public bool clipsChildren { get { return hasCumulativeClipping; } } /// <summary> /// Clipping area offset used to make it possible to move clipped panels (scroll views) efficiently. /// Scroll views move by adjusting the clip offset by one value, and the transform position by the inverse. /// This makes it possible to not have to rebuild the geometry, greatly improving performance. /// </summary> public Vector2 clipOffset { get { return mClipOffset; } set { if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f || Mathf.Abs(mClipOffset.y - value.y) > 0.001f) { mClipOffset = value; InvalidateClipping(); // Call the event delegate if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// <summary> /// Invalidate the panel's clipping, calling child panels in turn. /// </summary> void InvalidateClipping () { mResized = true; mMatrixFrame = -1; mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f; for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p != this && p.parentPanel == this) p.InvalidateClipping(); } } /// <summary> /// Texture used to clip the region. /// </summary> public Texture2D clipTexture { get { return mClipTexture; } set { if (mClipTexture != value) { mClipTexture = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// <summary> /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// </summary> [System.Obsolete("Use 'finalClipRegion' or 'baseClipRegion' instead")] public Vector4 clipRange { get { return baseClipRegion; } set { baseClipRegion = value; } } /// <summary> /// Clipping position (XY) and size (ZW). /// Note that you should not be modifying this property at run-time to reposition the clipping. Adjust clipOffset instead. /// </summary> public Vector4 baseClipRegion { get { return mClipRange; } set { if (Mathf.Abs(mClipRange.x - value.x) > 0.001f || Mathf.Abs(mClipRange.y - value.y) > 0.001f || Mathf.Abs(mClipRange.z - value.z) > 0.001f || Mathf.Abs(mClipRange.w - value.w) > 0.001f) { mResized = true; mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f; mClipRange = value; mMatrixFrame = -1; UIScrollView sv = GetComponent<UIScrollView>(); if (sv != null) sv.UpdatePosition(); if (onClipMove != null) onClipMove(this); #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } /// <summary> /// Final clipping region after the offset has been taken into consideration. XY = center, ZW = size. /// </summary> public Vector4 finalClipRegion { get { Vector2 size = GetViewSize(); if (mClipping != UIDrawCall.Clipping.None) { return new Vector4(mClipRange.x + mClipOffset.x, mClipRange.y + mClipOffset.y, size.x, size.y); } return new Vector4(0f, 0f, size.x, size.y); } } /// <summary> /// Clipping softness is used if the clipped style is set to "Soft". /// </summary> public Vector2 clipSoftness { get { return mClipSoftness; } set { if (mClipSoftness != value) { mClipSoftness = value; #if UNITY_EDITOR if (!Application.isPlaying) UpdateDrawCalls(); #endif } } } // Temporary variable to avoid GC allocation static Vector3[] mCorners = new Vector3[4]; /// <summary> /// Local-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// </summary> public override Vector3[] localCorners { get { if (mClipping == UIDrawCall.Clipping.None) { Vector3[] corners = worldCorners; Transform wt = cachedTransform; for (int i = 0; i < 4; ++i) corners[i] = wt.InverseTransformPoint(corners[i]); return corners; } else { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); } return mCorners; } } /// <summary> /// World-space corners of the panel's clipping rectangle. The order is bottom-left, top-left, top-right, bottom-right. /// </summary> public override Vector3[] worldCorners { get { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; Transform wt = cachedTransform; mCorners[0] = wt.TransformPoint(x0, y0, 0f); mCorners[1] = wt.TransformPoint(x0, y1, 0f); mCorners[2] = wt.TransformPoint(x1, y1, 0f); mCorners[3] = wt.TransformPoint(x1, y0, 0f); } else if (anchorCamera != null) { Vector3[] corners = mCam.GetWorldCorners(cameraRayDistance); //if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) //{ // Vector3 off = cachedTransform.position; // for (int i = 0; i < 4; ++i) // corners[i] += off; //} return corners; } else { Vector2 size = GetViewSize(); float x0 = -0.5f * size.x; float y0 = -0.5f * size.y; float x1 = x0 + size.x; float y1 = y0 + size.y; mCorners[0] = new Vector3(x0, y0); mCorners[1] = new Vector3(x0, y1); mCorners[2] = new Vector3(x1, y1); mCorners[3] = new Vector3(x1, y0); if (anchorOffset && (mCam == null || mCam.transform.parent != cachedTransform)) { Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) mCorners[i] += off; } } return mCorners; } } /// <summary> /// Get the sides of the rectangle relative to the specified transform. /// The order is left, top, right, bottom. /// </summary> public override Vector3[] GetSides (Transform relativeTo) { if (mClipping != UIDrawCall.Clipping.None) { float x0 = mClipOffset.x + mClipRange.x - 0.5f * mClipRange.z; float y0 = mClipOffset.y + mClipRange.y - 0.5f * mClipRange.w; float x1 = x0 + mClipRange.z; float y1 = y0 + mClipRange.w; float hx = (x0 + x1) * 0.5f; float hy = (y0 + y1) * 0.5f; Transform wt = cachedTransform; mSides[0] = wt.TransformPoint(x0, hy, 0f); mSides[1] = wt.TransformPoint(hx, y1, 0f); mSides[2] = wt.TransformPoint(x1, hy, 0f); mSides[3] = wt.TransformPoint(hx, y0, 0f); if (relativeTo != null) { for (int i = 0; i < 4; ++i) mSides[i] = relativeTo.InverseTransformPoint(mSides[i]); } return mSides; } else if (anchorCamera != null && anchorOffset) { Vector3[] sides = mCam.GetSides(cameraRayDistance); Vector3 off = cachedTransform.position; for (int i = 0; i < 4; ++i) sides[i] += off; if (relativeTo != null) { for (int i = 0; i < 4; ++i) sides[i] = relativeTo.InverseTransformPoint(sides[i]); } return sides; } return base.GetSides(relativeTo); } /// <summary> /// Invalidating the panel should reset its alpha. /// </summary> public override void Invalidate (bool includeChildren) { mAlphaFrameID = -1; base.Invalidate(includeChildren); } /// <summary> /// Widget's final alpha, after taking the panel's alpha into account. /// </summary> public override float CalculateFinalAlpha (int frameID) { #if UNITY_EDITOR if (mAlphaFrameID != frameID || !Application.isPlaying) #else if (mAlphaFrameID != frameID) #endif { mAlphaFrameID = frameID; UIRect pt = parent; finalAlpha = (parent != null) ? pt.CalculateFinalAlpha(frameID) * mAlpha : mAlpha; } return finalAlpha; } /// <summary> /// Set the panel's rectangle. /// </summary> public override void SetRect (float x, float y, float width, float height) { int finalWidth = Mathf.FloorToInt(width + 0.5f); int finalHeight = Mathf.FloorToInt(height + 0.5f); finalWidth = ((finalWidth >> 1) << 1); finalHeight = ((finalHeight >> 1) << 1); Transform t = cachedTransform; Vector3 pos = t.localPosition; pos.x = Mathf.Floor(x + 0.5f); pos.y = Mathf.Floor(y + 0.5f); if (finalWidth < 2) finalWidth = 2; if (finalHeight < 2) finalHeight = 2; baseClipRegion = new Vector4(pos.x, pos.y, finalWidth, finalHeight); if (isAnchored) { t = t.parent; if (leftAnchor.target) leftAnchor.SetHorizontal(t, x); if (rightAnchor.target) rightAnchor.SetHorizontal(t, x + width); if (bottomAnchor.target) bottomAnchor.SetVertical(t, y); if (topAnchor.target) topAnchor.SetVertical(t, y + height); #if UNITY_EDITOR NGUITools.SetDirty(this); #endif } } /// <summary> /// Returns whether the specified rectangle is visible by the panel. The coordinates must be in world space. /// </summary> #if UNITY_FLASH public bool IsVisible (Vector3 aa, Vector3 bb, Vector3 cc, Vector3 dd) #else public bool IsVisible (Vector3 a, Vector3 b, Vector3 c, Vector3 d) #endif { UpdateTransformMatrix(); // Transform the specified points from world space to local space #if UNITY_FLASH // http://www.tasharen.com/forum/index.php?topic=11390.0 Vector3 a = worldToLocal.MultiplyPoint3x4(aa); Vector3 b = worldToLocal.MultiplyPoint3x4(bb); Vector3 c = worldToLocal.MultiplyPoint3x4(cc); Vector3 d = worldToLocal.MultiplyPoint3x4(dd); #else a = worldToLocal.MultiplyPoint3x4(a); b = worldToLocal.MultiplyPoint3x4(b); c = worldToLocal.MultiplyPoint3x4(c); d = worldToLocal.MultiplyPoint3x4(d); #endif mTemp[0] = a.x; mTemp[1] = b.x; mTemp[2] = c.x; mTemp[3] = d.x; float minX = Mathf.Min(mTemp); float maxX = Mathf.Max(mTemp); mTemp[0] = a.y; mTemp[1] = b.y; mTemp[2] = c.y; mTemp[3] = d.y; float minY = Mathf.Min(mTemp); float maxY = Mathf.Max(mTemp); if (maxX < mMin.x) return false; if (maxY < mMin.y) return false; if (minX > mMax.x) return false; if (minY > mMax.y) return false; return true; } /// <summary> /// Returns whether the specified world position is within the panel's bounds determined by the clipping rect. /// </summary> public bool IsVisible (Vector3 worldPos) { if (mAlpha < 0.001f) return false; if (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) return true; UpdateTransformMatrix(); Vector3 pos = worldToLocal.MultiplyPoint3x4(worldPos); if (pos.x < mMin.x) return false; if (pos.y < mMin.y) return false; if (pos.x > mMax.x) return false; if (pos.y > mMax.y) return false; return true; } /// <summary> /// Returns whether the specified widget is visible by the panel. /// </summary> public bool IsVisible (UIWidget w) { UIPanel p = this; Vector3[] corners = null; while (p != null) { if ((p.mClipping == UIDrawCall.Clipping.None || p.mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen) { p = p.mParentPanel; continue; } if (corners == null) corners = w.worldCorners; if (!p.IsVisible(corners[0], corners[1], corners[2], corners[3])) return false; p = p.mParentPanel; } return true; } /// <summary> /// Whether the specified widget is going to be affected by this panel in any way. /// </summary> public bool Affects (UIWidget w) { if (w == null) return false; UIPanel expected = w.panel; if (expected == null) return false; UIPanel p = this; while (p != null) { if (p == expected) return true; if (!p.hasCumulativeClipping) return false; p = p.mParentPanel; } return false; } /// <summary> /// Causes all draw calls to be re-created on the next update. /// </summary> [ContextMenu("Force Refresh")] public void RebuildAllDrawCalls () { mRebuild = true; } /// <summary> /// Invalidate the panel's draw calls, forcing them to be rebuilt on the next update. /// This call also affects all children. /// </summary> public void SetDirty () { for (int i = 0, imax = drawCalls.Count; i < imax; ++i) drawCalls[i].isDirty = true; Invalidate(true); } /// <summary> /// Cache components. /// </summary> void Awake () { mGo = gameObject; mTrans = transform; mHalfPixelOffset = (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.XBOX360 || Application.platform == RuntimePlatform.WindowsWebPlayer || Application.platform == RuntimePlatform.WindowsEditor); // Only DirectX 9 needs the half-pixel offset if (mHalfPixelOffset && SystemInfo.graphicsDeviceVersion.Contains("Direct3D")) mHalfPixelOffset = (SystemInfo.graphicsShaderLevel < 40); } /// <summary> /// Find the parent panel, if we have one. /// </summary> void FindParent () { Transform parent = cachedTransform.parent; mParentPanel = (parent != null) ? NGUITools.FindInParents<UIPanel>(parent.gameObject) : null; } /// <summary> /// Find the parent panel, if we have one. /// </summary> public override void ParentHasChanged () { base.ParentHasChanged(); FindParent(); } /// <summary> /// Layer is used to ensure that if it changes, widgets get moved as well. /// </summary> protected override void OnStart () { mLayer = mGo.layer; } /// <summary> /// Reset the frame IDs. /// </summary> protected override void OnEnable () { mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; OnStart(); base.OnEnable(); mMatrixFrame = -1; } /// <summary> /// Mark all widgets as having been changed so the draw calls get re-created. /// </summary> protected override void OnInit () { if (list.Contains(this)) return; base.OnInit(); FindParent(); // Apparently having a rigidbody helps #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (rigidbody == null && mParentPanel == null) #else if (GetComponent<Rigidbody>() == null && mParentPanel == null) #endif { UICamera uic = (anchorCamera != null) ? mCam.GetComponent<UICamera>() : null; if (uic != null) { if (uic.eventType == UICamera.EventType.UI_3D || uic.eventType == UICamera.EventType.World_3D) { Rigidbody rb = gameObject.AddComponent<Rigidbody>(); rb.isKinematic = true; rb.useGravity = false; } // It's unclear if this helps 2D physics or not, so leaving it disabled for now. // Note that when enabling this, the 'if (rigidbody == null)' statement above should be adjusted as well. //else //{ // Rigidbody2D rb = gameObject.AddComponent<Rigidbody2D>(); // rb.isKinematic = true; //} } } mRebuild = true; mAlphaFrameID = -1; mMatrixFrame = -1; list.Add(this); list.Sort(CompareFunc); } /// <summary> /// Destroy all draw calls we've created when this script gets disabled. /// </summary> protected override void OnDisable () { for (int i = 0, imax = drawCalls.Count; i < imax; ++i) { UIDrawCall dc = drawCalls[i]; UIDrawCall.Destroy(dc); } drawCalls.Clear(); list.Remove(this); mAlphaFrameID = -1; mMatrixFrame = -1; if (list.Count == 0) { UIDrawCall.ReleaseAll(); mUpdateFrame = -1; } base.OnDisable(); } /// <summary> /// Update the world-to-local transform matrix as well as clipping bounds. /// </summary> void UpdateTransformMatrix () { int fc = Time.frameCount; if (mMatrixFrame != fc) { mMatrixFrame = fc; worldToLocal = cachedTransform.worldToLocalMatrix; Vector2 size = GetViewSize() * 0.5f; float x = mClipOffset.x + mClipRange.x; float y = mClipOffset.y + mClipRange.y; mMin.x = x - size.x; mMin.y = y - size.y; mMax.x = x + size.x; mMax.y = y + size.y; } } /// <summary> /// Update the edges after the anchors have been updated. /// </summary> protected override void OnAnchor () { // No clipping = no edges to anchor if (mClipping == UIDrawCall.Clipping.None) return; Transform trans = cachedTransform; Transform parent = trans.parent; Vector2 size = GetViewSize(); Vector2 offset = trans.localPosition; float lt, bt, rt, tt; // Attempt to fast-path if all anchors match if (leftAnchor.target == bottomAnchor.target && leftAnchor.target == rightAnchor.target && leftAnchor.target == topAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { // Anchored to a single transform Vector2 lp = GetLocalPos(leftAnchor, parent); lt = lp.x + leftAnchor.absolute; bt = lp.y + bottomAnchor.absolute; rt = lp.x + rightAnchor.absolute; tt = lp.y + topAnchor.absolute; } } else { // Left anchor point if (leftAnchor.target) { Vector3[] sides = leftAnchor.GetSides(parent); if (sides != null) { lt = NGUIMath.Lerp(sides[0].x, sides[2].x, leftAnchor.relative) + leftAnchor.absolute; } else { lt = GetLocalPos(leftAnchor, parent).x + leftAnchor.absolute; } } else lt = mClipRange.x - 0.5f * size.x; // Right anchor point if (rightAnchor.target) { Vector3[] sides = rightAnchor.GetSides(parent); if (sides != null) { rt = NGUIMath.Lerp(sides[0].x, sides[2].x, rightAnchor.relative) + rightAnchor.absolute; } else { rt = GetLocalPos(rightAnchor, parent).x + rightAnchor.absolute; } } else rt = mClipRange.x + 0.5f * size.x; // Bottom anchor point if (bottomAnchor.target) { Vector3[] sides = bottomAnchor.GetSides(parent); if (sides != null) { bt = NGUIMath.Lerp(sides[3].y, sides[1].y, bottomAnchor.relative) + bottomAnchor.absolute; } else { bt = GetLocalPos(bottomAnchor, parent).y + bottomAnchor.absolute; } } else bt = mClipRange.y - 0.5f * size.y; // Top anchor point if (topAnchor.target) { Vector3[] sides = topAnchor.GetSides(parent); if (sides != null) { tt = NGUIMath.Lerp(sides[3].y, sides[1].y, topAnchor.relative) + topAnchor.absolute; } else { tt = GetLocalPos(topAnchor, parent).y + topAnchor.absolute; } } else tt = mClipRange.y + 0.5f * size.y; } // Take the offset into consideration lt -= offset.x + mClipOffset.x; rt -= offset.x + mClipOffset.x; bt -= offset.y + mClipOffset.y; tt -= offset.y + mClipOffset.y; // Calculate the new position, width and height float newX = Mathf.Lerp(lt, rt, 0.5f); float newY = Mathf.Lerp(bt, tt, 0.5f); float w = rt - lt; float h = tt - bt; float minx = Mathf.Max(2f, mClipSoftness.x); float miny = Mathf.Max(2f, mClipSoftness.y); if (w < minx) w = minx; if (h < miny) h = miny; // Update the clipping range baseClipRegion = new Vector4(newX, newY, w, h); } static int mUpdateFrame = -1; /// <summary> /// Update all panels and draw calls. /// </summary> void LateUpdate () { #if UNITY_EDITOR if (mUpdateFrame != Time.frameCount || !Application.isPlaying) #else if (mUpdateFrame != Time.frameCount) #endif { mUpdateFrame = Time.frameCount; // Update each panel in order for (int i = 0, imax = list.Count; i < imax; ++i) list[i].UpdateSelf(); int rq = 3000; // Update all draw calls, making them draw in the right order for (int i = 0, imax = list.Count; i < imax; ++i) { UIPanel p = list[i]; if (p.renderQueue == RenderQueue.Automatic) { p.startingRenderQueue = rq; p.UpdateDrawCalls(); rq += p.drawCalls.Count; } else if (p.renderQueue == RenderQueue.StartAt) { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); } else // Explicit { p.UpdateDrawCalls(); if (p.drawCalls.Count != 0) rq = Mathf.Max(rq, p.startingRenderQueue + 1); } } } } /// <summary> /// Update the panel, all of its widgets and draw calls. /// </summary> void UpdateSelf () { mUpdateTime = RealTime.time; UpdateTransformMatrix(); UpdateLayers(); UpdateWidgets(); if (mRebuild) { mRebuild = false; FillAllDrawCalls(); } else { for (int i = 0; i < drawCalls.Count; ) { UIDrawCall dc = drawCalls[i]; if (dc.isDirty && !FillDrawCall(dc)) { UIDrawCall.Destroy(dc); drawCalls.RemoveAt(i); continue; } ++i; } } if (mUpdateScroll) { mUpdateScroll = false; UIScrollView sv = GetComponent<UIScrollView>(); if (sv != null) sv.UpdateScrollbars(); } } /// <summary> /// Immediately sort all child widgets. /// </summary> public void SortWidgets () { mSortWidgets = false; widgets.Sort(UIWidget.PanelCompareFunc); } /// <summary> /// Fill the geometry fully, processing all widgets and re-creating all draw calls. /// </summary> void FillAllDrawCalls () { for (int i = 0; i < drawCalls.Count; ++i) { if (drawCalls[i] != null) UIDrawCall.Destroy(drawCalls[i]); } drawCalls.Clear(); Material mat = null; Texture tex = null; Shader sdr = null; UIDrawCall dc = null; int count = 0; if (mSortWidgets) SortWidgets(); for (int i = 0; i < widgets.Count; ++i) { UIWidget w = widgets[i]; if (w.isVisible && w.hasVertices) { //Debug.LogError("999999999"); Material mt = w.material; Texture tx = w.mainTexture; Shader sd = w.shader; if (mat != mt || tex != tx || sdr != sd && !w.IsMyWidget)// { if (dc != null && dc.verts.size != 0) { drawCalls.Add(dc); dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; count = 0; dc = null; } mat = mt; tex = tx; sdr = sd; } if (mat != null || sdr != null || tex != null || w.IsMyWidget)//wycm || w.IsMyWidget { if (dc == null || w.IsMyWidget) { if (w.IsMyWidget) { dc = new UIDrawCall(); //UIDrawCall.Create(this, null, null, null, w.gameObject.name, true); drawCalls.Add(dc); } else { dc = UIDrawCall.Create(this, mat, tex, sdr); } dc.depthStart = w.depth; dc.depthEnd = dc.depthStart; dc.panel = this; } else { int rd = w.depth; if (rd < dc.depthStart) dc.depthStart = rd; if (rd > dc.depthEnd) dc.depthEnd = rd; } w.drawCall = dc; ++count; if (w.IsMyWidget) { //dc = UIDrawCall.Create(this, null, null, null, w.gameObject.name, true); //dc = new UIDrawCall(); dc.IsMyWidget = true; //w.drawCall.renderQueue = startingRenderQueue + i; dc.MyWidget = w; //dc.panel = this; //drawCalls.Add(dc); Debug.LogError("IsMyWidget"); //w.drawCall = dc; //w.resetdeth(startingRenderQueue + i); } else { if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } } } } else w.drawCall = null; } if (dc != null && dc.verts.size != 0) { drawCalls.Add(dc); dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; } } UIDrawCall.OnRenderCallback mOnRender; /// <summary> /// Fill the geometry for the specified draw call. /// </summary> bool FillDrawCall (UIDrawCall dc) { if (dc != null) { dc.isDirty = false; int count = 0; for (int i = 0; i < widgets.Count; ) { UIWidget w = widgets[i]; if (w == null) { #if UNITY_EDITOR Debug.LogError("This should never happen"); #endif widgets.RemoveAt(i); continue; } if (w.drawCall == dc) { if (w.isVisible && w.hasVertices) { ++count; if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } } else w.drawCall = null; } ++i; } if (dc.verts.size != 0) { dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; return true; } } return false; } /// <summary> /// Update all draw calls associated with the panel. /// </summary> void UpdateDrawCalls () { Transform trans = cachedTransform; bool isUI = usedForUI; if (clipping != UIDrawCall.Clipping.None) { drawCallClipRange = finalClipRegion; drawCallClipRange.z *= 0.5f; drawCallClipRange.w *= 0.5f; } else drawCallClipRange = Vector4.zero; int w = Screen.width; int h = Screen.height; // Legacy functionality if (drawCallClipRange.z == 0f) drawCallClipRange.z = w * 0.5f; if (drawCallClipRange.w == 0f) drawCallClipRange.w = h * 0.5f; // DirectX 9 half-pixel offset if (halfPixelOffset) { drawCallClipRange.x -= 0.5f; drawCallClipRange.y += 0.5f; } Vector3 pos; if (isUI) { Transform parent = cachedTransform.parent; pos = cachedTransform.localPosition; if (clipping != UIDrawCall.Clipping.None) { pos.x = Mathf.RoundToInt(pos.x); pos.y = Mathf.RoundToInt(pos.y); } if (parent != null) pos = parent.TransformPoint(pos); pos += drawCallOffset; } else pos = trans.position; Quaternion rot = trans.rotation; Vector3 scale = trans.lossyScale; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; if (dc.IsMyWidget) { dc.renderQueue = startingRenderQueue + i; if (dc.MyWidget != null) dc.MyWidget.resetdeth(startingRenderQueue + i); } else { Transform t = dc.cachedTransform; t.position = pos; t.rotation = rot; t.localScale = scale; dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i; dc.alwaysOnScreen = alwaysOnScreen && (mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip); dc.sortingOrder = mSortingOrder; dc.clipTexture = mClipTexture; } } } /// <summary> /// Update the widget layers if the panel's layer has changed. /// </summary> void UpdateLayers () { // Always move widgets to the panel's layer if (mLayer != cachedGameObject.layer) { mLayer = mGo.layer; for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; if (w && w.parent == this) w.gameObject.layer = mLayer; } ResetAnchors(); for (int i = 0; i < drawCalls.Count; ++i) drawCalls[i].gameObject.layer = mLayer; } } bool mForced = false; /// <summary> /// Update all of the widgets belonging to this panel. /// </summary> void UpdateWidgets() { #if UNITY_EDITOR bool forceVisible = cullWhileDragging ? false : (Application.isPlaying && mCullTime > mUpdateTime); #else bool forceVisible = cullWhileDragging ? false : (mCullTime > mUpdateTime); #endif bool changed = false; if (mForced != forceVisible) { mForced = forceVisible; mResized = true; } bool clipped = hasCumulativeClipping; // Update all widgets for (int i = 0, imax = widgets.Count; i < imax; ++i) { UIWidget w = widgets[i]; // If the widget is visible, update it if (w.panel == this && w.enabled) { #if UNITY_EDITOR // When an object is dragged from Project view to Scene view, its Z is... // odd, to say the least. Force it if possible. if (!Application.isPlaying) { Transform t = w.cachedTransform; if (t.hideFlags != HideFlags.HideInHierarchy) { t = (t.parent != null && t.parent.hideFlags == HideFlags.HideInHierarchy) ? t.parent : null; } if (t != null) { for (; ; ) { if (t.parent == null) break; if (t.parent.hideFlags == HideFlags.HideInHierarchy) t = t.parent; else break; } if (t != null) { Vector3 pos = t.localPosition; pos.x = Mathf.Round(pos.x); pos.y = Mathf.Round(pos.y); pos.z = 0f; if (Vector3.SqrMagnitude(t.localPosition - pos) > 0.0001f) t.localPosition = pos; } } } #endif int frame = Time.frameCount; // First update the widget's transform if (w.UpdateTransform(frame) || mResized) { // Only proceed to checking the widget's visibility if it actually moved bool vis = forceVisible || (w.CalculateCumulativeAlpha(frame) > 0.001f); w.UpdateVisibility(vis, forceVisible || ((clipped || w.hideIfOffScreen) ? IsVisible(w) : true)); } // Update the widget's geometry if necessary if (w.UpdateGeometry(frame)) { changed = true; if (!mRebuild) { if (w.drawCall != null) { w.drawCall.isDirty = true; } else { // Find an existing draw call, if possible FindDrawCall(w); } } } } } // Inform the changed event listeners if (changed && onGeometryUpdated != null) onGeometryUpdated(); mResized = false; } /// <summary> /// Insert the specified widget into one of the existing draw calls if possible. /// If it's not possible, and a new draw call is required, 'null' is returned /// because draw call creation is a delayed operation. /// </summary> public UIDrawCall FindDrawCall (UIWidget w) { Material mat = w.material; Texture tex = w.mainTexture; int depth = w.depth; for (int i = 0; i < drawCalls.Count; ++i) { UIDrawCall dc = drawCalls[i]; int dcStart = (i == 0) ? int.MinValue : drawCalls[i - 1].depthEnd + 1; int dcEnd = (i + 1 == drawCalls.Count) ? int.MaxValue : drawCalls[i + 1].depthStart - 1; if (dcStart <= depth && dcEnd >= depth) { if (dc.baseMaterial == mat && dc.mainTexture == tex) { if (w.isVisible) { w.drawCall = dc; if (w.hasVertices) dc.isDirty = true; return dc; } } else mRebuild = true; return null; } } mRebuild = true; return null; } /// <summary> /// Make the following widget be managed by the panel. /// </summary> public void AddWidget (UIWidget w) { mUpdateScroll = true; if (widgets.Count == 0) { widgets.Add(w); } else if (mSortWidgets) { widgets.Add(w); SortWidgets(); } else if (UIWidget.PanelCompareFunc(w, widgets[0]) == -1) { widgets.Insert(0, w); } else { for (int i = widgets.Count; i > 0; ) { if (UIWidget.PanelCompareFunc(w, widgets[--i]) == -1) continue; widgets.Insert(i+1, w); break; } } FindDrawCall(w); } /// <summary> /// Remove the widget from its current draw call, invalidating everything as needed. /// </summary> public void RemoveWidget (UIWidget w) { if (widgets.Remove(w) && w.drawCall != null) { int depth = w.depth; if (depth == w.drawCall.depthStart || depth == w.drawCall.depthEnd) mRebuild = true; w.drawCall.isDirty = true; w.drawCall = null; } } /// <summary> /// Immediately refresh the panel. /// </summary> public void Refresh () { mRebuild = true; mUpdateFrame = -1; if (list.Count > 0) list[0].LateUpdate(); } // <summary> /// Calculate the offset needed to be constrained within the panel's bounds. /// </summary> public virtual Vector3 CalculateConstrainOffset (Vector2 min, Vector2 max) { Vector4 cr = finalClipRegion; float offsetX = cr.z * 0.5f; float offsetY = cr.w * 0.5f; Vector2 minRect = new Vector2(min.x, min.y); Vector2 maxRect = new Vector2(max.x, max.y); Vector2 minArea = new Vector2(cr.x - offsetX, cr.y - offsetY); Vector2 maxArea = new Vector2(cr.x + offsetX, cr.y + offsetY); if (softBorderPadding && clipping == UIDrawCall.Clipping.SoftClip) { minArea.x += mClipSoftness.x; minArea.y += mClipSoftness.y; maxArea.x -= mClipSoftness.x; maxArea.y -= mClipSoftness.y; } return NGUIMath.ConstrainRect(minRect, maxRect, minArea, maxArea); } /// <summary> /// Constrain the current target position to be within panel bounds. /// </summary> public bool ConstrainTargetToBounds (Transform target, ref Bounds targetBounds, bool immediate) { Vector3 min = targetBounds.min; Vector3 max = targetBounds.max; float ps = 1f; if (mClipping == UIDrawCall.Clipping.None) { UIRoot rt = root; if (rt != null) ps = rt.pixelSizeAdjustment; } if (ps != 1f) { min /= ps; max /= ps; } Vector3 offset = CalculateConstrainOffset(min, max) * ps; if (offset.sqrMagnitude > 0f) { if (immediate) { target.localPosition += offset; targetBounds.center += offset; SpringPosition sp = target.GetComponent<SpringPosition>(); if (sp != null) sp.enabled = false; } else { SpringPosition sp = SpringPosition.Begin(target.gameObject, target.localPosition + offset, 13f); sp.ignoreTimeScale = true; sp.worldSpace = false; } return true; } return false; } /// <summary> /// Constrain the specified target to be within the panel's bounds. /// </summary> public bool ConstrainTargetToBounds (Transform target, bool immediate) { Bounds bounds = NGUIMath.CalculateRelativeWidgetBounds(cachedTransform, target); return ConstrainTargetToBounds(target, ref bounds, immediate); } /// <summary> /// Find the UIPanel responsible for handling the specified transform. /// </summary> static public UIPanel Find (Transform trans) { return Find(trans, false, -1); } /// <summary> /// Find the UIPanel responsible for handling the specified transform. /// </summary> static public UIPanel Find (Transform trans, bool createIfMissing) { return Find(trans, createIfMissing, -1); } /// <summary> /// Find the UIPanel responsible for handling the specified transform. /// </summary> static public UIPanel Find (Transform trans, bool createIfMissing, int layer) { UIPanel panel = NGUITools.FindInParents<UIPanel>(trans); if (panel != null) return panel; while (trans.parent != null) trans = trans.parent; return createIfMissing ? NGUITools.CreateUI(trans, false, layer) : null; } /// <summary> /// Get the size of the game window in pixels. /// </summary> public Vector2 GetWindowSize () { UIRoot rt = root; Vector2 size = NGUITools.screenSize; if (rt != null) size *= rt.GetPixelSizeAdjustment(Mathf.RoundToInt(size.y)); return size; } /// <summary> /// Panel's size -- which is either the clipping rect, or the screen dimensions. /// </summary> public Vector2 GetViewSize () { if (mClipping != UIDrawCall.Clipping.None) return new Vector2(mClipRange.z, mClipRange.w); Vector2 size = NGUITools.screenSize; //UIRoot rt = root; //if (rt != null) size *= rt.pixelSizeAdjustment; return size; } #if UNITY_EDITOR /// <summary> /// Draw a visible pink outline for the clipped area. /// </summary> void OnDrawGizmos () { if (anchorCamera == null) return; bool clip = (mClipping != UIDrawCall.Clipping.None); Transform t = clip ? transform : mCam.transform; Vector3[] corners = worldCorners; for (int i = 0; i < 4; ++i) corners[i] = t.InverseTransformPoint(corners[i]); Vector3 pos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 size = corners[2] - corners[0]; GameObject go = UnityEditor.Selection.activeGameObject; bool isUsingThisPanel = (go != null) && (NGUITools.FindInParents<UIPanel>(go) == this); bool isSelected = (UnityEditor.Selection.activeGameObject == gameObject); bool detailedView = (isSelected && isUsingThisPanel); bool detailedClipped = detailedView && mClipping == UIDrawCall.Clipping.SoftClip; Gizmos.matrix = t.localToWorldMatrix; #if UNITY_4_3 || UNITY_4_5 || UNITY_4_6 if (isUsingThisPanel && !clip && mCam.isOrthoGraphic) #else if (isUsingThisPanel && !clip && mCam.orthographic) #endif { UIRoot rt = root; if (rt != null && rt.scalingStyle != UIRoot.Scaling.Flexible) { float width = rt.manualWidth; float height = rt.manualHeight; float x0 = -0.5f * width; float y0 = -0.5f * height; float x1 = x0 + width; float y1 = y0 + height; corners[0] = new Vector3(x0, y0); corners[1] = new Vector3(x0, y1); corners[2] = new Vector3(x1, y1); corners[3] = new Vector3(x1, y0); Vector3 szPos = Vector3.Lerp(corners[0], corners[2], 0.5f); Vector3 szSize = corners[2] - corners[0]; Gizmos.color = new Color(0f, 0.75f, 1f); Gizmos.DrawWireCube(szPos, szSize); } } Gizmos.color = (isUsingThisPanel && !detailedClipped) ? new Color(1f, 0f, 0.5f) : new Color(0.5f, 0f, 0.5f); Gizmos.DrawWireCube(pos, size); if (detailedView) { if (detailedClipped) { Gizmos.color = new Color(1f, 0f, 0.5f); size.x -= mClipSoftness.x * 2f; size.y -= mClipSoftness.y * 2f; Gizmos.DrawWireCube(pos, size); } } } #endif // UNITY_EDITOR } Assets/NGUI/Scripts/UI/UIPanel.cs(907,44): error CS0619: `UnityEngine.RuntimePlatform.WindowsWebPlayer' is obsolete: `WebPlayer export is no longer supported in Unity 5.4+.' 这个代码是Unity5.3.3f1版本的,现在升级到Unity 2017.4.0f1 (64-bit)版本
07-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值