c# - 转换光线时 slider 未填充

标签 c# unity-game-engine

我正在开发 unity3d 并遇到问题。场景中有一个Main Camera,它有一个子对象作为worldspace canvas,并且该 Canvas 还有一个子对象,它是图像。 Main Camera我附加了用于旋转相机的脚本MouseLook,相机通过按A键转换光线。场景中还有一个 WorldSpace canvas,它具有一个 box collider 组件和一个子对象 Slider,以及附加了脚本 的 Canvas > slider 选择Slider

该脚本引用 slider gameobject 并具有一个 Coroutine,当我们按 A 将光线穿过相机转换到 Canvas 时,该协程会填充 slider 键。我的代码工作正常,但它没有正确填充 slider 。当光线转换时,场景立即改变。我想要的是第一个 slider 填充并且播放音频, slider 值等于 0。比场景更改。我认为我在 Coroutine 中做错了什么。

代码:
RayCast 脚本:

public class RayCast : MonoBehaviour
{
    private RaycastHit hit;

    [SerializeField]
    private AudioSource source;

    [SerializeField]
    private AudioClip clip;

    //Refrence of Slider Canvas Script
    [SerializeField]
    private SliderSelect sliderCanvasScript;

    private void Update()
    {
        Debug.DrawRay(transform.position, transform.forward, Color.cyan);

        if (Input.GetKeyDown(KeyCode.A) && SliderSelect.check)
        {
            if (Physics.Raycast(transform.position, transform.forward, out hit, 9f))
            {
                if (hit.collider.gameObject.name == "SliderCanvas")
                {
                    Debug.Log("Ray cast to the slider");
                    StartCoroutine(sliderCanvasScript.FillUp());
                    source.PlayOneShot(clip);
                    SceneManager.LoadScene("Scene0", LoadSceneMode.Single);
                }
            }
        }
    }
}

slider 选择脚本:

public class SliderSelect : MonoBehaviour
{
    [SerializeField]
    private Slider mSlider;

    public static bool check;
    private void Start()
    {
        mSlider.minValue = 0;
        mSlider.maxValue = 100;
        mSlider.wholeNumbers = true;
        mSlider.value = 0;
        check = true;
    }

    public IEnumerator FillUp()
    {
        int i = 0;

        while (i <= 100)
        {
            mSlider.value += 2;
            i += 2;
            yield return null;
        }
        mSlider.value = 0 ;
    }
}

最佳答案

My code is working fine but it doesn't fill the slider correctly. It's change the scene immediately when ray is cast. What i want is first slider is fill and audio is play than slider value equal to 0.Than scene change. I think i'm doing something wrong in Coroutine

那是因为你正在打电话

StartCoroutine(sliderCanvasScript.FillUp());
source.PlayOneShot(clip);
SceneManager.LoadScene("Scene0", LoadSceneMode.Single);

来自 Update 函数,它实际上并不等待 FillUp() 协程函数完成。

从 Update 函数启动一个新的协程函数,然后在该协程函数中执行这三行代码。然后,您可以将 StartCoroutine(sliderCanvasScript.FillUp()); 替换为 yield return StartCoroutine(sliderCanvasScript.FillUp()); ,它将在调用 之前等待它完成>source.PlayOneShot(clip); 后跟 SceneManager.LoadScene("Scene0", LoadSceneMode.Single);

此外,要等待音频完成播放,请勿使用静态 PlayOneShot 函数。

首先,使用 source.clip = Clip; 将剪辑分配给 AudioSource。现在使用source.Play();。接下来,使用 while (source.isPlaying){ yield return null;} 等待音频完成播放。就是这样。

该函数应如下所示:

IEnumerator doInOrder()
{
    //Wait for Fill to finish
    yield return StartCoroutine(sliderCanvasScript.FillUp());
    //Assign Audio Clip
    source.clip = clip;
    //Then Play Sound
    source.Play();

    //Wait for Audio to finish Playing
    while (source.isPlaying)
    {
        yield return null;
    }
    //Load new Scene
    SceneManager.LoadScene("Scene0", LoadSceneMode.Single);
}

整个代码应该是这样的:

public class RayCast : MonoBehaviour
{
    private RaycastHit hit;

    [SerializeField]
    private AudioSource source;

    [SerializeField]
    private AudioClip clip;

    //Refrence of Slider Canvas Script
    [SerializeField]
    private SliderSelect sliderCanvasScript;



    private void Update()
    {
        Debug.DrawRay(transform.position, transform.forward, Color.cyan);
        if (Input.GetKeyDown(KeyCode.A) && SliderSelect.check)
        {
            if (Physics.Raycast(transform.position, transform.forward, out hit, 9f))
            {
                if (hit.collider.gameObject.name == "SliderCanvas")
                {
                    Debug.Log("Ray cast to the slider");
                    StartCoroutine(doInOrder());
                }
            }
        }
    }

    IEnumerator doInOrder()
    {
        //Wait for Fill to finish
        yield return StartCoroutine(sliderCanvasScript.FillUp());
        //Then Play Sound
        source.clip = clip;
        //Then Play Sound
        source.Play();

        //Wait for Audio to finish Playing
        while (source.isPlaying)
        {
            yield return null;
        }
        //Load new Scene
        SceneManager.LoadScene("Scene0", LoadSceneMode.Single);
    }
}

不要将 Collider 放置在 Canvas UI 组件上

Colliders 只能在 Sprites/SpriteRenderer(2D 对象)和 MeshRenderer(2D 对象)上使用。它永远不应该放在 Canvas UI 组件上。

即使这对您有用,您也应该使用 OnPointerClick 检测 slider 的点击,然后使用 onValueChanged 事件检测 slider 值的更改。检测这两件事的脚本必须附加到 Slider GameObject。然后,您可以实现 2 个事件,您可以注册这些事件并在 Slider 上发生点击或 Slider 值更改时接收回调。

将下面的脚本附加到您的 slider :

public class SliderDetector : MonoBehaviour, IPointerClickHandler
{
    public Slider slider;

    public delegate void sliderClicked();
    public static event sliderClicked OnClicked;

    public delegate void valueChanged(float value);
    public static event valueChanged onValueChanged;

    // Use this for initialization
    void Awake()
    {
        slider = GetComponent<Slider>();
        //Subscribe To Slider Event
        slider.onValueChanged.AddListener(delegate { sliderCallBack(slider.value); });
    }


    public void OnPointerClick(PointerEventData eventData)
    {
        if (OnClicked != null)
        {
            //Notify All Subscribed function
            OnClicked();
        }
    }

    void sliderCallBack(float value)
    {
        if (onValueChanged != null)
        {
            //Notify All Subscribed function
            onValueChanged(value);
        }
    }

    void OnDisable()
    {
        //Un-Subscribe To Slider Event
        slider.onValueChanged.RemoveListener(delegate { sliderCallBack(slider.value); });
    }
}

然后要从 Raycast 脚本中使用它,请添加以下内容:

void OnEnable()
{
    //Subscribe to the Slider Click event
    SliderDetector.OnClicked += OnSliderClicked;
    //Subscribe to the Slider Value Changed event
    SliderDetector.onValueChanged += OnSliderValueChanged;
}

//Will be called when there is a click on that slider
private void OnSliderClicked()
{
    //Slider Clicked Start your coroutine function
    StartCoroutine(doInOrder());
}

//Will be called when the slider value changes
private void OnSliderValueChanged(float value)
{
    //Slider Value Changed, Do Something
}

void OnDisable()
{
    //Un-Subscribe to the Slider Click event
    SliderDetector.OnClicked -= OnSliderClicked;
    //Un-Subscribe to the Slider Value Changed event
    SliderDetector.onValueChanged -= OnSliderValueChanged;
}

关于c# - 转换光线时 slider 未填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40874112/

相关文章:

android - Unity 包名称必须匹配 com.Company.ProductName?苹果、安卓

c# - 通过 NuGet 错误 'Newtonsoft.Json' 安装 json.NET 已经为 Microsoft C# 定义了依赖项

c# - CurrentThread.CurrentUICulture 设置正确但总是 en-US

c# - 使用 HoloToolkit 重现 Hololens 手势教程

javascript - EntryPointNotFoundException 外部 JS 库错误

c# - 向 Catmull-Rom 添加 alpha

c# - .NET httpclient 不一致地保存 pdf 文件

c# - 身份 View 在哪里?

c# - 使用内部应用程序的模型将公共(public)表单提交到安全的内部应用程序

java - 无法下载 JDK 8