我有一个IObservable< TouchLocation>并且我试图从中获取手势。
能够拔出水龙头,但在双击时不能缠头。
TouchLocation具有位置和状态,因此通过基于两个标准聚合这些来获得Tap。
1)位置在任何方向上移动不超过10px(允许一些移动但不是阻力)
2)在“按下”状态的事件开始并继续,直到其中一个处于“已释放”状态
3)“释放”发生在“按下”的1秒内
现在我有一个IObservable< List< TouchLocation>> (聚合的结果)并且需要产生双击。
如何返回第一个手势(以产生初始点击),然后将第二个手势替换为双击手势,但仅在1秒计时器之前接收到第二个Tap。如果在计时器之后收到,那么它也应该是一个简单的Tap。
答案 0 :(得分:3)
一个有趣的问题。
// 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);
答案 1 :(得分:2)
我认为我能给你的最佳答案是“不要那样做”。
XNA具有内置机制,可提供点按,双击和other gestures。这些与系统范围的手势行为相匹配,并且比实现您自己的手势识别器更为可取。
有关如何使用内置手势功能的说明,请参阅this document on MSDN。这基本上是设置TouchPanel.EnabledGestures
,轮询IsGestureAvailable
,然后调用ReadGesture
。
答案 2 :(得分:2)
回到起点并意识到我已经过度复杂了......感谢Scott帮助重置我的方法!
“target”是IObservable&lt; TouchLocation&gt; (在扩展方法中)。
此设置处理发送第一个事件(因此我们不会丢失第一个事件,而zip正在等待),忽略保持(点击超过1秒),用双击替换第二个事件(但仅限于它发生在水龙头的1秒内,并且覆盖了一个我之前没有意识到的新请求,这确保了双击仅跟随水龙头而不是另一个双击(4个水龙头产生了Tap | DTap | DTap | DTap,现在是Tap | DTap | Tap | 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;
}
});