Jypeli  5
The simple game programming library
Mouse.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.ComponentModel;
32 using System.Collections.Generic;
33 using System.Diagnostics;
34 using Microsoft.Xna.Framework.Input;
35 using Microsoft.Xna.Framework.Graphics;
36 
37 using XnaMouse = Microsoft.Xna.Framework.Input.Mouse;
38 using XnaMouseState = Microsoft.Xna.Framework.Input.MouseState;
39 using XnaButtonState = Microsoft.Xna.Framework.Input.ButtonState;
40 
41 namespace Jypeli.Controls
42 {
46  public class Mouse : Controller<MouseState>, PointingDevice
47  {
48  private static int wcx = 800;
49  private static int wcy = 600;
50 
54  public int ActiveChannels { get { return 1; } }
55 
63  public bool IsCursorVisible
64  {
65  get
66  {
67 #if WINDOWS_PHONE
68  return false;
69 #else
70  return Game.Instance.IsMouseVisible;
71 #endif
72  }
73  set { Game.Instance.IsMouseVisible = value; }
74  }
75 
76  internal static Viewport Viewport
77  {
78  set
79  {
80  wcx = value.X + value.Width / 2;
81  wcy = value.Y + value.Height / 2;
82  }
83  }
84 
88  public Vector PositionOnScreen
89  {
90  get
91  {
92  return newState.Position;
93  }
94  set
95  {
96  newState.Position = value;
97  XnaMouse.SetPosition( wcx + (int)value.X, wcy - (int)value.Y );
98  }
99  }
100 
104  public Vector PositionOnWorld
105  {
106  get
107  {
108  return Game.Instance.Camera.ScreenToWorld(PositionOnScreen);
109  }
110  set
111  {
112  PositionOnScreen = Game.Instance.Camera.WorldToScreen(value);
113  }
114  }
115 
119  public int WheelState
120  {
121  get
122  {
123  return newState.Wheel / 120;
124  }
125  }
126 
131  public int WheelChange
132  {
133  get
134  {
135  return (newState.Wheel - oldState.Wheel) / 120;
136  }
137  }
138 
139  internal Mouse()
140  {
141  XnaMouse.SetPosition( wcx, wcy );
142  }
143 
144  internal override bool IsBufferEmpty()
145  {
146  // TODO: "Dead" tolerance for movement
147  return newState.AnyButtonDown;
148  }
149 
150  public void Enable( MouseButton button )
151  {
152  base.Enable( listener => ( listener.MouseButton == button ) );
153  }
154 
155  public void Disable( MouseButton button )
156  {
157  base.Disable( listener => ( listener.MouseButton == button ) );
158  }
159 
160  public bool IsTriggeredOnChannel( int channel, Listener listener )
161  {
162  return IsTriggered( listener );
163  }
164 
165  protected override bool IsTriggered( Listener listener )
166  {
167  if ( listener.Type == ListeningType.MouseMovement )
168  {
169  return false;
170  }
171 
172  if ( listener.Type == ListeningType.MouseWheel )
173  {
174  return IsWheelTriggered( listener );
175  }
176 
177  if ( listener.Type == ListeningType.MouseButton )
178  {
179  return IsButtonTriggered( listener );
180  }
181 
182  return base.IsTriggered( listener );
183  }
184 
185  protected override bool IsAnalogTriggered( Listener listener, out AnalogState state )
186  {
187  if ( listener.Type == ListeningType.MouseMovement )
188  {
189  return IsMotionTriggered(listener, out state);
190  }
191 
192  return base.IsAnalogTriggered(listener, out state);
193  }
194 
195  private bool IsButtonTriggered( Listener listener )
196  {
197  Debug.Assert( listener.Type == ListeningType.MouseButton );
198  MouseButton button = listener.MouseButton;
199 
200  if ( listener.GameObject != null && !IsCursorOn( listener.GameObject ) )
201  return false;
202 
203  return listener.State == ButtonState.Irrelevant || MouseState.GetButtonState( oldState, newState, button ) == listener.State;
204  }
205 
206  private bool IsWheelTriggered( Listener listener )
207  {
208  return WheelChange != 0;
209  }
210 
211  private bool IsMotionTriggered( Listener listener, out AnalogState state )
212  {
213  Debug.Assert( listener.Type == ListeningType.MouseMovement );
214  double xMovement = newState.X - oldState.X;
215  double yMovement = newState.Y - oldState.Y;
216  Vector movement = new Vector( xMovement, yMovement );
217 
218  if ( movement.Magnitude < listener.MovementTrigger )
219  {
220  state = new AnalogState();
221  return false;
222  }
223 
224  state = new AnalogState( listener.State, movement );
225  return true;
226  }
227 
228  internal override MouseState GetCurrentState()
229  {
230  MouseState state = GetMouseState();
231 
232  if ( !IsCursorVisible )
233  {
234  // Accumulate relative coordinates to get absolute ones
235  state.X += oldState.X;
236  state.Y += oldState.Y;
237  }
238 
239  return state;
240  }
241 
242  internal MouseState GetMouseState()
243  {
244  XnaMouseState xnaState = XnaMouse.GetState();
245  MouseState state = new MouseState();
246 
247  state.X = xnaState.X - wcx;
248  state.Y = -( xnaState.Y - wcy );
249  state.LeftDown = xnaState.LeftButton == XnaButtonState.Pressed;
250  state.RightDown = xnaState.RightButton == XnaButtonState.Pressed;
251  state.MiddleDown = xnaState.MiddleButton == XnaButtonState.Pressed;
252  state.X1Down = xnaState.XButton1 == XnaButtonState.Pressed;
253  state.X2Down = xnaState.XButton2 == XnaButtonState.Pressed;
254  state.Wheel = xnaState.ScrollWheelValue;
255 
256  if ( !IsCursorVisible )
257  {
258  // Reset the mouse to the center of the screen
259  XnaMouse.SetPosition( wcx, wcy );
260  }
261 
262  return state;
263  }
264 
265  internal override string GetControlText( Listener listener )
266  {
267  switch ( listener.Type )
268  {
269  case ListeningType.MouseButton:
270  return listener.MouseButton.ToString() + " mouse";
271  case ListeningType.MouseMovement:
272  return "Mouse";
273  case ListeningType.MouseWheel:
274  return "Mouse wheel";
275  default:
276  Debug.Assert( false, "Bad listener type for mouse" );
277  return null;
278  }
279  }
280 
284  public bool IsCursorOn( IGameObject obj )
285  {
286 #if WINDOWS_PHONE
287  return false;
288 #else
289  return obj.IsInside( Game.Instance.Camera.ScreenToWorld(this.PositionOnScreen, obj.Layer) );
290 #endif
291  }
292 
293 
294  #region Listen with no parameters
295 
303  public Listener Listen( MouseButton b, ButtonState state, Handler handler, string helpText )
304  {
305 #if WINDOWS
306  Listener l = new SimpleListener( this, ListeningType.MouseButton, helpText, handler );
307  l.MouseButton = b;
308  l.State = state;
309  Add( l );
310  return l;
311 #else
312  return Listener.Null;
313 #endif
314  }
315 
324  public Listener ListenOn( IGameObject obj, MouseButton b, ButtonState state, Handler handler, String helpText )
325  {
326 #if WINDOWS
327  Listener l = new SimpleListener( this, ListeningType.MouseButton, helpText, handler );
328  l.MouseButton = b;
329  l.State = state;
330  l.GameObject = obj;
331  Add( l );
332  return l;
333 #else
334  return Listener.Null;
335 #endif
336  }
337 
344  public Listener ListenMovement( double trigger, AnalogHandler handler, string helpText )
345  {
346 #if WINDOWS
347  Listener l = new AnalogListener( this, ListeningType.MouseMovement, helpText, handler );
348  l.MovementTrigger = trigger;
349  Add( l );
350  return l;
351 #else
352  return Listener.Null;
353 #endif
354  }
355 
361  public Listener ListenWheel(Handler handler, string helpText)
362  {
363 #if WINDOWS
364  Listener l = new SimpleListener(this, ListeningType.MouseWheel, helpText, handler);
365  Add(l);
366  return l;
367 #else
368  return Listener.Null;
369 #endif
370  }
371 
372  #endregion
373 
374  #region Listen with 1 parameter
375 
376  public Listener Listen<T1>( MouseButton b, ButtonState state, Handler<T1> handler, string helpText, T1 p1 )
377  {
378 #if WINDOWS
379  Listener l = new SimpleListener<T1>( this, ListeningType.MouseButton, helpText, handler, p1 );
380  l.MouseButton = b;
381  l.State = state;
382  Add( l );
383  return l;
384 #else
385  return Listener.Null;
386 #endif
387  }
388 
389  public Listener ListenOn<T1>( IGameObject obj, MouseButton b, ButtonState state, Handler<T1> handler, String helpText, T1 p1 )
390  {
391 #if WINDOWS
392  Listener l = new SimpleListener<T1>( this, ListeningType.MouseButton, helpText, handler, p1 );
393  l.MouseButton = b;
394  l.State = state;
395  l.GameObject = obj;
396  Add( l );
397  return l;
398 #else
399  return Listener.Null;
400 #endif
401  }
402 
403  public Listener ListenWheel<T1>(Handler<T1> handler, string helpText, T1 p1)
404  {
405 #if WINDOWS
406  Listener l = new SimpleListener<T1>(this, ListeningType.MouseWheel, helpText, handler, p1);
407  Add(l);
408  return l;
409 #else
410  return Listener.Null;
411 #endif
412  }
413 
414  public Listener ListenMovement<T1>( double trigger, AnalogHandler<T1> handler, string helpText, T1 p1 )
415  {
416 #if WINDOWS
417  Listener l = new AnalogListener<T1>( this, ListeningType.MouseMovement, helpText, handler, p1 );
418  l.MovementTrigger = trigger;
419  Add( l );
420  return l;
421 #else
422  return Listener.Null;
423 #endif
424  }
425 
426  #endregion
427 
428  #region Listen with 2 parameters
429 
430  public Listener Listen<T1, T2>( MouseButton b, ButtonState state, Handler<T1, T2> handler, string helpText, T1 p1, T2 p2 )
431  {
432 #if WINDOWS
433  Listener l = new SimpleListener<T1, T2>( this, ListeningType.MouseButton, helpText, handler, p1, p2 );
434  l.MouseButton = b;
435  l.State = state;
436  Add( l );
437  return l;
438 #else
439  return Listener.Null;
440 #endif
441  }
442 
443  public Listener ListenOn<T1, T2>( IGameObject obj, MouseButton b, ButtonState state, Handler<T1, T2> handler, String helpText, T1 p1, T2 p2 )
444  {
445 #if WINDOWS
446  Listener l = new SimpleListener<T1, T2>( this, ListeningType.MouseButton, helpText, handler, p1, p2 );
447  l.MouseButton = b;
448  l.State = state;
449  l.GameObject = obj;
450  Add( l );
451  return l;
452 #else
453  return Listener.Null;
454 #endif
455  }
456 
457  public Listener ListenWheel<T1, T2>(Handler<T1, T2> handler, string helpText, T1 p1, T2 p2)
458  {
459 #if WINDOWS
460  Listener l = new SimpleListener<T1, T2>(this, ListeningType.MouseWheel, helpText, handler, p1, p2);
461  Add(l);
462  return l;
463 #else
464  return Listener.Null;
465 #endif
466  }
467 
468  public Listener ListenMovement<T1, T2>( double trigger, AnalogHandler<T1, T2> handler, string helpText, T1 p1, T2 p2 )
469  {
470 #if WINDOWS
471  Listener l = new AnalogListener<T1, T2>( this, ListeningType.MouseMovement, helpText, handler, p1, p2 );
472  l.MovementTrigger = trigger;
473  Add( l );
474  return l;
475 #else
476  return Listener.Null;
477 #endif
478  }
479 
480  #endregion
481 
482  #region Listen with 3 parameters
483 
484  public Listener Listen<T1, T2, T3>( MouseButton b, ButtonState state, Handler<T1, T2, T3> handler, string helpText, T1 p1, T2 p2, T3 p3 )
485  {
486 #if WINDOWS
487  Listener l = new SimpleListener<T1, T2, T3>( this, ListeningType.MouseButton, helpText, handler, p1, p2, p3 );
488  l.MouseButton = b;
489  l.State = state;
490  Add( l );
491  return l;
492 #else
493  return Listener.Null;
494 #endif
495  }
496 
497  public Listener ListenOn<T1, T2, T3>( IGameObject obj, MouseButton b, ButtonState state, Handler<T1, T2, T3> handler, String helpText, T1 p1, T2 p2, T3 p3 )
498  {
499 #if WINDOWS
500  Listener l = new SimpleListener<T1, T2, T3>( this, ListeningType.MouseButton, helpText, handler, p1, p2, p3 );
501  l.MouseButton = b;
502  l.State = state;
503  l.GameObject = obj;
504  Add( l );
505  return l;
506 #else
507  return Listener.Null;
508 #endif
509  }
510 
511  public Listener ListenWheel<T1, T2, T3>(Handler<T1, T2, T3> handler, string helpText, T1 p1, T2 p2, T3 p3)
512  {
513 #if WINDOWS
514  Listener l = new SimpleListener<T1, T2, T3>(this, ListeningType.MouseWheel, helpText, handler, p1, p2, p3);
515  Add(l);
516  return l;
517 #else
518  return Listener.Null;
519 #endif
520  }
521 
522  public Listener ListenMovement<T1, T2, T3>( double trigger, AnalogHandler<T1, T2, T3> handler, string helpText, T1 p1, T2 p2, T3 p3 )
523  {
524 #if WINDOWS
525  Listener l = new AnalogListener<T1, T2, T3>( this, ListeningType.MouseMovement, helpText, handler, p1, p2, p3 );
526  l.MovementTrigger = trigger;
527  Add( l );
528  return l;
529 #else
530  return Listener.Null;
531 #endif
532  }
533 
534  #endregion
535 
536  #region Listen with 4 parameters
537 
538  public Listener Listen<T1, T2, T3, T4>( MouseButton b, ButtonState state, Handler<T1, T2, T3, T4> handler, string helpText, T1 p1, T2 p2, T3 p3, T4 p4 )
539  {
540 #if WINDOWS
541  Listener l = new SimpleListener<T1, T2, T3, T4>( this, ListeningType.MouseButton, helpText, handler, p1, p2, p3, p4 );
542  l.MouseButton = b;
543  l.State = state;
544  Add( l );
545  return l;
546 #else
547  return Listener.Null;
548 #endif
549  }
550 
551  public Listener ListenOn<T1, T2, T3, T4>( IGameObject obj, MouseButton b, ButtonState state, Handler<T1, T2, T3, T4> handler, String helpText, T1 p1, T2 p2, T3 p3, T4 p4 )
552  {
553 #if WINDOWS
554  Listener l = new SimpleListener<T1, T2, T3, T4>( this, ListeningType.MouseButton, helpText, handler, p1, p2, p3, p4 );
555  l.MouseButton = b;
556  l.State = state;
557  l.GameObject = obj;
558  Add( l );
559  return l;
560 #else
561  return Listener.Null;
562 #endif
563  }
564 
565  public Listener ListenWheel<T1, T2, T3, T4>(Handler<T1, T2, T3, T4> handler, string helpText, T1 p1, T2 p2, T3 p3, T4 p4)
566  {
567 #if WINDOWS
568  Listener l = new SimpleListener<T1, T2, T3, T4>(this, ListeningType.MouseWheel, helpText, handler, p1, p2, p3, p4);
569  Add(l);
570  return l;
571 #else
572  return Listener.Null;
573 #endif
574  }
575 
576  public Listener ListenMovement<T1, T2, T3, T4>( double trigger, AnalogHandler<T1, T2, T3, T4> handler, string helpText, T1 p1, T2 p2, T3 p3, T4 p4 )
577  {
578 #if WINDOWS
579  Listener l = new AnalogListener<T1, T2, T3, T4>( this, ListeningType.MouseMovement, helpText, handler, p1, p2, p3, p4 );
580  l.MovementTrigger = trigger;
581  Add( l );
582  return l;
583 #else
584  return Listener.Null;
585 #endif
586  }
587 
588  #endregion
589  }
590 
591  public struct MouseState
592  {
593  static MouseButton[] buttons =
594  { MouseButton.Left, MouseButton.Right, MouseButton.Middle,
595  MouseButton.XButton1, MouseButton.XButton2 };
596 
597  static ButtonState[] states =
598  { ButtonState.Up, ButtonState.Pressed,
599  ButtonState.Released, ButtonState.Down };
600 
601  public double X;
602  public double Y;
603  public int ButtonMask;
604  public int Wheel;
605 
606  public Vector Position
607  {
608  get { return new Vector( X, Y ); }
609  set
610  {
611  X = value.X;
612  Y = value.Y;
613  }
614  }
615 
616  public bool LeftDown
617  {
618  get { return ( ButtonMask & 1 ) > 0; }
619  set { if ( value ) ButtonMask |= 1; else ButtonMask &= ~1; }
620  }
621 
622  public bool RightDown
623  {
624  get { return ( ButtonMask & 2 ) > 0; }
625  set { if ( value ) ButtonMask |= 2; else ButtonMask &= ~2; }
626  }
627 
628  public bool MiddleDown
629  {
630  get { return ( ButtonMask & 4 ) > 0; }
631  set { if ( value ) ButtonMask |= 4; else ButtonMask &= ~4; }
632  }
633 
634  public bool X1Down
635  {
636  get { return ( ButtonMask & 8 ) > 0; }
637  set { if ( value ) ButtonMask |= 8; else ButtonMask &= ~8; }
638  }
639 
640  public bool X2Down
641  {
642  get { return ( ButtonMask & 16 ) > 0; }
643  set { if ( value ) ButtonMask |= 16; else ButtonMask &= ~16; }
644  }
645 
646  public bool AnyButtonDown
647  {
648  get { return ButtonMask > 0; }
649  }
650 
651  internal bool IsButtonDown( MouseButton button )
652  {
653  int bi = 1;
654 
655  for ( int i = 0; i < 5; i++ )
656  {
657  if ( button == buttons[i] )
658  return ( ButtonMask & bi ) > 0;
659 
660  bi *= 2;
661  }
662 
663  return false;
664  }
665 
666  internal static ButtonState GetButtonState( MouseState oldState, MouseState newState, MouseButton button )
667  {
668  int oldDown = oldState.IsButtonDown( button ) ? 2 : 0;
669  int newDown = newState.IsButtonDown( button ) ? 1 : 0;
670  return states[oldDown + newDown];
671  }
672  }
673 }
double Magnitude
Vektorin pituus.
Definition: Vector.cs:281
bool IsCursorOn(IGameObject obj)
Onko hiiren kursori annetun olion päällä.
Definition: Mouse.cs:284
Listener ListenMovement(double trigger, AnalogHandler handler, string helpText)
Kuuntelee hiiren liikettä.
Definition: Mouse.cs:344
Listener ListenWheel(Handler handler, string helpText)
Kuuntelee hiiren rullaa.
Definition: Mouse.cs:361
delegate void AnalogHandler< T1, T2 >(AnalogState analogState, T1 p1, T2 p2)
Ohjaintapahtumankäsittelijä kahdella parametrilla.
void Enable(MouseButton button)
Definition: Mouse.cs:150
ButtonState
Napin (minkä tahansa) asento.
Definition: ButtonState.cs:37
static Game Instance
Definition: Game.cs:149
MouseButton
Hiiren napit.
Definition: MouseButton.cs:11
override bool IsTriggered(Listener listener)
Definition: Mouse.cs:165
bool IsTriggeredOnChannel(int channel, Listener listener)
Definition: Mouse.cs:160
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
Hiiri peliohjaimena.
Definition: Mouse.cs:46
void Disable(MouseButton button)
Definition: Mouse.cs:155
delegate void Handler()
Ohjaintapahtumankäsittelijä ilman parametreja.
override bool IsAnalogTriggered(Listener listener, out AnalogState state)
Definition: Mouse.cs:185
Yhteinen rajapinta kaikille peliolioille.
Definition: IGameObject.cs:14
bool IsInside(Vector point)
delegate void Handler< T1, T2 >(T1 p1, T2 p2)
Ohjaintapahtumankäsittelijä kahdella parametrilla.
Camera Camera
Kamera, joka näyttää ruudulla näkyvän osan kentästä. Kameraa voidaan siirtää, zoomata tai asettaa seu...
Definition: Game.cs:166
delegate void AnalogHandler< T1, T2, T3 >(AnalogState analogState, T1 p1, T2 p2, T3 p3)
Ohjaintapahtumankäsittelijä kolmella parametrilla.
Listener Listen(MouseButton b, ButtonState state, Handler handler, string helpText)
Kuuntelee hiiren nappulan painalluksia.
Definition: Mouse.cs:303
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
delegate void AnalogHandler< T1 >(AnalogState analogState, T1 p1)
Ohjaintapahtumankäsittelijä yhdellä parametrilla.
Vector WorldToScreen(Vector point)
Muuntaa annetun pisteen maailmankoordinaateista ruutukoordinaatteihin.
Definition: Camera.cs:176
Vector ScreenToWorld(Vector point)
Muuntaa annetun pisteen ruutukoordinaateista maailmankoordinaatteihin.
Definition: Camera.cs:168
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
Listener ListenOn(IGameObject obj, MouseButton b, ButtonState state, Handler handler, String helpText)
Kuuntelee hiirenpainalluksia annetun peliolion päällä.
Definition: Mouse.cs:324