Unity/C# 如何在用户界面上连续运行脚本选择事件触发器 [英] Unity/C# How to run Script continuously on User Interface Select Event Trigger
问题描述
这里完全是初学者,我希望在 UI 中选择它作为子项的按钮时连续平滑地旋转我的球体.
Complete beginner here, I'm looking to smoothly rotate my sphere continuously while the button it is a child of is selected in the UI.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ButtonHandler : MonoBehaviour
{
private Vector3 rotationDirection = new Vector3(0, .25f, 0);
private float smoothTime = 1;
private float convertedTime = 200;
private float smooth;
public void SetText()
{
Transform target = transform.Find("Globe");
smooth = Time.deltaTime * smoothTime * convertedTime;
target.Rotate(rotationDirection * smooth);
}
}
问题是当我去选择我的按钮时,该功能只运行一次,而我希望它连续运行直到取消选择.
The issue is that when I go to select my button, the function is only ran a single time, whereas I want it to run continuously until deselected.
** 注意这是使用选择事件触发器
** Note this is using the Select Event Trigger
任何帮助将不胜感激!
如果您需要更多信息来回答,请告诉我
Please let me know if you need additional information to answer
谢谢!
推荐答案
扩展 Nicholas Sims 的回答 一个稍微更好的选择将是一个 协程.协程可以看作是临时的 Update
方法,因为默认情况下,每个迭代步骤都是在 Update
调用之后立即执行.
Extending Nicholas Sims' answer a slightly better option would be a Coroutine. Coroutines can be seen as temporary Update
method as by default each iteration step is Don right after the Update
call.
这样您就不会在触发器没有被激活时将资源浪费到 Update
方法上.
This way you don't waste resources to an Update
method when the trigger is not activated anyway.
另请注意,Find
通常是一个非常昂贵的调用,应尽可能避免!您至少要做的是在 Update
每一帧中使用它!而是尽可能早地存储引用......甚至可能已经通过检查器中的字段!
Also note that Find
in general is a very expensive call and should be avoided wherever possible! The least you want to do is using it in Update
every frame! Instead store the reference as early as possible .. maybe even already via a field in the Inspector!
// For storing the reference
// If possible already reference this via the Inspector
// by drag&drop to avoid Find entirely!
[SerializeField] private Transform target;
private bool rotate;
private void Start()
{
if(!target) target = GameObject.Find("Globe");
}
public void ToggleRoutine()
{
rotate = !rotate;
if(!rotate)
{
StopAllCoroutines();
}
else
{
StartCoroutine (RotateContinuously());
}
}
private IEnumerator RotateContinuously()
{
// Whut? o.O
// No worries, this is fine in a Coroutine as long as you yield somewhere inside
while (true)
{
// You should use Find only once .. if at all. You should avoid it wherever possible!
if(!target) target = transform.Find("Globe");
smooth = Time.deltaTime * smoothTime * convertedTime;
target.Rotate(rotationDirection * smooth);
// Very important for not freezing the editor completely!
// This tells unity to "pause" the routine here
// render the current frame and continue
// from this point on the next frame
yield return null;
}
}
如果您更喜欢While Pressed"行为,因此您希望在用户按住鼠标/按钮时继续旋转并在他松开时立即停止,您可以使用 IPointerXYHandler
接口,如
public class WhilePressedRotation : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private Transform target;
private void Start ()
{
if(!target) target = GameObject.Find("Globe");
}
public void OnPointerDown(PointerEventData pointerEventData)
{
StartCoroutine(RotateContinuously());
}
public void OnPointerUp(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
public void OnPointerEnter(PointerEventData pointerEventData)
{
// Actually not really needed
// but not sure if maybe required for having OnPointerExit work
}
public void OnPointerExit(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
private IEnumerator RotateContinuously()
{
// Whut? o.O
// No worries, this is fine in a Coroutine as long as you yield somewhere inside
while (true)
{
// You should use Find only once .. if at all. You should avoid it wherever possible!
if(!target) target = transform.Find("Globe");
smooth = Time.deltaTime * smoothTime * convertedTime;
target.Rotate(rotationDirection * smooth);
// Very important for not freezing the editor completely!
// This tells unity to "pause" the routine here
// render the current frame and continue
// from this point on the next frame
yield return null;
}
}
}
或者更通用的代码
Or a more general code
public class WhilePressedButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private UnityEvent whilePressed;
public void OnPointerDown(PointerEventData pointerEventData)
{
StartCoroutine(ContinuousButton());
}
public void OnPointerUp(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
public void OnPointerEnter(PointerEventData pointerEventData)
{
// Actually not really needed
// but not sure if maybe required for having OnPointerExit work
}
public void OnPointerExit(PointerEventData pointerEventData)
{
StopAllCoroutines();
}
private IEnumerator ContinuousButton()
{
// Whut? o.O
// No worries, this is fine in a Coroutine as long as you yield somewhere inside
while (true)
{
whilePressed.Invoke();
// Very important for not freezing the editor completely!
// This tells unity to "pause" the routine here
// render the current frame and continue
// from this point on the next frame
yield return null;
}
}
}
并在 whilePressed
中引用一个方法,就像通常在按钮 onClick
中通过检查器或代码一样.
And reference a method in whilePressed
like usually in a button onClick
via Inspector or code.
这篇关于Unity/C# 如何在用户界面上连续运行脚本选择事件触发器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!