我有一个IObservable
可以拉出"水龙头",但在"双击"的时候我的头很难绕起来。
TouchLocation有Position和State,所以Tap是根据两个条件聚合而来的。
1)位置在任何方向上移动不超过10px(允许一些移动,但不是拖动)
2)从状态为"按下"的事件开始,一直持续到状态为"释放"的事件进入
3)"释放"发生在"按下"后1秒内
现在我有一个IObservable
如何返回第一个手势(产生初始点击),然后将第二个手势替换为双击手势,但仅当在1秒计时器之前接收到第二个tap时。如果在计时器之后收到,那么它也应该是一个简单的Tap。
一个有趣的问题。
// Setup some parameters
var singleTapInterval = TimeSpan.FromSeconds(0.5);
var dblTapInterval = TimeSpan.FromSeconds(1);
// the source of touches
IObservable<TouchLocation> txs;
// Get single taps
// 0, 1, but no more than
// 2 touches in the timespan
IObservable<TouchLocation> taps = txs.Buffer(2,singleTapInterval)
.Where(touches => touches.Count == 2 &&
touches[0].state == "Pressed" &&
touches[1].state == "Released" &&
distance(touches) < distanceThreshold)
.Select(touches => touches[1]);
// now detect double taps
IObservable<TapKind> dbltaps = taps.Buffer(2,dblTapInterval)
.Where(taps => taps.Count == 2)
.Select(_ => TapKind.SingleTap);
// detect single taps - taps must be _slower_ than the dblTapInterval
// for this to work
IObservable<TapKind> singletaps = taps.Throttle(dblTapInterval)
.Select(_ => TapKind.SingleTap);
// compbine the two, so we see either tap condition
IObservable<TapKind> interestingTaps = dbltaps.Merge(singletaps);
我想我能给你的最好的答案是"不要那样做"。
XNA有一个内置机制来提供轻击、双击和其他手势。这些匹配系统范围内的手势行为,并且比实现自己的手势识别器要好得多。
有关如何使用内置手势功能的解释,请参阅MSDN上的此文档。这基本上是设置TouchPanel.EnabledGestures
,轮询IsGestureAvailable
,然后调用ReadGesture
的情况。
回到开头,我意识到我把它弄得太复杂了……感谢斯科特帮我调整了方法!
"target"是一个IObservable
这个设置处理发送第一个事件(所以我们不失去第一个事件在zip等待),忽略了持有(水龙头需要超过1秒),取代了二锥与双击(但只有1秒内发生tap),覆盖一个新的要求,我不知道之前确保双击只遵循一个水龙头,从来没有另一个双击(4水龙头生产水龙头| DTap | DTap | DTap现在是利用| DTap |开发| DTap正确行为)
可能会简化一些,但这是重构前的工作版本:
var grouped = (from t in target
group t by t.Id into groups
select groups);
var presses = (from g in grouped
from t in g
where t.State == TouchLocationState.Pressed
select t).Timestamp();
var releases = (from g in grouped
from t in g
where t.State == TouchLocationState.Released
select t).Timestamp();
var pressAndRelease = presses.Zip(releases, (press, release) =>
{
return new { Press = press, Release = release };
})
.Where(pr =>
{
var delta = (pr.Release.Timestamp - pr.Press.Timestamp).TotalSeconds;
return delta < 1;
})
.Timestamp();
var zipped = pressAndRelease.Zip(pressAndRelease.Skip(1), (prev, cur) =>
{
return new { Previous = prev, Current = cur };
});
pressAndRelease.TakeUntil(zipped).Subscribe(a =>
{
Debug.WriteLine("FIRST TAP!");
});
var wasDoubleTap = false;
zipped.Subscribe(a =>
{
var delta = (a.Current.Timestamp - a.Previous.Timestamp).TotalSeconds;
if (wasDoubleTap || delta > 1)
{
Debug.WriteLine("TAP");
wasDoubleTap = false;
}
else
{
Debug.WriteLine("DOUBLE TAP!");
wasDoubleTap = true;
}
});