ºÇ½ª¹¹¿·¡§
orika_ex_miyako 2025ǯ05·î10Æü(ÅÚ) 20:47:16ÍúÎò
¡¡¤³¤Îµ»ö¤ò³èÍѤ¹¤ë¤³¤È¤Ç¡¢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) ¤Ç¼ÂÁõ¤ò´Ê·é¤Ë
¡¡¥³¡¼¥ÉÁ´Ê¸¤Ç¤¹¡£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 () => ½èÍý¡×¤Î¤ß¤ÇÌäÂꤢ¤ê¤Þ¤»¤ó¡£
- ¥«¥Æ¥´¥ê¡§
- ¿Ê³Ø/¥¹¥¯¡¼¥ë
- ¥×¥í¥°¥é¥ß¥ó¥°
¥³¥á¥ó¥È¤ò¤«¤¯