Jypeli  5
The simple game programming library
GamePad.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.Collections.Generic;
31 using System.Diagnostics;
32 using Microsoft.Xna.Framework;
33 using Microsoft.Xna.Framework.Input;
34 using Physics2DDotNet;
35 
36 using XnaGamePad = Microsoft.Xna.Framework.Input.GamePad;
37 
38 namespace Jypeli.Controls
39 {
43  public class GamePad : Controller<GamePadState>
44  {
45  internal class Vibration
46  {
47  public PlayerIndex player { get; private set; }
48  public double leftMotor { get; private set; }
49  public double rightMotor { get; private set; }
50  public double leftAccel { get; set; }
51  public double rightAccel { get; set; }
52  public Lifespan lifetime { get; set; }
53 
54  public Vibration( PlayerIndex p, double lmotor, double rmotor, double laccel, double raccel, Lifespan ltime )
55  {
56  player = p;
57  leftMotor = lmotor;
58  rightMotor = rmotor;
59  leftAccel = laccel;
60  rightAccel = raccel;
61  lifetime = ltime;
62  }
63 
64  public void Update( Time time )
65  {
66  if ( lifetime.IsExpired )
67  {
68  leftMotor = 0;
69  rightMotor = 0;
70  return;
71  }
72 
73  // Acceleration
74  leftMotor += time.SinceLastUpdate.TotalSeconds * leftAccel;
75  rightMotor += time.SinceLastUpdate.TotalSeconds * rightAccel;
76 
77  // Lifetime progression
78  lifetime.Age += (float)time.SinceLastUpdate.TotalSeconds;
79  }
80 
81  public static void UpdateAll( Time time, List<Vibration> vibrations )
82  {
83  for ( int i = 0; i < vibrations.Count; i++ )
84  {
85  vibrations[i].Update( time );
86  }
87  }
88 
89  public static void Execute( PlayerIndex p, List<Vibration> vibrations )
90  {
91  // Total vibrations
92  double lmotort = 0;
93  double rmotort = 0;
94 
95  for ( int i = 0; i < vibrations.Count; i++ )
96  {
97  // Get the sum of all vibrations
98  if ( vibrations[i].player == p )
99  {
100  lmotort += vibrations[i].leftMotor;
101  rmotort += vibrations[i].rightMotor;
102  }
103  }
104 
105  // Clamp the results between 0 and 1
106  lmotort = AdvanceMath.MathHelper.Clamp( (float)lmotort, 0, 1 );
107  rmotort = AdvanceMath.MathHelper.Clamp( (float)rmotort, 0, 1 );
108 
109  // Set the vibration
110  XnaGamePad.SetVibration( p, (float)lmotort, (float)rmotort );
111  }
112  }
113 
114  private List<Vibration> vibrations;
115 
116  private PlayerIndex playerIndex;
117 
121  public bool IsConnected
122  {
123  get { return newState.IsConnected; }
124  }
125 
130  public Vector LeftThumbDirection
131  {
132  get
133  {
134  Vector2 v = newState.ThumbSticks.Left;
135  return new Vector( v.X, v.Y );
136  }
137  }
138 
143  public Vector RightThumbDirection
144  {
145  get
146  {
147  Vector2 v = newState.ThumbSticks.Right;
148  return new Vector( v.X, v.Y );
149  }
150  }
151 
156  public double LeftTriggerState
157  {
158  get { return newState.Triggers.Left; }
159  }
160 
165  public double RightTriggerState
166  {
167  get { return newState.Triggers.Right; }
168  }
169 
170  internal GamePad( PlayerIndex player )
171  : base()
172  {
173  oldState = XnaGamePad.GetState( player );
174  vibrations = new List<Vibration>();
175  playerIndex = player;
176  }
177 
181  public void Enable( Button button )
182  {
183  base.Enable( listener => ( listener.Button == button ) );
184  }
185 
189  public void Enable( AnalogControl control )
190  {
191  base.Enable( listener => ( listener.AnalogControl == control ) );
192  }
193 
197  public void Disable( Button button )
198  {
199  base.Disable( listener => ( listener.Button == button ) );
200  }
201 
205  public void Disable( AnalogControl control )
206  {
207  base.Disable( listener => ( listener.AnalogControl == control ) );
208  }
209 
210  protected override bool IsTriggered( Listener listener )
211  {
212  if ( listener.Type == ListeningType.ControllerButton )
213  return IsButtonTriggered( listener );
214 
215  return base.IsTriggered( listener );
216  }
217 
218  protected override bool IsAnalogTriggered( Listener listener, out AnalogState state )
219  {
220  if ( listener.Type == ListeningType.ControllerAnalogMovement )
221  return IsMovementTriggered( listener, out state );
222 
223  return base.IsAnalogTriggered( listener, out state );
224  }
225 
226  private bool IsButtonTriggered( Listener listener )
227  {
228  Buttons b = ToXnaButtons( listener.Button );
229 
230  switch ( listener.State )
231  {
232  case ButtonState.Irrelevant:
233  return true;
234  case ButtonState.Released:
235  return oldState.IsButtonDown( b ) && newState.IsButtonUp( b );
236  case ButtonState.Pressed:
237  return oldState.IsButtonUp( b ) && newState.IsButtonDown( b );
238  case ButtonState.Up:
239  return newState.IsButtonUp( b );
240  case ButtonState.Down:
241  return newState.IsButtonDown( b );
242  default:
243  return false;
244  }
245  }
246 
247  private bool IsMovementTriggered( Listener listener, out AnalogState analogState )
248  {
249  switch ( listener.AnalogControl )
250  {
251  case AnalogControl.DefaultStick:
252  case AnalogControl.LeftStick:
253  {
254  Vector2 current = newState.ThumbSticks.Left;
255  if ( current.Length() > listener.AnalogTrigger )
256  {
257  Vector2 previous = oldState.ThumbSticks.Left;
258  double change = ( current - previous ).Length();
259  analogState = new AnalogState( 0.0, change, new Vector( current.X, current.Y ) );
260  return true;
261  }
262  break;
263  }
264  case AnalogControl.RightStick:
265  {
266  Vector2 current = newState.ThumbSticks.Right;
267  if ( current.Length() > listener.AnalogTrigger )
268  {
269  Vector2 previous = oldState.ThumbSticks.Right;
270  double change = ( current - previous ).Length();
271  analogState = new AnalogState( 0.0, change, new Vector( current.X, current.Y ) );
272  return true;
273  }
274  break;
275  }
276  case AnalogControl.LeftTrigger:
277  {
278  double currentState = newState.Triggers.Left;
279  if ( currentState > listener.AnalogTrigger )
280  {
281  double change = currentState - oldState.Triggers.Left;
282  analogState = new AnalogState( currentState, change, Vector.Zero );
283  return true;
284  }
285  break;
286  }
287  case AnalogControl.RightTrigger:
288  {
289  double currentState = newState.Triggers.Right;
290  if ( currentState > listener.AnalogTrigger )
291  {
292  double change = currentState - oldState.Triggers.Right;
293  analogState = new AnalogState( currentState, change, Vector.Zero );
294  return true;
295  }
296  break;
297  }
298  default:
299  break;
300  }
301 
302  analogState = new AnalogState();
303  return false;
304  }
305 
306  internal override GamePadState GetCurrentState()
307  {
308  return XnaGamePad.GetState( playerIndex );
309  }
310 
317  {
318  Buttons buttons = ToXnaButtons( b );
319  bool down = newState.IsButtonDown( buttons );
320  bool lastdown = oldState.IsButtonDown( buttons );
321 
322  if ( lastdown && down )
323  return ButtonState.Down;
324  if ( !lastdown && down )
325  return ButtonState.Pressed;
326  if ( lastdown && !down )
327  return ButtonState.Released;
328 
329  return ButtonState.Up;
330  }
331 
332  private static Buttons ToXnaButtons( Button b )
333  {
334  return (Buttons)b;
335  }
336 
337  internal override bool IsBufferEmpty()
338  {
339  // TODO: "Dead" tolerance for axes and triggers
340  return AnyButtonDown();
341  }
342 
343  internal override void Update()
344  {
345  if ( !Enabled )
346  return;
347 
348  Vibration.UpdateAll( Game.Time, vibrations );
349  Vibration.Execute( playerIndex, vibrations );
350 
351  for ( int i = 0; i < vibrations.Count; i++ )
352  {
353  if ( vibrations[i].lifetime.IsExpired )
354  {
355  vibrations.RemoveAt( i );
356  i--;
357  }
358  }
359 
360  base.Update();
361  }
362 
363  internal override string GetControlText( Listener listener )
364  {
365  switch ( listener.Type )
366  {
367  case ListeningType.ControllerButton:
368  return listener.Button.ToString();
369  case ListeningType.ControllerAnalogMovement:
370  return listener.AnalogControl.ToString();
371  default:
372  Debug.Assert( false, "Bad listener type for gamepad" );
373  return null;
374  }
375  }
376 
381  internal bool AnyButtonDown()
382  {
383  Button[] buttons =
384  {
385  Button.DPadUp, Button.DPadDown, Button.DPadLeft, Button.DPadRight,
386  Button.A, Button.B, Button.X, Button.Y,
387  Button.Start, Button.Back, Button.BigButton,
388  Button.LeftShoulder, Button.RightShoulder
389  };
390  bool buttondown = false;
391 
392  for ( int i = 0; i < buttons.Length; i++ )
393  {
394  buttondown |= ( (GamePadState)newState ).IsButtonDown( ToXnaButtons( buttons[i] ) );
395  }
396 
397  return buttondown;
398  }
399 
408  public void Vibrate( double leftMotor, double rightMotor, double leftAcceleration, double rightAcceleration, double time )
409  {
410  vibrations.Add( new Vibration( playerIndex, leftMotor, rightMotor, leftAcceleration, rightAcceleration, new Lifespan( (float)time ) ) );
411  }
412 
413  #region Listen with no parameters
414 
415  public Listener Listen( Button button, ButtonState state, Handler handler, string helpText )
416  {
417  Listener l = new SimpleListener( this, ListeningType.ControllerButton, helpText, handler );
418  l.Button = button;
419  l.State = state;
420  Add( l );
421  return l;
422  }
423 
424  public Listener ListenAnalog( AnalogControl control, double trigger, AnalogHandler handler, string helpText )
425  {
426  Listener l = new AnalogListener( this, ListeningType.ControllerAnalogMovement, helpText, handler );
427  l.AnalogControl = control;
428  l.AnalogTrigger = trigger;
429  Add( l );
430  return l;
431  }
432 
433  #endregion
434 
435  #region Listen with 1 parameter
436 
437  public Listener Listen<T1>( Button button, ButtonState state, Handler<T1> handler, string helpText, T1 p1 )
438  {
439  Listener l = new SimpleListener<T1>( this, ListeningType.ControllerButton, helpText, handler, p1 );
440  l.Button = button;
441  l.State = state;
442  Add( l );
443  return l;
444  }
445 
446  public Listener ListenAnalog<T1>( AnalogControl control, double trigger, AnalogHandler<T1> handler, string helpText, T1 p1 )
447  {
448  Listener l = new AnalogListener<T1>( this, ListeningType.ControllerAnalogMovement, helpText, handler, p1 );
449  l.AnalogControl = control;
450  l.AnalogTrigger = trigger;
451  Add( l );
452  return l;
453  }
454 
455  #endregion
456 
457  #region Listen with 2 parameters
458 
459  public Listener Listen<T1, T2>( Button button, ButtonState state, Handler<T1, T2> handler, string helpText, T1 p1, T2 p2 )
460  {
461  Listener l = new SimpleListener<T1, T2>( this, ListeningType.ControllerButton, helpText, handler, p1, p2 );
462  l.Button = button;
463  l.State = state;
464  Add( l );
465  return l;
466  }
467 
468  public Listener ListenAnalog<T1, T2>( AnalogControl control, double trigger, AnalogHandler<T1, T2> handler, string helpText, T1 p1, T2 p2 )
469  {
470  Listener l = new AnalogListener<T1, T2>( this, ListeningType.ControllerAnalogMovement, helpText, handler, p1, p2 );
471  l.AnalogControl = control;
472  l.AnalogTrigger = trigger;
473  Add( l );
474  return l;
475  }
476 
477  #endregion
478 
479  #region Listen with 3 parameters
480 
481  public Listener Listen<T1, T2, T3>( Button button, ButtonState state, Handler<T1, T2, T3> handler, string helpText, T1 p1, T2 p2, T3 p3 )
482  {
483  Listener l = new SimpleListener<T1, T2, T3>( this, ListeningType.ControllerButton, helpText, handler, p1, p2, p3 );
484  l.Button = button;
485  l.State = state;
486  Add( l );
487  return l;
488  }
489 
490  public Listener ListenAnalog<T1, T2, T3>( AnalogControl control, double trigger, AnalogHandler<T1, T2, T3> handler, string helpText, T1 p1, T2 p2, T3 p3 )
491  {
492  Listener l = new AnalogListener<T1, T2, T3>( this, ListeningType.ControllerAnalogMovement, helpText, handler, p1, p2, p3 );
493  l.AnalogControl = control;
494  l.AnalogTrigger = trigger;
495  Add( l );
496  return l;
497  }
498 
499  #endregion
500 
501  #region Listen with 4 parameters
502 
503  public Listener Listen<T1, T2, T3, T4>( Button button, ButtonState state, Handler<T1, T2, T3, T4> handler, string helpText, T1 p1, T2 p2, T3 p3, T4 p4 )
504  {
505  Listener l = new SimpleListener<T1, T2, T3, T4>( this, ListeningType.ControllerButton, helpText, handler, p1, p2, p3, p4 );
506  l.Button = button;
507  l.State = state;
508  Add( l );
509  return l;
510  }
511 
512  public Listener ListenAnalog<T1, T2, T3, T4>( AnalogControl control, double trigger, AnalogHandler<T1, T2, T3, T4> handler, string helpText, T1 p1, T2 p2, T3 p3, T4 p4 )
513  {
514  Listener l = new AnalogListener<T1, T2, T3, T4>( this, ListeningType.ControllerAnalogMovement, helpText, handler, p1, p2, p3, p4 );
515  l.AnalogControl = control;
516  l.AnalogTrigger = trigger;
517  Add( l );
518  return l;
519  }
520 
521  #endregion
522  }
523 }
override bool IsAnalogTriggered(Listener listener, out AnalogState state)
Definition: GamePad.cs:218
void Enable(AnalogControl control)
Ottaa käytöstä poistetun analogiohjaimen takaisin käyttöön.
Definition: GamePad.cs:189
void Vibrate(double leftMotor, double rightMotor, double leftAcceleration, double rightAcceleration, double time)
Täristää peliohjainta.
Definition: GamePad.cs:408
Listener Listen(Button button, ButtonState state, Handler handler, string helpText)
Definition: GamePad.cs:415
delegate void AnalogHandler< T1, T2 >(AnalogState analogState, T1 p1, T2 p2)
Ohjaintapahtumankäsittelijä kahdella parametrilla.
ButtonState
Napin (minkä tahansa) asento.
Definition: ButtonState.cs:37
TimeSpan SinceLastUpdate
Aika joka on kulunut viime päivityksestä.
Definition: Time.cs:24
static readonly Vector Zero
Nollavektori.
Definition: Vector.cs:61
Sisältää tiedon ajasta, joka on kulunut pelin alusta ja viime päivityksestä.
Definition: Time.cs:13
ButtonState GetButtonState(Button b)
Palauttaa annetun napin tilan (ks. ButtonState).
Definition: GamePad.cs:316
delegate void Handler< T1, T2, T3 >(T1 p1, T2 p2, T3 p3)
Ohjaintapahtumankäsittelijä kolmella parametrilla.
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
Button
Definition: Button.cs:34
override bool IsTriggered(Listener listener)
Definition: GamePad.cs:210
Xbox-peliohjain.
Definition: GamePad.cs:43
delegate void Handler()
Ohjaintapahtumankäsittelijä ilman parametreja.
Listener ListenAnalog(AnalogControl control, double trigger, AnalogHandler handler, string helpText)
Definition: GamePad.cs:424
static Time Time
Peliaika. Sisältää tiedon siitä, kuinka kauan peliä on pelattu (Time.SinceStartOfGame) ja kuinka kaua...
Definition: Game.cs:309
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.
void Enable(Button button)
Ottaa käytöstä poistetun napin takaisin käyttöön.
Definition: GamePad.cs:181
delegate void Handler< T1, T2, T3, T4 >(T1 p1, T2 p2, T3 p3, T4 p4)
Ohjaintapahtumankäsittelijä neljällä parametrilla.
2D-vektori.
Definition: Vector.cs:56
void Disable(AnalogControl control)
Poistaa analogiohjaimen (tikku tai nappi) käytöstä.
Definition: GamePad.cs:205
delegate void AnalogHandler< T1 >(AnalogState analogState, T1 p1)
Ohjaintapahtumankäsittelijä yhdellä parametrilla.
AnalogControl
Analoginen ohjain. Tämä voi olla joko painike, jota voi painaa eri voimakkuuksilla (padiohjaimen liip...
Definition: Listeners.cs:57
delegate void AnalogHandler< T1, T2, T3, T4 >(AnalogState analogState, T1 p1, T2 p2, T3 p3, T4 p4)
Ohjaintapahtumankäsittelijä neljällä parametrilla.
Yleinen peliohjainluokka.
Definition: Controller.cs:40
void Disable(Button button)
Poistaa napin käytöstä.
Definition: GamePad.cs:197