Catégories
Liens
Ceci est une ancienne révision du document !
Pour créer des comportements, des actions, des interactions dans le moteur de jeu de Blender, on a vu qu'on pouvait utiliser les briques logiques. Nous pouvons également accéder à certaines fonctionnalités par des scripts écrits en langage Python. Le langage Python apporte à Blender modularité et extensibilité : on peut créer des extensions pour Blender (add-ons), des scripts pour les jeux et les animations, et utiliser les multiples bibliothèques qui existent pour Python.
La principale difficulté sera de savoir quand utiliser les briques logiques et quand utiliser les scripts Python. Certaines choses sont simples à faire en briques logiques, d'autres pourront être déléguées à des scripts.
Blender Python API : documentation de l'interface de programmation avec Python.
Il faut savoir que toutes les propriétés visibles dans le logiciel ne sont pas accessibles en mode bge (Blender Game). Elles sont accessibles en mode bpy (Application Module) qui est le mode pour créer des add-ons. C'est assez déroutant. Nous avons néanmoins deux moyens de savoir ce qu'il est possible de faire en mode jeu, utiliser la fonction dir() et consulter la documentation de l'API.
Pour commencer, il faut configurer son environnement de travail et le tester avec un premier script.
Afin de débugger et d'afficher des informations utiles, il faut pouvoir les afficher dans une console. Pour Windows, il suffit de cliquer sur Window > Toggle Python Console, pour Mac et Linux, il faut ouvrir Blender par le terminal.
Il faut tout d'abord faire apparaître l'éditeur de texte (Text Editor) et créer un fichier texte avec l'icône “+”, puis nommer ces fichiers avec l'extension .py. Au lieu de partir de zéro, vous pouvez aussi vous servir de trois modèles de scripts, en parcourant le menu Templates > Python > Game Logic.
L'appel des scripts se fait par une brique logique contrôleur de type Python, qu'il faut associer à un capteur. Il existe deux façons d'appeler un script : soit en appelant le script entier, soit en l'appelant par module.
Attention à la position des lignes en python, on appelle ça l'indentation. Il faut une indentation équivalente à 4 espaces pour délimiter les blocs.
Exemple correct :
def test(): print("test") test()
Exemple incorrect :
def test(): print("test") test()
Exemple d'interface avec un premier script python. Le script est actionné par un capteur “Always”. Lorsque le jeu démarre (touche “P”), il affiche simplement le nom de l'objet Cube dans la console.
# Premier script en Python ! # Importation de la bibliothèque du moteur de jeu (Blender Game Engine ou bge) # Elle nous permet de manipuler les objets et les briques logiques import bge # Premier module : afficher le nom de l'objet def afficherNomObjet(): # Attention à l'indentation des lignes ! # On récupère le contrôleur cont = bge.logic.getCurrentController() # Et ensuite l'objet auquel il appartient obj = cont.owner # On affiche le nom de cet objet print(obj.name) # Appel du module "afficherNomObjet" dès l'appel du script afficherNomObjet()
Les objets du jeu sont tous les objets que vous avez créé sur vos scènes, ils héritent tous de la classe bge.types.KX_GameObject.
Paramètres et fonctions d'un objet : actuators, addDebugProperty, alignAxisToVect, angularDamping, angularVelocity, angularVelocityMax, angularVelocityMin, applyForce, applyImpulse, applyMovement, applyRotation, applyTorque, attrDict, children, childrenRecursive, collisionCallbacks, collisionGroup, collisionMask, color, controllers, currentLodLevel, debug, debugRecursive, disableRigidBody, enableRigidBody, endObject, get, getActionFrame, getActionName, getAngularVelocity, getAxisVect, getDistanceTo, getLinearVelocity, getPhysicsId, getPropertyNames, getReactionForce, getVectTo, getVelocity, groupMembers, groupObject, invalid, isPlayingAction, isSuspendDynamics, life, linVelocityMax, linVelocityMin, linearDamping, linearVelocity, localAngularVelocity, localInertia, localLinearVelocity, localOrientation, localPosition, localScale, localTransform, mass, meshes, name, occlusion, orientation, parent, playAction, position, rayCast, rayCastTo, record_animation, reinstancePhysicsMesh, removeParent, replaceMesh, restoreDynamics, scaling, scene, sendMessage, sensors, setActionFrame, setAngularVelocity, setCollisionMargin, setDamping, setLinearVelocity, setOcclusion, setParent, setVisible, state, stopAction, suspendDynamics, timeOffset, visible, worldAngularVelocity, worldLinearVelocity, worldOrientation, worldPosition, worldScale, worldTransform
Toutes les 10 images, grâce au capteur Always “Tic10”, le contrôleur Python lance un module du script “script01.py”, qui a pour effet de faire tourner, grossir, avancer le cube “MonJoliCube”, ainsi que de changer sa couleur. La touche espace agrandit l'objet en largeur et la flèche du haut active un actionneur qui change d'état et donc arrête ces comportements.
# Deuxième script : GameObject # Exploration des possibilités d'actions sur les objets au cours du jeu # Touche "P" pour démarrer le jeu, "Echap" pour l'arrêter # Touche "Espace" pour agrandir le cube # Touche "Flèche du haut" pour passer à un autre état et donc arrêter les comportements # Importation des bibliothèques nécessaires pour ce script import bge import random # Module "getInfos" pour avoir des informations sur l'objet # Décommenter les lignes pour afficher les informations dans la console def getInfos(cont): # Pour utiliser l'objet on a besoin de récupérer la brique contrôleur. # Celle-ci est accessible directement en paramètre : "(cont)" obj = cont.owner # Affiche tous les paramètres et fonctions d'un "GameObject" # print(dir(obj)) # QUELQUES PROPRIETES # print(obj.name) # le nom de l'objet # print(obj.scene) # le nom de la scène # print(obj.life) # durée de vie de l'objet si il a été créé dynamiquement # print(obj.visible) # est-ce que l'objet est visible ? # LES PROPRIETES DE JEU (GAME PROPERTY) # Appuyer sur la touche "N" dans l'éditeur logique # print(obj.getPropertyNames()) # renvoie une liste des propriétés de l'objet # print(obj["majoliepropriete"]) # affiche la valeur de la propriété créée # obj["majoliepropriete"] = 100 # Affceter une valeur à cette propriété # CAPTEURS ET ACTIONNEURS # print(obj.sensors) # renvoie une liste des propriétés de l'objet # print(obj.actuators) # renvoie une liste des propriétés de l'objet # AFFICHER LES POSITIONS # print(obj.worldPosition) # print(obj.worldOrientation) # print(obj.worldOrientation.to_euler().x) # La fonction to_euler() simplifie le résultat # print(obj.localScale) # print(obj.getVectTo(obj.scene.objects["Sol"])) # print(obj.getDistanceTo(obj.scene.objects["Sol"])) # Module randObject() pour manipuler l'objet def randObject(cont): # On récupère l'objet obj = cont.owner # VISIBILITÉ : afficher ou non l'objet prob = random.randrange(100) # probabilité que l'objet soit visible if prob < 20 : # en dessous de 20% il n'est plus visible obj.setVisible(False) else: obj.setVisible(True) # TAILLE # On augmente la taille y obj.localScale.y += 0.1 # TRANSLATION # On applique un mouvement de translation très simple en ajoutant 1 à sa position obj.worldPosition.x += 0.1 # Si sa position en X est supérieure à 5, alors on la replace en arrière if obj.worldPosition.x > 5 : obj.worldPosition.x = -5 # ROTATION : 0.1 degré sur l'axe X obj.applyRotation((0.1,0,0)) # COULEURS # En mode GLSL, aller dans l'éditeur Properties et cocher "Material > Options > Object Color" r = random.random() # retourne un nombre entre 0 et 1 g = random.random() b = random.random() obj.color = (r, g , b, True) # AUTRES # alignAxisToVect(), applyMovement(), applyForce(), enableRigidBody(), endObject(), replaceMesh(), sendMessage(), playAction() # Avec le capteur "ToucheEspace", on change la hauteur du Cube def changeObject(cont): obj = cont.owner sensor = obj.sensors["ToucheEspace"] if sensor.positive : obj.localScale.z = 2 else: obj.localScale.z = 1 # Avec le capteur "ToucheHaut", on active l'actionneur qui nous fait changer d'état def changeState(cont): obj = cont.owner sensor = obj.sensors["ToucheHaut"] actuator = obj.actuators["ToState2"] if sensor.positive : cont.activate(actuator) else: cont.deactivate(actuator)