ºÇ½ª¹¹¿·¡§
orika_ex_miyako 2025ǯ11·î27Æü(ÌÚ) 12:03:03ÍúÎò
¡¡¤³¤Îµ»ö¤ò³èÍѤ¹¤ë¤³¤È¤Ç¡¢R3(UniRx) ¤ò³èÍѤ·¤¿¥Ü¥¿¥ó¤ÎÏ¢ÂÇËɻߵ¡Ç½¤ò´Ê·é¤ËµºÜ¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹¡£
[SerializeField] private Button normalButton;
// Ä̾ï(Ʊ´ü)¤Î¥¯¥ê¥Ã¥¯½èÍý(Ï¢ÂÇËɻߤλþ´Ö¤Ï 1 Éä˼«Æ°Åª¤ËÀßÄê)
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this);
// Ï¢ÂÇËɻ߻þ´Ö¤òÊÌÅÓÀßÄꤹ¤ë¾ì¹ç
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this, TimeSpan.FromMilliseconds(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 System;
using UnityEngine;
using UnityEngine.UI;
public class SampleUI : MonoBehaviour {
[SerializeField] Button normalButton;
void Start() {
// Ä̾ï(Ʊ´ü)¤Î¥¯¥ê¥Ã¥¯½èÍý
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this, TimeSpan.FromMilliseconds(2000));
}
}
¡¡¥Ü¥¿¥ó¤Î¹ØÆÉ¡¦Ï¢ÂÇËɻߵ¡Ç½¡¦¹ØÆÉ²ò½ü¤ËɬÍפʽèÍý¤¬£±¹Ô¤Çµ½Ò¤Ç¤¤Æ¤¤¤ë¤Î¤¬¤ï¤«¤ê¤Þ¤¹¡£
¤Þ¤¿ using R3; ¤ÎÀë¸À¤âÉÔÍפǤ¹¡£
¡¡Â裱°ú¿ô¤Ï () => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯") ¤ÎÉôʬ¤Ç¤¹¡£
ºÇ½é¤Î () => ¤Î¥é¥à¥À¼°¤Ë¤è¤ë¥Ç¥ê¥²¡¼¥ÈÉôʬ¤Ï¶¦ÄÌ»ÅÍͤǤ¹¡£¾ï¤Ë¤³¤Î·Á¤Ç½èÍý¤ò½ñ¤¤¤Æ¤¯¤À¤µ¤¤¡£
¤½¤Î¸å¡¢¥Ü¥¿¥ó¤ò²¡¤·¤¿ºÝ¤Ë¼Â¹Ô¤·¤¿¤¤½èÍý¤ä¥á¥½¥Ã¥É¤ò½ñ¤¤Þ¤¹¡£
¡¡Â裲°ú¿ô¤Ï this ¤ÎÉôʬ¤Ç¤¹¡£¤³¤ì¤Ï AddTo ¤È¤·¤ÆÍøÍѤµ¤ì¤ë Component ¤Î¾ðÊó¤Ç¤¹¡£
¡¡Â裳°ú¿ô¤Ï TimeSpan.FromMilliseconds(2000) ¤ÎÉôʬ¤Ç¤¹¡£¤³¤Á¤é¤Ï¾Êά²Äǽ¤Ç¤¹¡£
¾Êά¤·¤¿¾ì¹ç¤Ë¤Ï½é´üÃͤȤ·¤ÆÀßÄꤷ¤Æ¤¢¤ë 1000 ¤¬»ÈÍѤµ¤ì¤Þ¤¹¡£using System ¤ÎÀë¸À¤âÉÔÍפˤʤê¤Þ¤¹¡£
º£²ó¤Î¤è¤¦¤Ëµ½Ò¤·¤¿¾ì¹ç¤Î¤ß¡¢ThrottleFirst ¤Î»þ´Ö¤È¤·¤Æ»ØÄꤵ¤ì¤Þ¤¹¡£¤Ê¤ª TimeSpan ¤Ï TimeSpan.FromSeconds(2) ¤Ç¤â»ØÄê²Äǽ¤Ç¤¹¡£
<Âè3°ú¿ô¾Êά¤Î¾ì¹ç>
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this);
<Âè3°ú¿ô¤Ë TimeSpan.FromSeconds ¤òÍøÍѤ·¤¿¾ì¹ç>
using System;
normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this, TimeSpan.FromSeconds(2));
¡¡¥Ü¥¿¥ó¤ò²¡²¼¤·¤¿ºÝ¤Ë£²¤Ä°Ê¾å¤Î½èÍý¤ò¼Â¹Ô¤·¤¿¤¤¾ì¹ç¤Ë¤Ï¡¢²¼µ¤Î¤è¤¦¤Ë ¡Ð ¡Ñ ¤Ç°Ï¤ó¤Ç¤¯¤À¤µ¤¤(Ä̾ï¤Î¥Ç¥ê¥²¡¼¥È½èÍý¤ÈƱ¤¸¤Ç¤¹)¡£
// Ä̾ï¤Î¥¯¥ê¥Ã¥¯½èÍý
normalButton.OnClickExt(() => {
Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯_1");
Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯_2");
}, // ¤³¤³¤Þ¤Ç¤¬Â裱°ú¿ô
this); // Â裳°ú¿ô¤Ï¾Êά²Äǽ
¡¡Èó¾ï¤Ë¥·¥ó¥×¥ë¤Ê·Á¤Ç¡¢¥Ü¥¿¥ó¤Î¹ØÆÉ½èÍý¤ò¼ÂÁõ¤¹¤ë¤³¤È¤¬¤Ç¤¤Þ¤·¤¿¡£
¡¡¥Ü¥¿¥ó¤Î¹ØÆÉ½èÍý¤Ë¤Ä¤¤¤Æ¤Ï¡¢¤³¤Î¥á¥½¥Ã¥É¤òÍøÍѤ¹¤ë»ö¤Çǧ¼±¤Î¶¦Í²½¤ò¤·¤Æ¤ª¤¯¤³¤È¤Ë¤è¤ê¡¢
Ê£¿ô¿Í¤Çºî¶È¤¹¤ë¾ì¹ç¤Ë¤ª¤¤¤Æ¤â¡¢¤¹¤Ù¤Æ¤Î¥Ü¥¿¥ó¤Çϳ¤ì¤Ê¤¯Ï¢ÂÇËɻߵ¡Ç½¤¬¼«Æ°Åª¤Ë¼ÂÁõ¤µ¤ì¤ë¤³¤È¤â¤Ê¤ê¡¢°ÂÁ´À¤â¹â¤Þ¤ê¤Þ¤¹¡£
¡¡AddTo ¤Î¥¿¥¤¥ß¥ó¥°¤Ç¤Ï¤Ê¤¯¡¢Ê̤Υ¿¥¤¥ß¥ó¥°¤Ç¤Î¹ØÆÉ²ò½ü¤¬É¬Íפʥ±¡¼¥¹¤¬¤¢¤ê¤Þ¤¹¡£
Î㤨¤Ð¥ª¥Ö¥¸¥§¥¯¥È¥×¡¼¥ë¤Ê¤É¤òÍøÍѤ·¤Æ¤¤¤ë¾ì¹ç¤Ë¤Ï¡¢¥²¡¼¥à¥ª¥Ö¥¸¥§¥¯¥È¤¬ÇË´þ¤µ¤ì¤Þ¤»¤ó¤Î¤Ç¡¢AddTo ¤Ë¤è¤ë¼«Æ°²ò½ü¤¬¹Ô¤¨¤Þ¤»¤ó¡£
¡¡º£²óÍѰդ·¤Æ¤¤¤ë OnClickExt ¥á¥½¥Ã¥É¤ÎÌá¤êÃͤâ IDisposable ·¿¤Ç¤¹¡£
¤½¤Î¤¿¤á¡¢IDisposable ·¿¤ÎÊÑ¿ô¤òÍѰդ·¤Æ¤ª¤¡¢OnClickExt ¥á¥½¥Ã¥É¤Î¹ØÆÉ½èÍý¤òÊÝ»ý¤¹¤ë¤³¤È¤¬²Äǽ¤Ç¤¹¡£
¡¡ÊÝ»ý¤·¤Æ¤ª¤¯¤³¤È¤Ë¤è¤ê¡¢Î㤨¤Ð 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();
}
}
using System;
CompositeDisposable disposables; // CompositeDisposable ¤Ç¤â²Äǽ(¤½¤Î¾ì¹ç¤Ë¤Ï½é´ü²½¤ò˺¤ì¤º¤Ë¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤)
private void Start() {
disposables = new();
disposables = normalButton.OnClickExt(() => Debug.Log("Ä̾ï¥Ü¥¿¥ó¥¯¥ê¥Ã¥¯"), this);
}
private void OnDisable() {
Release();
}
private void Release() {
disposables?.Clear(); // 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 ¥á¥½¥Ã¥É¤Î°ú¿ô¤Î¥ª¡¼¥Ð¡¼¥í¡¼¥É¥á¥½¥Ã¥É¤Ë¤Ê¤ê¤Þ¤¹¡£
¡¡½èÍý¤ÎÆâÍÆ¤È¤·¤Æ¤Ï°ú¤Â³¤ Subscribe ¥á¥½¥Ã¥É¤Ç¤Ï¤Ê¤¯ SubscribeAwait ¥á¥½¥Ã¥É¤òÍøÍѤ·¤Æ¹ØÆÉ½èÍý¤ò¹Ô¤¦·Á¤Ë¤Ê¤Ã¤Æ¤ª¤ê¡¢
¥Ç¥ê¥²¡¼¥ÈÍѤΰú¿ô¤â Func<CancellationToken, UniTask> ·¿¤Ë¤Ê¤ê¡¢CancellationToken ¤¬¿·¤·¤¯Äɲäµ¤ì¤Æ¤¤¤Þ¤¹¡£
¤Þ¤¿ Component ·¿¤Î°ú¿ô¤â½é´üÃͤò null ¤ÇÅϤ»¤ë¤è¤¦¤Ë¤·¡¢ÇË´þ·ÐÏ©¤¬Æó½Å¤Ë¤Ê¤é¤Ê¤ë¤³¤È¤ò²óÈò¤Ç¤¤ë¤è¤¦¤Ë¤·¤Æ¤¤¤Þ¤¹¡£
ButtonExtentions.cs
/// <summary>
/// OnClick ¤ÎÈ󯱴ü·¿¤Î¹ØÆÉ½èÍý¤Î³ÈÄ¥¥á¥½¥Ã¥É
/// </summary>
/// <param name="button"></param>
/// <param name="onClickAsync"></param>
/// <param name="externalToken"></param>
/// <param name="owner"></param>
/// <param name="throttleTime"></param>
/// <returns></returns>
public static IDisposable OnClickExtAsync(this Button button, Func<CancellationToken, UniTask> onClickAsync, CancellationToken externalToken, Component owner = null, TimeSpan? throttleTime = null) {
// ¥Ü¥¿¥ó¤ÎºÆÍ¸ú²½¤Þ¤Ç¤ÎÂÔµ¡»þ´Ö¡£°ú¿ô»ØÄ꤬¤Ê¤¤¾ì¹ç¤Ë¤Ï½é´üÃÍ(1ÉÃ)¤òÀßÄê
TimeSpan time = throttleTime ?? TimeSpan.FromMilliseconds(1000);
// ½èÍý¤ò¤Þ¤È¤á¤Æ¤ª¤¯
IDisposable subscription = button.OnClickAsObservable()
.ThrottleFirst(time)
.SubscribeAwait(async (_, internalCt) => {
// CreateLinkedTokenSource ¤òÍøÍѤ·¡¢SubscribeAwait ¤¬ÆâÉôŪ¤Ë»ý¤ÄÇË´þ(internalCt)¤È¡¢³°Éô¤«¤éÅϤµ¤ì¤ë¥¥ã¥ó¥»¥ë(externalToken)À©¸æ¤òξΩ¤µ¤»¤¿¥È¡¼¥¯¥ó¤òºîÀ®¤¹¤ë
// ¤¤¤º¤ì¤«È¯²Ð»þ¤Ë¥¿¥¹¥¯¤ò»ß¤á¤ë
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(internalCt, externalToken);
await onClickAsync(linkedCts.Token);
});
// AddTo ÍѤÎɳ¤Å¤±Âоݤò¼õ¤±¼è¤ë
if (owner != null) {
subscription.AddTo(owner);
}
return subscription;
}
¡¡AddTo ¥á¥½¥Ã¥É¤Ç¤Î¹ØÆÉ²ò½ü¤Î¾¡¢°ú¿ô¤Ç¼õ¤±¼è¤Ã¤¿ CancellationToken ¤Ë¤è¤ë¥¥ã¥ó¥»¥ë¤È¡¢SubscribeAwait ¥á¥½¥Ã¥É¤¬ºîÀ®¤¹¤ë 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>, 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 () => ½èÍý¡×¤Î¤ß¤ÇÌäÂꤢ¤ê¤Þ¤»¤ó¡£
- ¥«¥Æ¥´¥ê¡§
- ¿Ê³Ø/¥¹¥¯¡¼¥ë
- ¥×¥í¥°¥é¥ß¥ó¥°




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