• 23 Avril 2025, 11:26:32


Auteur Sujet: [TUTO]Système d'inventaire  (Lu 4317 fois)

0 Membres et 1 Invité sur ce sujet

Hors ligne CarCrasher

  • *
  • Tueur en série
  • Messages: 144
    • Voir le profil
[TUTO]Système d'inventaire
« le: 20 Mars 2014, 13:04:01 »


Bonjour bonjour !

Aujourd'hui, je vous propose de créer un de mes scripts bien aimé, mon système d'inventaire.

Pour suivre ce tutoriel, je vous recommande de connaitre un minimum le pawn, de pas bêtement copier sans rien comprendre, c'est pour cela que je ne posterais aucun script complet, pour obliger les petits malins à lire jusqu'au bout ! :wink:
J'essayerai d'expliquer un maximum tout ce qui me semble être utile à savoir pour comprendre le script, et j'introduirai des petits conseils ! Mais bon, ça n'en reste jamais qu'un premier tuto, alors par pitié, ne mettez pas encore le feu à ma maison :sad:

Ce système d'inventaire ressemblerait à ceci une fois terminé :



Ainsi, comme vous pouvez le voir, ce système ne comporte qu'une seule place, il n'est donc peut-être pas adapté à tous les serveurs, mais comme c'est du script, et que je l'espère, vous n'allez pas bêtement copier-coller, vous saurez le personnaliser à votre goût !

Ouvrons donc notre Nouveau fichier, GameMode, notre Filterscript, ou, créons donc une include !

Comme vous pouvez le voir, dans le screenshot précédemment donné, le système "visuel" est basé sur 3 textdraws. Le premier, le texte "Inventaire", est le seul textdraw fixe. Les deux textdraws suivants sont l'image de l'objet ainsi que son cadre, et le nom de l'objet, ces deux derniers sont donc dynamiques (Ce serait pas très pratique un inventaire qui ne pourrait que supporter un hamburger !

Créons alors nos variables...

Code: ("Pawno") [Sélectionner]
new Text:InventTitre;
new Text:InventObjet[MAX_PLAYERS];
new Text:InventNom[MAX_PLAYERS];

Grâce à notre incroyable pouvoir de déduction (Et de lecture), on sait déterminer quelle variable correspondra à quel TextDraw :biggrin:

Si vous avez lu, vous constaterez que les deux dernières variables sont des tableaux de variables ! Mais lorsqu'on jette un coup d'oeil sur les limites de SA-MP, on peut voir que le maximum de TextDraws est fixé à 2048 ! Ca en fait déjà 1001 ! Mais non ! MAX_PLAYERS est défini dans a_samp.inc comme 500, étant le nombre maximum de joueurs... Mais on peut changer les defines (C'est d'ailleurs pour cela qu'on n'écrit pas directement le nombre dans le code, comme ça, si on veut changer, on peut le faire en un clin d'oeil !).

Donc ouvrez donc a_samp.inc (\pawno\include) et trouvez la ligne (J'espère que vous en serez capables !) et changez le 500 en la limite de joueurs de votre serveur ! Bah oui, pourquoi créer plus de variables qu'il n'en faut après tout ?

Revenons à nos TextDraws, maintenant que j'ai déclaré mes variables, que fais-je ? Oignon, je suis perdu, guidez-moi, soyez le phare dans la nuit de mon ignorance :laugh:

Créons donc nos TextDraws, pour cela, allons donc dans notre chère amie la callback OnGameMode(FilterScript)Init() :

- Vu qu'on aime la facilité, commençons par créer notre entête, "Inventaire" :

Code: (pawn) [Sélectionner]
        InventTitre = TextDrawCreate(520.000000, 200.000000, "Inventaire");//On crée le TextDraw, à sa position, et on écrit directement son contenu.
TextDrawBackgroundColor(InventTitre, 0x00000000);//La couleur de l'outline, de l'ombre, du contour des lettres, ici le noir, vous pouvez la modifier selon vos désirs !
TextDrawFont(InventTitre, 0);//La police d'écriture, voir plus bas !
TextDrawLetterSize(InventTitre, 0.700000, 2.000000);//La taille des lettres, la première valeur est la longueur, et la seconde, la hauteur, réglable selon vos désirs !
TextDrawColor(InventTitre, 0xFFFFFFFF);//La couleur des lettres, ici le blanc, modifiez par la couleur hexadécimale de vos désirs !
TextDrawSetOutline(InventTitre, 1);//Booléene, pour mettre ou non un contour aux lettres, 0 pour non, 1 pour oui !
TextDrawSetProportional(InventTitre, 1);//Permet de garder une proportionnalité de la taille des lettres ! Encore une fois, 0 = Non, 1 = Oui.

Voici les différentes polices disponibles pour les textdraws : http://wiki.sa-mp.com/wiki/TextDrawFont

Il n'y a pas grand chose à expliquer, surtout si on sait lire ne serait-ce qu'un peu l'anglais :smile:

Maintenant passons à la création d'un plus gros morceau !

Vu que chaque joueur aura son propre inventaire (Et par cela, j'entends un objet et son nom), et pas le même pour tout le monde, il nous faut un textdraw pour chaque joueur !

Alors, ici intervient le tableau, et notre très chère amie la boucle...

Code: (pawn) [Sélectionner]
for(new i = 0; i < MAX_PLAYERS; i++)//Pour chaque nombre entier i, qui va croitre tant qu'il sera inférieur au nombre MAX_PLAYERS
{
InventObjet[i] = TextDrawCreate(530.000000, 211.000000, "Inventaire");//Cette ligne n'est utile que pour créer le textdraw, le texte "Inventaire" n'est pas utile étant donné qu'il n’apparaîtra pas sur l'écran.
TextDrawBackgroundColor(InventObjet[i], 136);//Couleur de l'ombre, ou du contour, très important, car ce n'est pas la couleur de la boite qui déterminera la couleur de ce qui sera visible sur votre écran !
TextDrawFont(InventObjet[i], 5);//La police(font) d'un textdraw pour qu'il puisse afficher des objets modélisés de GTA3.IMG ou de SAMP.IMG doit OBLIGATOIREMENT être la 5 !
TextDrawLetterSize(InventObjet[i], -1.400000, -3.600000);//Inutile dans le cas d'un objet, mais on préférera le garder tout de même
TextDrawColor(InventObjet[i], -1);//Laissez sur -1 pour que l'objet qui sera affiché n'aie pas de reflets de couleurs autres qu'à l'origine.
TextDrawSetProportional(InventObjet[i], 1);//Garder des mesures proportionnelles, pour ne pas avoir votre objet étiré vers le haut ou bas, ou vers la gauche ou vers la droite !
TextDrawSetShadow(InventObjet[i], 1);//Permet d'activer l'ombre, et c'est cette ombre qui aura la couleur surpassant la boite entourant votre objet.
TextDrawUseBox(InventObjet[i], 1);//La boite autour d'un textdraw est obligatoire si l'on veut que la modélisation(l'objet) apparaisse (Je ne sais pas pourquoi, mais bon !)
TextDrawBoxColor(InventObjet[i], 255);//La couleur de la boite, pas forcément utile dans ce dernier cas !
TextDrawTextSize(InventObjet[i], 90.000000, 100.000000);//Vous pouvez modifier la taille de la boite en fonction de la taille désirée, j'y reviendrai après.
TextDrawSetPreviewModel(InventObjet[i], 18888);//L'objet avec l'ID 18888 est invisible, c'est donc parce que de base, on veut que si l'inventaire soit vide, on doit prendre quelque chose d'invisible !
TextDrawSetPreviewRot(InventObjet[i], 0.000000, 0.000000, 0.000000, 1.000000);//Vu que l'objet est invisible, on s'en fout de sa rotation, mais on l'utilisera plus tard !

J'avais dit que je reviendrai plus tard sur la ligne "TextDrawTextSize(InventObjet, 90.000000, 100.000000);", le moment est déjà venu !

Donc, si vous désirez une boite d'inventaire plus grande ou plus petite, vous changez la taille de la boite, 90.0 étant l’abscisse, et 100.0 étant l'ordonnée (X et Y quoi !)
Mais si vous souhaitez conserver le TextDraw avec le nom de l'objet à sa place, vous devrez changer sa position en conséquent !
Et d'ailleurs nous y voilà...
 
Code: (pawn) [Sélectionner]
//---
InventNom[i] = TextDrawCreate(535.000000, 286.000000, "Rien");//Encore une fois, pour désigner la position, mais cette fois le texte "Rien", n'est pas inutile, il désigne le nom de l'objet.
TextDrawFont(InventNom[i], 2);//Encore une fois la police d'écriture, réglez comme vous le voulez en fonction de ce qui vous plait le plus.
TextDrawLetterSize(InventNom[i], 0.300000, 1.000000);//La taille de votre calligraphie !
TextDrawColor(InventNom[i], 0x00000000);//La couleur de votre lettrage !
TextDrawSetOutline(InventNom[i], 0);//À nouveau, un contour, oui ou non autour de vos lettres.
TextDrawSetProportional(InventNom[i], 1);//Si vous ne voulez pas avoir de lettres difformes !
TextDrawSetShadow(InventNom[i], 1);//Vous pouvez modifier toutes ces infos à votre guise pour changer le texte, la police etc., je ne vais pas tout vous indiquer, vu que mon tuto ne porte pas directement sur cela.
}//On ferme la boucle

Voilà ! Nous en somme arrivés au bout !

Maintenant, vous allez me dire : "Mais nom d'un bulbizarre, je savais déjà faire des textdraw !"

Oui, et comme vous le savez, ce n'est pas tout de le créer, il faut l'afficher (C'est ça le pouvoir de la transition) :

Vous pourriez bêtement l'afficher à la connexion ou lorsque le joueur se connecte, mais non, on va utiliser la bonne vieille technique de la factorisation en créant une fonction qui sera utilisée plusieurs fois !

Tout d'abord, il nous faudrait des variables ! (On en mangerait tellement on nage dedans !) :

Code: (pawn) [Sélectionner]
new inventnomobjet[MAX_PLAYERS][30];
new inventidobjet[MAX_PLAYERS];
new Float:inventrot[MAX_PLAYERS][3];

- inventnomobjet[MAX_PLAYERS][30];

Cette variable va donc servir, comme son nom l'indique à stocker les caractères formant le nom de nos magnifiques objets. Pour ceux à qui cela ne parle pas vraiment, c'est un équivalent à la chaine de caractères que vous connaissez surement : new string[256];
Sauf que vu qu'un nom d'un objet ne fait certainement pas 255 caractères (Ce serait beaucoup trop long), mettons 30, cela devrait suffire.

- inventidobjet[MAX_PLAYERS];

Celle-ci va stocker l'id de l'objet (Comme dans la fonction CreateObject en gros !) que le joueur a dans son inventaire.

- Float:inventrot[MAX_PLAYERS][3]

Float ! Un nombre à virgule ! Vous comprenez surement le MAX_PLAYERS, mais le 3, qu'est-ce donc que cela ? Eh bien, la rotation se désigne par les axes X, Y & Z, et pour éviter de créer trois lignes, nous allons les condenser en un tableau.
Les paramètres de rotation de l'objet ne sont pas les plus utiles, néanmoins, certains objets rendent mieux sous un certain angle :smile:

Maintenant passons à la fonction directement !

Code: (pawn) [Sélectionner]
stock UpdatePlayerInventory(playerid)//Le stock indique la création d'une fonction, et ignorant les 'warnings' lors de la compilation, mettez le si vous écrivez une include, sinon, vous pourriez passer par dessus une erreur. (Si vous ne le mettez pas, écrivez simplement "UpdatePlayerInventory(playerid)"
{
if(inventidobjet[playerid] == 0) inventidobjet[playerid] = 18888;//Pour éviter que le skin de CJ apparaisse au lieu du 'vide' (Le modèle du skin CJ est le 0)
TextDrawSetPreviewModel(InventObjet[playerid], inventidobjet[playerid]);//On change d'objet à montrer.
TextDrawSetPreviewRot(InventObjet[playerid], inventrot[playerid][0], inventrot[playerid][1], inventrot[playerid][2], 1.000000);//On change sa rotation, et son zoom (1.000000, mais on n'y touchera pas pour garder une vue globale de l'objet)
TextDrawShowForPlayer(playerid, InventObjet[playerid]);//On affiche le TextDraw
TextDrawSetString(InventNom[playerid], inventnomobjet[playerid]);//On change le string du TextDraw contenant le nom par notre chaine de caractères.
  TextDrawShowForPlayer(playerid, InventObjet[playerid]);//On affiche le second aussi.
}

Vous allez éventuellement me dire, mais espèce de suppôt de Satan, à chaque fois qu'on va changer l'objet, on affiche le TextDraw ?! Eh bien oui, si on ne fait que changer ses paramètres, cela ne fera rien (Du moins visuellement). Mais pas de craintes, cela n'affichera pas plusieurs fois votre TextDraw.

Maintenant qu'on a créé notre fonction UpdatePlayerInventory(playerid);, qu'est-ce qu'on en fait ?!
Eh bien on l'utilise lorsque qu'on change l'objet de l'inventaire, soit quand on se connecte, et surtout si votre serveur est équipé d'un système de connexion, assurez-vous de l'utiliser après avoir récupéré les données ! Et aussi, si vous voulez que l'inventaire se sauvegarde, n'oubliez pas de sauvegarder les trois dernières variables que nous avons créé !

P.-S.: N'oubliez pas que dans la plupart des includes, la sauvegarde des Floats et des Strings diffère de celle d'une variable normale.

Bon !

Maintenant qu'on sait afficher des jolis petits objets dans un carré noir transparent, on fait quoi ?

Pour faire plus propre, on va déjà commencer par créer une nouvelle fonction !

Code: (pawn) [Sélectionner]
stock GivePlayerInventoryObject(playerid, name[], objectid, Float:xrot, Float:yrot, Float:zrot)//Encore une fois, n'ajoutez que le 'stock' si vous créez une include.
{
if(objectid == -1)
{
format(inventnomobjet[playerid], 30, "Rien");//On remplace donc le 'string' (La chaine de caractères) par "Rien" dans ce cas-ci.
inventidobjet[playerid] = 18888;//L'id de l'objet pour le joueur devient 18888.
inventrot[playerid][0] = xrot;//La rotation de l'objet se change selon les paramètres inscrits lors de l'exécution de la fonction, pour xrot, il s'agira du 4ème paramètre
inventrot[playerid][1] = yrot;//Pareil que pour au dessus, à l'exception qu'il s'agit de la rotation Y
inventrot[playerid][2] = zrot;//Pareil que pour au dessus, à l'exception qu'il s'agit de la rotation Z
}
else
{
    if(strlen(name) < 30)//Alors vous pouvez vous demander, 'Mais si jamais ça fait pile 30 ?!' Eh bien, il y a toujours quelque chose qu'on appelle la case vide à la fin d'une chaine, et il faut la prendre en compte !
    {
new string[30];
format(string, sizeof(string), name);//Lors de ces deux lignes, on crée une chaine de caractères dans laquelle inclure le paramètre 'name', il s'agit du nom de l'objet que vous donnerez.
  inventnomobjet[playerid] = string;//Le nom de l'objet pour le joueur devient le 'string'
inventidobjet[playerid] = objectid;//Maintenant, les quatre lignes ici sont déjà expliquées plus haut !
inventrot[playerid][0] = xrot;
inventrot[playerid][1] = yrot;
inventrot[playerid][2] = zrot;
}
else return 0;
}
UpdatePlayerInventory(playerid);
    return 1;
}

Analysons donc cette fonction !

Tout d'abord, nous affrontons une condition...

Si objectid vaut -1, alors l'inventaire affichera l'objet invisible, et changera le texte en "Rien", et d'un point de vue visuel, la rotation n'aura pas une réelle importance.

Exemple : GivePlayerInventoryObject(playerid, "Osef", -1, 180.0, 90.0, 0.0);

Cette fonction "videra" l'inventaire du joueur, mais ne prendra pas en compte le paramètre name[], il sera automatiquement changé en "Rien".

Maintenant, passons à plus intéressant, "else", si l'id ne vaut pas -1.
Si tel est le cas alors, la fonction vérifie un autre paramètre..."strlen", cette fonction vérifie la longueur d'un "string". Dans ce cas-ci, on vérifie si la longueur est inférieure à 30. Si elle ne l'est pas, la fonction ne fait rien.

Pourquoi ? Parce que la longueur maximale définie ici est de 30, et si on prend en compte les chaines où il y en a plus, on aura des textes coupés !

Alors donc; Si name contient moins de 30 caractères, le nouveau nom de l'objet devient name, l'objet devient l'id donné, et ainsi de suite pour la rotation.

Et puis, si l'id donné vaut -1, ou pas, alors, dans les deux cas, ça exécute la fonction UpdatePlayerInventory sur le joueur donné.

Fabuleux, maintenant on sait changer l'objet dans l'inventaire, maintenant j'en fais quoi ?!

Alors là, vous devrez en faire ce que votre imagination (Et vos capacités à scripter) vous dicteront !
Pour créer un objet, c'est très simple, vous allez sur MTA Map Editor, vous récupérez des ID d'objets, et vous leur donnez un nom, vous inventez une manière de l'obtenir (Par commande, un pickup à récupérer, etc. !)

Maintenant, passons à l'étape finale de ce tutoriel, et à sa question fatidique... Nom d'un réfrigérateur ! Qu'est-ce que je suis censé faire de ce truc ?! C'est bien beau d'avoir un joli petit truc qui affiche des objets, mais ma tortue vient d'échanger ma femme contre une brouette, je suis trop stressé pour réfléchir !

Eh bien, l'idéal, c'est de pouvoir utiliser les objets ! Et pour ça comment faire ?! Alors là, vous avez plusieurs alternatives, soit vous pouvez créer une commande comme /utiliser, /use, etc. Ou alors, ma méthode de prédilection, c'est-à-dire, utiliser une touche relativement peu utilisée dans SA-MP telle que la touche N.

Dans le cas de la commande cela se passera comme ceci :

Code: (pawn) [Sélectionner]
if(strcmp(cmdtext, "/use", true) == 0)
{
    if(inventidobjet[playerid] != 18888)
    {
        switch(inventidobjet[playerid])
        {
            case IDOBJET:
            {
                //Les actions perpétrées par tel objet
                        GivePlayerInventoryObject(playerid, "Osef", -1, 180.0, 90.0, 0.0);
            }
        }
    }
    else
    {
        SendClientMessage(playerid, 0xCC0000FF, "Vous n'avez pas d'objet !");
    }
return 1;
}

D'abord on vérifie si la commande utilisée est /use. Ensuite, si l'objet du joueur a comme ID 18888, la commande retourne un message "Vous n'avez pas d'objet !", sinon, il y a un switch, et si l'id de l'objet est par exemple égal à tel ou tel nombre, ça exécute telle action, de plus, vous revoyez notre amie la fonction GivePlayerInventoryObject, qui dans ce cas, videra l'inventaire !

Bonne chance ! N'hésitez pas à demander si vous ne comprenez pas quelque chose, à moi, ou à quelqu'un de plus compétent, ou bien, n'hésitez pas à montrer votre oeuvre !


P.-S.: Si un admin pouvait placer ce tuto dans la section appropriée si il est pas trop inutile, ce serait sympathique *-*
« Modifié: 20 Mars 2014, 14:03:59 par CarCrasher »

Hors ligne Kiloutre

  • Nolife, nerd et geek passionné d'Ordinatique ! ^^
  • *
  • Grand Banditisme
  • Messages: 567
    • Voir le profil
Re : [TUTO]Système d'inventaire
« Réponse #1 le: 20 Mars 2014, 13:25:20 »
Bon tuto, mais pas assez complet selon moi
Ton tuto nécessite la maîtrise des textdraws, chose que certaines personnes(dont moi) n'ont pas
Or le problème est que, ceux qui possèdent la maîtrise des textdraws, ils savent faire tout ce que tu fais
A l'exception de l'affichage de l'objet, mais l'affichage d'un objet c'est comme un affichage de textdraw, à deux fonctions et un paramètre près

Tu n'expliques pas beaucoup ce que tu fais: tu crées une fonction, mais à quoi sert ce "stock" devant le nom de la fonction ? Fait-t-il partie de son nom ?
Toute les fonctions que tu utilises, ne pourrais pas-tu faire un commentaire juste en dessous disant à quoi cela sert ? Le nom est peut-être explicite, mais certaines personnes ne savent pas forcément parler l'anglais, et il ne faut pas les mettre à l'écart. Même si le nom est explicite, il ne l'est pas forcément même pour ceux qui savent parler anglais
Les fonctions que tu crées, à quoi sert tel ou tel paramètre ?
Tu crées tes textdraw à des positions particulières, c'est un détail très négligé: tout le monde n'a pas la même taille d'écran, quelqu'un en 1080 verra très probablement ton textdraw légèrement décalé du milieu
Il me semble qu'il y a moyen de bien positionner sur tous les écrans grâce à GetPlayerCameraAspectRatio

PS: Veille à bien utiliser les balises de code, pour la coloration syntaxique
[ code = pawn ] CODE PAWN [ / CODE ]

[/url]

Hors ligne CarCrasher

  • *
  • Tueur en série
  • Messages: 144
    • Voir le profil
Re : [TUTO]Système d'inventaire
« Réponse #2 le: 20 Mars 2014, 13:33:30 »
Ah bah déjà merci pour cette critique  :smile:

Mais oui, j'explique pas vraiment pas tout ce que je fais, mais je pensais avoir assez préciser tout ce qui est important :/

Aussi, pour les TextDraws, les positions sont basées sur le fait que la résolution est en 640*480, et qu'elle est automatiquement calculée pour les différentes résolutions, (D'ailleurs, moi je suis en 1080, et j'ai testé différentes résolutions, comme le 4:3 aussi, et le coup de faire ALT+Enter pour avoir le jeu en fenêtré et pouvoir modifier à volonté la taille de la fenêtre).

Mais je vais modifier, et ajouter plus de détails sur la création des textdraws !  :smile:

Hors ligne Gzsume

  • *
  • Compétent dans l'inutile
  • Messages: 2236
    • Voir le profil
Re : Re : [TUTO]Système d'inventaire
« Réponse #3 le: 20 Mars 2014, 13:42:43 »
Tu crées tes textdraw à des positions particulières, c'est un détail très négligé: tout le monde n'a pas la même taille d'écran, quelqu'un en 1080 verra très probablement ton textdraw légèrement décalé du milieu
Il me semble qu'il y a moyen de bien positionner sur tous les écrans grâce à GetPlayerCameraAspectRatio

Ça fait vingt fois que je te répète que c'est proportionnel mais tu ne veux jamais me croire. :biggrin:

Tiens, un peu de lecture :
wiki.sa-mp.com/wiki/Textdraw#Creating_the_Textdraw
wiki.sa-mp.com/wiki/TextDrawCreate

@ Notes :
Citer
The x,y coordinate is the top left coordinate for the text draw area based on a 640x480 "canvas" (irrespective of screen resolution). If you plan on using TextDrawAlignment with alignment 3 (right), the x,y coordinate is the top right coordinate for the text draw.