Translations of this page:

This is an old revision of the document!
—-

6. L'inventaire

Dans ce cahpitre nous allons nous focaliser sur le fonctionnement de l'inventaire. Comme il va y avoir beaucoup de problème à couvrir, nous devrions aller directement à eux.

D'abord clarifions ce qu'est l'inventaire. Un des aspect typique du jeu d'aventure est la possibilités de collecter diverses ordures qui trainent dans le monde du jeu et de les utiliser avec une autre afin que le joueur atteigne son ultime but, comme sauvez le monde, etc… Aussi parfois vous pourriez vouloir vous venger et utiliser de ces détritus (en parlant des articles de l'inventaire) sur quelque chose dans le monde virtuel.

WME a un excellent support pour l'inventaire incluant les articles combinés et l'article stocké. WME supporte aussi plusieurs inventaires, au cas où vous auriez plus d'un acteur principal ou que vous vouliez intégrer du commerce dans votre jeu.

L'inventaire a deux principaux fichiers de définition:

  1. La définition de la boite d'inventaire - définit l'endroit où votre inventaire sera stocké. Il se compose de zones rectangulaires et de barres de défilement pour naviguer dans votre inventaire.
  2. La définition des articles de l'inventaire – définit les articles individuels et les scripts attachés pour que vous puissiez mettre en place des interactions nécessaires.

Ces deux fichiers sont attribué dans le gestionnaire de projet et nous en avons parlé précédemment. Mais pour vous rappeler, c'est le fichier inventory.def et le fichier items.items. Bien sûr vous pouvez les nommer comme vous voulez, mais restons pour le moment avec les éléments qu'on a sous la main.

Avant de commencer avec ça, copiez quelque part le contenu de la ressource pour le chapitre 5. Il se compose du projet vierge que nous avons vu précédemment et on va, éventuellement, construire un jeu simple sur la base de ces fichiers.

Commençons avec la définition de la boite d'inventaire. Nous allons baser notre interface sur l'image inventory.bmp qui se trouve dans le dossier data/interface. L'image ressemble à ça:

C'est très simple, néanmoins nous pouvons expliquer vaguement y expliquer la mécanique de l'inventaire. Avant de nous plongez dans le fichier de définition lui-même, nous devrions regarder l'image. Nous voyons deux rectangles rouge, que nous ne verrons pas dans notre jeu, car ils servent uniquement à réserver la place pour les touches utilisées dans l'inventaire, défiler vers la gauche ou vers la droite. Puis on vois 10 carré qui seront les emplacements pour nos articles.

Bon avec ça en tête, regardons le fichier inventory.def se trouvant dans le dossier de l'interface.

INVENTORY_BOX 
{ 
  ITEM_WIDTH = 65 
  ITEM_HEIGHT = 65

Ce sont les dimensions de chaque articles et elles correspondent au dimensions de chaque carré de la boite d'inventaire.

SPACING = 10

Ceci défini à quelle distance sont chaque carré (articles). Cette valeur est en pixels.

  SCROLL_BY = 1

Quand le joueur sur le bouton précédent ou suivant, les articles se deplace respectivement vers la gauche ou vers la droite. Cette valeur spécifie combien d'article seront déplacé (1 par 1, 2 par 2…)

  HIDE_SELECTED = TRUE

Si le joueur sélectionne un article de l'inventaire, il disparait de la boite d'inventaire (pour empêcher d'utiliser l'article sur lui même par exemple).

AREA { 30, 12, 770, 77 }

AREA définit la zone des articles de l'inventaire. C'est relatif à la fenêtre d'inventaire, pas à l'écran. Donc même si vous souhaitez afficher l'inventaire en bas, ces valeurs restent les mêmes. Ces valeurs sont les coordonnées X,Y du coin supérieur gauche et les coordonnées X,Y du coin inférieur droit de la fenêtre d'inventaire. En d'autres termes, les coordonnées (30,12) correspondent au coin supérieur gauche du premier article et (770,77) correspondent au coin inférieur droit du 10e article de l'inventaire.

  EXCLUSIVE = FALSE

Si c'est réglé sur TRUE, le joueur ne peut rien faire d'autre tant qu'il n'a pas fermé la fenêtre d'inventaire.

Maintenant arrive la définition de la fenêtre proprement dit. Notez que notre prochain chapitre traitera des fenêtres et des contrôles plus largement, mais nous allons présenter ici ce qui doit être expliqué.

  WINDOW 
  { 
    X = 0 
    Y = 0 
    WIDTH = 800 
    HEIGHT = 90

Nous commençons par définir la position et les dimensions de la fenêtre. Ces nombres sont absolus, donc contrairement à AREA, elle font référence à l'écran. Notre fenêtre sera positionnée en haut de l'écran et fera 800 pixels de large et 90 pixels de haut. Si nous avions voulu positionner cette fenêtre en bas de l’écran (800x600), nous aurions simplement passer Y à 510 (600-90).

IMAGE = "interface\inventory.bmp"

L'image de fond qui sera utilisée pour l'inventaire - Nous l'avons déjà vu plus-haut.

    BUTTON 
    { 
      TEMPLATE = "ui_elements\template\but.button" 
      NAME = "prev" 
      TEXT = "<" 
      X = 0 
      Y = 0 
      WIDTH = 30 
      HEIGHT = 90 
    } 
 
    BUTTON 
    { 
      TEMPLATE = "ui_elements\template\but.button" 
      NAME = "next" 
      TEXT = ">" 
      X = 770 
      Y = 0 
      WIDTH = 30 
      HEIGHT = 90 
    }

Arrive maintenant la définition des deux boutons. Pour que l'inventaire fonctionne correctement, ils doivent être nommé prev pour le défilement à gauche et next pour le défilement à droite dans la boite de l'inventaire.
TEXT est ce que nous allons écrire sur le bouton (dans notre cas < et >). X,Y,WIDTH et HEIGHT définissent les dimensions et la position, ils doivent couvrir les zones rouges. Notez que la position est à nouveau relative à la fenêtre parent.
TEMPLATE c'est le modèle de bouton. Nous verrons ça dans le chapitre des fenêtres, pour l'instant, utilisons celui par défaut.

  }

Nous terminons le bloc WINDOW.

}

Nous terminons le bloc INVENTORY_BOX

Ok, voyons à quoi ressemble notre inventaire. Ouvrez le fichier game.script et avant

Game.ChangeScene("scenes\Room\Room.scene");


mettez

Game.InventoryVisible = true;


Bien, c’était pas trop dur, n'est ce pas? Lancer le jeu et regardez l'inventaire en haut.

La prochaine étape dans la découverte de l'inventaire sera la définition des articles. Pour que les articles soit bien utilisés dans le jeu nous devons définir leurs bloc de données (datablock). Ces datablock apparaissent dans e fichier items.items et nous les avons dans le répertoire data/items. Jusqu'à présent notre fichier ressemble à ceci:

ITEM 
{ 
   CURSOR_COMBINED = TRUE // Défini si vous voyez pas seulement l'article mais aussi le pointeur standard quand vous avez sélectionnez l'article. 
 
   CAPTION = "WME User's Guide"  // Légende de l'article quand la souris passe par dessus. 
 
   NAME = "book"  // Nom dans le jeu. Vous ferez référence a celui-ci dans vos scripts 
 
   SPRITE = "items\book.bmp"  // Image ou sprite de l'article dans l'inventaire. 
 
   CURSOR = "items\book.bmp" // image pointeur (sprite) quand vous avez sélectionné l'article. 
 
   CURSOR_HOVER = "items\book_h.bmp"  // Défini une image à utiliser comme pointeur de souris quand cet article est sélectionné et est sur un hot-spot actif.. 
 
   SCRIPT = "items\book.script" // Script attaché à l'article qui contient les interactions. 
}

Nous pouvons évidemment définir d'autre paramètres pour l'article:

SPRITE_HOVER – Quand la souris passe au dessus de l'image de l'inventaire elle peut changer pour une autre.
ALPHA – Spécifie la transparence de l'image de l'article (0 = invisible, 255 = Complétement visible)
TALK - l'animation de parler pour cet article.
FONT - quelle police doit être utilisée pour les sous-titres et pour afficher la quantité.
AMOUNT - Quantité actuel d'articles
DISPLAY_AMOUNT – (TRUE / FALSE) si le la quantité actuelle d'article devrait être affichée?
AMOUNT_ALIGN - L'alignement de l’étiquette quantité ("left"(gauche), "right"(droite) ou "center"(centré))
AMOUNT_OFFSET_X - Le décalage en X en pixels de l’étiquette quantité relatif à la position de l'article.
AMOUNT_OFFSET_Y - Le décalage en Y en pixels de l’étiquette quantité relatif à la position de l'article.

Nous sommes, maintenant, capable de définir notre inventaire et chaque articles et regardons la façons de lier les articles avec le jeu actuel.

Comme je l'ai déjà écrit, il y a deux façon d'aborder l'inventaire - Globale (Un inventaire pour tout le jeu) et basé sur l'acteur - Chaque acteur a son propre inventaire.

Faisons e sorte que notre première interaction avec l'article arrive. Qu'allons nous faire là? - Nous plaçons un article (Livre) dans la scène. dès que qu'il y un clic gauche de notre souris sur cet article et qu'il est ramassé. L'article disparait de la scène et apparait dans l'inventaire.

  • ouvrir notre salle dans l'éditeur de scene.
  • Ajouter un élément Sprite et choisir le fichier data\items\book.bmp comme fichier graphique
  • Comme légende et nom écrire Book
  • Dans le champ Item écrire book (en minuscule)
  • Attacher un script a cet élément (Vous devriez déjà etre familiarisé avec cette façon de faire, ou retournez au chapitre précédent)
  • Remplir dans Walk to: et régler la direction en fonction de la position de votre livre.

Nous devrions avoir le resultat suivant :

Sauvegardez la scène et ouvrir le fichier appelé book.script dans votre répertoire data\scenes\Room\scr.

Écrivez dedans ce qui suit:

on "LeftClick" 
{ 
	actor.GoToObject(this); 
	Game.TakeItem("book");	 
}

Sauvegardez et test le jeu. Cool, Molly va vers le livre et le place dans l'inventaire! Le livre a également disparu. Mais pourquoi?

Si nous remplissons la valeur de Item avec le nom correspondant au fichier items.items, il devient liée donc à chaque fois que nous appelons la méthode TakeItem, il disparait et chaque fois que nous appelons DropItem il réapparaît. Modifions notre petit script pour démontrer cela:

on "LeftClick" 
{ 
	actor.GoToObject(this); 
	Game.TakeItem("book");	 
	actor.GoTo(100,100); 
	Game.DropItem("book"); 
}

Pas très logique cette façon de jouer, hein? Mais ça montre ce que je veux dire. Quelque fois c'est bien de détruire complétement l'article, par exemple si on veut combiner deux articles pour en faire un ou si nous utilisons l'article et que le joueur ne veuille pas avoir la possibilité de le récupérer. Pour cela nous avons en stock la méthode DeleteItem.

Avant de nous pencher un peu plus dans la manipulation d'objets, regardons l'élément dans l'inventaire. Nous savons, que dans items.items il y a un script lié à lui. C'est le fichier, qui prend en charge l'élément quand il arrive dans l'inventaire. Ce n'est pas limitée à une seule scène comme notre script précédent était et ainsi nous devrions compter sur le fait que le joueur voudrait essayer d'utiliser cet élément n'importe où dans le jeu. Ce serait vraiment pénible de créer des réponses individuelles pour chaque hot-spot donc en gros nous voulons avoir des réponses uniques pour des choses logiques et certaines génériques "ça n'a aucun sens d'utiliser ce livre ici." pour les autres hot-spots

Restaurer book.script à sa version originale (sans le lacher d'article) et ouvrez data\items\book.script. Et modifiez le contenu pour avoir:

on "LeftClick" 
{ 
    Game.SelectedItem = "book"; 
}

Cette simple ligne signifie, que nous assignons l'article de l'inventaire comme l'article actif et ainsi tout les clics de souris "utiliserons" cet article dans l'environnement du jeu. si SelectedItem est Null, Nous n'avons rien de selectionné et donc les actions du pointeur normal s'applique.

Testez le jeu et vous pouvez voir, que si nous sélectionnons le livre dans l'inventaire, nous pouvons l'utiliser ailleurs, mais nous devons nous débarrasser de lui. Comme nous allons maintenant construire l'action générique, nous allons décidé que si nous faisons un clic droit avec l'article sélectionné, nous remettons cet article dans la boîte de l'inventaire.

Alors comme c'est une action génériques pour l'ensemble du jeu, ouvrez scripts/game.script et ajouter un événement RightClick, qui va s'occuper de ce problème.

on "RightClick" 
{ 
  if (Game.SelectedItem != null){ 
    Game.SelectedItem = null; 
  } 
}

En fait, nous vérifions seulement si nous avons choisi un objet et si oui, nous le retournons dans l'inventaire.

Jusqu'ici tout va bien et maintenant nous allons présenter le gros changement à notre salle. Nous allons introduire le nouveau personnage, qui s'appelle Sally. Elles sont jumelles donc elles partage les mêmes graphiques. :P

Aller dans le répertoire des acteurs et copiez le fichier molly.actor en sally.actor et molly.script en sally.script.

Dans molly.actor changez le début pour que ça ressemble à :

  NAME = "molly" 
  CAPTION="Molly" 
  SCALABLE = TRUE 
  INTERACTIVE = TRUE 
  X = 100 
  Y = 100 
  SCRIPT="actors\molly\molly.script"

Dans sally.actor changez le début pour que ça ressemble à :

  NAME = "sally" 
  CAPTION="Sally" 
  SCALABLE = TRUE 
  INTERACTIVE = TRUE 
  X = 460 
  Y = 400 
  SCRIPT="actors\molly\sally.script"

Ouvrez data\scripts\base.inc et ajoutez les lignes

global molly; 
global sally;

Ensuite ouvrez le fichier game.script et ajoutez un nouvel acteur juste après avoir chargé le premier:

// load our main actor 
molly = Game.LoadActor("actors\molly\molly.actor"); 
sally = Game.LoadActor("actors\molly\sally.actor"); 
actor = molly; 
Game.MainObject = actor;

Enfin ouvrez data/scenes/Room/scr/scene_init.script et modifiez le début pour que ça ressemble à ça:

#include "scripts\base.inc" 
 
molly.SkipTo(400, 400); 
molly.Direction = DI_DOWN; 
molly.Active = true; 
 
sally.SkipTo(100, 400); 
sally.Direction = DI_DOWN; 
sally.Active = true;

Now what we’ve done is that we’ve created another actor named Sally which uses the same graphics as a Molly, but it’s entirely different person. We have her reference stored in the global variable actor2 and we’ve placed her in our Room scene. Next thing we’re going to do is that we’re going to implement a neat character switching.

If player clicks on Molly or Sally (without an inventory item selected) game gives control to the second actor.

Now remember that everything in our scripts is set to use the global variable “actor”. So if we want to implement character switching, we simply set this variable to character of our liking. Also we have to change the Game.MainObject because it drives the screen scrolling and we want to maintain this functionality as well. So let’s open the file molly.script in the actor folder and add here the LeftClick handler:

on "LeftClick" 
{ 
	if (Game.MainObject == molly) actor.Talk("I am already selected!"); 
	else 
	{ 
		actor = molly; 
		Game.MainObject = actor; 
	} 
}

Analogically we’ll modify the sally.script to read:

on "LeftClick" 
{ 
	if (Game.MainObject == sally) actor.Talk("I am already selected!"); 
	else 
	{ 
		actor = sally; 
		Game.MainObject = actor; 
	}	 
}

Although we could use single file for this, later on it pays off to have those separated when we want to perform different tasks with each actor.

Now run the game and note that we can switch between actors by simple Left Click on them.

Having this done, we’ll return to our inventory and we try some interactions. First thing what we need to do is open our trusty game.script and actually code in the generic logic of inventory item interaction. What we want to achieve is that whenever we left click with a selected item on a hotspot, we try to call the corresponding method named by an item name. So if we click with a book, we’d try to call a method “Book” of the target entity.

This can be easily done by modifying the Left Click event to read:

on "LeftClick" 
{ 
  var ActObj = Game.ActiveObject; 
  if(ActObj!=null) 
  { 
    if(Game.SelectedItem != null && Game.SelectedItem!=ActObj) 
    { 
      var Item = Game.SelectedItem; 
      if(ActObj.CanHandleEvent(Item.Name)) ActObj.ApplyEvent(Item.Name); 
    } 
    else 
	     ActObj.ApplyEvent("LeftClick"); 
  } 
  else 
  { 
    Scene.ApplyEvent("LeftClick"); 
  } 
}

What are we programming here is the fact, that if we have selected inventory item and we’re not clicking with this item on itself (which would be applicable if we didn’t “hide” the inventory item upon selecting), then we test if the target hotspot can handle the event by the name of our item and if so, this event is fired.

Take some time to think about this concept and when you’re sure you understand it, read up.

Now in our case we have two active objects on the screen (provided that you already picked up the book) - Molly and Sally. So our goal is to make them react to the book usage.



Let’s start with the concept. We want the following: if Molly is active and reads a book, she should be able to read the book. If however you try to read a book with Sally while Molly is active, Sally refuses. The same applies vice versa.

Let’s open molly.script first and add the following code:

on "book" 
{	 
	if (actor == molly) actor.Talk("It's always important to read WME documentation! I'll do it now!"); 
	else 
	molly.Talk("Read it yourself Sally!"); 
}

Then open the sally.script and write there the following:

on "book" 
{	 
	if (actor == sally) actor.Talk("It's always important to read WME documentation! I'll do it now!"); 
	else 
	sally.Talk("Read it yourself Molly!"); 
}

Again it’s very simple logic. If actor variable containing the active actor is set to the clicked actor, we read the documentation or we say the other line. The event “book” is called because we modified the game.script to do this. Clear as mud?

Now we have one illogical thing. It doesn’t matter who picks up the book, both have the book in the inventory. This is the global inventory approach and it’s ok if we have one actor on the stage. But as we’ve introduced two actors, we should separate their inventories.

We’re going to try the following scenario. Whoever picks up the book will get it in his personal inventory. If this person use the book on the other character, she gives the book to the other.

We’re going to introduce new Game attribute called InventoryObject. This attribute accepts the actor variable and we’re going to modify the actor scripts that together with the actor switching also the inventory object gets switched.

But it’s not enough. We also no longer use Game.TakeItem (Game.DropItem, Game.DeleteItem etc.) but we’ll use actor.TakeItem (actor.DropItem, actor.DeleteItem).

So our first stop is in game.script in our too familiar place:

actor = molly; 
 
Game.MainObject = actor; 
Game.InventoryObject = actor;

Next stop is in data\scenes\Room\scr\book.script:

on "LeftClick" 
{ 
	actor.GoToObject(this); 
	actor.TakeItem("book");	 
}

And our last stop for now is molly and sally script adding in the Left Click handler of both this line:

Game.MainObject = actor; 
Game.InventoryObject = actor;

Now when you test the game, you see, that those girls have separate inventories and moreover who grabs the book, has it.

Now let’s handle the book giving:

sally.script

on "book" 
{	 
	if (actor == sally) actor.Talk("It's always important to read WME documentation! I'll do it now!"); 
	else 
	{ 
		Game.SelectedItem = null; 
 		molly.DropItem("book"); 
		sally.TakeItem("book");	 
		sally.Talk("Thank you"); 
	} 
}

If we clicked by Molly with a book on Sally, we first put away the item (SelectedItem = null), then Molly drops the book and Sally takes it. This way the item gets transferred. At the end Sally thanks Molly for the book. If we didn’t call the DropItem method, both girls would have the book in their inventories.

Molly script is almost the same:

on "book" 
{	 
	if (actor == molly) actor.Talk("It's always important to read WME documentation! I'll do it now!"); 
	else 
	{ 
		Game.SelectedItem = null; 
		sally.DropItem("book"); 
		molly.TakeItem("book");	 
		molly.Talk("Thank you"); 
	} 
}

Last couple of methods closing this chapter are dealing with the additional item methods.

Game.IsItemTaken([item name]); returns true if anyone has an item in his/her inventory.

If we want to check specific inventory for item, we’d query it through sally.HasItem([item name]); and again this method returns true or false.
(So in praxis Game.IsItemTaken("book"); or sally.HasItem("book");)

That’s enough for the items apart from the important tip. Sometimes you don’t need an actor for a NPC as it can be for example only a shadow or a head mounted on the wall. WME doesn’t limit you by that and so even entities can have their inventories!

Documentation link:
Contents→ Inside a game→ Working with the inventory - for the general description of the inventory work

 
fr/wmebook/ch6.1319108584.txt.gz · Last modified: 2011/10/20 13:03 by Anto0085
Recent changes RSS feed Creative Commons License Driven by DokuWiki