Ceci est la troisième et dernière partie du tuto publié dans ce même forum
Je vous rappelle que nous pouvons inclure des paramètres lors de la construction d'un bâtiment sur la carte.
C'est ce que je vous propose de développer maintenant.
Les paramètres de construction
------------------------------
Je vous ai dit, au début de ce tuto qu'il était possible d'utiliser des paramètres de construction. Cela se fait avec la liste "params = {}".
Lorsqu'on programme des paramètres dans cette liste, une boîte de dialogue s'ouvre lorsqu'on place la construction sur la carte et lorsqu'on veut modifier une construction déjà placée.
Chaque paramètre est lui-même constitué d'une liste comprenant les éléments suivants:
{ key = "xxxx" où xxxx est le nom utilisé pour la variable de ce paramètre
name = _("nom") où nom est le titre qui apparaîtra dans la boîte de dialogue
values = {_("val1"),_("val2"),...,_("valn")} est une liste de valeurs qui apparaissent dans la boîte de dialogue et que le joueur peut sélectionner.
defaultIndex = x où x est le numéro d'ordre de la liste des valeurs et qui sera mis en surbrillance par défaut dans la boîte de dialogue.
}
On peut utiliser autant de paramètres que l'on veut, mais sachez que plus il y en a plus cela pourrait devenir confus dans l'esprit du joueur.
Tout comme pour les noms utilisés dans le jeu, je vous conseille de traduire les mots qui apparaissent dans la boîte de dialogue afin d'en faciliter la compréhension par le joueur.
Je vous expliquerai en annexe 1 comment procéder pour traduire les mots. Sachez déjà que le principe est d'utiliser la syntaxe : _("mot") pour pouvoir traduire ce mot dans le fichier "strings.lua".
Dans notre construction, je vais donner la possibilité aux joueurs de pouvoir choisir le nombre de clients qui fréquenteront, par mois, notre commerce.
Ils pourront également choisir si la rue latérale peut être reliée d'un seul côté ou des deux côtés. Avec un seul côté, les véhicules devront faire demi-tour en haut de la rue alors qu'avec une liaison avant-arrière, ils pourront poursuivre leur route.
Ils pourront aussi relier le haut de ce segment de route à un dépôt de marchandises.
Une remarque à ce sujet.
Si le joueur sélectionne l'option "avant-arrière" le segment de rue restera même si le bâtiment principal est détruit.
En outre, il faudra détruire ce segment avant d'apporter une modification à une construction existante sinon le programme dira qu'il y a collision.
Tout se passe donc comme si ce segment de route appartenait au réseau routier et non plus à la construction.
Cela ne se produit pas si l'option "avant uniquement" est choisie.
Le joueur pourra aussi choisir entre 3 types de marchandises ou pas de marchandise du tout (Denrées alimentaires, matériaux de construction, outils ou aucune marchandise)
Enfin, il choisira la quantité annuelle maximale de marchandises pouvant entrer dans ce magasin (très faible, faible, moyenne, élevée, très élevée).
Voici comment procéder:
params =
{
{
key = "nbpeople",
name = _("Monthly attendance"),
values = {_("100"),_("500"),_("1000"),_("2500")},
defaultIndex = 3,
},
{ key = "nbentrees",
name = _("Points d'entree"),
values = {_("avant uniquement"),_("avant et arriere")},
defaultIndex = 0,
},
{ key = "cargotype",
name = _("Cargo type"),
values = {_("None"),_("Food"),_("Tools"),_("Goods"),_("Construction material")},
defaultIndex = 1,
},
{ key = "nbcargo",
name = _("Cargo per year"),
values = {_("TFaible"),_("Faible"),_("Moyen"),_("Eleve"),_("TEleve")},
defaultIndex = 3,
},
},
Alles anzeigen
Maintenant que nous avons défini nos paramètres, comment les utiliser?
Cela se fait dans updateFn:
updateFn = function(params)
local numpeople = 0
local numentree = 0
local capacount = 0
local idmdl = ""
local cartype = "NONE"
if (params.nbpeople == 0) then
numpeople = 100
elseif (params.nbpeople == 1) then
numpeople = 500
elseif (params.nbpeople == 2) then
numpeople = 1000
else numpeople = 2500
end
if (params.nbentrees == 0) then
numentree = { 1 } -- les voitures et le bus entrent et sortent uniquement par avant du bâtiment
else numentree = { 1,0 } -- les voitures et le bus entrent par l'avant et ressortent par l'arrière du bâtiment
end
if (params.nbcargo == 0) then
capacount = 50
elseif (params.nbcargo == 1) then
capacount = 100
elseif (params.nbcargo == 2) then
capacount = 500
elseif (params.nbcargo == 3) then
capacount = 1500
else capacount = 3000
end
if (params.cargotype == 1) then
idmdl = "industry/cargo/food_small.mdl"
cartype = "FOOD"
elseif (params.cargotype == 2) then
idmdl = "industry/cargo/tools_small.mdl"
cartype = "TOOLS"
elseif (params.cargotype == 3) then
idmdl = "industry/cargo/goods_small.mdl"
cartype = "GOODS"
elseif (params.cargotype == 4) then
idmdl = "industry/cargo/construction_materials_small.mdl"
cartype = "CONSTRUCTION_MATERIALS"
else cartype = "NONE"
end
Alles anzeigen
Je définis 4 variables locales qui me serviront dans la suite de mon script:
numpeople = 0 -- variable de type integer qui contiendra le nombre mensuel de clients
-- cette variable sera utilisée dans result.personCapacity
numentree = {} -- variable de type list qui contiendra les noeuds (snapNodes) de liaison du segment de route latérale
-- variable utilisée dans result.edgeLists
capacount = 0 -- variable de type integer qui définit le nombre annuel de marchandises
-- variable utilisée dans constructionutil.makeStocks
idmdl = "" -- variable de type string qui contiendra le chemin d'accès au fichier modèle de la marchandise stockée
-- variable utilisée dans result.models
cartype = "NONE" -- variable de type string qui définira le type de marchandise
-- variable utilisée dans constructionutil.makeStocks
Vous pouvez voir le script complet dans le fichier lidl.con du module ML_Tuto2_1 que vous avez certainement déjà téléchargé sur ce site.
Vous pouvez l'utiliser tel quel ou le modifier à votre guise!
Ici se termine le tuto.
On pourrait aller encore plus loin, par exemple en ajoutant des arrêts de bus sur le parking de ce magasin. Cela a été développé dans mon tuto 1 ("Création d'arrêts de bus dans une station") que vous retrouverez ici:
https://www.transportfever.net…?postID=262884#post262884
On pourrait aussi créer un dépôt de marchandises afin d'éviter de devoir placer un dépôt à proximité. Cela fera l'objet d'un autre tutoriel.
Annexe 1 : Le fichier strings.lua
L'avantage de TF c'est de pouvoir traduire les mots importants qui apparaissent dans le jeu, les menus et même dans la descriptions des mods.
Cela se fait avec un fichier appelé "strings.lua" situé dans la racine du mod.
Chaque fois que le programme rencontre une valeur de type _("mot"), il regarde d'abord dans sa base de données standard si ce mot existe et le traduit dans la langue du joueur.
Si ce mot n'existe pas, il regarde dans ce fichier strings.lua et si ce fichier n'existe pas ou que ce mot n'y est pas repris, alors il affiche le "mot" directement.
Pour ma part, j'utilise toujours un fichier strings.lua qui comporte un dictionnaire de 3 langues:
le Français (Fr), qui est ma langue maternelle, l'Anglais (En) et l'Allemand (De).
Rien ne vous empêche d'en utiliser d'autres.
Ouvrez le fichier "strings.lua" de ce tuto (ML_tuto2_1) que vous pouvez télécharger sur ce site et vous comprendrez aisément comment on procède pour créer des dictionnaires.
Annexe 2 : Transformation d'un modèle au moyen d'une matrice 4x4
Je vais vous expliquer comment le jeu TF (et d'autres jeux qui utilisent les objets en 3D) emploie les matrices 4x4 pour effectuer toutes sortes d'opérations sur les objets en 3 dimensions.
Je vais faire appel à des notions de mathématiques assez pointues, mais si cela vous rebute, retenez uniquement les grandes lignes de ce qui va suivre.
Un objet en 3 dimensions, comme une construction par exemple, est construit au moyen d'un programme de modélisation 3D (par exemple, Blender).
Chaque point de l'objet est placé dans un repère orthonormé euclidien à 3 dimensions (x,y,z) qui sont les coordonnées de ce point dans l'espace.
Dans TF, ce sont les fichiers .mdl qui gèrent ces objets.
Une fois qu'un objet est réalisé et programmé dans l'un de ces fichiers, il nous est toujours possible de les manipuler: les faire tourner, les déplacer ou encore modifier leurs dimensions.
Mais vous comprenez bien que s'il fallait modifier chaque point un à un, ce serait trop fastidieux.
Alors, on utilise une matrice que le programme va exploiter automatiquement pour tous les points de l'objet afin que chaque point soit manipulé de la même façon.
Par exemple, si on veut faire tourner l'objet sur lui-même de 90 degrés, on crée une matrice qui fait cela et on applique cette matrice sur chacun des points de l'objet.
Donc une seule programmation pour des miliers de points!
Mais c'est quoi une matrice?
C'est un tableau de valeurs que l'on représente entre deux grands crochets (ou parenthèses).
Exemple de la matrice A comportant 2 lignes et 3 colonnes appelée aussi matrice 2x3:
A=
| 1 0 -7 |
| 2 5 3 |
Cette matrice comporte donc 6 éléments (3x2) appelés aussi coefficients.
Chaque élément de la matrice représente une information, par exemple une valeur ou la position d'un objet.
Ces éléments peuvent alors être traités facilement dans un programme informatique.
On peut réaliser différentes opérations sur ces éléments (addition, soustraction, multiplication, etc...)
Puisqu'il faut 3 coordonnées (x,y,z) pour définir un point dans l'espace, on pourrait se dire qu'une matrice 3x3 serait suffisante. Et bien non, car pour pouvoir programmer correctement un objet, nous avons besoin d'une dimension supplémentaire (w) afin de traiter les translations.
Une translation est le déplacement d'un point vers un autre endroit de l'espace. C'est un vecteur qui possède une direction et une dimension.
Regardez l'exmple ci-dessous (Fig. 6)
J'ai représenté l'espace euclidien avec ses 3 axes de coordonnées (x,y,z). Ces axes définissent l'orientation de mon espace avec son origine commune et ses 3 directions.
Le point "a" se situe aux coordonnées (-3,0,2) et le point "b" aux coordonnées (3,4,0). Le vecteur V qui a son origine au point a et son extrémité au point b possède une direction symbolisée par la flèche et une dimension qui est la longueur du segment entre le point a et le point b.
Je vais vous expliquer comment on peut utiliser une matrice pour réaliser ce déplacement.
Avec une quatrième coordonnée (w), on parle de coordonnées homogènes et on obtient une transformation "affine" lorsque cette coordonnée est égale à 1.
Cela veut dire que les objets qui composent la construction héritent des valeurs de leurs parents. Ainsi, si l'on change la position d'un élément appartenant à un groupe d'objets, on change également la position de toutes les structures qui composent ce groupe.
Pour passer des coordonnées euclidiennes d'un point P(x,y,z) aux coordonnées homogènes P(x,y,z,w) il suffit de poser w=1. Nous avons donc P(x,y,z,1).
(Si w = 0 alors les points sont situés à l'infini).
Voilà pourquoi on utilise une matrice 4x4 c'est-à-dire qui comporte 4 lignes et 4 colonnes.
Pour manipuler les objets 3D en informatique, on utilise, une matrice 4x4, c'est-à-dire un tableau d'éléments qui comporte 4 lignes et colonnes:
M=
| M11 M12 M13 M14 |
| M21 M22 M23 M24 |
| M31 M32 M33 M34 |
| M41 M42 M43 M44 |
M11 est l'élément M de la ligne 1 et colonne 1
M12 est l'élément M de la ligne 1 et colonne 2
...
M34 est l'élément M de la ligne 3 et colonne 4
etc...
Puisque nous voulons avoir des coordonnées homogènes la dernière ligne doit comporter les éléments 0 0 0 1
Donc la matrice M devient:
M=
| M11 M12 M13 M14 |
| M21 M22 M23 M24 |
| M31 M32 M33 M34 |
| 0 0 0 1 |
- -
Dans TF on écrit cette matrice dans une liste:
transf = {M11,M12,M13,M14,M21,M22,M23,M24,M31,M32,M33,M34,0,0,0,1}
Lorsque le modèle inscrit dans le fichier .mdl est utilisé tel quel, c'est-à-dire sans transformation, alors la matrice 4x4 a la structure suivante:
M=
| 1 0 0 0 |
| 0 1 0 0 |
| 0 0 1 0 |
| 0 0 0 1 |
ou transf = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}
Vous remarquerez que les éléments de la diagonale allant de M11 à M44 ont pour valeur 1 et les autres 0. Cela veut dire que le modèle est de même taille que son original et est positionné exactement comme il a été défini dans le fichier .mdl.
Les valeurs contenues dans la première ligne correspondent à l'axe des X, celles de la seconde ligne à l'axe des Y et celles de la troisième ligne à l'axe des Z.
Les valeurs de la quatrième ligne ne changent pas dans TF de manière à garder les coordonnées homogènes d'une transformation affine.
On peut effectuer des modifications du modèle original en modifiant la matrice M.
Par exemple, si on attribue la valeur 2 à M11, l'objet sera 2 fois plus grand dans sa largeur (axe des X). C'est pareil si on change M22, on modifiera la longueur (axe des Y) et si on change M33 (axe des Z), on modifiera la hauteur de cet objet.
Si on veut déplacer un modèle, on modifiera les valeurs x,y,z de la quatrième colonne (M14,M24,M34)
Par exemple, si M14 = 5, le modèle se déplacera de 5 unités (5 mètres dans TF) par rapport à son point de départ dans le sens de l'axe des X (puisque nous utilisons une valeur positive).
On peut aussi faire tourner le modèle autour de n'importe quel axe.
Dans mon tuto j'ai fait tourner de 90° le modèle "food_small.mdl" de manière à voir l'empilement des caisses de marchandises correctement par rapport au bâtiment principal.
Donc j'ai fait tourner de 90° le modèle dans le sens des aiguilles d'une montre (signe négatif) par rapport à l'axe vertical Z.
Pour cela, la valeur M11 est 0 et la valeur M12 est -1.1
Je vous égargnerai les calculs effectués pour arriver à ce résultat car cela fait appel à la trigonométrie (sinus et cosinus d'angle).
En plus, comme j'ai agrandi de 10 % le modèle(1.1 pour les valeurs M11,M22,M33), et que le modèle a été déplacé par rapport à son point d'origine (M41=17,M42=4 et M43=0.5), il y a donc 3 transformations qui interviennent dans ce modèle.
On doit alors faire appel au produit matriciel pour obtenir les valeurs de ces transformations.
Heureusement, il existe un utilitaire en ligne réalisé par Xanos pour TF qui calcule toutes les transformations à votre place en un clin d'oeil! (merci à lui).
Voici le lien : http://ftp.train-fever.net/transformation/
Je reprends, à titre d'illustration, le calcul de la translation d'un point "a" vers le point "b" (comme expliqué plus haut à la Fig 6).
Sur cette figure, vous voyez que le point a(-3,0,2) est déplacé vers le point b(3,4,0). Quelle est la matrice M qui permet de faire cette translation?
b = M * a
b = M * a
|3| |1 0 0 6 | |-3|
|4| |0 1 0 4 | | 0|
|0| |0 0 1-2 | | 2|
|1| |0 0 0 1 | | 1|
Pour l'axe des X (M14) nous avons une translation de -3 à + 3, soit +6
Pour l'axe des Y (M24) nous avons une translation de 0 à +4, soit +4
Pour l'axe des Z (M34) nous avons une translation de 2 à 0, soit -2
Comme il n'y a pas de modification de la taille, la diagonale M11,M22,M33 reste avec la valeur 1.
La dernière ligne reste toujours inchangée afin de respecter la transformation affine et les autres éléments de la matrice restent à 0 puisqu'il n'y a pas de rotation.
Voilà qui termine ce long tuto.
J'espère avoir été clair et que vous pourrez, vous aussi, effectuer des modifications de constructions.
Merci de votre attention.
Michel Lacoste.