| |
|
Attention !
Ceci est la traduction de la documentation de CEL en version 1.0. Elle ne figure ici que dans l'unique but d'aider à la compréhension.
Pour une version plus à jour, lui préférer la version 1.2 (eng). Dans l'attente d'une prochaine mise à jour.
Contents |
Classes de propriété
Utilisation générale d'une Classe de Propriété
Voici quelques indications générales sur l'utilisation des Classes de Propriété. Avant de pouvoir en utiliser une, vous devez préalablement vous assurez que la Fabrique de Classes de Propriété est chargée et enregistrée avec la Couche Physique. Pour cela vous avez besoin de l'ID Fabrique pour la Classe de Propriété que vous trouverez dans la documentation de chaque Classe de Propriété. Puis vous ajouterez la ligne suivante à l'initialisation de votre application (exemple pour la Classe de Propriété pcmesh) :
if (!pl->LoadPropertyClassFactory ("cel.pcfactory.mesh")) return false;
Pour utiliser l'API depuis cette Classe de Propriété, vous devez charger l'entête (également donnée avec la documentation de chaque Classe de Propriété). Il y a deux façons de créer une Classe de Propriété pour une Entité. La première est de les créer ensemble avec l'Entité elle-même :
csRef<iCelEntity> entity = pl->CreateEntity (entname, behaviourlayer, behavename, "pcmesh", ... (other property classes) CEL_PROPCLASS_END);
La seconde est de créer une Classe de Propriété sur une Entité déjà créée :
iCelPropertyClass* pc = pl->CreatePropertyClass (entity, "pcmesh");
Pour demander une Classe de Propriété à partir une Entité, vous pouvez utiliser :
csRef<iPcMesh> pcmesh = CEL_QUERY_PROPCLASS_ENT (entity, iPcMesh);
Classes de Propriété tagguées
Normalement une Entité n'a qu'une instance pour un type de Classe de Propriété donné (autrement dit seulement un pcmesh au maximum). Parfois il est utile de pouvoir ajouter de multiples instances de Classe de Propriété du même type. Pour faire la distinction entre les différentes instances, vous pouvez utiliser des tags. Voici comment vous pouvez créer une Classe de Propriété tagguée sur une Entité :
iCelPropertyClass* pc = pl->CreateTaggedPropertyClass (entity, "pcmesh", "main_mesh");
Et pour chercher une Classe de Propriété tagguée vous pouvez utiliser :
csRef<iPcMesh> pcmesh = CEL_QUERY_PROPCLASS_TAG_ENT (entity, iPcMesh, "main_mesh");
Notez qu'il y a là le concept d'une Classe de Propriété par défaut pour un type donné. En général la Classe de Propriété par défaut est celle qui n'a pas d'étiquette (tag égal à 0). Donc si vous appellez CEL_QUERY_PROCLASS_ENT, ça cherchera d'abord la Classe de Propriété avec l'étiquette égale à 0. Si toutes les Classes de Propriété ont une étiquette alors ça vous en retournera une au hasard.
Gestionnaire de quêtes
La Classe de Propriété Quêtes utilise le gestionnaire de quête en arrière-plan, donc cette section va également présenter ce dernier.
Détails de la Classe de Propriété
- Nom : pcquest
- Factory ID (ID de la fabrique): cel.pcfactory.quest
- Interface : iPcQuest
- Header (Entête) : include/propclass/quest.h
Information générale
Le gestionnaire de quêtes est l'un des plus importants modules de CEL. Une quête est simplement une histoire dans un jeu. Le mot histoire étant ici entendu dans son sens le plus large. Une quête peut être une simple tâche consistant à allumer une lumière dans une pièce si le joueur appuie sur un bouton, ou une suite complexe de quêtes gardant des traces des discussions avec les PNJs et des interactions alambiquées avec des objets.
Une quête est une machine à états. A chaque temps donné correspond un état spécifique, et vous pouvez changer un état en réponse à un évènement donné. Il y a des Fabriques de Quête (iQuestFactory) et des quêtes (iQuest). Une fabrique agit comme un gabarit à partir duquel on crée des quêtes. Dans toute quête se trouve à la base cinq concepts distincts : les états (states), les déclencheurs (triggers), les récompenses (rewards), les réponses (responses) et les séquences (sequences).
Les déclencheurs (Triggers)
Les déclencheurs amènent la progression dans une quête. Dès qu'un déclencheur se met en route, la quête agira et exécutera certaines récompenses (rewards - voir plus bas).
Les déclencheurs suivants sont actuellement définis dans CEL :
- cel.questtrigger.entersector
- s'active lorsqu'une caméra pénètre dans un secteur. Voir iEnterSectorQuestTriggerFactory.
- cel.questtrigger.meshentersector
- s'active lorsqu'un mesh pénètre dans un secteur. Voir iEnterSectorQuestTriggerFactory.
- cel.questtrigger.timeout
- s'active après un temps donné. Voir iTimeoutQuestTriggerFactory.
- cel.questtrigger.propertychange
- s'active lorsqu'une propriété change. Voir iPropertyChangeQuestTriggerFactory.
- cel.questtrigger.sequencefinish
- s'active lorsqu'une séquence se termine. Voir iSequenceFinishQuestTriggerFactory.
- cel.questtrigger.trigger
- s'active lorsqu'un pctrigger se lance. Voir iTriggerQuestTriggerFactory.
- cel.questtrigger.inventory
- s'active lorsqu'un objet intègre l'inventaire. Voir iInventoryQuestTriggerFactory.
- cel.questtrigger.meshselect
- s'active lorsqu'un mesh est sélectionné. Voir iMeshSelectQuestTriggerFactory.
Bien sûr il est possible de définir vos propres déclencheurs et de les enregistrer dans le gestionnaire de quêtes.
Récompenses (Rewards)
Dès qu'un déclencheur se lance, une ou plusieurs récompenses sont exécutées. Une récompense est à la base une opération spécifique nécessitant d'être accomplie en réponse à un déclencheur. Actuellement, les récompenses suivantes sont définies dans Crystal Entity Layer :
- cel.questreward.debugprint
- Ceci imprimera un message de debuggage vers stdout. Voir iDebugPrintQuestRewardFactory.
- cel.questreward.newstate
- Ceci basculera vers la recherche d'un nouvel état. Voir iNewStateQuestRewardFactory.
- cel.questreward.changeproperty
- Ceci modifiera une propriété. Voir iChangePropertyQuestRewardFactory.
- cel.questreward.inventory
- Ceci manipulera l'inventaire. Voir iInventoryQuestRewardFactory.
- cel.questreward.sequence
- Ceci lancera une séquence. Voir iSequenceQuestRewardFactory.
- cel.questreward.sequencefinish
- Ceci terminera une séquence. Voir iSequenceFinishQuestRewardFactory.
Il est également possible de définir vos propres récompenses.
Réponses (Responses)
Une réponse (response) est simplement un déclencheur et une ou plusieurs récompenses réunis. Dans un état vous pouvez définir de muliples réponses. Toute réponse va définir un ensemble différent de récompenses.
Etats (States)
Une quête est constituée de différents états. Tout état comporte zéro ou plus réponses.
Séquences
Une récompense est toujours une opération en-un-coup. Elle s'accomplit, et dès son effet produit, s'arrête immédiatement. Les séquences, à l'inverse, ont une durée et représentent des opérations qui prendront typiquement quelques frames pour s'exécuter. Par exemple, pour ouvrir une porte en réponse à un déclencheur, on utiliserait une séquence pour modifier la porte en quelques frames. Les séquences peuvent être lancées par une récompense.
Les opérations suivantes sont actuellement définies comme une séquence :
- cel.questseqop.debugprint
- Imprime un message de débuggage via stdout. Voir iDebugPrintQuestSeqOpFactory.
- cel.questseqop.transform
- Transforme un mesh. Voir iTransformQuestSeqOpFactory.
- cel.questseqop.movepath
- Bouge un mesh le long d'un chemin. Voir iMovePathQuestSeqOpFactory.
- cel.questseqop.light
- Anime une lampe colorée. Voir iLightQuestSeqOpFactory.
Vous pouvez définir vos propres opérations de séquence pour le gestionnaire de quête.
Définir une quête en XML
Ici nous allons voir comment définir une quête en XML. Noux utilisons l'addon cel.addons.questdef (voir la section Définition de Quête), ainsi nous pouvons introduire la définition de la quête dans un fichier de monde normal :
<addon plugin="cel.addons.questdef"> <quest name="SlideDoor"> <state name="locked"> <trigger type="trigger"> <fireon entity="$this" /> <reward type="debugprint" message="Door is closed!" /> </trigger> <trigger type="inventory"> <fireon entity="camera" child_entity="$key_ent" /> <reward type="debugprint" message="The door is unlocked!" /> <reward type="changeproperty" entity="$key_ent" pc="pcbillboard" property="cel.property.visible" bool="true" /> <reward type="newstate" state="closed" /> </trigger> </state> <state name="closed"> <trigger type="trigger"> <fireon entity="$this" /> <reward type="debugprint" message="Door Opens!" /> <reward type="sequencefinish" entity="$this" sequence="closedoor" /> <reward type="sequence" entity="$this" sequence="opendoor" /> <reward type="newstate" state="opened" /> </trigger> </state> <state name="opened"> <trigger type="trigger"> <fireon entity="$this" leave="true" /> <reward type="debugprint" message="Door Closes!" /> <reward type="sequencefinish" entity="$this" sequence="opendoor" /> <reward type="sequence" entity="$this" sequence="closedoor" /> <reward type="newstate" state="closed" /> </trigger> </state> <sequence name="opendoor"> <op type="transform" duration="500" entity="$this"> <v x="$openx" y="$openy" z="$openz" /> </op> </sequence> <sequence name="closedoor"> <op type="transform" duration="500" entity="$this"> <v x="$closex" y="$closey" z="$closez" /> </op> </sequence> </quest> </addon>
Cette quête a trois états : locked (verrouillée), closed (fermée) et opened (ouverte). En utilisant cette quête, vous pouvez démarrer à partir de n'importe lequel de ces trois états, selon comment vous voulez que la porte soit au départ. Pour passer de locked à closed, vous avez besoin d'un objet. Le nom de cet objet est donné au paramètre de quête key_ent (qui est donné lors de l'instanciation de la quête). Dans l'état closed on regarde aussi le déclencheur afin de voir si l'on est en train de s'approcher la porte. Dans ce cas on affiche le message à l'utilisateur pour indiquer que la porte est toujours fermée.
Si la porte est en état closed, alors on attend simplement que le joueur s'approche, puis on lance la séquence opendoor pour ouvrir la porte et rejoindre l'état opened. De même pour l'état opened, on attend que le joueur s'éloigne du déclencheur.
Pour définir une Entité utilisant cette quête, on utilise l'addon cel.addons.celentity (voir la section Addon CelEntity) de cette manière :
<addon plugin="cel.addons.celentity" entityname="SlidingDoor"> <propclass name="pcmesh"> <action name="SetMesh"> <par name="name" string="SlidingDoor" /> </action> </propclass> <propclass name="pctrigger"> <property name="monitor" string="camera" /> <action name="SetupTriggerSphere"> <par name="sector" string="Corridors" /> <par name="position" vector="-118,-8,78.7" /> <par name="radius" float="4" /> </action> </propclass> <propclass name="pcquest"> <action name="NewQuest"> <par name="name" string="SlideDoor" /> <par name="openx" string="-3.5" /> <par name="openy" string="0" /> <par name="openz" string="0" /> <par name="closex" string="3.5" /> <par name="closey" string="0" /> <par name="closez" string="0" /> </action> <property name="state" string="closed" /> </propclass> </addon>
Mesh
La Classe de Propriété Mesh peut être utilisée pour assignée un modèle 3D à une Entité. Cette Classe de Propriété définit une représentation visuelle pour une Entité.
Details de la Classe de Propriété
- Nom : pcmesh
- Factory ID (ID de fabrique) : cel.pcfactory.mesh
- Interface : iPcMesh
- Header (entête) : include/propclass/mesh.h
Information générale
En utilisant cette Classe de Propriété on peut assigner un mesh 3D depuis Crystal Space vers une Entité.
Définir les Données du Mesh
Il y a plusieurs façons de définir le mesh dans pcmesh :
- Si vous avez déjà un pointeur vers un mesh empaqueté depuis Crystal space, alors vous pouvez simplement utiliser iPcMesh->SetMesh() avec ce mesh empaqueté comme paramètre.
- Si vous savez que la Fabrique de Mesh est déjà chargée en mémoire, alors vous pouver régler le mesh directement depuis le nom de la Fabrique de Mesh, en appelant iPcMesh->SetMesh() avec le factname donné et filename égal à 0.
- Autrement vous devrez donner un nom de fichier valide, auquel cas SetMesh() sera d'abord consulté pour voir si laFfabrique est déjà chargée. Si ce n'est pas le cas, elle sera chargée depuis le nom de fichier donné. Si vous appelez iPcMesh->SetPath() alors vous pourrez aussi contrôler le chemin VFS d'où le fichier Fabrique sera chargé.
Notez que le fichier peut aussi être un fichier XML meshfact ou encore un fichier XML library.
Du Mesh à l'Entité et inversement
Il est facile de passer de l'Entité au mesh en utilisant le code suivant :
csRef<iPcMesh> pcmesh = CEL_QUERY_PROPCLASS_ENT (entity, iPcMesh); iMeshWrapper* mesh = pcmesh->GetMesh ();
Mais vous pouvez aussi repasser du mesh vers l'Entité très facilement, la Couche Physique maintenant un lien :
iMeshWrapper* mesh = ...; iCelEntity* entity = pl->FindAttachedEntity (mesh->QueryObject ());
Mouvement Linéaire
La Classe de Propriété Mouvement Linéaire implémente un système de mouvement gérant la gravité et la détection des collisions mais pas des physics précis.
Détails de la Classe Propriété
- Nom : pclinearmovement
- Factory ID (ID de fabrique) : cel.pcfactory.linmove
- Interface : iPcLinearMovement
- Header (entête): include/propclass/linmove.h
Information générale
- TODO
Timer (Temporisateur)
La Classe de Propriété Timer implémente un simple temporisateur.
Détails de la Classe de Propriété
- Nom : pctimer
- Factory ID (ID de fabrique) : cel.pcfactory.timer
- Interface : iPcTimer
- Header (entête) : include/propclass/timer.h
Information générale
- TODO
Gestionnaire de Zone
Le gestionnaire de zone est une Classe de Propriété très utile pour gérer le chargement des niveaux.
Détails de la Classe de Propriété
- Nom : pczonemanager
- Factory ID (ID de fabrique): cel.pcfactory.zonemanager
- Interface : iPcZoneManager
- Header (entête): include/propclass/zone.h
Information générale
Le gestionnaire de zone est une puissante Classe de Propriété qui gère les chargements dynamiques (chargement des fichiers map requis à un moment donné dans le jeu), mais il peut aussi être utilisé pour le chargement d'une map unique dans le cas de jeux simples. Un scénario communément utilisé est d'installer le gestionnaire de zone avec un fichier de map unique pour la géométrie et un autre fichier pour les descriptions d'Entités.
Concepts
Les concepts suivants sont définis dans le gestionnaire de zone :
- zone
- une zone est une collection de régions qui sont, soit toutes ensembles en mémoire, soit pas du tout.
- region
- une régions est un set de maps. Une région peut consister en de multiples zones, auquel cas ces zones seront chargées quand la région sera active. C'est utile pour des petites régions de transition entre deux grandes régions.
- map
- une map est soit un fichier de monde, soit un fichier de description d'Entité.
Chargement d'un fichier map simple
La méthode iPcZoneManager->Load() qui accepte un chemin VFS et un fichier, accepte à la fois les fichiers de monde Crystal Space normaux ou encore un fichier de description de zone XML. Dans le premier cas le gestionnaire de zone installera automatiquement une région et une zone toutes deux appelées main (principale).
Chargement d'un ensemble de niveau complexe
L'autre cas est celui où vous passez un fichier de description XML à la méthode Load() (bien sûr vos pouvez aussi installer le gestionnaire de zone directement avec les appels API, mais utiliser un fichier de description XML est plus flexible et sans doute plus facile). Voici un exemple d'un tel fichier de description :
<level name="SuperLevel" description="Super Complex Level"> <mount vfs="/sl/part1" real="$*data$/levels$/part1.zip" /> <mount vfs="/sl/part2" real="$*data$/levels$/part2.zip" /> <mount vfs="/sl/part_trans" real="$*data$/levels$/part_trans.zip" /> <mount vfs="/sl/textures" real="$*data$/levels$/textures.zip" /> <region name="part1"> <map name="part1_entities" path="/sl/part1" file="entities.xml" /> <map name="part1_world" path="/sl/part1" file="world" /> </region> <region name="part2"> <map name="part2_entities" path="/sl/part2" file="entities.xml" /> <map name="part2_world" path="/sl/part2" file="world" /> </region> <region name="part_trans"> <map name="part_trans_entities" path="/sl/part_trans" file="entities.xml" /> <map name="part_trans_world" path="/sl/part_trans" file="world" /> </region> <zone name="zone1"> <region>part1</region> <region>part_trans</region> </zone> <zone name="zone2"> <region>part2</region> <region>part_trans</region> </zone> <start> <region>part1</region> <name>Camera</name> </start> </level>
Dans cet exemple, on a créé trois niveaux dans notre programme de modélisation 3D : part1, part2 et part_trans. Le dernier est un niveau de transition qui fait la connexion entre part1 et part2. C'est de préférence un petit niveau, comme un corridor, qui devrait assurer que de part1 vous ne pouvez rien voir de part2 en regardant à travers part_trans (et vice versa). Tout niveau de fichier zip contient un fichier world avec une géométrie et un fichier entities.xml pour la description des Entités.
Pour chaque fichier map (géométrie et Entités), nous avons une région. Finalement on crée deux zones. Les deux contiennent la map transitoire qui est toujours nécessaire. Dès que le joueur entre dans la map transitoire, les deux zones vont être activées et tout sera en mémoire. Si vous voulez éviter cela, alors vous aurez besoin de définir deux maps de transition.
Planeur (Hover)
Cette Classe de Propriété définit un objet planant, lorsqu'elle est utilisée en conjonction avec pcmechobject.
Détails de la Classe de Propriété
- Nom : pchover
- Factory ID (ID de fabrique): cel.pcfactory.hover
- Interface : iPcHover
- Header (entête) : include/propclass/hover.h
Information générale
Un objet planant peut être quelque chose comme un aéroglisseur ou un vaisseau anti-gravité. Tout comme faire planer votre objet, cette classe permettra aussi de l'aligner par rapport au terrain, de façon à ce que s'il descend une colline, le vaisseau s'inclinera en conséquence.
Paramètres PID
La façon dont votre objet corrige sa hauteur peut être réglé en jouant sur trois paramètres nommés p_factor, i_factor et d_factor.
iPcHover->SetAngularBeamOffset (2.0, 3.0, 4.0)
Ceci règlera p_factor sur 2.0, i_factor sur 3.0 et d_factor sur 4.0 - il n'y a aucune formule magique pour ajuster ces valeurs, c'est juste un travail d'intuition et de jeu sur les réglages auquel il faut se plier.
Vous pouvez aussi souhaiter régler la hauteur de survol grâce à iPcHover->SetHoverHeight (réel)
Stopper le survol au-dessus de certains objets
Si vous ne voulez pas que le survol soit possible au dessus d'un objet, placer simplement le drapeau CS_ENTITY_NOHITBEAM sur cet objet.
Vous pouvez désactivez totalement le fait de planer avec iPcHover->HoverOff () et le réactiver avec iPcHover->HoverOn (). Noter que la correction angulaire sera encore active malgré cela (ce qui ne changera rien si vous restez sur le sol).
Correction angulaire
Ceci se réfère à l'objet qui corrige son angle quand il vole au dessus d'un terrain (épouser la pente lorsqu'il vole le long d'une colline).
L'implémentation de ce mécanisme est opéré en calculant la hauteur de l'objet à son centre puis en calculant la hauteur depuis le centre. En utilisant les différences de hauteur et un peu de trigonométrie, vous pouvez voir l'angle de l'objet relatif au terrain.
- iPcHover->SetAngularBeamOffset (réel)
- se réfère à quelle distance du centre de l'objet le second test de hauteur est fait. Les valeurs les plus réduites sont les meilleures sur les terrains les plus accidentés, mais moins précises et plus saccadées, alors que les valeurs plus grandes sont plus à même de faire une approximation (les petites bosses ne seront pas remarquées). Les valeurs comme 0.5 sont en général suffisamment réduites pour suffire.
- iPcHover->SetAngularCorrectionStrength (réel)
- correspond à la vitesse à laquelle l'objet corrige sa rotation. Des valeurs hautes et vous aurez des saccades très rapides, de plus réduites et l'alignement sera très linéaire. 1.0 est le degré normal.
- iPcHover->SetAngularCutoffHeight (réel)
- est la hauteur à laquelle la correction angulaire cesse de fonctionner. De toute évidence, il n'y a aucun intérêt à faire se réaligner un vaisseau par rapport au terrain s'il vole dans les airs.
Langue:
English •
Brazilian •
Chinese •
Deutsch •
Español •
Esperanto •
Français •
Magyar
Translate this page
