Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 29 di 53
  • livello principiante
Indice lezioni

Da polling a eventi e viceversa

Trasformare le modalità di gestione dell'input in base alle esigenze dell'applicazione
Trasformare le modalità di gestione dell'input in base alle esigenze dell'applicazione
Link copiato negli appunti

Convertire Polling in Eventi

In moltissime architetture è preferibile esporre l'input come una serie di eventi, piuttosto che come una serie di valori di cui eseguire continuamente il polling. In questo modo, infatti, possiamo anche esporre sequenze di input nei nostri eventi, e non solo valori elementari.

Per far questo realizziamo un GameComponent (in genere denominato InputManager) che nel proprio metodo Update si occupi di leggere tutti i dispositivi di input di nostro interesse, lanciando uno o più eventi (a cui ci saremo debitamente sottoscritti) una volta che i valori dei dispositivi di input siano quelli desiderati.

Prendiamo come esempio gli input da GamePad e dichiariamo un oggetto di tipo GamePadState:

GamePadState current_gps;

Nel metodo Update del nostro InputManager aggiorniamo a ogni loop lo stato del GamePad (per semplicità limitato al solo controller principale):

current_gps = GamePad.GetState(PlayerIndex.One);

A questo punto possiamo collegare la pressione di un bottone (A, nel nostro esempio) allo scatenarsi dell'evento APressed (a patto, ovviamente, che qualcuno sia in ascolto):

if (current_gps.Buttons.A == ButtonState.Pressed)
  if(APressed != null)
    APressed();

È evidente che, anche in questo caso, possiamo "salvare" sequenze di stati per confrontarli ed eventualmente combinarli per generare input più complessi del semplice "il tasto è giù". Per far questo dichiariamo due oggetti di tipo GamePadState per registrare sia lo stato "corrente" del gamePad, sia quello precedente:

GamePadState last_gps, current_gps;
last_gps = current_gps;
current_gps = GamePad.GetState(PlayerIndex.One);

In questo modo, possiamo decidere di scatenare l'evento al momento in cui il tasto di Back viene effettivamente premuto (passando dallo "stato" di IsButtonUp a quello di IsButtonDown):

if (current_gps.IsButtonDown(Buttons.Back) && last_gps.IsButtonUp(Buttons.Back))
  if (OnBack != null)
    OnBack();

Convertire Eventi in Polling

Analogamente, potremmo essere interessati all'operazione contraria, ossia trasformare eventi come quelli legati all'accelerometro in un sistema di polling da interrogare a ogni loop. Per far questo avremo bisogno di creare una classe in grado di fungere da "ponte" tra il codice del gioco e e l'accelerometro stesso: questa classe si metterà in ascolto dell'evento ReadingChanged, memorizzando i relativi dati internamente ed esponendoli tramite un metodo statico (nell'esempio che segue tale metodo è chiamato GetValues).

La classe utilizzata per contenere i dati (denominata AccelerometerValues) è piuttosto semplice, contenendo unicamente un campo di tipo Vector3 (inizializzato a zero) in grado di memorizzare i valori relativi ai tre assi (X, Y, Z).

public class AccelerometerValues
{
  public Vector3 Acceleration = Vector3.Zero; 
  public AccelerometerValues() {  }
}

La classe destinata a leggere l'accelerometro (denominata AccelerometerHelper) ha un membro statico che rappresenta il sensore vero e proprio (accelerometerSensor) e un altro membro, anch'esso statico, di tipo AccelerometerValues, che rappresenta, come si è detto, gli ultimi valori di accelerazione "salvati" (values).

public class AccelerometerHelper
{
  static Accelerometer accelerometerSensor;
  static AccelerometerValues values = new AccelerometerValues();

Il costruttore statico di questa classe svolge tre funzioni: inizializza l'accelerometro, si mette in ascolto dell'evento ReadingChanged e avvia l'accelerometro stesso (omettiamo il try/catch per brevità):

static AccelerometerHelper()
  {
    accelerometerSensor = new Accelerometer();
    accelerometerSensor.ReadingChanged += new EventHandler< AccelerometerReadingEventArgs>(accelerometerSensor_ReadingChanged);
    accelerometerSensor.Start();
  }

Ogni volta che il sensore registra nuovi dati, il relativo event handler provvede a "salvare" i dati stessi nella proprietà Acceleration della variabile statica values.

static void accelerometerSensor_ReadingChanged(object sender, AccelerometerReadingEventArgs e)
  {
    values.Acceleration.X = (float)e.X;
    values.Acceleration.Y = (float)e.Y;
    values.Acceleration.Z = (float)e.Z;
  }

Da notare la necessaria conversione dei valori in float, trattandosi di un Vector3 (mentre i valori restituiti dall'accelerometro sono, come si è detto, di tipo double).

Infine, il metodo statico GetValues restituisce i valori salvati, che naturalmente potrebbero anche essere non "nuovi", dal momento che niente ci dice quando è stata l'ultima volta che l'evento ReadingChanged è stato invocato. Questo permette di avere un codice più "lineare":

public static AccelerometerValues GetValues()
{
  return values;
}

Ti consigliamo anche