我在XNA概念證明中使用Rx,並且遇到了一些障礙,它們組成了一些查詢,我希望你們可以幫助我理解這些操作員中的一些如何工作。在定時器上產生事件時切換值
在我的POC中,我希望玩家的分數只在沒有發生主動拖動操作的情況下增加。另外,有一個'搶規',我想消耗,每當有一個持續的拖動,並填充時,沒有。最後,如果正在進行拖動操作,並且抓鬥的高度低於0,我想取消拖動操作。
我已經得到了分數遞增工作得很好這一點:當它應該
IObservable<bool> PrincessGrabbed; // e.g., OnGrabbedBegin
_playerScoreChanged = IObservable<Unit>
// ... //
// In the initialization method
_playerScoreChanged = from startTrigger in PrincessGrabbed.StartWith(false)
.Where(x => !x)
from i in Observable.Interval(TargetElapsedTime)
.TakeUntil(PrincessGrabbed
.Where(x => x)
select new Unit();
_playerScoreChanged.Subscribe(unit => PlayerScore += 1);
分數將增加,而當人物被選中了停止。然而,讓量表行爲正常工作一直很麻煩。我已經嘗試了一大堆使用Window
,Generate
等的變體......但是最終發生的結果是,要麼它根本不起作用,要麼增量/減量量表操作最終會相互爭鬥,或者它將似乎都能正常工作,但繼續在背景中減去或添加點/量表。這裏的計實現(表現極差,經過約10-15s崩潰,無法正常工作):
var a = from startTrigger in PrincessGrabbed.StartWith(false).Where(x => x)
from i in Observable.Interval(TargetElapsedTime)
.Where(x => GrabGaugeFillAmount > 0)
.TakeUntil(PrincessGrabbed.Where(x => !x))
select new Unit();
a.TimeInterval().Subscribe(unit =>
GrabGaugeFillAmount -= (float)unit.Interval.TotalSeconds *
GrabGaugeDepletionPerSecond);
我毫不懷疑我缺乏的,其中Rx的理解是錯在某種程度上,形狀,或形式,但我已經達到了試驗不同運營商/查詢的極限。任何見解?
專題:Gideon Engelberth的答案符合我的需求點 - 我希望我可以upvote它10倍!下面是他的回答快C#表示(不是100%對IDisposable.Dispose(),而應該是接近):
public class AlternatingSubject : IDisposable
{
private readonly object _lockObj = new object();
private int _firstTriggered;
private readonly ISubject<Unit> _first = new Subject<Unit>();
public ISubject<Unit> First { get { return _first; }}
private readonly ISubject<Unit> _second = new Subject<Unit>();
public ISubject<Unit> Second { get { return _second; }}
public void TriggerFirst()
{
if (System.Threading.Interlocked.Exchange(ref _firstTriggered, 1) == 1)
return;
First.OnNext(Unit.Default);
}
public void TriggerSecond()
{
if (System.Threading.Interlocked.Exchange(ref _firstTriggered, 0) == 0)
return;
Second.OnNext(Unit.Default);
}
#region Implementation of IDisposable
public void Dispose()
{
lock (_lockObj)
{
First.OnCompleted();
Second.OnCompleted();
}
}
#endregion
}
和邏輯掛鉤在遊戲類的事件(有一些重構機會)。總結:作品像魅力!謝謝!
public class PrincessCatcherGame : Game
{
// ... //
public IObservable<bool> PrincessGrabbed // external source fires these events
{
get
{
return princessGrabbed.AsObservable();
}
}
// ... //
private readonly ISubject<bool> _princessGrabbed = new Subject<bool>();
private readonly ISubject<Unit> _grabGaugeEmptied = new Subject<Unit>();
private readonly ISubject<Unit> _grabGaugeFull = new Subject<Unit>();
private readonly AlternatingSubject _alternatingSubject = new AlternatingSubject();
private ISubject<Unit> _grabs;
private ISubject<Unit> _releases;
// ... //
private void SubscribeToGrabbedEvents()
{
var decrements = from g in _grabs
from tick in Observable.Interval(TargetElapsedTime).TakeUntil(_releases)
select Unit.Default;
decrements.Subscribe(x =>
{
Debug.Assert(GrabGaugeFillAmount >= 0);
GrabGaugeFillAmount -= (GrabGaugeDepletionPerSecond/30f);
if (GrabGaugeFillAmount <= 1)
{
GrabGaugeFillAmount = 0;
_alternatingSubject.TriggerSecond();
_grabGaugeEmptied.OnNext(Unit.Default);
}
});
decrements.Subscribe(x => PlayerScore += 1);
var increments = from r in _releases
from tick in Observable.Interval(TargetElapsedTime).TakeUntil(_grabs.Merge(_grabGaugeFull))
select Unit.Default;
increments.Subscribe(x =>
{
Debug.Assert(GrabGaugeFillAmount <= 100);
GrabGaugeFillAmount += (GrabGaugeFillPerSecond/30f);
if (GrabGaugeFillAmount >= 100)
{
GrabGaugeFillAmount = 100;
_grabGaugeFull.OnNext(Unit.Default);
}
});
}
關於配置,我其實只是處理這兩個主題。大多數處置最終只是「處置所有非空的一次性域」,這就是爲什麼我將其排除在外。 – 2012-04-04 16:08:22