您遇到的問題是,你的功能得到每場比賽週期期間調用,而刷卡過程中,你的函數最終得到多次調用。基本上,你想有一種方法來過濾更新事件流,只選擇相關的事件。你能做到這
一種方式是通過使用無擴展。您可以下載反應式擴展的統一兼容版本here。
一旦你這樣做了,你就可以將單位輸入轉換爲可觀察流。下面是你如何做到這一點:
using UnityEngine;
// You'll need to include these namespaces.
using UniRx;
using System.Linq;
using System;
// This will be responsible for converting unity input
// into a stream of events.
public class SwipeListener : MonoBehaviour
{
// Rx Subjects allow you to create an observable stream of your
// own. You can push events to the stream by calling OnNext().
private Subject<float> _subject;
// We'll expose the above stream via this property for a couple reasons.
// 1) If we exposed the subject directly, other code could push events to
// our stream by calling OnNext(). Preventing that helps avoid bugs.
// 2) We'll be filtering the stream to avoid having too many swipe-events.
public IObservable<float> InputStream { get; private set; }
// Event values will be grouped by threes and averaged
// to smooth out noise.
[SerializeField]
private int _bufferCount = 3;
// Average displacement level below which no swipe event
// will be triggered.
[SerializeField]
private float _minimumThreshhold = 15;
// To prevent back-to-back swipe events.
[SerializeField]
private float _slidingTimeoutWindowSeconds = .25f;
private void Update()
{
// We push values to our stream by calling OnNext() on our
// Subject in each game step.
_subject.OnNext(GetInputValue());
}
// Here is where we get the value that will be pushed into the stream.
// For this demonstration, I'm using the mouse-position. You could easily
// override this and return touch positions instead.
protected virtual float GetInputValue()
{
return Input.mousePosition.x;
}
public SwipeListener()
{
_subject = new Subject<float>();
// This is where the real magic happens. IObservable supports many of the
// same LINQ operations as IEnumerable.
IObservable<float> filtered = _subject
// Convert stream of horizontal mouse positions into a stream of
// mouse speed values.
.Pairwise()
.Select(x => x.Current - x.Previous)
// Group events and average them to smooth out noise. The group size
// can be configured in the inspector.
.Buffer(_bufferCount)
.Select(x => x.Average())
// Filter out events if the mouse was not moving quickly enough. This
// can be configured in the inspector. You'll want to play around with this.
.Where(x => Mathf.Abs(x) > _minimumThreshhold);
// Now we'll apply a sliding timeout window to throttle our stream. this
// will help prevent multiple back-to-back swipe events when you swipe once.
// I've split the event stream into two separate streams so we can throttle
// left and right swipes separately. This will help ensure that there isn't
// unnecessary lag when swiping left after having swiped right, or vice-versa.
TimeSpan seconds = TimeSpan.FromSeconds(_slidingTimeoutWindowSeconds);
IObservable<float> left = filtered
.Where(x => x < 0)
.Throttle(seconds);
IObservable<float> right = filtered
.Where(x => x > 0)
.Throttle(seconds);
// Now that we've throttled left and right swipes separately, we can merge
// them back into a single stream.
InputStream = left.Merge(right);
}
}
現在你所要做的就是編寫一個消耗上述腳本的腳本。這裏有一個如何做到這一點的例子:
using UnityEngine;
using System.Collections;
using UniRx;
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(SwipeListener))]
public class ColorFlasher : MonoBehaviour
{
[SerializeField]
private Material _left;
[SerializeField]
private Material _right;
private Material _normal;
[SerializeField]
private float _flashPeriod = .1f;
private MeshRenderer _meshRenderer;
private SwipeListener _inputListener;
void Start()
{
_meshRenderer = GetComponent<MeshRenderer>();
_normal = _meshRenderer.material;
_inputListener = GetComponent<SwipeListener>();
_inputListener.InputStream
.Subscribe(x => StartCoroutine(FlashColor(x)));
_inputListener.InputStream.Subscribe(x => Debug.Log(x));
}
private IEnumerator FlashColor(float swipe)
{
Material material = _normal;
if (swipe > 0)
material = _right;
else if (swipe < 0)
material = _left;
_meshRenderer.material = material;
yield return new WaitForSeconds(_flashPeriod);
_meshRenderer.material = _normal;
}
}
上述腳本只是有閃爍不同顏色的簡要只要檢測到刷卡的立方體。
上面的例子中的一個完整的版本可以在on my github。