Animazione grafica
double buffering


Ora che è stata messa a punto l'ossatura del progetto si può passare alla fase operativa, dotando l'interfaccia dell'applicazione di un menù principale articolato in due items:

  1. MnVelocita
  2. MnInizio

MnVelocita per mette all'utente di modificare la velocità della palla (e quindi sulla difficoltà del gioco). La velocità della palla è rappresentata dalla proprietà v dell'oggetto palla e viene inizializzata a 5 dal suo costruttore.

Impostando l'evento CmdVelocita si apre l'editor di TFrmPing.cpp per la scrittura del metodo

void __fastcall TFrmPing::CmdVelocita(TObject *Sender)
{
}

Come si è mostrato negli esempi precedenti, si può usare la funzione InputQuery.

void __fastcall TFrmPing::CmdVelocita(TObject *Sender)
{
AnsiString aux = FloatToStr(palla->v);
  if (InputQuery("Ping","Velocità della palla?",aux))
    {
      try
        {
          StrToFloat(aux);
        }
      catch(...)
        {
          ShowMessage("Valore improprio.");
          return;
        }
      palla->v = StrToFloat(aux);
    }
}

Come si è osservato in precedenza, bisogna sempre rendere gli input a prova di 'distrattoni', quindi, prima di accettare l'input si controlla se può rappresentare un numero reale.

Associando all'evento OnClick di MnInizio il metodo CmdInizio si apre l'editor di TFrmPing.cpp per la scrittura del metodo

void __fastcall TFrmPing::CmdInizio(TObject *Sender)
{
}

Viene proposto un possibile modo di simulare il movimento della palla e della racchetta. Si spera che i commenti siano esaurienti per aiutare a comprendere senso e modalità delle tecniche usate.

void __fastcall TFrmPing::CmdInizio(TObject *Sender)
{
Cursor = crNone; // Il cursore non deve essere visibile.
Refresh(); // Riporta la finestra al colore di sfondo, cancellando
             // eventuali tracce precedenti
randomize(); // Il generatore di numeri casuali parte da un numero casuale.
/*
Sfondo è la superficie rettangolare nascosta su cui si producono le nuove figure:
  le sue dimensioni devono coincidere con quelle della parte attiva della
  finestra.
*/
sfondo->Width=ClientWidth;
  sfondo->Height=ClientHeight;
// Posizione iniziale della racchetta.
racchetta->yg = ClientHeight-racchetta->altezza;
  racchetta->xg = ClientWidth/2;
// Posizione iniziale della palla.
palla->x = 0;
  palla->y = 0;
/*
Angolazione iniziale della velocità della palla:
M_PI è pi greco;
M_PI/20 è un decimo di angolo retto;
random(9) genera un numero intero a caso tra 0 e 8.
*/
palla->theta = M_PI/20*(1+random(9));
// Componenti vx e vy della velocità della palla.
palla->vx = palla->v*cos(palla->theta);
  palla->vy = palla->v*sin(palla->theta);

// Ciclo per le posizioni successive della palla e della racchetta.
do
    {
/*
Si disegna su sfondo un rettangolo dello stesso colore del pennello (brush):
in pratica si cancella lo sfondo.
*/
sfondo->Canvas->Rectangle(0,0,sfondo->Width,sfondo->Height);
//Nuova posizione della palla.
palla->x += palla->vx;
      palla->y += palla->vy;
// Si arrotondano le coordinate reali per avere valori interi per la grafica.
palla->xg = floor(palla->x);
      palla->yg = floor(palla->y);
// Se la palla è oltre la parete destra, invertire la velocità x.
if (palla->xg+palla->diametro > ClientWidth)
        palla->vx = -palla->vx;
// Se la palla è oltre la parete sinistra invertire la velocità x.
if (palla->xg<0)
        palla->vx = -palla->vx;
// Se la palla è  oltre la parete superiore invertire la velocità y.
if (palla->yg < 0)
        palla->vy = -palla->vy;
// Se la palla tocca la racchetta invertire la velocità y.
palla->xc=palla->xg+palla->diametro/2;
      if ((palla->yg+palla->diametro > racchetta->yg)
        && (palla->xc > racchetta->xg)
        && (palla->xc < racchetta->xg+racchetta->larghezza))
        {
          palla->vy = -palla->vy ;
        }
// Disegno della palla su sfondo.
sfondo->Canvas->Draw(palla->xg,palla->yg,palla->img);
/*
La posizione orizzontale della racchetta è collegata
alla corrispondente posizione del mouse.
*/
racchetta->xg = Mouse->CursorPos.x; 
// Disegno della racchetta su sfondo.
sfondo->Canvas->Draw(racchetta->xg,racchetta->yg,racchetta->img);
/*
Finalmente tutto sfondo viene ricopiato sulla Canvas della finestra.
La tecnica del double buffering consiste in questo: si disegna sulla
superficie nascosta 'sfondo': a fine disegno lo sfondo è reso visibile
ricopiandolo sulla Canvas della finestra.
Questa tecnica riproduce il movimento in modo abbastanza continuo.
*/
Canvas->Draw(0,0,sfondo);
      Sleep(1); // Pausa di un millisecondo.
} while (palla->y+palla->diametro < ClientHeight);
// Ciclare fino a che la palla supera la parete inferiore.

Cursor= crDefault; // Mostrare il cursore.
ShowMessage("Fine del gioco");
  Refresh();
}

Il gioco è pronto per funzionare. Salvare e compilare. Se qualcosa non funziona, cercare pazientemente gli errori dopo aver ben letto e meditato i messaggi del compilatore.

Provare a rendere il gioco un tantino più emozionante, ad esempio, producendo mutamenti casuali nella direzione della velocità della palla ad ogni contatto con la racchetta e introducendo il calcolo di un punteggio per il giocatore.


prontuario

ping2

Valid XHTML 1.0