Jypeli  5
The simple game programming library
Controller.cs
Siirry tämän tiedoston dokumentaatioon.
1 #region MIT License
2 /*
3  * Copyright (c) 2009 University of Jyväskylä, Department of Mathematical
4  * Information Technology.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #endregion
25 
26 /*
27  * Authors: Tero Jäntti, Tomi Karppinen, Janne Nikkanen.
28  */
29 
30 using System;
31 using System.Collections.Generic;
32 using System.Text;
33 
34 namespace Jypeli.Controls
35 {
39  [Save]
40  public abstract class Controller
41  {
42  protected enum ListenerActionType { Add, Remove, Enable, Disable, RemoveAll };
43 
44  protected struct ListenerAction
45  {
46  public ListenerActionType actionType;
48 
49  public ListenerAction( Listener l, ListenerActionType a )
50  {
51  actionType = a;
52  listener = l;
53  }
54  }
55 
56  protected class ListenerPrecedenceComparer : IComparer<Listener>
57  {
58  public int Compare( Listener x, Listener y )
59  {
60  // 1. Gestures first
61  if ( x.gestureType != null && y.gestureType == null ) return -1;
62  if ( x.gestureType == null && y.gestureType != null ) return 1;
63 
64  // 2. Then the game objects, top-down layerwise
65  if ( x.GameObject != null && y.GameObject != null )
66  {
67  int xi = Game.Instance.Layers.IndexOf( x.GameObject.Layer );
68  int yi = Game.Instance.Layers.IndexOf( y.GameObject.Layer );
69  return yi.CompareTo( xi );
70  }
71  if ( x.GameObject != null ) return -1;
72  if ( y.GameObject != null ) return 1;
73 
74  return 0;
75  }
76  }
77 
78  protected static ListenerPrecedenceComparer ListenerComparer = new ListenerPrecedenceComparer();
79 
80  [Save]
81  internal List<Listener> listeners = new List<Listener>();
82  protected Queue<ListenerAction> listenerActions = new Queue<ListenerAction>();
83  protected List<Listener> disabledListeners = new List<Listener>();
84  protected Dictionary<Delegate, string> helpTextsForHandlers = new Dictionary<Delegate, string>();
85 
89  internal bool BufferPurging { get; set; }
90 
94  public bool Enabled { get; set; }
95 
96  internal Controller()
97  {
98  Enabled = true;
99  }
100 
101  internal void Add( Listener l )
102  {
103  listenerActions.Enqueue( new ListenerAction( l, ListenerActionType.Add ) );
104  }
105 
106  internal void Remove( Listener l )
107  {
108  listenerActions.Enqueue( new ListenerAction( l, ListenerActionType.Remove ) );
109  }
110 
117  public void AddHelpText( Handler controlHandler, string text )
118  {
119  helpTextsForHandlers.Add( controlHandler, text );
120  }
121 
122  public void AddHelpText<T1>( Handler<T1> controlHandler, string text )
123  {
124  helpTextsForHandlers.Add( controlHandler, text );
125  }
126 
127  public void AddHelpText<T1, T2>( Handler<T1, T2> controlHandler, string text )
128  {
129  helpTextsForHandlers.Add( controlHandler, text );
130  }
131 
132  public void AddHelpText<T1, T2, T3>( Handler<T1, T2, T3> controlHandler, string text )
133  {
134  helpTextsForHandlers.Add( controlHandler, text );
135  }
136 
137  public void AddHelpText<T1, T2, T3, T4>( Handler<T1, T2, T3, T4> controlHandler, string text )
138  {
139  helpTextsForHandlers.Add( controlHandler, text );
140  }
141 
142  public void AddHelpText( AnalogHandler controlHandler, string text )
143  {
144  helpTextsForHandlers.Add( controlHandler, text );
145  }
146 
147  public void AddHelpText<T1>( AnalogHandler<T1> controlHandler, string text )
148  {
149  helpTextsForHandlers.Add( controlHandler, text );
150  }
151 
152  public void AddHelpText<T1, T2>( AnalogHandler<T1, T2> controlHandler, string text )
153  {
154  helpTextsForHandlers.Add( controlHandler, text );
155  }
156 
157  public void AddHelpText<T1, T2, T3>( AnalogHandler<T1, T2, T3> controlHandler, string text )
158  {
159  helpTextsForHandlers.Add( controlHandler, text );
160  }
161 
162  public void AddHelpText<T1, T2, T3, T4>( AnalogHandler<T1, T2, T3, T4> controlHandler, string text )
163  {
164  helpTextsForHandlers.Add( controlHandler, text );
165  }
166 
171  internal abstract string GetControlText( Listener listener );
172 
173 
174  internal void GetHelpTexts( List<string> texts )
175  {
176  var controlTextsForHandlerMethods = new Dictionary<Delegate, StringBuilder>();
177 
178  foreach ( var listener in listeners )
179  GetHelpText( listener, controlTextsForHandlerMethods, texts );
180  foreach ( var action in listenerActions )
181  {
182  if ( action.actionType == ListenerActionType.Add ||
183  action.actionType == ListenerActionType.Enable )
184  GetHelpText( action.listener, controlTextsForHandlerMethods, texts );
185  }
186 
187  foreach ( var item in controlTextsForHandlerMethods )
188  {
189  texts.Add( item.Value + " - " + helpTextsForHandlers[item.Key] );
190  }
191  }
192 
193  private void GetHelpText(
194  Listener listener,
195  Dictionary<Delegate, StringBuilder> controlTextsForHandlerMethods,
196  List<string> texts )
197  {
198  Delegate handlerMethod = listener.Handler;
199  string controlText = this.GetControlText( listener );
200 
201  if ( helpTextsForHandlers.ContainsKey( handlerMethod ) )
202  {
203  // Helptext related to a given method:
204 
205  if ( !controlTextsForHandlerMethods.ContainsKey( handlerMethod ) )
206  {
207  controlTextsForHandlerMethods[handlerMethod] = new StringBuilder( controlText );
208  }
209  else
210  {
211  controlTextsForHandlerMethods[handlerMethod].Append( ", " + controlText );
212  }
213  }
214  else if ( listener.HelpText != null )
215  {
216  // Helptext related to a single Listen-call:
217 
218  texts.Add( controlText + " - " + listener.HelpText );
219  }
220  }
221 
226  public void Disable( Predicate<Listener> predicate )
227  {
228  foreach ( Listener l in listeners )
229  {
230  if ( predicate( l ) )
231  {
232  listenerActions.Enqueue( new ListenerAction( l, ListenerActionType.Disable ) );
233  }
234  }
235  }
236 
241  public void Enable( Predicate<Listener> predicate )
242  {
243  foreach ( Listener l in disabledListeners )
244  {
245  if ( predicate( l ) )
246  {
247  listenerActions.Enqueue( new ListenerAction( l, ListenerActionType.Enable ) );
248  }
249  }
250  }
251 
255  public void EnableAll()
256  {
257  Enable( x => true );
258  }
259 
263  public void DisableAll()
264  {
265  Disable( x => true );
266  }
267 
271  public virtual void Clear()
272  {
273  listenerActions.Enqueue( new ListenerAction( null, ListenerActionType.RemoveAll ) );
274  }
275 
276  protected void ProcessListenerActions()
277  {
278  bool sortListeners = false;
279 
280  while ( listenerActions.Count > 0 )
281  {
282  ListenerAction action = listenerActions.Dequeue();
283 
284  switch ( action.actionType )
285  {
286  case ListenerActionType.Add:
287  listeners.Add( action.listener );
288  sortListeners = true;
289  break;
290  case ListenerActionType.Remove:
291  listeners.Remove( action.listener );
292  disabledListeners.Remove( action.listener );
293  action.listener.Disassociate();
294  break;
295  case ListenerActionType.Enable:
296  listeners.Add( action.listener );
297  sortListeners = true;
298  disabledListeners.Remove( action.listener );
299  break;
300  case ListenerActionType.Disable:
301  foreach ( Listener listener in listeners )
302  listener.Disassociate();
303  listeners.Remove( action.listener );
304  disabledListeners.Add( action.listener );
305  break;
306  case ListenerActionType.RemoveAll:
307  listeners.Clear();
308  disabledListeners.Clear();
309  helpTextsForHandlers.Clear();
310  break;
311  }
312  }
313 
314  if ( sortListeners )
315  listeners.Sort( Controller.ListenerComparer );
316  }
317 
318  internal virtual void Update()
319  {
320  ProcessListenerActions();
321  }
322 
323  protected static int CompareByContext( Listener l1, Listener l2 )
324  {
325  int v1 = 0;
326  int v2 = 0;
327 
328  if ( !l1.HasDefaultContext ) v1 = 1;
329  if ( !l2.HasDefaultContext ) v2 = 1;
330 
331  return v1 - v2;
332  }
333 
337  internal abstract bool IsBufferEmpty();
338 
344  internal void PurgeBuffer()
345  {
346  // oldState = QueryState();
347  BufferPurging = true;
348  }
349  }
350 
354  public abstract class Controller<ControllerState> : Controller
355  {
356  internal ControllerState oldState;
357  internal ControllerState newState;
358 
359  internal abstract ControllerState GetCurrentState();
360 
361  protected virtual bool IsTriggered( Listener listener ) { return false; }
362  protected virtual bool IsAnalogTriggered( Listener listener, out AnalogState state ) { state = new AnalogState(); return false; }
363 
364  protected virtual void UpdateState() {}
365 
366  internal override void Update()
367  {
368  if ( !Enabled )
369  return;
370 
371  ProcessListenerActions();
372 
373  oldState = newState;
374  newState = GetCurrentState();
375  UpdateState();
376 
377  if ( BufferPurging )
378  {
379  if ( !IsBufferEmpty() )
380  {
381  // Wait until the buffer empties itself
382  newState = oldState = GetCurrentState();
383  return;
384  }
385 
386  // The buffer is empty, clear the flag
387  BufferPurging = false;
388  }
389 
390  for ( int i = listeners.Count - 1; i >= 0; i-- )
391  {
392  Listener l = listeners[i];
393 
394  if ( l == null || l.IsDestroyed || l.Context.IsDestroyed )
395  {
396  listeners.RemoveAt( i );
397  continue;
398  }
399  }
400 
401  PointingDevice thisPointing = this as PointingDevice;
402  int numChannels = thisPointing != null ? thisPointing.ActiveChannels : 1;
403 
404  for ( int ch = 0; ch < numChannels; ch++ )
405  {
406  List<Listener> mostPrecedent = null;
407 
408  for ( int i = 0; i < listeners.Count; i++ )
409  {
410  Listener l = listeners[i];
411  AnalogState state;
412 
413  if ( !l.Context.Active )
414  continue;
415 
416  if ( l is IAnalogListener && IsAnalogTriggered( l, out state ) )
417  l.Invoke( state );
418 
419  if ( thisPointing != null )
420  {
421  // Pointing device
422  if ( thisPointing.IsTriggeredOnChannel( ch, l ) )
423  {
424  if ( mostPrecedent == null )
425  {
426  mostPrecedent = new List<Listener>();
427  mostPrecedent.Add( l );
428  }
429  else
430  {
431  int cmp = ListenerComparer.Compare( l, mostPrecedent[0] );
432 
433  if ( cmp == 0 )
434  {
435  // This listener has equal precedence
436  mostPrecedent.Add( l );
437  }
438  else if ( cmp < 0 )
439  {
440  // This listener has greater precedence
441  mostPrecedent.Clear();
442  mostPrecedent.Add( l );
443  }
444  }
445  }
446  }
447  else if ( IsTriggered( l ) )
448  {
449  // Non-pointing device
450  l.Invoke();
451  }
452  }
453 
454  if ( mostPrecedent != null )
455  {
456  // Invoke only the most precedent listeners
457  foreach ( Listener l in mostPrecedent )
458  l.Invoke( ch );
459  }
460  }
461  }
462  }
463 }
void EnableAll()
Ottaa takaisin käyttöön kaikki Disable-metodilla poistetut kontrollit.
Definition: Controller.cs:255
virtual bool IsAnalogTriggered(Listener listener, out AnalogState state)
Definition: Controller.cs:362
virtual void UpdateState()
Definition: Controller.cs:364
Sisältää ohjaimet.
Definition: Controls.cs:146
void DisableAll()
Poistaa kaikki kontrollit käytöstä.
Definition: Controller.cs:263
static int CompareByContext(Listener l1, Listener l2)
Definition: Controller.cs:323
delegate void AnalogHandler< T1, T2 >(AnalogState analogState, T1 p1, T2 p2)
Ohjaintapahtumankäsittelijä kahdella parametrilla.
void Disable(Predicate< Listener > predicate)
Poistaa tietyt kuuntelutapahtumat käytöstä.
Definition: Controller.cs:226
static Game Instance
Definition: Game.cs:149
void AddHelpText(Handler controlHandler, string text)
Lisää ohjeteksti, joka on sama kaikille näppäimille tai muille ohjaimille, jotka käyttävät samaa alio...
Definition: Controller.cs:117
void AddHelpText(AnalogHandler controlHandler, string text)
Definition: Controller.cs:142
delegate void Handler< T1, T2, T3 >(T1 p1, T2 p2, T3 p3)
Ohjaintapahtumankäsittelijä kolmella parametrilla.
SynchronousList< Layer > Layers
Kerrokset, joilla pelioliot viihtyvät.
Definition: Game.cs:95
Peliluokka reaaliaikaisille peleille.
Definition: DebugScreen.cs:10
delegate void AnalogHandler(AnalogState analogState)
Ohjaintapahtumankäsittelijä ilman parametreja.
delegate void Handler< T1 >(T1 p1)
Ohjaintapahtumankäsittelijä yhdellä parametrilla.
Parametrit analogisen ohjauksen (hiiren tai ohjaustikun) tapahtumalle.
Definition: AnalogState.cs:35
bool IsTriggeredOnChannel(int ch, Listener l)
delegate void Handler()
Ohjaintapahtumankäsittelijä ilman parametreja.
ListenerAction(Listener l, ListenerActionType a)
Definition: Controller.cs:49
virtual void Clear()
Poistaa tämän ohjaimen kaikki kuuntelijat.
Definition: Controller.cs:271
delegate void Handler< T1, T2 >(T1 p1, T2 p2)
Ohjaintapahtumankäsittelijä kahdella parametrilla.
delegate void AnalogHandler< T1, T2, T3 >(AnalogState analogState, T1 p1, T2 p2, T3 p3)
Ohjaintapahtumankäsittelijä kolmella parametrilla.
bool IsDestroyed
Onko olio tuhottu.
Definition: Listeners.cs:168
virtual bool IsTriggered(Listener listener)
Definition: Controller.cs:361
delegate void Handler< T1, T2, T3, T4 >(T1 p1, T2 p2, T3 p3, T4 p4)
Ohjaintapahtumankäsittelijä neljällä parametrilla.
delegate void AnalogHandler< T1 >(AnalogState analogState, T1 p1)
Ohjaintapahtumankäsittelijä yhdellä parametrilla.
delegate void AnalogHandler< T1, T2, T3, T4 >(AnalogState analogState, T1 p1, T2 p2, T3 p3, T4 p4)
Ohjaintapahtumankäsittelijä neljällä parametrilla.
void Enable(Predicate< Listener > predicate)
Ottaa käytöstä poistetun kontrollin takaisin käyttöön.
Definition: Controller.cs:241
Yleinen peliohjainluokka.
Definition: Controller.cs:40