<含泪活着>-观后感

下班回来,想搜部电影看,结果搜到了这部<含泪活着>.纪录片讲述的是主人公在日本十五年的黑户生涯.

主人公丁尚彪在89年面临返城知青上大学无望的现状,希望能够重新转动命运的齿轮而改变这一切.于是在海外朋友的来信建议下,义无反顾的借债踏上了异国日本的国土,然而樱花树下一样有血泪.日本语言学校位于偏僻的北海道山区,无法打工赚钱兼顾学习的现实,导致他不得不出逃北海道到东京,成了一名黑户,为了生存不得不改变人生目标,将向上攀登的接力棒交给自己的女儿,自己在日本打三份工,还要防着被日本政府强制遣返,遭受着身体和心理的双重压力,只希望能够攒足够的钱让女儿能够出人头地.就这样过了八年才再见到自己的女儿,此时女儿去美国纽约大学留学在日本过境,才换得这一次机会,而五年后也就是在日本待了十三年才和自己的妻子再见面.又过了两年,在女儿即将成为医生时才主动从日本回国.

主人公在纪录片里,给人的感觉是平实,坚定.面对命运的玩笑,他选择了主动去面对,忍常人所不能忍,就像他女儿说的没有一般人能够付出这么大的代价.是的,他只是个小人物,所以只能这样用时间去面对.去时风华正茂,回时已垂垂老矣 ,就这样在日本留下了15年的血泪.

纪录片跨度有十几年,从这一点我觉得就很了不起,一部关注普通人物十几年的纪录片,这种认真和专注本身就值得我们现在中国人学习.现在一直都在讲的,在飞速的发展的中国,浮躁和喧嚣充斥了整个社会.反省自身,我也是做什么事情都一直很着急,但是又不持久,稍微看不到光明就想放弃了.虽然不专注也可能成功,但是专注是肯定可以成功的!

主人公的这种平凡中的韧性,也是让人感动和学习的地方.他说都是被逼的,其实也说对了,现在来看很多人的成功也可以说是被逼的.但是有些人被逼之后,可能是感觉人生无望,一了百了.但是里面的老丁却也是勇于去面对,虽然没有做出什么惊天动地的大事,但是确实是稳打稳扎步步前行.比起一飞冲天的瞬间,这种平凡中的扎实容易被人忽略.而这种在人生的夹缝中,于异国他乡,身份被黑,各种困难重重,只能滞留忍受这一切,却又能够及时调整方向迂回向前的平凡智慧,更接地气,也给同样平凡的我们带来更多的生活启示.

片中老丁目标坚定,也是一个很重要的因素,他把对女儿的爱和对家庭的责任都化成了在日本努力奋斗的动力.否则想一想,按照黑户的身份,想要回来只要随便被警察抓住就可以被遣返了,而且回来了也有接口,心里也未必不能接受.但是他是和决绝的.他的妻子,同样的,能够等丈夫十几年,真不是一般女人能做到的,虽然纪录片里同样讲到了她也有误会,但是这反而更显纪录片的真实,不管怎么样,她确实等了15年才等到他回来,而且是心心念念的等着他.

除了上述,还有一点额外的感想:环境和眼界也很重要.同样是小人物,如果老丁是深山沟沟里的农民,那么出国这些,培养孩子这些估计都不会想了,因为根本不会接触到这些思想,没有这个眼界.虽然老丁一直在说自己没有什么文化,但是知青可能没上过大学,但是基本文化知识还是有的,而且出生和生活在上海这样的中国前沿大城市,才有了眼界和出去的念头.所以,扩展眼界,提升见识也是一直前行的必要任务.

总之,建议大家看一看,虽然影片开始提示要准备一打纸巾,但还是没有哭,可能环境不对,也可能是真老了...

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值