IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Blender pour le jeu vidéo


précédentsommairesuivant

VI. Description du jeu

Commençons par créer notre premier jeu. Il sera simple, épuré, sans son et peut-être pas très élaboré graphiquement, ou en tout cas pas autant que nous l'espérerions. Il sera toutefois possible de l'étoffer par la suite avec des sons, des graphismes plus riches et davantage d'interactions, mais ces points seront abordés dans les prochaines sections. Il nous semble ici plus important de présenter une première base opérationnelle, un peu comme un prototype. Dans toute production, on aura tendance à séparer ainsi les différents secteurs de travail. Cela nous permettra de nous focaliser sur les fonctions interactives de base et de bien appréhender l'utilisation du moteur temps réel.

Pour notre premier jeu, nous utiliserons les formes et fonctionnalités intégrées de Blender afin de ne pas avoir à utiliser des ressources extérieures. Vous pourrez personnaliser cela autant que vous le souhaitez. Faites attention cependant à ne pas vous noyer d'emblée dans des projets trop complexes, ce qui pourrait diminuer l'intelligibilité du projet.

VI-A. Notre histoire

Image non disponible

Notre personnage, un cube bleu, se trouve dans un espace fermé par des murs, une place orangée. Son objectif sera de parcourir cet espace pour arriver à atteindre le cube rouge. Il pourra au passage récupérer des bonus jaunes dispersés dans l'espace ce qui viendra améliorer le score. Sortir en touchant le cube rouge arrêtera notre niveau en quittant le jeu.

L'histoire est simpliste, mais reprend des principes essentiels souvent utilisés dans des jeux :

  • déplacer un personnage ;
  • interagir avec l'environnement (cogner et/ou récupérer des objets) ;
  • stocker et afficher des données (le score) ;
  • déclencher un événement (ouvrir une porte, sortir du jeu).

VI-B. Les modèles

Pour réaliser ce jeu, nous allons partir d'objets simples : cinq grands cubes orangés pour le terrain, un petit cube bleu pour notre personnage, des cylindres aplatis jaunes pour représenter les objets à récupérer, un cube rouge pour la porte. Bref, des modèles simples seulement issus des primitives de base de Blender. Si vos compétences en graphisme dépassent ce stade, n'hésitez pas à jouer dessus. Sinon vous pourrez toujours importer des modèles déjà conçus pour le Game Engine. Mais ne passez pas trop de temps sur ces aspects dans un premier temps, car ce n'est pas une priorité pour cette étape-ci.

Nous avons simplement colorisé ces objets en utilisant la couleur du panneau Diffuse dans l'onglet Material et aussi en réduisant le Specular à zéro pour supprimer des brillances superflues et finalement en ajoutant un peu d'Emit pour ne pas avoir d'ombres trop noires. Pour ce qui est des textures, nous nous en passerons pour le moment. Il vaut mieux se référer (ou attendre d'arriver) aux chapitres qui traitent en détail des spécificités de leur affichage dans le Game Engine.

VI-C. Ce que nous apprendra cet exercice

La réalisation de ce minijeu nous permettra de parcourir des fonctions fondamentales du BGE :

  • lancer le jeu ;
  • récupérer des événements clavier pour déplacer un personnage à l'aide de briques logiques ;
  • manipuler un objet texte pour afficher un score grâce à la création d'une propriété ad hoc  ;
  • gérer une collision entre des acteurs du jeu ;
  • déclencher un événement comme ouvrir une porte ou sortir du jeu.

Nous en profiterons pour utiliser autant que possible les briques logiques (logic bricks) qui sont les éléments de l'interface graphique qui permettent la programmation du jeu. Nous verrons aussi en parallèle comment de petits morceaux de code (plus précisément des scripts Python) peuvent être utilisés pour réaliser les mêmes choses.

VII. Déplacer le personnage

Pour notre jeu, nous avons créé une pièce, représentée par cinq grands cubes orangés et un petit cube bleu pour notre personnage. Une vidéo, 01a_preparation-deplacements.webm, résume le processus de fabrication de cette scène.

Lorsque notre personnage est sélectionné, nous pouvons alors passer dans l'éditeur Logic Editor pour lui attacher des actions. C'est dans leLogic Editorque nous allons lier des événements-clavier, comme le fait d'appuyer sur la flèche vers le haut pour activer le déplacement vers l'avant du personnage.

Image non disponible

VII-A. Introduction au Logic Editor

Dans le Logic Editor, il y a trois colonnes :

Image non disponible
  • la colonne de gauche, concerne les sensors, c'est-à-dire tout ce qui détecte et déclenche une action. Par exemple, le fait que le joueur appuie sur une touche du clavier, bouge la souris ou utilise une manette, mais également quand un personnage du jeu cogne un objet ou quand le scénario du jeu requière le déclenchement d'un événement ;
  • la colonne de droite, appeléeactuators, s'occupe d'activer les événements dans le jeu. Comme changer de scène, déplacer un objet, lancer une animation, modifier certaines propriétés du jeu, etc. ;
  • la colonne du milieu, lescontrollers, détermine comment lier les déclencheurs (lessensors) et les activateurs d'événements (les actuators). Par exemple, lorsque mon personnage cogne un objet (sensor), cela lance l'animation d'un personnage (actuator). Il faut donc lier une briquesensorqui détecte la collision avec une briqueactuatorqui lance l'animation via une brique controller.

VII-B. Créer les trois premières logic bricks

Nous allons donc créer notre toute première logique de jeu !

VII-B-1. Récupérer la frappe au clavier

Pour faire avancer notre personnage, nous allons d'abord créer un sensor de type clavier.

  1. Pour cela, appuyons sur le bouton Add Sensor et choisissons l'option Keyboard.
  2. Dans ce sensor nouvellement créé, il y a une option appelée Key avec un bouton vide et un bouton All Keys. Cliquons sur le bouton vide et ensuite sur la flèche vers le haut. Le bouton s'appelle maintenant Up Arrow pour bien montrer que c'est lorsque le joueur appuiera sur cette touche du clavier que le sensor sera activé.
Image non disponible

VII-B-2. Activer un déplacement d'objet

Nous ajoutons ensuite dans la colonne de droite, un actuator qui va effectivement déplacer notre personnage vers l'avant.

  1. En cliquant sur Add Actuator et en choisissant l'option Motion, nous créons cet actuator de déplacement, qui par défaut se trouve en Simple Motion, ce qui nous convient pour cet exercice.
  2. Les deux lignes suivantes représentent les valeurs en x, y et z qui seront ajoutés à la position (Loc) ou à la rotation (Rot) du personnage dans l'espace lorsque cet actuatorsera activé. En valeur dey, nous allons entrer 0.10, ce qui correspond à un déplacement d'un dixième d'unité Blender.
Image non disponible

VII-B-3. Lier frappe au clavier et déplacement d'objet

Nous allons maintenant lier l'appui sur la flèche vers le haut avec le déplacement dans l'espace. Pour cela, nous utilisons un contrôleur (controller). Les contrôleurs peuvent être de types différents, et vérifient que tout ce qui leur est envoyé en entrée (venant de la colonne de gauche) est actif avant d'activer sa sortie (tout ce qui se trouve en colonne de droite).

  1. Dans la colonne du milieu, nous cliquons sur Add Controller et choisissons l'option And.
  2. Dans notre cas, nous lions la sortie de sensorkeyboard avec ce controller And en cliquant et glissant un lien entre la sortie du sensor et l'entrée du controller à l'aide des petits points situés à droite du premier et à gauche du second. Le lien entre les deux sera ensuite représenté par une ligne liant les deux éléments (voir capture d'écran).
  3. Ensuite, nous lions, de la même manière, la sortie du controller Andavec l'entrée de l'actuator Motion.
Image non disponible

VII-B-4. Tester le déplacement dans le jeu

Nous pouvons maintenant vérifier que notre personnage avance bien comme on le désire en lançant une prévisualisation du jeu. Pour cela, déplacez le curseur de la souris au-dessus de la vue 3D et appuyez sur P pour lancer le Game Engine. La souris va disparaître et la fenêtre changer de couleur, signe que le Game Engine a démarré. Appuyons maintenant sur flèche vers le haut et vérifions que le personnage avance bien. Échap permet de sortir du jeu.

Image non disponible

VII-B-5. Résoudre les problèmes

Lorsque nous avons lancé le jeu et appuyé sur la flèche du haut, il se pourrait que rien ne se produise. Nous pouvons alors nous placer dans une logique de recherche d'erreur sur différents niveaux.

  • Dans un premier temps, vérifions que c'est bien Up Arrow qui est enregistrée dans le sensorkeyboard.
  • Si le réglage précédent est bon, nous pouvons tester une autre touche du clavier en reconfigurant ce sensor pour tester uniquement la validité de la touche.
  • Vérifions également que nos différents sensors, controllers et actuators sont liés correctement.

Il s'agit d'évaluer à chaque fois les éléments qui ne vont pas et de trouver tout ce qui intervient éventuellement dans le dysfonctionnement et d'évaluer leur validité, un par un, pour les éliminer jusqu'à trouver le bon.

Il est possible aussi que notre personnage ne se soit pas déplacé vers l'avant, mais qu'il avançait de côté, ou même reculait. Peut-être qu'il avançait beaucoup trop vite ou alors très lentement. Retournons voir les paramètres de Loc de l'Actuator Motion. Si notre personnage n'avançait pas, mais reculait, c'est qu'il faut changer le signe de notre valeur en y et placer -0.10. S'il avançait trop lentement, il faut encore augmenter cette valeur à 0.5 par exemple. S'il avançait de côté, il faut plutôt changer les valeurs de position en x ou celles en z. Retenons, que par défaut, ces changements de position se font par rapport aux coordonnées locales de l'objet auquel ils s'appliquent (lorsque le bouton L, à droite est coché).

Image non disponible

VII-C. Ajouter d'autres directions de déplacement

À cette étape, notre personnage va dans une seule direction. Bien que cela puisse être déjà un jeu amusant en soi, nous serons vite tentés d'ajouter d'autres degrés de liberté de mouvement, comme la possibilité de reculer, tourner à gauche, tourner à droite, courir, voler, etc. En bref, tout ce que nous avons défini dans la phase de conception du jeu (game design).

VII-C-1. Faire reculer le personnage

Nous devons ajouter un nouveau sensor qui va récupérer l'événement quand le joueur appuiera sur flèche vers le bas du clavier. Nous devons créer un nouvel actuator Motion qui appliquera un déplacement négatif en y à notre objet, par exemple -0.10. Et nous devons créer un controller And qui liera cet événement clavier avec le déplacement de l'objet vers l'arrière.

Image non disponible

VII-C-2. Organiser le Logic Editor

Nous sentons bien que lorsque nous allons ajouter de multiples briques logiques pour gérer les différentes façons de déplacer notre personnage, nous allons vite avoir un grand nombre d'éléments. Il va falloir organiser. C'est pourquoi il est important de nommer les briques de manière claire et descriptive. Nommer nos sensors, actuators et controllers nous sera bien utile lorsque nous commencerons à utiliser des scripts Python afin de les identifier et de récupérer leurs paramètres au sein de notre code.

En cliquant sur le champ textuel à côté de la liste décrivant le type de sensor en haut de la brique, renommons en haut le sensor Keyboard qui récupère la touche clavier flèche vers le haut . Renommons en avant l'actuator Motion qui fait avancer le personnage, et ainsi de suite pour les autres : en bas et en arriere.

En cliquant sur la petite flèche située à gauche dans l'entête de la brique, il est possible de la réduire pour qu'elle occupe moins d'espace et ainsi avoir un meilleur aperçu global.

Image non disponible

Une fois réduites, seules les briques qui ont été renommées sont compréhensibles, comme le montre cette capture d'écran de comparaison. Renommer un controller And n'a pas d'importance pour l'instant. Mais il sera impératif de le faire pour des cas plus complexes où l'entrée du And sera reliée à plusieurs sensors.

VII-C-3. Faire tourner le personnage

Nous sommes maintenant capable d'ajouter deux nouveaux sensors Keyboard pour récupérer les frappes sur flèche gauche et flèche droite du clavier et les lier via des controllers aux actuators Motion qui feront tourner l'objet dans un sens ou dans l'autre. Introduisons une valeur de 0.20° en z dans la ligne Rot pour faire tourner notre objet à gauche ou -0.20° en z pour faire tourner notre objet à droite.

Notre conseil est de tester à nouveau les ajouts, et cela aussi souvent que possible, en particulier tant que vous n'êtes pas encore très expérimentés. Cela permet de détecter les erreurs au plus vite et de faciliter la recherche en cas de problème, ainsi que de tester le jeu, ce qui reste un élément essentiel.

Image non disponible

VII-D. Scrypthon !

Nous allons aborder ici très simplement comment déplacer le personnage, mais cette fois-ci en utilisant un script Python. Il s'agit de notre première utilisation du Python. Coder dans ce cas n'est pas nécessaire, mais cela permet d'offrir d'autres voies d'explorations et d'interaction.

VII-D-1. Python ou briques logiques

De manière générale, toutes leslogic bricks(briques logiques) peuvent être remplacées par des scripts Python, mais l'inverse n'est pas nécessairement vrai. Les scripts permettent, avec le temps et les connaissances nécessaires, de créer des fonctions de jeu beaucoup plus complexes. Il est donc important de se familiariser très tôt avec leur fonctionnement.

Néanmoins, les scripts Python ont au moins toujours besoin de deux briques logiques pour fonctionner. Un sensor, qui déterminera quand activer le script Python et un controllerde type Python qui détermine quel script est à activer à cet instant-là. D'autres sensors et actuators peuvent être présents et l'on peut combiner l'utilisation de scripts et delogic bricksdans tout projet, sans restriction. Ce n'est pas parce qu'on décide d'utiliser des scripts Python pour telle ou telle fonction que l'on doit à partir de ce moment-là, tout coder en Python.

Image non disponible

VII-D-2. Créer un script Python

Dans le Text Editor, créons un nouveau texte que nous appelons avancer.py. L'extension « .py » est communément celle des fichiers textes qui représentent du code Python. Pour les fichiers textes inclus dans le .blend, il n'est pas nécessaire d'ajouter une extension, mais, de manière générale, c'est une bonne pratique. Comme ça, sans ouvrir le fichier, nous avons une idée de ce qu'il contient.

VII-D-3. Charger un module

La première ligne que nous devons (et devrons) toujours écrire, c'est celle qui détermine quel module Python nous devons importer. Il existe beaucoup de modules Python différents. Chaque module regroupe une collection de fonctions et méthodes particulières, regroupées autour d'un sujet. Le module render, par exemple, regroupe toutes les méthodes liées au rendu du jeu.

Pour faire avancer notre personnage, nous devons importer le module logic. Ce module contient entre autres les fonctions nécessaires pour manipuler des objets dans le Game Engine. Voici comment cela s'écrit en Python :

 
Sélectionnez
from bge import logic

VII-D-4. Récupérer le controller

Le script Python ne « sait » pas qui ou quoi l'active. Pour cela, il existe une méthode qui permet de récupérer le controller qui l'a lancé. Nous la stockons dans une variable nommée cont.

 
Sélectionnez
cont = logic.getCurrentController()

VII-D-5. Appliquer le déplacement

Une fois que nous avons notre controller. Nous pouvons savoir quel est l'objet auquel il est attaché, ou, en d'autres termes, quel est son propriétaire. Dans ce cas-ci, comme nos logic bricks sont attachées à notre objet personnage, c'est bien lui que nous récupérons.

 
Sélectionnez
personnage = cont.owner

Nous pouvons donc lui appliquer un déplacement de 0.10 en coordonnée locale y, comme nous le faisions avec le premier actuator de notre exemple.

 
Sélectionnez
personnage.localPosition.y += 0.10

En pratique, ce que nous faisons ici, c'est ajouter 0.10 à la coordonnée y de notre objet.

VII-D-6. Activer le script à chaque frappe du clavier

Voici notre script complet :

 
Sélectionnez
from bge import logic 
# Recuperer le controller qui active le script 
cont = logic.getCurrentController() 
# Récupérer l'objet attache personnage = cont.owner 
# Déplacer l'objet vers l'avant 
personnage.localPosition.y += 0.1

Il doit bien porter le nom « avancer.py » dans le Text Editor.

Dans le Logic Editor, nous avons aussi un sensor Keyboard configuré pour répondre lorsque l'on presse la touche flèche vers le haut et ce sensor est relié à un controller Python.

Dans notre controller Python, devant le menu déroulant qui affiche par défaut Script, cliquons dans la boîte vide et nous voyons une liste des scripts et autres textes disponibles dans notre projet Blender. Choisissons « avancer.py ».

Image non disponible

En lançant maintenant le jeu (P), s'il n'y a pas de faute de frappe et que tout est lié correctement, le personnage devrait faire un microdéplacement vers l'avant à chaque appui sur la touche flèche vers le haut.

VII-E. Des améliorations progressives

Tout travail sur des mécaniques de jeu (que ce soit des jeux vidéo ou d'autres genres de jeux comme des jeux de société) demande de longues heures de tests et d'essais. Nous ne trouverons peut-être pas tout de suite les bonnes valeurs de rotation ou de déplacement. L'ajout de fonctions et de paramètres d'un côté ou d'un autre du jeu demande souvent de revoir des choses définies plus tôt. Un jeu est un assemblage subtil de règles et de paramètres pour trouver un équilibre agréable ou parfois même juste utilisable. Il est donc recommandé, après chaque changement de paramètre ou ajout de fonction de tester son jeu. Vous gardez ainsi le fil, en comprenant plus facilement quelle option a cassé ce qui marchait avant ou de comprendre comment tel paramètre influe sur la jouabilité du projet.

VIII. Collisions

Un espace 3D virtuel est constitué de points, lignes et surfaces qui n'ont pas d'existence physique. Des surfaces peuvent donc s'interpénétrer sans autre conséquence, et notre univers 3D peut sembler être, sur ce point, passablement irréel, fantomatique.

Pour permettre l'interaction entre les éléments du jeu, le moteur de physique intégré de Blender (Bullet*) est utilisé. Il permet de prendre en compte les volumes et surfaces des objets pour déclencher des événements lorsque ceux-ci entrent en collision (virtuelle), en s'interpénétrant.

La détection de collision se fait par le sensor Collision, très simple d'utilisation. Par défaut, toute collision le déclenchera, mais l'option property permet de filtrer quels objets déclencheront le sensor en se limitant seulement à ceux possédant une propriété du nom choisi (le type de la propriété n'a pas d'importance). Le bouton M/P permet de filtrer les objets collisionnant selon un matériau donné plutôt qu'une propriété. Si un objet possède plusieurs matériaux, il suffit alors qu'il apparaisse au moins une fois sur l'objet pour qu'il réagisse.

Image non disponible

Il est aussi possible de gérer les objets qui collisionnent avec des groupes de collision tels que décrits dans la section Comportement des objets et personnages au chapitre intitulé Comportement des objets de notre monde.

Nous en profiterons pour introduire un nouvel actuator, Edit Object. Il permet d'effectuer différentes actions sur l'objet : le détruire, ajouter un nouvel objet, etc. et sera extrêmement utile dans les jeux.

Image non disponible

Améliorons notre jeu en ajoutant une fonctionnalité très simple : le joueur doit ramasser des bonus, que nous représenterons par des cylindres aplatis jaunes. Nous allons devoir détecter la collision entre le bonus et le joueur, et faire disparaître le bonus.

Image non disponible

Sélectionnons notre objet joueur et dans le Logic Editor, cliquons sur Add Game Property. Nous détaillerons son utilisation dans le chapitre Compter et afficher le score. Pour le moment elle sert simplement d'étiquette pour l'actuator Collision : préoccupons-nous donc simplement de lui donner le nom player (joueur).

Image non disponible

Dans le Logic Editor ajoutons cette configuration de Logic Brick sur nos objets bonus :

  1. Un sensor de type Collision, avec dans le champ Property, la valeur qui identifie le joueur (player) ;
  2. Lié à un controller And ;
  3. Lié à un actuator de type Edit Object, réglé via sa liste déroulante pour être en mode End Object.
Image non disponible

Pour aller vite, faisons l'opération sur un objet, sélectionnons tous les bonus et utilisons le menu Object > Game > Copy Logic Bricks pour recopier les briques existantes sur tous les objets sélectionnés.

En appuyant sur Pet en déplaçant le joueur sur le bonus, nous constatons que ça ne fonctionne pas. C'est normal, la détection des collisions étant une fonction coûteuse en ressource, elle n'est pas activée par défaut, par souci d'optimisation. Cette option est à activer uniquement quand cela est nécessaire.

Image non disponible

Sélectionnons notre objet joueur et rendons-nous dans l'onglet Physics et son panneau Physics. Assurez-vous de bien avoir sélectionné le mode Blender Game sinon le panneau Physics n'affichera pas les mêmes options que dans la copie d'écran ci-dessous. Dans Physic Type, sélectionnons Character, qui convient très bien pour un personnage. Cette fois, en appuyant sur P, le joueur est capable de ramasser le bonus !
On remarquera également quelque chose d'important, le joueur est à présent soumis à la gravité (il tombe) et aux collisions avec les objets statiques (il ne passe pas à travers le sol et les murs de la salle).

Image non disponible

À l'inverse des murs, les bonus ne doivent pas empêcher le joueur d'avancer. Néanmoins, ils doivent être capables de détecter les collisions (pour déclencher une action). Il existe un type de physique dédié à ce cas, le type Sensor.

Sélectionnons donc nos objets bonus un à un et dans le panneau Physics, et dans Physics Type, choisissons Sensor.

Image non disponible

À présent, le bonus disparaît bien lorsque le joueur le touche ! C'est un bon début, mais un tel bonus n'est pas franchement motivant. Dans le chapitre suivant, nous verrons comment récompenser le joueur en ajoutant des points à son score.

Image non disponible

VIII-A. Scrypthon !

Il est parfois plus utile et plus facile de mettre en place du Python pour remplacer un controller ou un actuator. Il peut par contre être intéressant d'avoir un sensor simple en brique logique auquel on ajoutera un controller Python qui fera des traitements plus fins que ce qu'aurait pu faire un sensor seul .

Voici un exemple de code qui fonctionne ainsi. Pour le tester, vous pouvez créer un controller Python que vous pourrez accrocher au sensor Collision de l'objet bonus.

 
Sélectionnez
from bge import logic

# Récupère le controller
cont = logic.getCurrentController()

# Récupère le premier sensor attache au controller
sensor = cont.sensors[0]
 
# Si le Player se trouve dans la liste des objets entrés en collision
if "Player" in [obj.name for obj in sensor.hitObjectList]:
    # Destruction de l'objet bonus
    cont.owner.endObject()

Nous commençons par importer le module logic du Blender Game Engine. Nous récupérons ensuite le controller Python courant que nous plaçons dans une variable cont. Tous les controllers permettent de récupérer la liste des sensors qui leur sont rattachés grâce à leur attribut sensors.

 
Sélectionnez
sensor = cont.sensors[0]

Par cette commande, nous récupérons le premier sensor, dans notre cas le seul des sensors, celui qui détecte les collisions.

La condition qui suit est un peu plus technique au niveau Python.

 
Sélectionnez
if "Player" in [obj.name for obj in sensor.hitObjectList]:
    co.owner.endObject()

Nous parcourons la totalité des éléments de sensor.hitObjectList. Cette liste contient tous les éléments qui sont en collision avec l'objet auquel est rattaché le sensor. À partir de cette liste, nous construisons une liste ne contenant que les noms des objets (les noms étant stockés dans l'attribut name des objets). Nous testons ensuite grâce au mot-clé in si un des objets a pour nom Player. Si c'est le cas, nous effectuerons alors le code qui se trouve dans le if, à savoir, lancer la fonction endObject() de l'objet auquel est attaché le sensor Collison. C'est-à-dire que nous allons le faire disparaître.

L'utilisation des Lists Comprehension (compréhension de liste) est à la fois courante et recommandée en Python. Si vous n'avez pas l'habitude de les utiliser, voici une version plus explicite.

 
Sélectionnez
# Nous créons une variable temporaire
del_object = False

# Nous bouclons sur la liste des objets en collision
for obj in sensor.hitObjectList:
    # Si un objet porte le nom Player
    if obj.name == "Player" :
        # La variable temporaire est changée
        del_object = True
        # Et on peut quitter la boucle
        break

# Si la variable temporaire a été changée
if del_object:
    # Destruction de l'objet bonus
    cont.owner.endObject()

VIII-A-1. Gestion des listes, les spécificités de Blender

Un bon nombre des listes d'objets, que va vous fournir Blender, ne sont pas des listes classiques Python. Ce sont des listes, mais légèrement modifiées par Blender. On les appelle des CListValue. On peut, avec une CListValue, récupérer un objet par son index (liste_test[0]), mais aussi en utilisant son nom(list_test["Player"]). En utilisant cette spécificité Blender, notre code d'exemple devient beaucoup plus court.

 
Sélectionnez
from bge import logic 
cont = logic.getCurrentController() 
sensor = cont.sensors[0] 
if "Player" in sensor.hitObjectList:
     cont.owner.endObject()

IX. Compter et afficher le score

Que serait un jeu sans les systèmes de comptage ou les scores ? Il s'agit là d'éléments importants dans les mécaniques de jeu, le joueur pouvant même décider de jouer en valorisant plus tel ou tel aspect. Globalement, l'affichage d'informations textuelles sur l'écran sera essentiel, et le cas échéant, ces informations devront être calculées. Dans ce chapitre nous verrons comment ajouter un score à notre jeu et l'afficher.

IX-A. Créer un objet texte pour stocker et afficher le score

Nous allons commencer par créer un objet de type Text, qui servira à la fois à stocker la valeur du score et à l'afficher à l'écran.

Dans la vue 3D, créons un objet de type Text (Maj + A > Text). Dans les propriétés de l'objet en bas à gauche, cochons Align to View.

Image non disponible

Nommons l'objet score (dans l'onglet Object). N'oublions pas de le placer dans une zone visible par la caméra, et de lui donner les dimensions de notre choix.

Pour l'instant, le texte est statique, il ne pourra jamais afficher autre chose que 0. Nous allons le rendre accessible depuis le BGE.

Vérifions que l'objet texte est bien sélectionné et, dans le Logic Editor, cliquons sur le champ Add Text Game Property. Notre score sera un nombre entier, choisissons Integer à la place de String.Lorsque nous déclenchons le jeu, le texte change pour 0 quand on lance le jeu avec P.

Image non disponible

Les Propertiespermettent de stocker différents types d'informations que vous pourrez manipuler plus tard dans votre jeu. (Quel est le score du joueur ? Quel est son nom ? etc.). À ce titre, elles ressemblent beaucoup à des variables existant dans de nombreux langages de programmation. Elles peuvent être de différents types :

  • Boolean : Vrai ou Faux (par exemple le joueur est-il actif (Vrai) ou inactif (Faux) ?) ;
  • Integer: un nombre entier (par exemple quel est le score ? 1000.) ;
  • Float: un nombre à virgule (par exemple combien lui reste-t-il de vie ? 8,5.) ;
  • String: une chaîne de caractères (par exemple quel est le nom du joueur ? Suzanne.) ;
  • Timer: un compteur de temps (par exemple depuis quand la partie a commencé ? 10 secondes.).

IX-B. Augmenter le score lorsque le joueur ramasse un bonus

Dans le chapitre précédent, nous avons vu comment détecter une collision entre le joueur et un bonus. Cette collision déclenche la disparition du bonus. Nous aimerions qu'elle déclenche également l'augmentation du score.

  1. Ajoutons à l'objet score un actuator de type Property, associé à la property Text.
  2. Sélectionnons à la fois notre objet Score et notre objet Bonus en maintenant enfoncée la touche Maj durant la sélection.
  3. Dans le Logic Editor, nous voyons à présent à la fois les briques appartenant aux deux objets, nous pouvons donc relier le controller And (déclenché par la collision détectée par Bonus), à l'actuator Property de l'objet Score.
    Image non disponible

    L'actuator Property permet d'agir sur la valeur de Text :

    • Assign lui assigne une valeur fixée ;
    • Add lui ajoute une valeur (un nombre négatif peut également être ajouté afin d'opérer une soustraction) ;
    • Copy copie la valeur d'une autre property ;
    • Switch la bascule, dans le cas d'une valeur booléenne (comme un interrupteur : on et off, Vrai et Faux, 0 et 1).
  4. Dans notre cas, nous voulons ajouter des points au score, donc choisissons Add, et pourValue, le nombre de points que nous souhaitons attribuer au joueur pour cette réussite.

À présent, lorsque le personnage ramasse le bonus, le score est bien augmenté ! Il est maintenant aisé de dupliquer le bonus paramétré à l'aide de la combinaison de touche Maj+D afin d'en proposer plusieurs dans la même scène.

Image non disponible

Sur cette image, notre cube personnage a fait disparaître trois bonus placés sur sa course. Le score est passé à 600 points, soit trois fois 200 points par bonus.

Lorsque vos projets deviendront plus complexes, utiliser le menu Object et le sous-menu Gamevous permettra de copier facilement briques logiques et propriétés de l'objet actif à des objets d'aspect différent.

Image non disponible

IX-C. Scrypthon !

Agir sur le texte sera une action courante dans le jeu. Les objets de type texte (KX_FontObject) ont un attribut text (qui correspond à leur Game Property Text). Il est possible d'utiliser cet attribut pour modifier à la volée ses valeurs sous la forme owner.text (ou owner["Text"]).

 
Sélectionnez
from bge import logic 
cont = logic.getCurrentController() 
own = cont.owner own.text = "10"

Remarquez que même si la propriété est définie comme Integer, il faudra respecter le fait que Python gère la valeur comme une chaîne et faire les conversions qui s'imposent.

 
Sélectionnez
from bge import logic cont = logic.getCurrentController() own = cont.owner own.text = str(int(own.text)+10)

IX-C-1. Comment accéder à des Game Property en Python ?

Nous pourrions tout d'abord vouloir changer la valeur d'une Game Property, voici un exemple de code pour le faire :

 
Sélectionnez
from bge import logic 
cont = logic.getCurrentController() 
own = cont.owner
own["Text"] = "Hello World!"

Nous pourrions aussi vouloir récupérer la valeur d'une Game Property. Dans ce cas-là, une façon évidente de faire est d'utiliser la même syntaxe.

 
Sélectionnez
from bge import logic 
cont = logic.getCurrentController() 
own = cont.owner

# Affiche en console la valeur de la property "Text" 
print(own["Text"])

Cette manière de faire fonctionne parfaitement sauf dans un cas, celui où la Game Property n'existe pas. Dans ce cas-là, Python va nous renvoyer une erreur sous la forme d'une exception de type KeyError. Dans le cas où vous n'êtes pas sûr de l'existence de votre Game Property, il faut donc utiliser la fonction get() qui permet en plus de définir une valeur à renvoyer si justement la Game Property n'existe pas.

Notre code devient alors : 

 
Sélectionnez
from bge import logic 
cont = logic.getCurrentController() 
own = cont.owner
print(own.get("Text", "Sans Game Property"))

Le print affichera soit la valeur de la Game Property appelée « Text », soit « Sans Game Property ».

X. Quitter le jeu

Une fois notre objectif atteint (ou l'envie de faire une pause) nous voulons pouvoir quitter le jeu.

Image non disponible

Dans le cadre de notre minijeu, nous voulons que notre personnage quitte le jeu après avoir atteint la porte. L'objet porte est pour l'instant un simple cube rouge. Pour procéder au paramétrage de cette porte, nous allons, comme vu dans le chapitre précédent, le gérer par une simple collision. Seul l'événement de fin changera pour terminer la partie.

Sélectionnons notre cube rouge renommé « Porte » et ajoutons-lui les Logic Brick suivantes :

  • le Sensor de type Collision ;
  • le Controller de type And ;
  • l' Actuator de type Game, paramétré pour exécuter un Quit Game.

Il ne faudra pas oublier de changer le Physics Type de l'objet pour Sensor.

Image non disponible

Voilà, nous avons notre fin du jeu ! Le procédé est similaire pour le cas où la fin du jeu serait déclenchée par une collision avec un ennemi. On peut également proposer de relancer le jeu en changeant l'actuator Game en lui mettant l'option Restart Game.

X-A. Quitter à l'aide d'une touche de clavier

Par défaut, la touche permettant de quitter est Échap. Mais si  par exemple, nous préférons afficher un menu de pause plutôt que de quitter le jeu abruptement avec cette touche, pour sortir du jeu à tout moment, nous pouvons redéfinir une autre touche (comme F12) en changeant la valeur Exit Key dans Properties > Render > System.

Image non disponible

Maintenant que nous avons redéfini la touche par défaut, nous allons assigner une nouvelle touche via les Logic Brick.

  1. Nous allons donc commencer par ajouter une brique Sensor de type Keyboard qui sera la touche à actionner pour quitter le jeu.
  2. Relions cette brique à une brique Controller de type And qui sera elle-même branchée sur une brique Actuator de type Game.
  3. Ensuite, il nous reste juste à changer l'action à effectuer dans la brique Game pour mettre Quit Game.

Cet actuator pourrait également lancer une scène plutôt que de quitter, par exemple pour afficher un menu de pause. Ceci sera discuté dans le chapitre Créer un Menu dans la section Développer l'ergonomie.

Image non disponible

X-B. Scrypthon!

Il nous suffit de faire appel au code suivant avec unebrique Controller de type Python :

 
Sélectionnez
from bge import logic 
logic.endGame()
Image non disponible

Nous avons juste un petit morceau de code, mais nous pouvons aller bien plus loin en gérant avec Python l'événement qui fera quitter le jeu.

 
Sélectionnez
from bge import logic, events 
# On récupère l'objet qui lance le script
cont = logic.getCurrentController() own = cont.owner

# On assigne les événements du clavier à une variable kboard = logic.keyboard.events 
# Si la touche echap est appuyee if kboard[events.ESCKEY] == logic.KX_INPUT_JUST_ACTIVATED :
 # Quitter le jeu logic.endGame()
 # Si le score est de minimum 5 if own['score'] >= 5 :
 # Quitter le jeu logic.endGame()

Il ne nous reste plus qu'à remplacer la brique sensor qui lançait le script par une brique sensor Alwayspour laquelle on enclenche le Pulse mode (bouton « … » de gauche) afin que le script soit exécuté en permanence.

Image non disponible

Le Pulse mode sert à envoyer un signal à chaque image (frame) pour que le script soit toujours exécuté.

XI. Remplacer les primitives par des ressources

Dans le chapitre précédent, nous avons obtenu un jeu fonctionnel, mais il faut reconnaître qu'il n'est pas très joli. La prochaine étape sera donc de remplacer nos objets temporaires, par des objets que nous aurons modélisés et texturés, ou téléchargés sur un site de ressources libres, comme BlendSwap.com ou OpenGameArt.org. Attention de bien choisir des objets adaptés au temps réel (voir la section précédente, chapitre Spécificités du Game Engine).

Il est conseillé de créer chaque objet dans un fichier .blend distinct, ainsi il sera facile de se constituer progressivement une bibliothèque d'objets (on les appelle souvent assets), réutilisable dans de futurs projets.

Pour ce chapitre, nous pourrons utiliser les ressources qui sont associées à ce manuel.

Selon le type d'objet et ses conditions d'utilisation, différentes techniques s'offrent à nous, chacune ayant ses avantages et inconvénients.

XI-A. Remplacement manuel du mesh(maillage)

C'est sans doute la méthode la plus simple et la plus rapide. Elle conviendra parfaitement pour des objets simples, comme des éléments de décor. Ici, nous allons remplacer la sphère qui figure un bonus, par un asset représentant un bambou.

Commençons par importer le mesh de l'asset dans notre fichier blend : File > Append > bambou.blend > Mesh > Bambou.

Sélectionnons l'objet Bonus et rendons-nous dans le panneau Mesh.

Image non disponible

Il suffit de remplacer le nom de notre mesh temporaire (Cylinder), par le nom du mesh de notre asset (bamboo). Nommer correctement ses meshs et ses objets est évidemment indispensable !

Notre Mesh importé va hériter de la taille et de la rotation de notre objet précédent, ce qui a de fortes chances de le déformer.

Image non disponible

Nous changerons donc pour chaque élément les propriétés de tailles et de rotations des objets pour les adapter à notre scène via le panneau des propriétés de la vue 3D (touche N).

Nous pourrions aussi appliquer les transformations réalisées sur le maillage de base avant de le remplacer. Pour cela, nous utiliserions Ctrl + A puis choisirions l'option à appliquer.

Image non disponible

Dans le jeu, nos bonus ont à présent l'apparence de bambous.

Image non disponible

XI-A-1. Faites des économies d'échelle!

En temps réel, la gestion des ressources est cruciale : elle fait la différence entre un jeu fluide et un jeu saccadé (ou même entre un jeu qui fonctionne, et un jeu qui plante au démarrage).

Il est important de comprendre que si deux objets partagent le même mesh (maillage), ce dernier ne sera chargé qu'une seule fois en mémoire. Il est donc très avantageux de réutiliser autant que possible les mêmes mesh. Ce principe fondamental s'applique également pour les textures, les sons, etc.

XI-B. Parenter une ressource

Lorsque l'asset est plus complexe (typiquement, un groupe composé de plusieurs objets, comprenant des animations, etc.), la première méthode ne sera pas suffisante. Par contre, on peut attacher (parenter) notre asset à notre objet basique et masquer ce dernier. Ici, nous allons « remplacer » le cube représentant le joueur, par un asset plus sympathique.

Importons le Group contenant notre asset : File > Append >(...)voiture.blend > Group > Bambou.

Positionnons-le de manière à ce qu'il s'inscrive dans notre cube, puis parentons-le (sélectionner le groupe, puis le cube, CTRL + P > Set parent to Object).

Image non disponible

Nous avons toujours besoin de notre cube (il contient les briques logiques et gère les collisions), mais nous ne souhaitons pas le voir s'afficher : dans l'onglet Physics, cochons Invisible.
À l'inverse, nous souhaitons voir l'asset, mais nous ne souhaitons pas qu'il gère les collisions : on vérifiera donc que No Collision est bien coché dans le panneau Physics de chaque objet du groupe.

XI-B-1. Gestion des ressources

Pour des projets plus complexes, on préférera lier les assets plutôt que les importer (utiliser Link plutôt que Append). Ainsi, une modification de l'asset sera automatiquement répercutée à l'ensemble du projet. Cela facilite également le travail en équipe. Dans ce cas, il convient de placer les assets dans un sous-dossier de votre projet, et d'utiliser des chemins relatifs, comme pour un projet Blender classique.

Image non disponible

XI-C. Remplacement dynamique avec la brique logique Replace Mesh

Parfois, il est utile de remplacer dynamiquement un asset au cours du jeu ; par exemple, une caisse en bois sera remplacée par des débris si le joueur la percute.

  1. Importons les deux objets représentant la caisse et les débris : File> Append > (...)caisse.blend > Object > Caisse Debris .
  2.  La caisse a besoin de pouvoir détecter les collisions, nous allons donc lui donner une physique simple : dans l'onglet Physics > Physic Type, sélectionnons Dynamics.
  3. La partie logique sera très simple également, avec trois briques logiques :

    1. Un sensor Collision, qui détecte la property Player (vérifier que notre objet joueur possède bien cette property) ;
    2. Lié à un controller And;
    3. Lié à un actuator Edit Object .
  4. L'actuator Edit Object permet différentes actions, ici c'est Replace Meshqui nous intéresse. Dans le champ Mesh, entrons le nom du meshqui représente les débris :Debris.
  5. L'objet qui contient le mesh Debris doit exister dans notre scène pour que le Replace Mesh fonctionne. Néanmoins, on ne souhaite pas qu'il soit réellement présent au début du jeu. Il suffit de le déplacer dans un calque inactif.
  6. Lançons le jeu et dirigeons le joueur vers la caisse : elle se brise en morceaux.
Image non disponible

L'effet mériterait bien entendu d'être amélioré, par exemple en projetant quelques débris (section Comportement des objets et personnages au chapitre Génération d'objets) qui rebondiront dans le décor et en agissant sur le joueur (section Comportement des objets et personnages chapitre Comportement des objets dans notre monde).

XII. Partager son jeu

Une fois le projet finalisé, nous souhaitons le partager. Blender permet d'exporter les scènes de manière à les lire sans lancer Blender. Le logiciel Blenderplayer permet de lire les fichiers .blend comme des séquences interactives autonomes afin de les distribuer.

XII-A. Configuration de l'affichage du jeu

Blender permet depuis l'interface de tester le comportement du jeu. Dans le panneau Render, lorsqu'on est en mode Game Engine, les onglets Embedded Player et Standalone Playerapparaissent. Ils permettent de tester le jeu en le lançant dans l'interface de Blender pour Embedded Player ou dans une fenêtre séparée avec Standalone Player.

Image non disponible

Les paramètres de cette fenêtre permettent de configurer le jeu pour son export :

  • Resolution : permet d'adapter la taille de l'image du jeu ;
  • Fullscreen : lance le jeu en plein écran. Lorsque cette case est cochée, l'option Desktop devient disponible. Si cette option est cochée, le jeu sera lancé dans la résolution actuelle de l'écran, outrepassant le réglage Resolution ;
  • Quality : AA Samples : permet de configurer l'anticrénelage. Par contre, il faut faire attention, car cette option nécessite plus de ressources graphiques ;
  • Bit Depth : règle le nombre de couleurs. Généralement, on garde 32 bits pour une qualité des couleurs idéale sur les machines actuelles ;
  • Refresh Rate : nombre maximum d'images par seconde. La plupart des écrans d'ordinateur actuels fonctionnent à 60 Hz, qui est l'option par défaut.
Image non disponible

L'onglet Stereo : permet de faire un rendu stéréoscopique (3D) suivant plusieurs procédés (par lunettes teintées,côte à côte ) ou d'activer le rendu anamorphique en Dome, permettant de projeter l'image sur un dôme (ex. planétarium) ou éventuellement d'autres géométries…

L'onglet Shading :

  • l'option Multitexture permet de faire un rendu simplifié, adapté à des cartes graphiques ne supportant pas OpenGL 2.0, par exemple anciennes ou dédiées aux SOC* (systèmes embarqués), comme les smartphones et les tablettes ;
    Le BGE ne permet pas actuellement d'exporter directement pour les plateformes ne supportant qu'OpenGLES 2.0 comme Android ou iOS. Par contre, on peut tout à fait utiliser Blender et le BGE pour concevoir des ressources exportables vers des moteurs dédiés à ces plateformes.
  • l'option GLSL active le rendu OpenGL2.0 avec les effets de texture et de lumière avancés, permettant un rendu optimal, mais nécessitant un matériel plus récent.
    Image non disponible

L'onglet System :Use Frame Rate, utilise la fréquence de rafraichissement actuellement utilisée par l'écran ;

  • Restrict Animation Update : contraint le rafraichissement des animations à la fréquence de rafraichissement de l'écran. Cette option permet d'optimiser certaines performances en réduisant le calcul des animations, mais peut provoquer des incohérences dans certains mouvements rapides ou complexes ;
  • Use Material Caching : option d'optimisation permettant de minimiser les lectures disque des textures ;
  • Vsync: synchronise le rendu au rafraichissement de l'écran (l'option Adaptive est recommandée si vous ne connaissez pas) ;
  • Storage Mode : option d'optimisation graphique. Le mode par défaut (auto select) n'est à changer qu'en cas de problème ;
  • Exit key : définition de la touche permettant de sortir du jeu.
Image non disponible

L'onglet Display concerne le rendu dans l'interface d'édition, et ses paramètres n'ont pas d'influence lors de l'export d'un jeu en dehors du paramètre Animation Frame Rate que nous aborderons dans la section Comportement des objets et personnages dans le chapitre Animer des personnages dans le Game Engine. Cet onglet comporte donc des options de débogage, permettant de visualiser les paramètres internes du jeu, comme les propriétés des objets, la fréquence de rafraichissement de l'image réelle, les contraintes physiques, les avertissements de dépréciation pour le code Python (pour ne pas utiliser des fonctions Python anciennes et non supportées) et l'affichage du curseur de la souris.

  • Le Framing permet de configurer la vue camera dans l'éditeur.

L'onglet Sound permet de régler la diffusion du son, plus précisément sa simulation physique.

L'onglet Bake concerne une optimisation des textures et du rendu, qui sera détaillée dans la section Optimisations dans le chapitre Précalcule des textures et de la lumière.

XII-B. Publier un binaire

Lorsque nous souhaitons exporter une scène, l'entièreté du jeu peut être contenue avec le Player dans un même fichier exécutable. De la sorte, tout le jeu est présent dans un seul fichier (accompagné de bibliothèques DLL), et donc plus simple à partager. Sous cette forme, le code et le contenu sont soumis à la licence GPLv3*, et nous sommes dès lors obligé de publier également le fichier .blend de manière séparée.

Pour cela, allons dans le menu File > Export > Save as Game Engine Runtime.

Image non disponible

Nous pouvons également choisir de sauver le contenu sous la forme d'un fichier .blend, et de le lire avec le binaire Blenderplayer. De cette manière le contenu artistique n'est pas soumis à la licence GPL (mais reste lisible par ailleurs avec Blender).

Il suffit donc de mettre le fichier .blend dans le même répertoire que l'exécutable Blenderplayer.

Pour lancer le jeu, il faut alors lancer Blenderplayer en lui spécifiant quel fichier lire.

sur GNU-linux et MacOS :

 
Sélectionnez
user@desktop:~/mondossier/$: ./blenderplayer monjeu.blend

sur Windows, utiliser la ligne de commande :

 
Sélectionnez
C:\mondossier\> blenderplayer.exe monjeu.blend

Pour créer un lanceur il faut créer un raccourci, ou un fichier de script batch avec cette commande.

Certains ont développé des scripts permettant de crypter le fichier .blend, de sorte à en protéger le contenu, mais ceci dépasse le cadre de ce manuel.

À noter que si le contenu artistique n'est pas soumis ici à la licence GNU GPL*, le code Python faisant référence à l'API du Blender Game Engine reste lui sous cette licence. Il y a lieu donc de publier les scripts, séparément au besoin.

XII-C. Empaqueter son contenu

Pour être certain de ne rien perdre entre les manipulations de copie et d'installation du jeu, nous pouvons empaqueter le contenu directement dans le .blend (par exemple, textures et sons).

La façon la plus simple est de cocher l'option d'empaquetage automatique. De la sorte les données externes sont intégrées dans le fichier .blend à chaque enregistrement. Sinon, il faut s'assurer que les données soient toujours dans le bon répertoire (répertoire du .blend ou sous-dossier).

Image non disponible

Une fois les éléments empaquetés, il est possible de les désempaqueter et donc de les retravailler ultérieurement avec l'option Unpack all files. L'empaquetage n'est donc pas une mesure de protection du contenu, simplement une méthode facile pour conserver les données accessibles au jeu dans un même fichier.

XII-D. Export vers d'autres moteurs de jeu

Blender permet d'exporter le contenu et parfois (une partie de) la logique. Ceci dépend de la plateforme ou du moteur de jeu visé, et la plupart du temps on utilise les plugins d'exportateurs adaptés, soit pour exporter directement (par exemple, l'animation pour le moteur Unreal - plugin à activer dans les préférences utilisateurs) soit en passant par un format intermédiaire (par exemple, .dxf ou .obj pour les objets, collada pour géométrie et animations, etc.).

XII-E. Notions de licences

Les créations de l'esprit sont soumises, dans nos contrées, à un régime de propriété intellectuelle. Le droit d'auteur (et copyright) s'exerce a priori sur toute création et a priori restreint les droits des utilisateurs, lecteurs, spectateurs à une consultation privée. Toute autre utilisation est normalement soumise à autorisation des ayants droit (auteur, héritiers de l'auteur ou éditeur).

Blender, en tant que logiciel libre est distribué avec une licence GNU GPLv3*. Ceci implique que tout code lié au code de Blender est lui-même soumis à cette licence.

La licence GPLv3 est une licence garantissant les libertés des utilisateurs, en obligeant à publier les sources des logiciels, et permettant aux utilisateurs de modifier et d'utiliser ce logiciel comme bon leur semble, à la seule condition que toute modification soit également publiée sous cette licence.

Elle garantit tant la liberté de l'utilisateur que le droit d'auteur du créateur, en lui assurant la citation de son nom et le fait qu'il bénéficiera des modifications ultérieures au programme.

Qui dit publication dit distribution. Si les créations ne sont pas distribuées, elles ne doivent pas nécessairement divulguer leurs sources (par exemple, dans le cas d'une installation interactive sur une machine spécifique pour un événement ou un musée).

Il y a eu beaucoup de discussions sur ce sujet et souvent beaucoup de confusion, voire de peur de voir son travail pillé par d'autres parce que sous licence libre. Ceci est souvent le fait de personnes ne comprenant pas les implications ni la protection offerte par la licence GNU GPL.

De manière générale, cette question n'a finalement pas beaucoup d'importance pour l'usage qui est généralement fait du BGE, entre application à usage interne, exemples didactiques et prototypage.

Parce que ce qui compte généralement dans un jeu, c'est le contenu et non le code, certains ont par ailleurs publié des jeux de manière commerciale sans problème, sous ces conditions de licence, sans en souffrir. Tout comme certaines grosses sociétés de jeux vidéo qui ont libéré le code de leur moteur de jeu (Quake Engine par exemple). Les contenus eux peuvent rester protégés pour pouvoir être vendus.

Les contenus peuvent être également libres pour pouvoir être modifiés par d'autres et réutilisés comme Yo Frankie! ou sur http://opengameart.org/.

Ainsi, être libre n'empêche nullement le financement, mais oblige parfois à revoir le modèle économique envisagé.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2014 flossmanuals. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.