Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
TapGestureRecognizer.cs
1using System.Drawing;
3
5
24public sealed class TapGestureRecognizer : IDisposable
25{
26 private readonly ITouchInput _touchInput;
27
28 // Per-touch tracking: key = touch ID
29 private readonly Dictionary<int, TapState> _activeTaps = new();
30 private readonly HashSet<int> _activeContacts = new();
31 private bool _isMultiTouchSequence;
32
33 internal SwipeGestureRecognizer? CompetingSwipeRecognizer { get; set; }
34
35 private bool _isDisposed;
36
42 public double MaxTapDurationSeconds { get; set; } = 0.3;
43
49 public double MaxTapMovementPixels { get; set; } = 20;
50
54 public event EventHandler<TappedEventArgs>? Tapped;
55
67 {
68 _touchInput = touchInput ?? throw new ArgumentNullException(nameof(touchInput));
69 _touchInput.TouchBegan += OnTouchBegan;
70 _touchInput.TouchMoved += OnTouchMoved;
71 _touchInput.TouchEnded += OnTouchEnded;
72 }
73
74 private void OnTouchBegan(object? sender, TouchEventArgs e)
75 {
76 _activeContacts.Add(e.Touch.Id);
77
78 if (_activeContacts.Count > 1)
79 {
80 _isMultiTouchSequence = true;
81 _activeTaps.Clear();
82 return;
83 }
84
85 if (!_isMultiTouchSequence)
86 _activeTaps[e.Touch.Id] = new TapState(e.Touch.Position, e.Tick);
87 }
88
89 private void OnTouchMoved(object? sender, TouchEventArgs e)
90 {
91 if (!_activeTaps.TryGetValue(e.Touch.Id, out var state))
92 return;
93
94 if (state.Cancelled)
95 return;
96
97 var dx = e.Touch.Position.X - state.StartPosition.X;
98 var dy = e.Touch.Position.Y - state.StartPosition.Y;
99 var distance = Math.Sqrt(dx * dx + dy * dy);
100
101 if (distance > MaxTapMovementPixels)
102 _activeTaps[e.Touch.Id] = state with { Cancelled = true };
103 }
104
105 private void OnTouchEnded(object? sender, TouchEventArgs e)
106 {
107 _activeContacts.Remove(e.Touch.Id);
108
109 if (_isMultiTouchSequence)
110 {
111 _activeTaps.Remove(e.Touch.Id);
112 if (_activeContacts.Count == 0)
113 _isMultiTouchSequence = false;
114 return;
115 }
116
117 if (!_activeTaps.TryGetValue(e.Touch.Id, out var state))
118 return;
119
120 _activeTaps.Remove(e.Touch.Id);
121
122 // A system-cancelled contact (e.g. incoming call) must never fire Tapped.
123 if (state.Cancelled || e.Touch.Phase == TouchPhase.Cancelled)
124 return;
125
126 var dx = e.Touch.Position.X - state.StartPosition.X;
127 var dy = e.Touch.Position.Y - state.StartPosition.Y;
128 var distance = Math.Sqrt(dx * dx + dy * dy);
129 var elapsed = HighResTimer.GetDuration(state.StartTick, e.Tick);
130
131 if (distance <= MaxTapMovementPixels &&
132 elapsed <= MaxTapDurationSeconds &&
133 !(CompetingSwipeRecognizer?.WouldRecognize(distance, elapsed) ?? false))
134 {
135 Tapped?.Invoke(this, new TappedEventArgs(e.Touch.Id, state.StartPosition));
136 }
137 }
138
143 public void Dispose()
144 {
145 if (_isDisposed) return;
146 _isDisposed = true;
147
148 _touchInput.TouchBegan -= OnTouchBegan;
149 _touchInput.TouchMoved -= OnTouchMoved;
150 _touchInput.TouchEnded -= OnTouchEnded;
151 Reset();
152 }
153
154 internal void Reset()
155 {
156 _activeTaps.Clear();
157 _activeContacts.Clear();
158 _isMultiTouchSequence = false;
159 }
160
161 private record struct TapState(Point StartPosition, long StartTick, bool Cancelled)
162 {
168 public TapState(Point startPosition, long startTick) : this(startPosition, startTick, false) { }
169 }
170}
Recognizes swipe gestures by listening to touch events from an ITouchInput source....
double MaxTapDurationSeconds
Gets or sets the maximum duration in seconds that a touch may last to still be considered a tap....
EventHandler< TappedEventArgs >? Tapped
Occurs when a qualifying single-finger tap gesture is detected.
double MaxTapMovementPixels
Gets or sets the maximum distance in pixels that a touch may travel from its start position to still ...
void Dispose()
Releases all resources held by this recognizer and unsubscribes from the touch input source....
TapGestureRecognizer(ITouchInput touchInput)
Initializes a new instance of the TapGestureRecognizer class, subscribing to touch events from the sp...
Provides data for touch contact events raised by ITouchInput, including the touch point and engine ti...
TouchPoint Touch
Gets the touch contact point associated with this event.
long Tick
Gets the engine tick at which this touch event was emitted.
Represents a touch input source that tracks active contact points and raises lifecycle events when fi...
TouchPhase
Describes the current phase of a single touch contact point in its lifecycle.
Definition TouchPhase.cs:7
@ Cancelled
A finger or pointer contact was cancelled by the system (for example, an incoming call on a phone).
Definition TouchPhase.cs:33