| |
|
Couche Comportement Python
Une des Couches Comportement prédéfinies dans Crystal Entity Layer est la Couche Comportement BLPYTHON. Dans la Couche Comportement PYTHON est utilisé un langage de script simple. Ceci vous permet de créer une logique de jeu en utilisant PYTHON, et ainsi de créer des jeux entièrement scriptés sans avoir besoin de recompiler.
Raccourcis Python CEL et CS
Il y a plusieurs modules Python pour CS et CEL :
- cspace : c'est le module Python CS principal, qui fournit la plupart des fonctionnalités via son API.
- blcelc : c'est le module Python CEL principal, qui fournit la plupart des fonctionnalités via son API.
- pycel : c'est une couche haut niveau, accessible lorsque vous lancez des scripts sous la Couche Comportement Python. Il fournit un accès facile à certaines des fonctionnalités les plus communes de CEL, et habituellement c'est ce que vous importerez dans vos scripts. Notez que pycel inclut toutes les fonctionnalités des deux modules précédents.
Aussi il faut noter que pycel est automatiquement importé dans chaque espace de nom de comportement, vous n'avez donc pas besoin de l'importer , à moins de l'importer grâce à la commande import * à partir de ce dernier.
Comportements
En utilisant la Couche Comportement BLPYTHON, vous créez des scripts. Tout script correspond à un comportement pour une Entité (plusieurs Entités peuvent bien sûr s'en servir).
Chaque script doit inclure un comportement du même nom.
Un comportement Python possède la structure suivante :
# file fovcontrol.py from pycel import * class fovcontrol: api_version = 2 def __init__(self,celEntity): print "Initializing fovcontrol...",celEntity.Name # get camera from main actor (called camera in this case) self.camera = celGetDefaultCamera(Entities["camera"]).Camera self.initfov = self.camera.GetFOV () # get/create a pcinput.standard self.input = celCommandInput(celEntity) self.input.Bind("z","zoomin") self.input.Bind("x","zoomout") self.input.Bind("c","zoom0") # get/create a timer self.timer = celTimer(celEntity) self.timer.WakeUpFrame(CEL_EVENT_PRE) # define some initial values self.zoomin = False self.zoomout = False # get initial time self.time = Clock.GetCurrentTicks() # property class message callbacks def pctimer_wakeupframe(self,pc,args): self.time = Clock.GetCurrentTicks() - self.time if self.zoomin: self.camera.SetFOV(int(self.camera.GetFOV()+(5*(self.time/1000.0))),Graphics2D.GetWidth()) if self.zoomout: self.camera.SetFOV(int(self.camera.GetFOV()-(5*(self.time/1000.0))),Graphics2D.GetWidth()) def pccommandinput_zoomin1(self,pc,args): self.zoomin = True def pccommandinput_zoomout1(self,pc,args): self.zoomout = True def pccommandinput_zoomin0(self,pc,args): self.zoomin = False def pccommandinput_zoomout0(self,pc,args): self.zoomout = False def pccommandinput_zoom01(self,pc,args): self.camera.SetFOV(self.initfov,Graphics2D.GetWidth())
Comme on peut le voir nous avons une classe avec plusieurs méthodes.
D'abord nous avons le constructeur (méthode __init__()) qui obtient un pointeur de l'Entité à laquelle il s'attache à (CelEntity). Comme d'habitude avec Python toutes les méthodes de la classe ont un premier paramètre qui pointe sur sa propre instance de classe (self) du comportement, et nous pouvons l'utiliser pour sauvegarder des variables pour cette instance.
Ensuite nous avons quelques fonctions de rappel, dans beaucoup de situations CEL appellera certaines fonctions dans nos Comportements Python, donc nous pouvons réagir aux évènements. Par exemple pctimer_wakeup est obtenu quand l'Entité reçoit un évènement de réveil de la part d'un temporisateur, pctrigger_entertrigger est obtenu quand l'Entité entre dans la zone d'un déclencheur.
Notez la présence de la variable api_version = 2, elle spécifie la version des retours de fonction à utiliser. La version 2 est apparue dans CEL version 1.2, et est recommandée en lieu et place de la version 1 qui reste la version par défaut pour des raisons de compatibilité.
Comportements Python dans le fichiers monde XML
Des Comportements Python peuvent être directement définis au format CEL XML comme déjà vu dans ce manuel.
Voici un exemple d'Entité dotée de Classes de Propriété et d'un Comportement Python définis comme suit :
<addon entityname="camera" plugin="cel.addons.celentity"> <propclass name="pcobject.mesh"> <action name="SetMesh"> <par name="name" string="ActorMesh"/> </action> </propclass> <propclass name="pccamera.old"> <action name="SetCamera"> <par name="modename" string="thirdperson"/> </action> </propclass> <propclass name="pcinput.standard"/> <propclass name="pcobject.mesh.select"> <action name="SetCamera"> <par name="entity" string="camera"/> </action> <action name="SetMouseButtons"> <par name="buttons" long="2"/> </action> </propclass> <behaviour layer='blpython' name='actor'/> </addon>
Notez que le Comportement Python sera chargé depuis le fichier actor.py qui doit se trouver quelque-part sur le PYTHONPATH (notez que celstart ajoutera le dossier principal de votre fichier ZIP à votre PYTHONPATH si vous l'utilisez).
Habituellement l'addon CelEntity est placé dans un secteur Crystal Space à l'intérieur des fichiers world.
pycel
Pycel est une couche de haut niveau définissant quelques termes pour certaines des choses les plus fréquemment utilisées :
La Couche Physique
La Couche Physique est votre pointeur principal vers les fonctionnalités de CEL, et vous en aurez besoin pour créer des Entités, les détruire, obtenir des string IDs... On peut y accéder depuis Python via pycel.PhysicalLayer.
Dictionnaires de la Couche Physique
On peut accéder à tous les dictionnaires de la Couche Physique directement depuis pycel :
- pycel.Entities : utilisé pour obtenir les objets d'Entité par nom.
- pycel.EntityTemplates : utilisé pour obtenir des Modèles d'Entité par nom.
- pycel.PcFactories : utilisé pour obtenir ou enregistrer les Fabriques de Classe de Propriété par ID (comme cel.pcfactory.timer).
- pycel.BehaviourLayers : utilisé pour obtenir ou enregistrer des Couches Comportement avec CEL.
Plugins Crystal Space
Des plugins souvent utilisés dans Crystal Space sont prêt à être utilisés (si présents). Ce sont :
- pycel.Engine : le plugin Engine où vous pouvez accéder à la plupart des objets Crystal space dans votre map (interface iEngine).
- pycel.Vfs : le plugin Système de Fichier Virtuel que vous pouvez utiliser pour vous promener à l'intérieur du système de fichier (interface iVFS).
- pycel.Clock : le plugin d'horloge virtuelle, utilisé pour obtenir des temps précis dans le calcul des mouvements (interface iVirtualClock).
- pycel.Graphics2D : le plugin Graphismes 2D, utilisé pour dessiner des choses en 2D sur l'écran (interface iGraphics2D).
- pycel.Graphics3D : le plugin Graphismes 3D, utilisé pour dessiner des choses en 3D sur l'écran (interface iGraphics3D).
- pycel.Config : le plugin Gestionnaire de Configuration, utilisé pour chercher ou charger des fichiers de configuration (interface iConfigManager).
- pycel.Loader : le plugin Chargement de Crystal Space, utilisé pour charger des fichiers mondes ou de bibliothèques (interface iLoader).
- pycel.KeyboardDriver : Le plugin de Pilotage du Clavier, utilisé pour lancer une requête sur l'état du Clavier (interface iKeyboardDriver).
- pycel.JoystickDriver : Le plugin de Pilotage du Joystick, utilisé pour lancer une requête sur l'état du Joystick (interface iJoystickDriver).
- pycel.MouseDriver : Le plugin de Pilotage de la Souris, utilisé pour lancer une requête sur l'état de la Souris (interface iMouseDriver).
- pycel.PluginManager : Le Gestionnaire de Plugin de Crystal Space, utilisé pour charger des plugins additionnels (interface iPluginManager).
- pycel.FontServer : Le plugin de Chargement de Police de Crystal Space, utilisé pour charger et accéder aux objets Font (interface iFontServer).
- pycel.Stringset : le plugin Réglage de chaîne, utilisé pour transformer les IDs de chaîne CS en chaîne de caractères normales (interface iStringSet).
getid / fromid et autres fonctions relatives aux StringID
Fonctions permettant de transformer des chaînes (string) en ID de chaînes (stringid) et inversement.
- pycel.getid(string) : retourne une ID de chaîne pour une chaîne donnée.
- pycel.parid(string) : retourne une ID de chaîne à partir de la chaîne de l'identifieur de paramètre donné. Ceci ajoute le préfixe cel.parameter. à la chaîne donnée, automatiquement.
- pycel.propid(string) : retourne une ID de chaîne à partir de la chaîne de l'identifieur de propriété donnée. Ceci ajoute un préfixe cel.property. à la chaîne donnée, automatiquement.
- pycel.actid(string) : retourne une ID de chaîne à partir de la chaîne de l'identifieur d'action donné. Ceci ajoute un préfixe cel.action. à la chaîne donnée, automatiquement.
- pycel.fromid(stringid) : retourne une chaîne pour une ID de chaîne donnée.
parblock
Fonctions permettant de créer un celParameterBlock depuis un dictionnaire ou une liste Python. Ceci sera décrit en détails plus tard.
CreateEntity / RemoveEntity
On peut avoir accès à ces fonctions directement depuis pycel pour créer ou détruire des Entités. Utilisez-les de la même façon que les fonctions de la Couche Physique du même nom.
Accesseurs de Classe de Propriété
Certaines fonctions sont définies pour créer facilement des Classes de Propriété CEL pour des Entités, ou accéder à celles pré-existantes. Ceci sera décrit dans la prochaine section du manuel.
Mécanismes d'accès aux Classes de Propriété
Certaines fonctions sont définies pour créer facilement des Classes de Propriété CEL pour les Entités, ou pour accéder à celles pré-existantes. Ceci sera décrit dans la prochaine section.
Accès aux Classes de Propriété des Entités
Les Classes de Propriété sont des objets que l'on peut créer attachés à une Entité, et qui augmentent les fonctionnalités de l'Entité (voir la section Classes de Propriété).
D'abord il doit être noté qu'avant d'utiliser chaque Classe de Propriété, on doit s'assurer qu'elles sont enregistrées dans la Couche Physique, et pour faire cela dans Python, il suffit d'ajouter le nom entier de la Fabrique de Classe de Propriété (cel.pcfactory.pcclass) au dictionnaire PcFactories (qui est une partie de la Couche Physique, mais doté d'un accès global dû à la couche pycel).
En voici un exemple :
pcclasses = ["world.region","2d.tooltip","object.mesh","move.solid", "object.mesh.select","world.zonemanager","logic.trigger", "logic.quest","object.light","tools.inventory", "camera.old","move.gravity","input.standard","move.linear", "move.actorold","move.colldet","tools.timer", "sound.listener","sound.source","2d.billboard", "toolsproperties"] for pcclass in pcclasses: PcFactories.append("cel.pcfactory."+pcclass)
Pour chaque Classe de Propriété il y a plusieurs fonctions dans le module pycel qui permettent facilement de chercher ou de créer la Classe de Propriété appropriée depuis un objet Entité :
- celPropertyClass(celEntity,tag=None) : trouve la Classe de Propriété si elle existe ou en crée une nouvelle. Si tag n'est pas défini alors elle créera la Classe de Propriété s'il n'y a pas de Classe de Propriété de ce type. Si tag est défini, il cherchera uniquement la Classe de Propriété correspondant au tag, ou sinon en créera une nouvelle avec ce tag. Pour s'assurer de la création/requête d'une Classe de Propriété non-tagguée si des Classes de Propriété tagguées existent, définissez le tag en tant que chaîne vide ("").
- celAddPropertyClass(celEntity,tag=None) : ajoute la Classe de Propriété à l'Entité. Si tag est défini, alors la Classe de Propriété sera créée avec ce tag, sinon une Classe de Propriété non-tagguée sera créée.
- celGetPropertyClass(celEntity,tag=None) : trouve la Classe de Propriété si elle existe. Si tag est utilisé, alors il trouvera la Classe de Propriété avec le tag approprié (ou sans tag si "" est utilisé). Sinon elle retournera une Classe de Propriété non-tagguée, ou si elle n'existe pas, la première Classe de Propriété tagguée trouvée.
Où PropertyClass serait substituée par le nom approprié, comme celGetTimer, celAddCommandInput, etc.
Comme exemple de section d'initialisation, on pourrait faire :
def __init__(self,celEntity): self.input = celCommandInput(celEntity) self.timer = celAddTimer(celEntity) self.timer.WakeUpFrame (CEL_EVENT_POST) self.select = celMeshSelect(celEntity)
Accéder aux propriété de Classe de Propriété
Pour accéder aux propriétés des Classes de Propriété à partir de Python, vous pouvez utiliser la syntaxe standard de Python. Par exemple, pour accéder au jitter d'un pctrigger :
oldjitter = trigger.jitter trigger.jitter = 100
Messages
Chaque Classe de Propriété dans CEL peut générer un nombre de messages. Un Comportement Python reçoit ces messages comme des appels de fonction Python avec le même nom que le message. Nous pouvons utiliser ces appels pour répondre aux évènements depuis les différentes Classes de Propriété appropriées.
Dans le premier exemple, nous recevons un appel de fonction pctimer_wakeupframe à chaque frame, dû au pctimer activé.
Aussi il y a quelques fonctions pccommandinput_* qui sont déclenchées par les liens pccomandinput. Notez pour chaque lien d'entrée que nous faisons via pccommandinput, le comportement va recevoir trois évènements distincts nommés pccommandinput_bind1, pccommandinput_bind0 et pccommandinput_bind_, respectivement pour les évènements : touche pressée, relâchée et maintenue.
Les autres Classes de Propriétés comme pcphysics.object, pcobject.mesh.select, pc2d.billboard, pclogic.damage, pcmove.linear génèrent aussi leurs propres messages spéciaux.
Les appels de fonction message ont trois paramètres. Le premier est l'instance de Classe Comportement, le second l'Entité recevant le message, et le dernier un celParameterBlock qui fixe toutes les valeurs spécifiques d'un message.
Vous pouvez accéder aux valeurs depuis le bloc de paramètre comme un dictionnaire Python avec des StringIDs CEL pour index au lieu de chaines de caractères normales.
# a pcbillboard select message def pcbillboard_select(self,pc,args): print pc.Tag bx = args["x"] by = args["y"] button = args["button"]
Il est possible de tester l'existence d'un certain paramètre, or iterate over the values. A noter que par efficacité, nous sauverons les StringIDs pour une utilisation ultérieure au lieu de refaire la requête à chaque fois.
Un dernier bout de code pour sortir tous les paramètres vers un message :
def pcbillboard_select(self,pc,args): for strid in args.keys(): print fromid(strid),args[strid]
Nouveau Style de retour de fonction de Classe de Propriété
Il existe un nouveau style pour la réception des messages de retour des Classes de Propriété dans CEL version 1.2, ceci afin de corriger certaines erreurs de conception dans la version précédente. Ce nouveau style est celui présent dans cette documentation et donc dans tous les exemples de comportement dans CEL.
En spécifiant api_version = 2 dans le corps d'une Classe de Ccomportement, vous pouvez utiliser le nouveau style de message de retour (voir le premier exemple de ce chapitre).
L'ancien style de retour de message était :
def pcbillboard_select(self,celEntity,args): ...
And the new one in cel 1.2 is:
def pcbillboard_select(self,pc,args): ...
Toutefois l'ancien style est toujours celui par défaut, pour des raisons de compatibilité. Il est recommandé de débuter avec le nouveau, qui vous donnera accès à l'envoi de message pc, requis au cas où vous voudriez établir une sélection parmi les classes pc présentes dans l'entité.
A noter que la spécification de api_version est requise dans CEL version 1.2 pour ainsi être capable de maintenir une compatibilité dans les futures versions si retour de fonction par défaut viendrai à changer
Si vous avez besoin d'accéder au paramètre d'entité, vous devez le sauvegarder dans le constructeur de comportement.
Envoi de Messages
Certains messages (comme __init__ et des messages des Classes de Propriété) sont automatiquement appelés, mais vous pouvez aussi définir vos propres messages et les appeler en utilisant la fonction iCelBehaviour.SendMessage.
Pour envoyer un message/évènement vers une Entité, nous devons créer la même sorte de liste de paramètres. Il existe une fonction d'aide dans la Couche Physique pour faire celà, appelée CreateParameterBlock et aussi le terme pycel alias parblock. Il accepte soit un dictionnaire, soit une liste ou soit un tuple pour arguments. Si nous fournissons un dictionnaire, il initialisera les IDs et valeurs dans le bloc de paramètre, si nous fournissons une liste ou un tuple, il complètera uniquement les IDs et demandera de remplir les valeurs plus tard :
#Creating a parameter block from a list. This is more similar to the c++ method pars = parblock(["control","x","y"]) pars["control"] = "specular" pars["x"] = 15 pars["y"] = 200 #Creating a parameter block from a dictionary. pars2 = parblock({"control":"shininess","x":30,"y":200})
La différence réside dans la vitesse, habituellement si vous envoyez le même type de bloc de paramètres plusieurs fois, vous le construirez dans le constructeur à partir du Comportement, et le remplirez avec des valeurs avant de l'envoyer. Dans d'autres situations, il peut être approprié de créer entièrement le bloc de paramètre à partir d'un dictionnaire si besoin.
Après ceci, le message sera envoyé en utilisant SendMessage dans le Comportement Entité ciblé :
Entities["player"].Behaviour.SendMessage("control_variable", None, pars)
Un monde en Python pour celstart
La meilleure façon de lancer des mondes CEL uniquement en Python (ou XML et Python) est d'utiliser l'application CEL celstart.
Pour celà, vous avez besoin de charger la Couche Comportement Python à partir du fichier de configuration celstart. Une autre procédure utile est de définir une Entité de départ, à créer avec un comportement. De là, il est possible de charger entièrement la map à partir de Python bien qu'il soit à noter que d'autres configurations soient possibles.
Pour faire celà, nous ajouterions par exemple, les lignes suivantes au fichier de configuration :
CelStart.BehaviourLayer.blpython = cel.behaviourlayer.python CelStart.Entity.bootstrap = bootstrap CelStart.EntityBehaviour.bootstrap = appinit CelStart.EntityBehaviourLayer.bootstrap = blpython
Celà créera une Entité de départ et chargera le Comportement Python appinit, lequel sera chargé par le fichier appinit.py.
A partir de ce Comportement, vous pouvez charger une map en utilisant soit l'API CS ou CEL, habituellement on le fait via une Classe de Propriété celZoneManager (voir la section Gestionnaire de Zone sur une Entité initiale :
def __init__(self,celEntity): zoneMgr = celZoneManager(celEntity) Vfs.ChDirAuto("/tmp/celstart/") zoneMgr.Load("/tmp/celstart","level.xml")
Notez que /tmp/celstart/ est le chemin VFS où celstart cartographie le fichier ZIP, ceci ne changera pas suivant le système d'exploitation ou l'emplacement du fichier réel.
Langue:
English •
Brazilian •
Chinese •
Deutsch •
Español •
Esperanto •
Français •
Magyar
Translate this page
