Ver Mensaje Individual
  #24 (permalink)  
Antiguo 06/05/2005, 18:43
Avatar de Boxmaster
Boxmaster
 
Fecha de Ingreso: agosto-2004
Ubicación: Ahorita... frente a mi PC
Mensajes: 74
Antigüedad: 20 años, 9 meses
Puntos: 0
Exclamación Tutorial del PACMAN en VB.NET (2a Parte)

Pour dessiner une image, c’est aussi simple. Sous VB6, il fallait charger une image dans un PictureBox invisible et de faire des BitBlt ou des PaintPicture sur la Form de destination. On pouvait également utiliser des images en mémoire uniquement, mais cela nécessitait une bonne maîtrise des API. Avec VB.NET, no problemo (citation de Homer. S.) :

e.DrawImage( mBitmapPacMan, 10,10)

Ou, vous l’aurez deviné, mBitmapPacMan est un objet Image.



Bien, vous savez maintenant charger le fichier grâce à System.IO, dessiner votre décor, votre PacMan et vos fantômes (grâce à System.Drawing). Pour les détails, je vous laisse le soin de regarder dans le code sur le CDROM)

En ce qui concerne votre Pacman et vos fantômes, pour que ce soit plus sympathique, il faut les animer. La solution retenue à été d’alterner l’objet Image utilisé toutes les x millisecondes (ces dernières sont en réalité stockées dans une collection ArrayList). Rien de bien compliqué sauf qu’il faut générer cet événement toutes les x millisecondes. Vous pourriez utiliser un contrôle Timer dans votre Form comme sous VB6, mais cela lierait votre objet cPacMan (et cFantome) à votre Form et nuierait à la suite de cet article. Heureusement, vous pouvez maintenant instancier un Timer dans une classe et surtout, s’abonner à son événement : plus besoin de contrôle.

Les évènements
Il existe deux sortes de Timers sous VB.NET. Un dans le NameSpace System.Winforms (le contrôle Timer traditionnel ) et un dans System.Threading. C’est ce dernier que vous allez utiliser. Pour s’abonner à son événement, vous allez utiliser la délégation (nous reviendrons plus en détail dans un autre numéro sur la délégation et les évènements avec VB.NET) grâce à un objet TimeCallBack.

Dim oTCallBack as New TimerCallback(AddressOf Me.Change)
Dim objTimerChange As New Timer(oTCallBack, Me, 50, 0)

Grâce au constructeur de l’objet TimerCallback, vous indiquez que la procédure Change de l’objet où il est instancié (Me) doit être appelée. L’événement généré par le Timer exécutera la procédure Change. Puis vous abonnez votre objet au callback du nouveau Timer. Contrairement au Timer traditionnel qui génère un événement qui se répète régulièrement, le Timer de Threading génère l’événement (au bout de 50ms dans notre cas) puis se détruit. Si l’on veut de nouveau rappeler la procédure Change 50 ms après, il faut recréer un nouveau Timer :

Private Sub Change(ByVal sender As Object)

Dim objTimerChange As New Timer(New TimerCallback(AddressOf Me.Change), Me, 50, 0)
End Sub

Il est important dans la déclaration de Change d’ajouter le paramètre sender as Object pour que la délégation fonctionne.

Petite remarque concernant la beta 1 de MS.NET Framework : au début du développement de cette application, j’avais envisagé de créer un Threading.Timer pour chaque Sprite animé. Malheureusement, au bout de quelques secondes, il perd un peu les pinceaux et les évènements ne sont plus générés. On se limitera donc à un seul Timer pour l’instant.

Deuxième remarque, l’implémentation du Threading.Timer ne fonctionne que sous Windows 2000 pour l’instant.

Tant qu’on y est avec les évènements, vous allez ajouter un événement à votre classe PacMan : Score_Changed. Dès que notre cher PacMan mange des bonus, son score est augmenté. Pour en avertir l’application, vous décidez de créer un événement dans sa classe. Pour la création et la génération de l’événement, rien ne change en apparence :

Public Event Score_Changed(ByVal iScore As Integer)

Public Sub Change()

RaiseEvent Score_Changed(iScore)

End Sub

Pour pouvoir s’abonner à cet événement, la classe (ici cAppli) doit d’abord en avertir le compilateur avec la ligne classique :

Private WithEvents mHero As cPacMan

En revanche, la déclaration de l’évènement change quelque peu :

Public Sub mHero_Score_Changed(ByVal iScore As System.Integer) Handles mHero.Score_Changed

Vous reprenez la définition de l’évènement et pour assurer la délégation, vous utilisez le mot clé Handles en précisant quelle fonction est gérée. Cela se passe exactement de la même façon pour capturer les évènements des contrôles dans une form :

Dim WithEvents Form1 As System.WinForms.Form

Public Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Form1.Click

End Sub

Hiérarchisons un peu le tout
Je vous ai dit au début de cet article que les classes cPacMan et cFantome héritaient d’une classe cSprite. Il est temps maintenant de s’expliquer plus avant. Si l’on considère ces deux objets graphiques, tous deux possèdent des propriétés et des méthodes qui se ressemblent étrangement. On doit dessiner un bitmap, ils ont une position X, Y tous les deux, ils se déplacent de la même façon, c’est-à-dire qu’ils évitent les murs, etc. Donc plutôt que de dupliquer le code dans ces deux classes, vous allez créer la classe cSprite qui contiendra les membres communs. Le code dans les classes qui en hériteront sera donc bien spécifique à leur nature. Pour qu’une classe hérite d’une autre (attention, contrairement au C++, les classes MS.NET ne peuvent hériter que d’une seule classe), juste après la définition de la classe, ajoutez la ligne suivante :

Public Class cPacMan
Inherits cSprite

Il y a beaucoup de membres communs si l’on se penche en détail sur le programme mais nous ne regarderons ici que quelques uns d’entres eux.

Les membres Public
Les propriétés X et Y qui représentent la case où se trouve le sprite doivent être accessibles à l’extérieur de la classe. Définissez les ainsi dans la classe cSprite :

Private mX as Integer

Public Property X() As Integer
Get
Return mX
End Get
Set
mX = Value
End Set
End Property

Comme cPacMan hérite de cSprite, vous pourrez écrire :

ObjPacMan.X = 5

Et c’est le code dans la classe parente qui sera exécutée.

C’est le cas le plus simple.

Les membres protégés
Maintenant, comment créer des membres qui sont privées à la classe mais qui peuvent être utilisées dans les classes filles. Si vous définissez une variable comme Private dans la classe cSprite, celle-ci ne sera visible que dans les objets cSprite. Pour remédier à ce problème, vous allez les déclarer comme Protected. Par exemple, pour la taille du sprite qui n’est pas visible à l’extérieur de la classe :

Protected mWidth as Integer
Protected mHeight as Integer

C’est le cas également pour la méthodes CalculPosition :

Protected Function CalculPosition() As Boolean

Ces membres, définis dans la classe cSprite sont visibles dans la classe cPacMan mais invisibles à l’extérieur de la classe.

Redéfinition d’un membre
Dans certains cas, vous allez devoir redéfinir des membres. Pour vos deux classes, vous devez à chaque appel du Timer afficher le sprite, le code est donc commun. Mais pour le PacMan, vous en profitez pour réactualiser son score et pour les fantômes, calculer leurs trajets. Il faut donc avertir le compilateur que la méthode commune (Change) doit pouvoir être redéfinissable grâce au mot clé Overridable :

Public Overridable Sub Change()

Vous redéfinnissez la procédure Change de la classe cPacMan avec le mot clé Overrides. Comme vous devez faire appel à la méthode Change de la classe parente, vous utilisez MyBase, qui fait référence à la classe parente puis vous ajoutez son code spécifique :

Public Overrides Sub Change()
MyBase.Change()
… ‘code spécifique
End Sub