Tutorial 1 - Préparation
16 pages
Français

Tutorial 1 - Préparation

-

Le téléchargement nécessite un accès à la bibliothèque YouScribe
Tout savoir sur nos offres
16 pages
Français
Le téléchargement nécessite un accès à la bibliothèque YouScribe
Tout savoir sur nos offres

Description

RPG-A en C# et SDLPartie 1-PréparationAvant-ProposVoici la première étape d'une série d'articles qui, je l'espère, nous amènera à l'élaboration et ledéveloppement des bases d'un jeu vidéo. J'ai choisi le style RPG-A, du type Zelda – A Link to thepast sur SuperNintendo. Ce choix s'est fait tout simplement, puisque cela fait déjà quelques tempsque je souhaite développer un jeu de ce genre.Au niveau des choix techniques, j'ai choisi d'utiliser le langage C# et la bibliothèque d'affichageSDL. Pour le premier, le choix a été très rapide car c'est le seul langage qui m'intéressait vraiment pourdévelopper le jeu. J'utiliserai la version 2,0 du framework, ainsi que l'éditeur de code SharpDevelopdans sa version 2.0.J'ai choisi SDL après avoir pesé le pour et le contre avec XNA. Et j'avoue que c'est un choix pardéfaut, puisque ma carte graphique n'est pas capable de lancer XNA. On attendra donc pour utiliserl'environnement de développement de jeu conçu pour le C#. Pour SDL, j'ai choisi le portageSdlDotNet dans sa version 6.0.0, qui permet d'utiliser facilement les fonctionnalités de la SDL avecun langage DotNet.N'hésitez pas à commenter et intervenir à propos de ce tutorial. Je le publie sous licence CreativeCommons CC-By-SA. Cela signifie que vous pouvez en faire (presque) ce que vous voulez, tantque vous n'oubliez pas de mentionner sa provenance, et que vous conservez cette même licence.Bon dév' !Nota Bene : ce tutorial est destiné à ceux qui connaissent ...

Informations

Publié par
Nombre de lectures 44
Langue Français

Extrait

RPG-A en C# et SDL
Partie 1 -Préparation
Avant-Propos
Voici la première étape d'une série d'articles qui, je l'espère, nous amènera à l'élaboration et le développement des bases d'un jeu vidéo. J'ai choisi le style RPG-A, du type Zelda – A Link to the past sur SuperNintendo . Ce choix s'est fait tout simplement, puisque cela fait déjà quelques temps que je souhaite développer un jeu de ce genre. Au niveau des choix techniques, j'ai choisi d'utiliser le langage C# et la bibliothèque d'affichage SDL. Pour le premier, le choix a été très rapide car c'est le seul langage qui m'intéressait vraiment pour développer le jeu. J'utiliserai la version 2,0 du framework, ainsi que l'éditeur de code SharpDevelop dans sa version 2.0. J'ai choisi SDL après avoir pesé le pour et le contre avec XNA. Et j'avoue que c'est un choix par défaut, puisque ma carte graphique n'est pas capable de lancer XNA. On attendra donc pour utiliser l'environnement de développement de jeu conçu pour le C#. Pour SDL, j'ai choisi le portage SdlDotNet dans sa version 6.0.0, qui permet d'utiliser facilement les fonctionnalités de la SDL avec un langage DotNet. N'hésitez pas à commenter et intervenir à propos de ce tutorial. Je le publie sous licence Creative Commons CC-By-SA. Cela signifie que vous pouvez en faire (presque) ce que vous voulez, tant que vous n'oubliez pas de mentionner sa provenance, et que vous conservez cette même licence. Bon dév' ! Nota Bene : ce tutorial est destiné à ceux qui connaissent les bases de la programmation en C#. Si vous découvrez ce langage, je vous invite à suivre les cours disponibles un peu partout sur Internet (Google's your friend !), ou à acheter un livre traitant de ce langage.
1 – Installation
Avant de commencer à programmer, il va falloir installer les différents outils. Ayant déjà programmé en C#, vous devriez avoir un IDE favori, que vous pourrez utiliser sans problèmes. Pour ma part, j'ai choisi SharpDevelop. Le Framework et le SDK DotNet 2.0 doivent également être installés.
Il nous reste à installer SdlDotNet. L'archive à télécharger se trouve sur le site  http://cs  -sdl.sourceforge.net/  , dans la section Downloads. Déchargez le contenu de l'archive dans un répertoire de votre choix. Mémorisez ce répertoire, car il faudra y retourner chercher quelques fichiers plus tard.
Nous sommes fins prêts pour lancer notre éditeur de code !
2 – Création du projet
Nous allons partir d'un projet Console que nous nommerons RPGA_SDL. Nous avons donc deux fichiers sources pour l'instant : Main.cs AssemblyInfo.cs Le premier nous servira à lancer le programme, le second à renseigner la version (entre autres choses). Avant de commencer à coder quoi que ce soit, ajoutons la bibliothèque SdlDotNet. Pour cela, il faut sélectionner le menu Projet / Ajouter une Référence (un clic droit sur References dans l'arbre du projet marche également). A l'aide du Browser d'Assemblies , nous allons rechercher le fichier SdlDotNet.dll qui se trouve dans le répertoire où nous avons dézippé l'archive téléchargée dans l'étape précédente, plus précisément dans le sous-répertoire bin/assemblies . Pour tester tout ça, nous allons rentrer un code simple dans la fonction Main : Surface screen = Video . SetVideoModeWindow ( 800 , 600 ); screen . Fill ( Color . Aqua ); while ( true ) screen . Update (); Cela devrait nous afficher une fenêtre SDL de résolution 800 par 600, au fond Aqua . Le code présenté devrait générer des erreurs à la compilation. En effet, nous avons oublié de spécifier les espaces de noms que nous utilisons. Avant la définition de la classe Main , ajoutez ces deux lignes : using System . Drawing ; using SdlDotNet.Graphics ; La première de ces deux lignes génère toujours une erreur, car l'espace de noms System.Drawing n'est pas disponible par défaut. Ouvrez la même fenêtre qui nous a permis de sélectionner la bibliothèque SdlDotNet précédemment. Cette fois, dans l'onglet GAC, choisissez la bibliothèque System.Drawing , et ajoutez-la. Le programme compile enfin, mais génère une exception à son exécution. C'est parce que SdlDotNet nécessite l'usage des DLL natives de la SDL. Retournez dans le répertoire bin  de SdlDotNet, et sélectionnez tous les fichiers du répertoire win32deps . Tous ces fichiers ne seront pas nécessaires, mais cela évitera d'avoir à chercher quel fichier est manquant à chaque erreur. Recopiez ces fichiers dans le répertoire bin/Debug de votre projet. Exécutez le programme ... Ca fonctionne ! Mais ce programme n'est pas vraiment viable, il ne peut d'ailleurs pas être arrêté autrement qu'en fermant la console derrière. Nous allons améliorer ça dans la partie suivante.
3 – GameStates et ScreenManager
J'ai décidé d'employer les utiles GameStates dans l'organisation du code. Cela me permettra de facilement séparer les différentes parties du jeu, rendant le code plus "propre" et plus facilement maintenable. Pour plus d'informations sur les GameStates, je vous invite à consulter cette page : http://www.games-creators.org/wiki/Gestion_des_Game_States_en_C_plus_plus  Le code présenté est du C++, et je vais légèrement adapter ce qui y est présenté. Pour commencer, nous allons avoir besoin d'une classe définissant la notion de GameState. Les différents états du jeu possèderont tous les même méthodes de base, à savoir Init() , Draw() , Update() , CleanUp()  et HandleEvents() . On pourrait faire une classe de base GameState , dont hériterait tous nos GameStates. Mais le C# n'accepte pas l'héritage multiple, et, qui plus est, nous aurons à redéfinir ces cinq méthodes dans presque chacune des classes. Pas très intéressant. Les Interfaces sont là pour ça ! Elles servent de modèles que sont obligées de suivre les classes les employant. Allons-y pour notre interface : using System ; _ namespace RPGA SDL . GameStates { public interface IGameState { void Init (); void Draw (); void Update (); void HandleEvents (); void CleanUp (); } } Vous aurez remarqué que j'ai défini cette interface dans un sous-namespace GameStates . Cela permettra de regrouper tous les éléments propres aux GameStates. Avec SharpDevelop, en créant un répertoire dans l'arbre des fichiers du projet, le namespace sera automatiquement renseigné dans les nouveaux fichiers créés.
Pour gérer ces états, il faudra ... un gestionnaire d'états ! Cet élément du programme doit être accessible en permanence, et une seule et unique instance doit être utilisée. Nous allons donc mettre en place les principes du Design Pattern Singleton à l'aide d'une classe statique. Pour notre GameStateManager (c'est ainsi que nous l'appellerons), nous allons avoir besoin de différentes fonctions comme l'initialisation, le changement d'état, l'accès aux fonctions de l'état courant, l'arrêt du programme. Pour le moment, notre gestionnaire ne gèrera qu'un seul état. Nous pourrons étoffer ce comportement plus tard. L'objet dynamique ressemble donc à ça : using System ; namespace RPGA SDL . GameStates _ { public sealed class GameStateManager { # region Objet Dynamique _ IGameState currentState ; _ IGameState nextState ; bool bRunning ; _ private GameStateManager () { _ currentState = null ; nextState = null ; _ _ bRunning = true ; } private void changeState ( IGameState newState ) { if ( currentState != null ) _ _ currentState . CleanUp (); currentState = null ; _ _ nextState = newState ; } private void checkState () { if (( _currentState != null ) || ( nextState == null )) _ return ; // Un nouvel état est utilisé currentState = nextState ; _ _ nextState = null ; _ currentState . Init (); _ } private void handleEvents () { if ( currentState != null ) _ currentState . HandleEvents (); _ } private void update () { if ( currentState != null ) _ currentState . Update (); _ }
}
}
private void draw () { _ if ( currentState != null ) _ currentState . Draw (); } private void quit () { bRunning = false ; _ _ currentState . CleanUp (); currentState = null ; _ } # endregion
En ayant lu l'article sur les GameStates, vous devriez comprendre le code précédent. J'ai néanmoins rajouté l'élément CheckState . En effet, le code de changement d'état peut théoriquement être appelé depuis n'importe quel endroit du code. S'il est appelé pendant l'étape de l' Update() , le nouveau GameState passera directement à l'étape du Draw() , ce qui peut causer quelques soucis. Le code présent ici permettra de limiter ces problèmes. Bon, tout le code de cette classe est déclaré en private , aussi n'est-il pas accessible. Nous allons donc maintenant fournir les fonctions statiques accessibles à tout le code :
# region Objet Statique private static GameStateManager instance = new GameStateManager (); public static bool Running { get { return instance . bRunning ;} _ } public static void ChangeState ( IGameState state ) { instance . changeState ( state ); } public static void CheckState () { instance . checkState (); } public static void HandleEvents () { instance . handleEvents (); } public static void Update () { instance . update (); } public static void Draw () { instance . draw (); }
public static void Quit () { instance . quit (); } # endregion Il ne s'agit ici que de fournir un accès unique aux fonctions de l'objet dynamique. Le squelette de notre programme commence à s'assembler. Il n'y a pas que le GameStateManager  qui nécessite un accès global et unique. La surface d'affichage principale, représentant l'écran, devrait être également être accessible depuis n'importe quel endroit du code. Définissons une nouvelle classe à la racine du projet, que nous nommons ScreenManager . Cette classe possèdera la même définition que notre GameStateManager , à savoir sealed . Cela signifie qu'aucune autre classe ne pourra en dériver, ce qui est ce que nous souhaitons. Dans cette classe, nous reprendrons une partie du code présenté dans la partie 2, pour obtenir ceci : using System ; using System . Drawing ; using SdlDotNet.Graphics ; namespace RPGA SDL _ { public sealed class ScreenManager { # region Objet Statique private static ScreenManager instance = new ScreenManager (); public static Surface MainScreen { get { return instance . mainScreen ;} _ } public static void Init () { instance . Init (); } # endregion # region Objet Dynamique Surface mainScreen ; _ private ScreenManager () { } private void init () { _ mainScreen = Video . SetVideoModeWindow ( 800 , } # endregion
600 ); } }
Nous en avons assez pour construire notre premier GameState, qui ne fera rien d'autre que d'afficher un fond coloré. Dans le sous-répertoire GameStates, définissez une nouvelle classe GS_ColoredBackground . Elle implémentera l'interface IgameState . Voyez cela comme un contrat à respecter. Vous devez donc définir toutes les fonctions de l'interface, même si elles restent vides. Pour l'exemple, voici le code présent dans GS ColoredBackground : _ using System ; using System . Drawing ; using SdlDotNet.Core ; using SdlDotNet.Input ; _ using RPGA SDL ; namespace RPGA SDL . GameStates _ { _ public class GS ColoredBackground : IgameState { Color bgColor ; _ public GS ColoredBackground () _ { } # region Membres de IgameState public void Init () { bgColor = Color . Azure ; _ } public void HandleEvents () { } public void Update () { } public void Draw () { ScreenManager . MainScreen . Fill ( bgColor ); _ } public void CleanUp () { ScreenManager . MainScreen . Fill ( Color . Black ); } # endregion
}
}
4 – Un programme qui tourne !
Nous avons presque terminé cette première étape. Il nous reste encore à utiliser le GameStateManager  dans notre boucle d'affichage, et à gérer la fin du programme. Dans notre boucle principale, nous opèreront successivement 4 étapes : vérification des GameStates gestion des événéments mise à jour des éléments affichage Voici à quoi donc ressembler notre boucle principale, dans le fichier Main.cs : public static void Main ( string [] args ) { // Initialisation de la zone d'affichage ScreenManager . Init (); // Chargement de l'état initial GameStateManager . ChangeState ( new GS ColoredBackground ()); _ // Boucle principale while ( GameStateManager . Running ) { GameStateManager . CheckState (); GameStateManager . HandleEvents (); GameStateManager . Update (); GameStateManager . Draw (); ScreenManager . MainScreen . Update (); } } Ca fonctionne, mais il manque tout de même de quoi terminer l'application proprement. Retournons dans notre état GS_ColoredBackground et ajoutons, dans la gestion des événements, ce petit bout de code : if (! Events . Poll ()) return ; // On quitte le programme quand on appuie sur Echap KeyboardState keyState = new KeyboardState (); if ( keyState . IsKeyPressed ( Key . Escape )) GameStateManager . Quit (); Ce code nous permet de vérifier si la touche Echap  du clavier est pressée. Si c'est le cas, on appelle la fonction Quit() du GameStateManager , qui fait que la boucle principale ne s'exécutera plus. Et voilà, votre premier programme en C# et SDL, totalement fonctionnel !
Appendice 1 Licence
Ce document est publié sous licence Creative Commons CC-By-SA, dont vous trouverez l'énoncé complet en Appendice 2. Pour informations, par le biais de cette licence : Vous êtes libres : de reproduire, distribuer et communiquer cette création au public de modifier cette création Selon les conditions suivantes : Paternité . Vous devez citer le nom de l'auteur original de la manière indiquée par l'auteur de l'oeuvre ou le titulaire des droits qui vous confère cette autorisation (mais pas d'une manière qui suggérerait qu'ils vous soutiennent ou approuvent votre utilisation de l'oeuvre). Partage des Conditions Initiales à l'Identique . Si vous modifiez, transformez ou adaptez cette création, vous n'avez le droit de distribuer la création qui en résulte que sous un contrat identique à celui-ci. A chaque réutilisation ou distribution de cette création, vous devez faire apparaître clairement au public les conditions contractuelles de sa mise à disposition. La meilleure manière de les indiquer est un lien vers cette page web. Chacune de ces conditions peut être levée si vous obtenez l'autorisation du titulaire des droits. Rien dans ce contrat ne diminue ou ne restreint le droit moral de l'auteur ou des auteurs.
Le code fourni avec ce tutorial est disponible sous licence GNU/GPL, dont vous trouverez un exemplaire dans le fichier GNU.txt fourni dans l'archive (si vous avez récupéré l'archive contenant les sources). Ce document a été publié par Gulix (alias Nicolas Ronvel) sur le site http://gulix.free.fr Dernière version publiée le 08/05/07.
  • Univers Univers
  • Ebooks Ebooks
  • Livres audio Livres audio
  • Presse Presse
  • Podcasts Podcasts
  • BD BD
  • Documents Documents