Unity¤Ë´ØÏ¢¤¹¤ëµ­»ö¤Ç¤¹

¡ß

¤Ç¤­¤ë¤³¤È


¡¡¤³¤Îµ­»ö¤ò³èÍѤ¹¤ë¤³¤È¤Ç¡¢R3(UniRx) ¤ò³èÍѤ·¤¿¥Ü¥¿¥ó¤ÎÏ¢ÂÇËɻߵ¡Ç½¤ò´Ê·é¤Ëµ­ºÜ¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹¡£

[SerializeField] Button normalButton;

// Ä̾ï(Ʊ´ü)¤Î¥¯¥ê¥Ã¥¯½èÍý
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this, 2000);

¡¡½¾Íè¤Î¥Ü¥¿¥óÍÑ¤Î¹ØÆÉ½èÍý(OnClickAsObservable¡¢ThrottleFirst¡¢Subscribe¡¢AddTo)¤ò½ñ¤«¤º¡¢OnClickExt ¥á¥½¥Ã¥É£±¤Ä¤ÇÂåÂØ¤·¤Æ¤¤¤Þ¤¹¡£

¡¡¤½¤ì¤Ç¤Ï½çÈ֤˲òÀ⤷¤Æ¤¤¤­¤Þ¤¹¡£


¤Ï¤¸¤á¤Ë


¡¡Unity ¤Ç Button ¤ò°·¤¦ºÝ¡¢¥Ü¥¿¥ó¤ÎÏ¢ÂǤˤè¤ë°Õ¿Þ¤·¤Ê¤¤Â¿½Å¼Â¹Ô¤òËɤ°¤¿¤á¤Ë¡¢Reactive Extensions¡ÊR3 ¤ä UniRx¡Ë¤ò»È¤Ã¤Æ°Ê²¼¤Î¤è¤¦¤Êµ­½Ò¤ò¤¹¤ë¤³¤È¤¬Â¿¡¹¤¢¤ê¤Þ¤¹¡£

(È´¿è)
using R3;
using System;
using UnityEngine;
using UnityEngine.UI;

[SerializeField] private Button button;

button.OnClickAsObservable()
      .ThrottleFirst(TimeSpan.FromMilliseconds(1000))
      .Subscribe(_ => Debug.Log("Clicked"))
      .AddTo(this);



¡¡¤³¤Î¤è¤¦¤Ë¡¢R3 ¤ò»È¤¨¤Ð¥Ü¥¿¥ó¤ÎÏ¢ÂÇÂкö¤Ï´Êñ¤Ë¼ÂÁõ¤Ç¤­¤Þ¤¹¤·¡¢AddTo(this) ¤Ë¤è¤ë¹ØÆÉ²ò½ü¤â¥¹¥Þ¡¼¥È¤Ë¹Ô¤¨¤Þ¤¹¡£
¤Þ¤¿¥Ü¥¿¥ó¤Î¹ØÆÉ½èÍý¤Ë¤ª¤¤¤Æ¤Ï¡¢´ðËÜŪ¤Ë¤³¤Î·Á¤Ç¤Î¼ÂÁõ¤¬Â¿¤¤¤È»×¤¤¤Þ¤¹¡£

¡¡¤Ç¤¹¤¬¡¢¼ÂºÝ¤Î³«È¯´Ä¶­¤Ç¤Ï

£±¡¥Ëè²ó ThrottleFirst ¤Ë¤è¤ëÏ¢ÂÇËÉ»ßÂкö¤ò½ñ¤¯¤Î¤¬ÃÏÌ£¤ËÌÌÅÝ

£²¡¥È󯱴ü½èÍý¤¬Íí¤à¤È¤µ¤é¤Ëµ­½Ò¤¬¿­¤Ó¤ÆÊ£»¨²½

£³¡¥AddTo ¤ò˺¤ì¤ë¤È¥á¥â¥ê¥ê¡¼¥¯¤Î¸¶°ø¤Ë¤â¤Ê¤ë

£´¡¥Ê£¿ô¿Í¤Çºî¶È¤·¤¿¾ì¹ç¤Î½èÍý¤ÎÅý°ìÀ­

¡¡¤³¤¦¤¤¤Ã¤¿¡ÖƱ¤¸½èÍý¤òËè²ó½ñ¤¯ÈѤ路¤µ¡×¤«¤é¤¯¤ëÌäÂê¤Ë¤âľÌ̤·¤¬¤Á¤Ç¤¹¡£



¡¡¤½¤³¤Ç¡¢¤³¤ì¤é¤Î¶¦Ä̽èÍý¤ò³ÈÄ¥¥á¥½¥Ã¥É¤È¤·¤Æ¤Þ¤È¤á¤ë¤³¤È¤Ç¡¢
¡Ö»È¤¤¤ä¤¹¤¯¡¦¥·¥ó¥×¥ë¡¦°ÂÁ´¡¦ºÆÍøÍѲÄǽ¡×¤Ê½ñ¤­Êý¤ò¼Â¸½¤·¤¿¤Î¤¬¡¢º£²ó¾Ò²ð¤¹¤ë Button ¤Î³ÈÄ¥¥¯¥é¥¹(ButtonExtensions ¥¯¥é¥¹)¤Ç¤¹¡£

¡¡¤³¤Îµ­»ö¤Ç¤Ï¡¢¤½¤Î¥¯¥é¥¹¤Î¼ÂÁõÆâÍÆ¤È¡¢¼ÂºÝ¤Î»È¤¤Êý¤Ë¤Ä¤¤¤Æ²òÀ⤷¤Þ¤¹¡£

¡¡¼ÂºÝ¤Ë»È¤Ã¤Æ¤ß¤ë¤È¡¢½èÍý¤Î¸«Ä̤·¤¬³ÊÃʤˤ褯¤Ê¤ê¡¢UI ¼ÂÁõ¤Î®ÅÙ¤ÈÉʼÁ¤òξΩ¤Ç¤­¤Þ¤¹¡£


¼ÂÁõ¤Î¥Ý¥¤¥ó¥È¤ÈɬÍ×À­


¡¡Unity ¤Îɸ½à²ÝÂê¤È¤·¤Æ¡¢Button.onClick.AddListener() ¤Ï»È¤¤¾¡¼ê¤¬¤è¤¯¤Ê¤¤¡Ê²ò½ü˺¤ì¡¢Ï¢ÂÇÌäÂê¡¢È󯱴ü½èÍý¤È¤ÎÁêÀ­¡Ë¤È¤¤¤¦ÌäÂ꤬¤¢¤ê¤Þ¤¹¡£
¤³¤ì¤é¤Ï R3(+ UniTask) ¤ò³èÍѤ¹¤ë¤³¤È¤Ç²ò·è²Äǽ¤Ê¤Î¤Ç¤¹¤¬¡¢º£²ó¤Ï¤µ¤é¤Ë°ìÊâÆ§¤ß¹þ¤ó¤Ç¡¢¡Ö¥Ü¥¿¥ó½èÍý¤´¤È¤ËËè²óƱ¤¸½èÍý¤òµ­½Ò¤·¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¡×Éôʬ¤ò²ò·è¤·¤è¤¦¤È¤¤¤¦¤Î¤¬¥Ý¥¤¥ó¥È¤Ë¤Ê¤ê¤Þ¤¹¡£
¡¦ThrottleFirst ¤Ë¤è¤êÏ¢ÂÇËÉ»ß
¡¦SubscribeAwait ¤Ë¤è¤êÈ󯱴ü½èÍý¤ËÂбþ
¡¦³ÈÄ¥¥á¥½¥Ã¥É²½ + AddTo(owner) ¤Ç¼ÂÁõ¤ò´Ê·é¤Ë


ButtonExtensions ¥¯¥é¥¹


¡¡¥³¡¼¥ÉÁ´Ê¸¤Ç¤¹¡£R3 ¥Ù¡¼¥¹¤Ç¤¹¡£
¤â¤·¤âƱ̾¤Î³ÈÄ¥¥¯¥é¥¹¤¬¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢namespace ¤ò³èÍѤ·¤¿¤ê¡¢¥¯¥é¥¹Ì¾¤òÊѹ¹¤·¤ÆÂбþ¤·¤Æ¤¯¤À¤µ¤¤¡£

¡¡ºîÀ®¤·¤¿¥¯¥é¥¹¤Ï Editor °Ê³°¤ÎÄ̾ï¤Î¥Õ¥©¥ë¥À¤ËÇÛÃÖ¤·¤Æ¤¯¤À¤µ¤¤¡£


ButtonExtensions.cs
using Cysharp.Threading.Tasks;
using Cysharp.Threading.Tasks.Linq;
using R3;
using System;
using UnityEngine;
using UnityEngine.UI;

public static class ButtonExtensions {

    /// <summary>
    /// OnClick ¤Î¹ØÆÉ½èÍý¤Î³ÈÄ¥¥á¥½¥Ã¥É
    /// </summary>
    /// <param name="button"></param>
    /// <param name="onClick">¥Ü¥¿¥ó²¡²¼»þ¤Î½èÍý</param>
    /// <param name="owner">AddTo ¤Ëɳ¤Å¤±¤ë¥³¥ó¥Ý¡¼¥Í¥ó¥È</param>
    /// <param name="throttleTime">¥Ü¥¿¥ó¤ÎºÆÍ­¸ú²½¤Þ¤Ç¤ÎÂÔµ¡»þ´Ö¡£»ØÄê¤Ê¤±¤ì¤Ð1ÉÃÂÔµ¡</param>
    /// <returns></returns>
    public static IDisposable OnClickExt(this Button button, Action onClick, Component owner, TimeSpan? throttleTime = null) {

        // ¥Ü¥¿¥ó¤ÎºÆÍ­¸ú²½¤Þ¤Ç¤ÎÂÔµ¡»þ´Ö¡£°ú¿ô»ØÄ꤬¤Ê¤¤¾ì¹ç¤Ë¤Ï½é´üÃÍ(1ÉÃ)¤òÀßÄê
        TimeSpan time = throttleTime ?? TimeSpan.FromMilliseconds(1000);

        // ¹ØÆÉ½èÍý¤ò¤Þ¤È¤á¤ë
        IDisposable subscription = button.OnClickAsObservable()
            .ThrottleFirst(time)
            .Subscribe(_ => onClick?.Invoke());

        // AddTo ÍѤÎɳ¤Å¤±Âоݤò¼õ¤±¼è¤ë(¼ç¤Ë this ¤Ê¤É)
        if (owner != null) {
            subscription.AddTo(owner);
        }

        return subscription;
    }

    /// <summary>
    /// OnClick ¤ÎÈ󯱴ü·¿¤Î¹ØÆÉ½èÍý¤Î³ÈÄ¥¥á¥½¥Ã¥É
    /// </summary>
    /// <param name="button"></param>
    /// <param name="onClickAsync"></param>
    /// <param name="owner"></param>
    /// <param name="throttleTime"></param>
    /// <returns></returns>
    public static IDisposable OnClickExtAsync(this Button button, Func<UniTask> onClickAsync, Component owner, TimeSpan? throttleTime = null) {

        // ¥Ü¥¿¥ó¤ÎºÆÍ­¸ú²½¤Þ¤Ç¤ÎÂÔµ¡»þ´Ö¡£°ú¿ô»ØÄ꤬¤Ê¤¤¾ì¹ç¤Ë¤Ï½é´üÃÍ(1ÉÃ)¤òÀßÄê
        TimeSpan time = throttleTime ?? TimeSpan.FromMilliseconds(1000);

        // ¹ØÆÉ½èÍý¤ò¤Þ¤È¤á¤ë
        IDisposable subscription = button.OnClickAsObservable()
            .ThrottleFirst(time)
            .SubscribeAwait(async (_, ct) => await onClickAsync());

        // AddTo ÍѤÎɳ¤Å¤±Âоݤò¼õ¤±¼è¤ë(¼ç¤Ë this ¤Ê¤É¡£¤³¤Î¾ðÊ󤬡¢¾åµ­¤Î ct ¤Ë¤âÍøÍѤµ¤ì¤ë)
        if (owner != null) {
            subscription.AddTo(owner);
        }

        return subscription;
    }
}



¡¡³ÈÄ¥¥á¥½¥Ã¥É¤ÏƱ´ü½èÍýÍѤÈÈ󯱴ü½èÍýÍѤΣ²¼ïÎढ¤ê¤Þ¤¹(È󯱴ü½èÍý¤Ï R3 ¤Î¾ì¹ç¤Î¤ß¤Ç¤¹¡£)
¤É¤Á¤é¤â¡¢°ìÄê»þ´Ö¥Ü¥¿¥ó¤ò̵¸ú²½¡ÊThrottleFirst¡Ë¤·¤Æ¡¢°Õ¿Þ¤·¤Ê¤¤Ï¢ÂǤòËɤ®¤Ä¤Ä¡¢¹ØÆÉ²ò½ü¤ò AddTo ¤Ç¼«Æ°²½¤¹¤ë¡¢°ìÈÌŪ¤ÊÏ¢ÂÇËɻߤλÅÁȤߤǤ¹¡£

¡¡Ìá¤êÃÍ¤âÆ±¤¸ IDisposable ¤Ç¤¹¤Î¤Ç¡¢½èÍý¤ÎÀßÄê»þ¤Ë AddTo °Ê³°¤Ç¤âǤ°Õ¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤â²Äǽ¤Ç¤¹¡£



¡¡¤Þ¤¿°ú¿ô¤òÍѰդ·¤Æ³ÈÄ¥À­¤ò¹â¤¯¤·¤Æ¤¢¤ê¤Þ¤¹¤Î¤Ç¡¢²¼µ­¤Î¤è¤¦¤ÊÆÃħ¤¬¤¢¤ê¤Þ¤¹¡£

¡¡¡¦TimeSpan ¤ò½é´üÃͤ¢¤ê¤Î°ú¿ô¤Ë¤·¤Æ¤¤¤ë¤¿¤á¡¢¥Ü¥¿¥ó¤´¤È¤Ë ThrottleFirst »þ´Ö¤òÄ´À°²Äǽ¡£»ØÄꤷ¤Ê¤±¤ì¤Ð½é´üÃÍ(1ÉÃ)¤òÍøÍÑ

¡¡¡¦Component owner ¤ò null ¤Ë¤¹¤ì¤Ð¹ØÆÉ²ò½ü¤·¤Ê¤¤»È¤¤Êý¤â²Äǽ

¡¡¡¦º£¸å¡¢Interactable ̵¸ú²½¤Ê¤É¤ÎÀ©¸æ¤âÄɲ䷤䤹¤¤¹½Â¤


»ÈÍÑÎã

£±¡¥Æ±´ü½èÍý­¡


¡¡¥µ¥ó¥×¥ë¥³¡¼¥É¤Ç¤¹¡£µ­»ö¤ÎºÇ½é¤ËÄ󼨤·¤¿¤â¤Î¤ÈƱ¤¸ÆâÍÆ¤Ç¤¹¡£
½¾Íè¤Î OnClickAsObsevable¡¢ThrottleFirst¡¢Subscribe¡¢AddTo ¤ò½ñ¤«¤º¡¢OnClickExt ¥á¥½¥Ã¥É£±¤Ä¤ÇÂåÂØ¤·¤Æ¤¤¤Þ¤¹¡£

using UnityEngine;
using UnityEngine.UI;

public class SampleUI : MonoBehaviour {

    [SerializeField] Button normalButton;

    void Start() {
        // Ä̾ï(Ʊ´ü)¤Î¥¯¥ê¥Ã¥¯½èÍý
        normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this, 2000);
    }
}



¡¡¥Ü¥¿¥ó¤Î¹ØÆÉ¡¦Ï¢ÂÇËɻߵ¡Ç½¡¦¹ØÆÉ²ò½ü¤ËɬÍפʽèÍý¤¬£±¹Ô¤Çµ­½Ò¤Ç¤­¤Æ¤¤¤ë¤Î¤¬¤ï¤«¤ê¤Þ¤¹¡£
¤Þ¤¿ using R3; ¤ÎÀë¸À¤âÉÔÍפǤ¹¡£

¡¡Â裱°ú¿ô¤Ï () => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯") ¤ÎÉôʬ¤Ç¤¹¡£
ºÇ½é¤Î () => ¤Î¥é¥à¥À¼°¤Ë¤è¤ë¥Ç¥ê¥²¡¼¥ÈÉôʬ¤Ï¶¦ÄÌ»ÅÍͤǤ¹¡£¾ï¤Ë¤³¤Î·Á¤Ç½èÍý¤ò½ñ¤¤¤Æ¤¯¤À¤µ¤¤¡£
¤½¤Î¸å¡¢¥Ü¥¿¥ó¤ò²¡¤·¤¿ºÝ¤Ë¼Â¹Ô¤·¤¿¤¤½èÍý¤ä¥á¥½¥Ã¥É¤ò½ñ¤­¤Þ¤¹¡£

¡¡Â裲°ú¿ô¤Ï this ¤ÎÉôʬ¤Ç¤¹¡£¤³¤ì¤Ï AddTo ¤È¤·¤ÆÍøÍѤµ¤ì¤ë Component ¤Î¾ðÊó¤Ç¤¹¡£

¡¡Â裳°ú¿ô¤Ï 2000 ¤ÎÉôʬ¤Ç¤¹¡£¤³¤Á¤é¤Ï¾Êά²Äǽ¤Ç¤¹¡£µ­ºÜ¤·¤¿¾ì¹ç¤Î¤ß¡¢ThrottleFirst ¤Î»þ´Ö¤È¤·¤Æ»ØÄꤵ¤ì¤Þ¤¹¡£



¡¡¥Ü¥¿¥ó¤ò²¡²¼¤·¤¿ºÝ¤Ë£²¤Ä°Ê¾å¤Î½èÍý¤ò¼Â¹Ô¤·¤¿¤¤¾ì¹ç¤Ë¤Ï¡¢²¼µ­¤Î¤è¤¦¤Ë ¡Ð ¡Ñ ¤Ç°Ï¤ó¤Ç¤¯¤À¤µ¤¤(Ä̾ï¤Î¥Ç¥ê¥²¡¼¥È½èÍý¤ÈƱ¤¸¤Ç¤¹)¡£

        // Ä̾ï¤Î¥¯¥ê¥Ã¥¯½èÍý
        normalButton.OnClickExt(() => {
            Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯_1");
            Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯_2");
        },                                    // ¤³¤³¤Þ¤Ç¤¬Â裱°ú¿ô              
        this);                                // Â裳°ú¿ô¤Ï¾Êά²Äǽ

¡¡Èó¾ï¤Ë¥·¥ó¥×¥ë¤Ê·Á¤Ç¡¢¥Ü¥¿¥ó¤Î¹ØÆÉ½èÍý¤ò¼ÂÁõ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤·¤¿¡£

¡¡¥Ü¥¿¥ó¤Î¹ØÆÉ½èÍý¤Ë¤Ä¤¤¤Æ¤Ï¡¢¤³¤Î¥á¥½¥Ã¥É¤òÍøÍѤ¹¤ë»ö¤Çǧ¼±¤Î¶¦Í­²½¤ò¤·¤Æ¤ª¤¯¤³¤È¤Ë¤è¤ê¡¢
Ê£¿ô¿Í¤Çºî¶È¤¹¤ë¾ì¹ç¤Ë¤ª¤¤¤Æ¤â¡¢¤¹¤Ù¤Æ¤Î¥Ü¥¿¥ó¤Çϳ¤ì¤Ê¤¯Ï¢ÂÇËɻߵ¡Ç½¤¬¼«Æ°Åª¤Ë¼ÂÁõ¤µ¤ì¤ë¤³¤È¤â¤Ê¤ê¡¢°ÂÁ´À­¤â¹â¤Þ¤ê¤Þ¤¹¡£


£²¡¥Æ±´ü½èÍý­¢


¡¡AddTo ¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Ï¤Ê¤¯¡¢Ê̤Υ¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤¬É¬Íפʥ±¡¼¥¹¤¬¤¢¤ê¤Þ¤¹¡£
¤½¤Î¾ì¹ç¤Ë¤Ï¡¢IDisposable ¤òÌÀ¼¨Åª¤ËÊÝ»ý¤·¤Æ¤ª¤­¡¢É¬Íפ˱þ¤¸¤Æ¡¢ÍѰդ·¤Æ¤ª¤¤¤¿ Dispose ¥á¥½¥Ã¥É¤Ç¹ØÆÉ²ò½ü¤Ç¤­¤ë¤è¤¦¤Ë¤·¤Æ¤ª¤¯¤³¤È¤ÇÂбþ²Äǽ¤Ç¤¹¡£

¡¡¤Þ¤¿¥ª¥Ö¥¸¥§¥¯¥È¥×¡¼¥ë¤Ê¤É¤òÍøÍѤ·¤Æ¤¤¤ë¾ì¹ç¤Ë¤Ï OnDisable ¥á¥½¥Ã¥É¤òÍѰդ·¤Æ¤ª¤¯¤³¤È¤Ç¡¢
¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤ÎÇË´þ¤Ç¤Ï¤Ê¤¯¡¢Èó¥¢¥¯¥Æ¥£¥Ö¾õÂÖ¤Ç¤Î¹ØÆÉ²ò½ü¤â¼ÂÁõ¤Ç¤­¤Þ¤¹¡£


using UnityEngine;
using UnityEngine.UI;
using System;

public class SampleButtonHandler : MonoBehaviour
{
    [SerializeField] private Button sampleButton;

    private IDisposable clickSubscription;

    void Start() {

        // ¹ØÆÉ½èÍý¤òÌá¤êÃͤò¼õ¤±¼è¤Ã¤ÆÊÑ¿ô¤ÇÊÝ»ý¡£³ÈÄ¥¥á¥½¥Ã¥É¤ò»È¤Ã¤Æ¹ØÆÉ³«»Ï(Âè1°ú¿ô¤Î½èÍý¤¬1¹Ôʬ¤Ç¤¢¤Ã¤Æ¤â { } ¤Ç°Ï¤ó¤Ç¤è¤¤)
        clickSubscription = sampleButton.OnClickExt(() => {
            Debug.Log("Button Clicked!");
        }, this, TimeSpan.FromMilliseconds(1500));
    }

    public void Dispose() {

        // ¼êư¤Ç¹ØÆÉ²ò½ü¤¹¤ë¾ì¹ç¡ÊAddTo ¤¬»È¤¨¤Ê¤¤¾õ¶·¤Ê¤É¡Ë
        clickSubscription?.Dispose();
    }

    void OnDisable() {

        // Èó¥¢¥¯¥Æ¥£¥Ö¾õÂ֤Υ¿¥¤¥ß¥ó¥°¤Ç˺¤ì¤º Dispose ¸Æ¤Ó½Ð¤·
        Dispose();
    }
}

¡¡¤³¤Î¤è¤¦¤Ë½àÈ÷¤·¤Æ¤ª¤¯¤³¤È¤Ë¤è¤ê¡¢ÍÍ¡¹¤Ê¾õ¶·¤ËÂбþ¤·¤¿¹ØÆÉ²ò½ü¤¬²Äǽ¤Ë¤Ê¤ê¤Þ¤¹¡£


£³¡¥È󯱴ü½èÍý­¡


¡¡¥Ü¥¿¥ó²¡²¼»þ¤Î½èÍý¤òÈ󯱴ü½èÍý¤Ç¹Ô¤¤¤¿¤¤¾ì¹ç¡¢R3 ¤Ç¤Ï SubscribeAwait ¥á¥½¥Ã¥É¤¬ÍѰդµ¤ì¤Æ¤¤¤ë¤Î¤ÇÂбþ¤¬²Äǽ¤Ç¤¹¡£
¤½¤Á¤é¤Î³ÈÄ¥¥á¥½¥Ã¥É¤È¤·¤Æº£²ó OnClickExtAsync ¥á¥½¥Ã¥É¤òÍѰդ·¤Æ¤¢¤ê¤Þ¤¹¤Î¤Ç¡¢¤½¤Á¤é¤ÇÂåÂØ¤·¤¿¥±¡¼¥¹¤Ç¤¹¡£

using UnityEngine;
using UnityEngine.UI;

public class SampleUIAsync : MonoBehaviour {

    [SerializeField] Button asyncButton;

    void Start() {

        // È󯱴ü¤Î¥¯¥ê¥Ã¥¯½èÍý
        asyncButton.OnClickExtAsync(async (_, ct) => {
            await UniTask.Delay(1000);
            Debug.Log("È󯱴ü¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯´°Î»");
        }, this);
    }
}



¡¡¤Ê¤ª¤³¤Á¤é¤â¡¢IDisposable ·¿¤ÎÊÑ¿ô¤ÇÊÝ»ý¤·¤Æ¤ª¤¯¤³¤È¤Ç¡¢Ç¤°Õ¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤â²Äǽ¤Ç¤¹¡£

    private IDisposable clickSubscription;

    // Start ¥á¥½¥Ã¥É¤Ê¤É¤Ç¹ØÆÉ½èÍý
¡¡¡¡clickSubscription = asyncButton.OnClickExtAsync(
    ¡¡¡¡async (_, ct) => {
        ¡¡¡¡await UniTask.Delay(3000, cancellationToken: ct);
    ¡¡¡¡}, this);

¡¡°ú¿ô¤Î½ñ¤­Êý¤¬Æ±´ü½èÍý¤È¤Ï°Û¤Ê¤ê¤Þ¤¹¤Î¤ÇÃí°Õ¤·¤Æ¤¯¤À¤µ¤¤¡£

¡¡¤³¤Î½èÍý¤Î¾ì¹ç¡¢È󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë¤¬ this ¤Èɳ¤Å¤¤¤Æ¤¤¤ë¤Î¤Ç¡¢
¥Ü¥¿¥ó¤Î¹ØÆÉ²ò½ü¤ÈƱ»þ¤Ë¡¢È󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë¤â°ì½ï¤Ë¹Ô¤ï¤ì¤ë¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹¡£



¡¡¤ä¤Ï¤ê¤³¤Á¤é¤Î¾ì¹ç¤â AddTo ¥á¥½¥Ã¥É°Ê³°¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤ò¹Ô¤¤¤¿¤¤¥±¡¼¥¹¤¬¤¢¤ê¤Þ¤¹¡£
¤½¤Î¤¿¤á Dispose ¥á¥½¥Ã¥É¤òÍѰդ·¤Æ¤ª¤¯¤³¤È¤Ç¡¢Ç¤°Õ¤Î¥¿¥¤¥ß¥ó¥°¤Ç¥Ü¥¿¥ó¤Î¹ØÆÉ²ò½ü¤ÈƱ»þ¤ËÈ󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë¤¬¹Ô¤¨¤Þ¤¹¡£

    public void Dispose() {

        // ¼êư¤Ç¹ØÆÉ²ò½ü¤¹¤ë¾ì¹ç¡ÊAddTo ¤¬»È¤¨¤Ê¤¤¾õ¶·¤Ê¤É¡Ë
        clickSubscription?.Dispose();
    }

¡¡¤¿¤À¤·¡¢È󯱴ü½èÍý¤Î¾ì¹ç¤Ë¤Ï¡¢¥Ü¥¿¥ó¤Î¹ØÆÉ²ò½ü¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Ï¤Ê¤¯¤Æ¡¢³°Éô¥¯¥é¥¹¤ÎÈ󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë½èÍý¤ÈϢư¤µ¤»¤¿¤¤¥±¡¼¥¹¤â¤¢¤ê¤Þ¤¹¤Î¤Ç¡¢
¼¡¤Ï¤½¤Á¤é¤Î¥±¡¼¥¹¤Ç¤ÎÂбþÊýË¡¤òµ­½Ò¤·¤Æ¤ª¤­¤Þ¤¹¡£


£´¡¥È󯱴ü½èÍý­¢


¡¡³°Éô¥¯¥é¥¹¤ÎÈ󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë½èÍý¤ÈϢư¤µ¤»¤¿¤¤¥±¡¼¥¹¤Ç¤¹¡£

¡¡¤Þ¤ººÇ½é¤Ë¸½ºß¤Î ButtonExtentions ¥¯¥é¥¹¤Ë¤¢¤ë³ÈÄ¥¥á¥½¥Ã¥É¤Î¤ß¤Ç¤ÏÂбþ¤¬¤Ç¤­¤Þ¤»¤ó¤Î¤Ç¡¢½èÍý¤ÎÄɲäò¹Ô¤¤¤Þ¤¹¡£



¡¡¤Þ¤º ButtonExtentions ¥¯¥é¥¹¤Ë¡¢¼¡¤Î¥á¥½¥Ã¥É¤òÄɲä·¤Þ¤¹¡£
¤³¤ì¤Ï OnClickExtAsync ¥á¥½¥Ã¥É¤Î¥ª¡¼¥Ð¡¼¥í¡¼¥É¤Ç¡¢°ú¿ô¤Ë CancellationToken ¤¬Äɲäµ¤ì¤Æ¤¤¤Þ¤¹¡£


ButtonExtentions.cs
public static IDisposable OnClickExtAsync(this Button button, Func<UniTask> onClickAsync, CancellationToken token, TimeSpan? throttleTime = null)
{
    TimeSpan time = throttleTime ?? TimeSpan.FromMilliseconds(1000);

    IDisposable subscription = button.OnClickAsObservable()
        .ThrottleFirst(time)
        .SubscribeAwait(async (_, _) => await onClickAsync(), token); // ¢« ¤³¤³¤Ç³°Éô¤Î token ¤òÅϤ¹

    return subscription;
}

¡¡AddTo ¥á¥½¥Ã¥É¤Ç¤Î¹ØÆÉ²ò½ü¤Ç¤Ï¤Ê¤¯¡¢°ú¿ô¤Ç¼õ¤±¼è¤Ã¤¿ CancellationToken ¤òÍøÍѤ·¤Æ¹ØÆÉ²ò½ü¤ò¹Ô¤¦·Á¤Ë¤Ê¤Ã¤Æ¤¤¤Þ¤¹¡£



¡¡¾åµ­¤Î¥á¥½¥Ã¥É¤òÍøÍѤ¹¤ë·Á¤Ç¡¢¤Û¤«¤ÎÈ󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤ò¼ÂÁõ¤Ç¤­¤Þ¤¹¡£

¡¡¤³¤Î¥µ¥ó¥×¥ë¥³¡¼¥É¤Ç¤Ï¥¯¥é¥¹Æâ¤Ç¥­¥ã¥ó¥»¥ë¥È¡¼¥¯¥ó¤òÀ¸À®¤·¤Æ¤¤¤Þ¤¹¤¬¡¢
¤³¤Á¤é¤Î¥­¥ã¥ó¥»¥ë¥È¡¼¥¯¥ó¾ðÊó¤ò³°Éô¤«¤é¼õ¤±¼è¤Ã¤Æ°ú¿ô¤Ë»ØÄꤹ¤ë¤³¤È¤Ç¡¢¤½¤Î¥­¥ã¥ó¥»¥ë¥È¡¼¥¯¥ó¤Èɳ¤Å¤¯¤Û¤«¤Î½èÍý¤È¹ç¤ï¤»¤Æ¹ØÆÉ²ò½ü¤¬¹Ô¤ï¤ì¤Þ¤¹¡£


using UnityEngine;
using UnityEngine.UI;
using System;
using Cysharp.Threading.Tasks;
using System.Threading;

public class SampleButtonHandlerAsyncWithToken : MonoBehaviour, IDisposable
{
    [SerializeField] private Button sampleButton;

    private IDisposable clickSubscription;
    private CancellationTokenSource cts;      // ³°Éô¥¯¥é¥¹¤«¤é¤â¤é¤¦·Á¤À¤¬¡¢º£²ó¤Ï¥Ç¥Ð¥Ã¥°ÍѤˤ³¤³¤Ëµ­½Ò

    // ¥Ç¥Ð¥Ã¥°ÍÑ¡£¼ÂºÝ¤Ë¤Ï³°Éô¥¯¥é¥¹¤Ç¹Ô¤¦½èÍý
    void Start() {

        cts = new CancellationTokenSource();

        SetupAsyncButton(cts.Token);
    }

    public void SetupAsyncButton(CancellationToken token) {

        clickSubscription = sampleButton.OnClickExtAsync(
            async () => {
                Debug.Log("Start async task...");
        
                try {
                    await UniTask.Delay(3000, cancellationToken: token);
                    Debug.Log("Async task finished.");
                } 
                catch (OperationCanceledException) {
                    Debug.Log("Async task was cancelled.");
                }
            },
            token);
    }

    public void Dispose()
    {
        clickSubscription?.Dispose();

        // ¤³¤³¤Ï¼«¥¯¥é¥¹Æâ¤Ç¥­¥ã¥ó¥»¥ë¥È¡¼¥¯¥ó¤òÀ¸À®¤·¤Æ¤¤¤ë¾ì¹ç¤Î¤ßµ­½Ò¤¹¤ë
        if (cts != null)
        {
            if (!cts.IsCancellationRequested)
            {
                cts.Cancel();
            }
            cts.Dispose();
            cts = null;
        }

        Debug.Log("Button subscription disposed manually.");
    }

    void OnDisable() {

        // ˺¤ì¤º Dispose ¸Æ¤Ó½Ð¤·
        Dispose();
    }
}

¡¡SubscribeAwait ¥á¥½¥Ã¥É¤Ë¤è¤ê¡¢onClickAsync() Æâ¤Ç»È¤¦¥­¥ã¥ó¥»¥ë¥È¡¼¥¯¥ó¤¬¼«Á°¤Ç¥³¥ó¥È¥í¡¼¥ë²Äǽ¤Ë¤Ê¤ê¤Þ¤¹¡£
¤³¤Á¤é¤Î¾ì¹ç¡¢Unity ¥é¥¤¥Õ¥µ¥¤¥¯¥ë¤ÈÀÚ¤êÎ¥¤·¤ÆÀ©¸æ¤Ç¤­¤ë¤¿¤á¡¢¤è¤ê½ÀÆð¤Ê¥Ü¥¿¥ó¥¤¥Ù¥ó¥È´ÉÍý¤¬¤Ç¤­¤Þ¤¹¡£



¡¡»È¤¤Ê¬¤±¤È¤·¤Æ¤Ï¡¢°Ê²¼¤Î¤è¤¦¤Ë¤Ê¤ê¤Þ¤¹¡£
¡Ö郎¥­¥ã¥ó¥»¥ë¤ò´ÉÍý¤¹¤ë¤«¡©¡×¤Ë¤è¤Ã¤Æ¡¢¤É¤Á¤é¤Î¥ª¡¼¥Ð¡¼¥í¡¼¥É¤ò»È¤¦¤«¤òÀÚ¤êÂØ¤¨¤ë¤Î¤¬´ðËÜ¥¹¥¿¥ó¥¹¤Ç¤¹¡£
¥á¥½¥Ã¥É·Á¼°¥­¥ã¥ó¥»¥ëÂоݻÈÍÑ¥·¡¼¥óÂè1°ú¿ô¤Î½ñ¤­Êý¡¢Âè2°ú¿ô¤Î»ØÄê
OnClickExtAsync(Func<UniTask>, Component)Unity ¥é¥¤¥Õ¥µ¥¤¥¯¥ë¤ËϢưthis ¤Ê¤É¤Ëɳ¤Å¤±¤¿¤¤¾ì¹çasync (_, ct) => ½èÍý, Âè2°ú¿ô¤Ë¤Ï OnClickExtAsync ¥á¥½¥Ã¥É¤ÎÂè2°ú¿ô¤ÇÆÏ¤¤¤Æ¤¤¤ë Component ÊÑ¿ô(this ¤Ê¤É)
OnClickExtAsync(Func<UniTask>, CancellationToken)³°ÉôÀ©¸æ¤µ¤ì¤¿¥È¡¼¥¯¥ó¤ËϢưDispose() ¤ä Cancel() ¤Ë¤è¤ëºÙ¤«¤¤À©¸æ¤ò¤·¤¿¤¤¾ì¹çasync () => ½èÍý, Âè2°ú¿ô¤Ë CancellationToken ÊÑ¿ô

¡¡¹ØÆÉ²ò½üÍѤΰú¿ô¤Ï¡¢OnClickExtAsync ¥á¥½¥Ã¥É¤ÎÂè2°ú¿ô(Component ·¿¤«¡¢CancellationToken ·¿)¤Ç»ØÄꤷ¤¿·¿¤¬É³¤Å¤­¤Þ¤¹¡£OnClickExtAsync ¥á¥½¥Ã¥É¤¬£²¤ÄÍѰդµ¤ì¤Æ¤¤¤ë¤Î¤Ï¤½¤Î¤¿¤á¤Ç¤¹¡£
¤è¤Ã¤Æ¡¢¥é¥¤¥Õ¥µ¥¤¥¯¥ë(¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È(¥¯¥é¥¹)¤ÎÇË´þ)¤Ëɳ¤Å¤±¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¤·¡¢¤Û¤«¤ÎÈ󯱴ü½èÍý¤Î¥­¥ã¥ó¥»¥ë¥¿¥¤¥ß¥ó¥°¤È°ì½ï¤Ë²ò½ü¤¹¤ë¤³¤È¤â¤Ç¤­¤Þ¤¹¡£


ÌÜŪÁª¤Ö¤Ù¤­³ÈÄ¥¥á¥½¥Ã¥ÉÈ÷¹Í
Component ¤Î¥é¥¤¥Õ¥µ¥¤¥¯¥ë¡ÊÇË´þ¡Ë¤Ë¹ç¤ï¤»¤Æ¥­¥ã¥ó¥»¥ë¤·¤¿¤¤OnClickExtAsync(this Button, Func<UniTask> onClickAsync, Component owner, ...)AddTo(owner) ¤Ë¤è¤ê¡¢¼«Æ°Åª¤Ë CancellationToken ¤¬ÆâÉô¤ÇÅϤµ¤ì¤ë
³°Éô¤«¤éÅϤµ¤ì¤¿ CancellationToken ¤Î¥­¥ã¥ó¥»¥ë¥¿¥¤¥ß¥ó¥°¤Ë¹ç¤ï¤»¤¿¤¤OnClickExtAsync(this Button, Func<UniTask> onClickAsync, CancellationToken token, ...)¼«Á°¤Î cts.Token ¤ä³°Éô¥¯¥é¥¹¤Î¥È¡¼¥¯¥ó¤Ê¤É¡¢Ç¤°Õ¤Î¥È¡¼¥¯¥ó¤ò¼êư¤Ç´ÉÍý¤·¤¿¤¤¤È¤­¤Ë»È¤¦

¡¡AddTo(owner) ¤Ç¥­¥ã¥ó¥»¥ë¤·¤¿¤¤¤Ê¤é (_, ct) ¤ò¼è¤ë·Á¼°¤ÇÆâÉô¥È¡¼¥¯¥ó¤Ë°Ñ¤Í¤Þ¤¹¡£

¡¡¼«Á°¤Ç CancellationTokenSource ¤ò´ÉÍý¤·¤¿¤¤¾ì¹ç¤ä³°Éô¥¯¥é¥¹¤«¤é´ÉÍý¤·¤¿¤¤¾ì¹ç¡ÊÎ㤨¤Ð°ìÏ¢¤Î UI ½èÍý¤ÎÃæÃǤʤɡˤˤϡ¢³°¤«¤é¥È¡¼¥¯¥ó¤òÅϤ¹¥ª¡¼¥Ð¡¼¥í¡¼¥É¤ò»È¤¤¤Þ¤¹¡£

¡¡Ã±½ã¤ÊÈ󯱴ü½èÍý¤À¤±¤·¤¿¤¤¤Ë¤Ï¡¢¡Öasync () => ½èÍý¡×¤Î¤ß¤ÇÌäÂꤢ¤ê¤Þ¤»¤ó¡£


¤ª¤ï¤ê¤Ë


¡¡¤³¤Î¤è¤¦¤Ê¾®¤µ¤Ê³ÈÄ¥¥á¥½¥Ã¥É¤Ç¤â¡¢¥Ü¥¿¥ó¤Î¼ÂÁõ¸úΨ¤ÈÊݼéÀ­¤òÂ礭¤¯²þÁ±¤Ç¤­¤Þ¤¹¡£
Ʊ¤¸½èÍý¤ò·«¤êÊÖ¤·½ñ¤¤¤Æ¤¤¤ë¤Ê¤¡¡¢¤È´¶¤¸¤ë¤³¤È¤¬¤¢¤Ã¤¿¤é¡¢¤³¤¦¤¤¤Ã¤¿³ÈÄ¥¥á¥½¥Ã¥É¤òºîÀ®¤¹¤ë¤³¤È¤â¸¡Æ¤¤·¤Æ¤ß¤Þ¤·¤ç¤¦¡£

¥³¥á¥ó¥È¤ò¤«¤¯


¡Öhttp://¡×¤ò´Þ¤àÅê¹Æ¤Ï¶Ø»ß¤µ¤ì¤Æ¤¤¤Þ¤¹¡£

ÍøÍѵ¬Ìó¤ò¤´³Îǧ¤Î¤¦¤¨¤´µ­Æþ²¼¤µ¤¤

Menu


´ðÁÃ

µ»½Ñ/Ãμ±(¼ÂÁõÎã)

3D¥¢¥¯¥·¥ç¥ó¥²¡¼¥à

2D¤ª¤Ï¤¸¤­¥²¡¼¥à(ȯŸÊÔ)

2D¶¯À©²£¥¹¥¯¥í¡¼¥ë¥¢¥¯¥·¥ç¥ó(ȯŸÊÔ)

2D¥¿¥Ã¥×¥·¥å¡¼¥Æ¥£¥ó¥°(³ÈÄ¥ÊÔ)

¥ì¡¼¥¹¥²¡¼¥à(È´¿è)

2DÊüÃÖ¥²¡¼¥à(ȯŸÊÔ)

3D¥ì¡¼¥ë¥¬¥ó¥·¥å¡¼¥Æ¥£¥ó¥°(±þÍÑÊÔ)

3Dæ½Ð¥²¡¼¥à(È´¿è)

2D¥ê¥¢¥ë¥¿¥¤¥à¥¹¥È¥é¥Æ¥¸¡¼

3D¥¿¥Ã¥×¥¢¥¯¥·¥ç¥ó(NavMeshAgent »ÈÍÑ)

2D¥È¥Ã¥×¥Ó¥å¡¼¥¢¥¯¥·¥ç¥ó(¥«¥¨¥ë¤Î°Ù¤Ë¡Á¡¢¥Ü¥³¥¹¥«¥¦¥©¡¼¥ºÉ÷)

VideoPlayer ¥¤¥Ù¥ó¥ÈϢư¤Î¼ÂÁõÎã

VideoPlayer ¥ê¥¹¥ÈÆâ¤«¤é¥à¡¼¥Ó¡¼ºÆÀ¸¤Î¼ÂÁõÎã(ȯŸ)

AR ²èÁüÉÕ¤­¥ª¥Ö¥¸¥§¥¯¥ÈÀ¸À®¤Î¼ÂÁõÎã

AR ¥ê¥¹¥ÈÆâ¤«¤éÀ¸À®¤Î¼ÂÁõÎã(ȯŸ)

2D¥È¥Ã¥×¥Ó¥å¡¼¥¢¥¯¥·¥ç¥ó(¥µ¥Ð¥¤¥Ð¡¼É÷)

private



¤³¤Î¥µ¥¤¥ÈÆâ¤ÎºîÉʤϥæ¥Ë¥Æ¥£¤Á¤ã¤ó¥é¥¤¥»¥ó¥¹¾ò¹à¤Î¸µ¤ËÄ󶡤µ¤ì¤Æ¤¤¤Þ¤¹¡£

´ÉÍý¿Í/Éû´ÉÍý¿Í¤Î¤ßÊÔ½¸¤Ç¤­¤Þ¤¹