source: 2014/24/EemeliK/Zombieland/Jypeli/Controls/GamePad.cs @ 5974

Revision 5974, 19.0 KB checked in by empaheik, 4 years ago (diff)
Line 
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
30using System.Collections.Generic;
31using System.Diagnostics;
32using Microsoft.Xna.Framework;
33using Microsoft.Xna.Framework.Input;
34using Physics2DDotNet;
35
36using XnaGamePad = Microsoft.Xna.Framework.Input.GamePad;
37
38namespace Jypeli.Controls
39{
40    /// <summary>
41    /// Xbox-peliohjain.
42    /// </summary>
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
118        /// <summary>
119        /// Onko ohjain kytkettynä.
120        /// </summary>
121        public bool IsConnected
122        {
123            get { return newState.IsConnected; }
124        }
125
126        /// <summary>
127        /// Vasemman tatin suuntavektori.
128        /// Vaihtelee välillä (-1, -1) - (1, 1)
129        /// </summary>
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
139        /// <summary>
140        /// Oikean tatin suuntavektori.
141        /// Vaihtelee välillä (-1, -1) - (1, 1)
142        /// </summary>
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
152        /// <summary>
153        /// Vasemman liipaisimen tila.
154        /// Vaihtelee välillä 0 - 1.
155        /// </summary>
156        public double LeftTriggerState
157        {
158            get { return newState.Triggers.Left; }
159        }
160
161        /// <summary>
162        /// Oikean liipaisimen tila.
163        /// Vaihtelee välillä 0 - 1.
164        /// </summary>
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
178        /// <summary>
179        /// Ottaa käytöstä poistetun napin takaisin käyttöön.
180        /// </summary>
181        public void Enable( Button button )
182        {
183            base.Enable( listener => ( listener.Button == button ) );
184        }
185
186        /// <summary>
187        /// Ottaa käytöstä poistetun analogiohjaimen takaisin käyttöön.
188        /// </summary>
189        public void Enable( AnalogControl control )
190        {
191            base.Enable( listener => ( listener.AnalogControl == control ) );
192        }
193
194        /// <summary>
195        /// Poistaa napin käytöstä.
196        /// </summary>
197        public void Disable( Button button )
198        {
199            base.Disable( listener => ( listener.Button == button ) );
200        }
201
202        /// <summary>
203        /// Poistaa analogiohjaimen (tikku tai nappi) käytöstä.
204        /// </summary>
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
311        /// <summary>
312        /// Palauttaa annetun napin tilan (ks. <c>ButtonState</c>).
313        /// </summary>
314        /// <param name="b">Nappi.</param>
315        /// <returns>Napin tila</returns>
316        public ButtonState GetButtonState( Button b )
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
377        /// <summary>
378        /// Palauttaa, onko yksikään ohjaimen nappi alhaalla.
379        /// </summary>
380        /// <returns><c>bool</c></returns>
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
400        /// <summary>
401        /// Täristää peliohjainta.
402        /// </summary>
403        /// <param name="leftMotor">Vasemmanpuoleisen moottorin tärinän määrä (maksimi 1).</param>
404        /// <param name="rightMotor">Oikeanpuoleisen moottorin tärinän määrä (maksimi 1) .</param>
405        /// <param name="leftAcceleration">Vasemmanpuoleisen moottorin tärinäkiihtyvyys (yksikköä sekunnissa).</param>
406        /// <param name="rightAcceleration">Oikeanpuoleisen moottorin tärinäkiihtyvyys (yksikköä sekunnissa).</param>
407        /// <param name="time">Aika, jonka tärinä kestää (sekunteina).</param>
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}
Note: See TracBrowser for help on using the repository browser.