Wumbaloo Posted October 20, 2015 Share Posted October 20, 2015 Bonsoir, Enfaite, je cherche une fonction semblable au onClientGUIClick mais pour les dx par exemple j'ai des dxCreateLabel, j'aimerai exercer la fonction onClientGUIClick la dessus, un peu m'a conseillé de mettre un gui avec un alpha dessus, mais ça me génerai pour ce que j'aimerai faire ensuite. J'ai trouvé cette fonction: https://wiki.multitheftauto.com/wiki/Dx ... entDXClick Mais elle me semble assez bugué et l'exemple ne marche pas. Link to comment
Moderators Citizen Posted October 20, 2015 Moderators Share Posted October 20, 2015 J'ai trouvé cette fonction: https://wiki.multitheftauto.com/wiki/Dx ... entDXClickMais elle me semble assez bugué et l'exemple ne marche pas. Tu es en train de regarder un event d'une ressource spécifique (à savoir dxGui), si tu n'utilises pas dxGui, tu n'as effectivement aucune chance de pouvoir utiliser un des events de cette ressource. Pourrais-tu nous montrer à quoi ressemble la création de (je suppose) ton dx button ainsi que son affichage ? Si tu ne crées pas d'élement (dxCreateElement) pour représenter d'une manière logique ton bouton et que tu fais juste des dxDraw, on va être incapable de faire un onClientDXClick de façon simple. Link to comment
Wumbaloo Posted October 20, 2015 Author Share Posted October 20, 2015 Le lien vers dxCreateElement est mort, mais de ce que j'ai compris, on peut pas intéragir directement sur des dxDrawImage ? Concernant mon code, rien de compliquer. for numColonne, player in pairs(players) do local w, h = 880, 450; local x, y = (scr[1]/2)-(w/2), (scr[2]/2)-(h/2); local y = (scr[2]/2)-(h/2) + 110 numColonne = numColonne + 15 ly = y + numColonne username = string.gsub(getPlayerName(player), "_", " ") local rank = tonumber(getElementData(player, "rankfaction")) or 0 if rank == 6 then name = dxDrawText(username.." (Leader)", x+155, ly, left, top, white, 1.2, "default", "center", "center", false, false, true) else name = dxDrawText(username, x+155, ly, left, top, white, 1.2, "default", "center", "center", false, false, true) end end D'ailleurs, ce code possède un bug, je n'arrive pas à ajuster la taille du dxDrawText "name" en fonction du numColonne, mais c'est un autre problème. Link to comment
Moderators Citizen Posted October 21, 2015 Moderators Share Posted October 21, 2015 Ouai je voulais écrire createElement, dxCreateElement n'existe pas et j'utilise les balises [ wiki][ /wiki] qui met le lien automatiquement en fonction du nom que tu mets, et donc forcément, la page de wiki dxCreateElement n'éxiste pas. Les dxDraw servent juste à afficher quelque chose à l'écran, c'est des fonctions ultra basiques qui ne stockent ou ne créent aucune donnée. Les fonctions de GUI en revanche sont représentés par un élément que tu dois créer via guiCreateWindow, guiCreateButtonetc. Une fois que ton élément est créé, MTA se charge de l'afficher avec ses propres fonctions "guiDraw" (j'explique de façon simple, mais la logique globale reste correcte). Tu peux ensuite interagir avec tes éléments GUI avec les guiSetPosition, onClientGUIClicketc. Dans ton cas tu n'utilises que les fonctions de draw et tu n'as donc aucun élément avec lequel tu pourrais interagir. Dans ton code c'est quoi left et top ? tu les as réellement définit plus haut ? oO Parce que si t'as juste recopié les noms de variables du wiki, sans les avoir définit ça ne devrait pas marcher ! Voici ma solution (non testée car je ne suis pas sur mon pc). Commence par copier coller ces fonctions: -- Fonction de création d'un élément dxText function dxCreateText(text, left, top, width, height, color, scale, font, alignX, alignY, clip, wordBreak, postGUI) -- On crée l'élément local dxText = createElement("dxText") -- On lui set les données nécessaires au dxDrawText setElementData(dxText, "text", text, false) setElementData(dxText, "position", {x=left, y=top}, false) setElementData(dxText, "size", {w=width, h=height}, false) setElementData(dxText, "color", color, false) setElementData(dxText, "scale", scale, false) setElementData(dxText, "font", font, false) setElementData(dxText, "align", {x=alignX, y=alignY}, false) setElementData(dxText, "clip", clip, false) setElementData(dxText, "wordBreak", wordBreak, false) setElementData(dxText, "postGUI", postGUI, false) -- On retourne l'élement return dxText end -- Fonction de render des dx elements function dxRenderEverything() -- render des dxText: for k, i in ipairs (getElementsByType("dxText")) do local text = getElementData(dxText, "text") local pos = getElementData(dxText, "position") local size = getElementData(dxText, "size") -- dxDrawText ne prend pas de width ni de height, il prend les positions de fin, donc faut les calculer: local right, bottom = pos.x + size.w, pos.y, size.h local color = getElementData(dxText, "color") local scale = getElementData(dxText, "scale") local font = getElementData(dxText, "font") local align = getElementData(dxText, "align") local clip = getElementData(dxText, "clip") local wordBreak = getElementData(dxText, "wordBreak") local postGUI = getElementData(dxText, "postGUI") -- On render dxDrawText(text, pos.x, pos.y, right, bottom, color, scale, font, align.x, align.y, clip, wordBreak, postGUI) end --[[ on pourra rajouter pour un dxButton: for k, i in ipairs (getElementsByType("dxButton")) do -- faire les calculs nécessaires et faire les dxDraw end]] end addEventHandler("onClientRender", root, dxRenderEverything) addEvent("onClientDXClick") -- Fonction qui s'occupe de trigger l'event onClientDXClick function onClientDXClickWatcher(button, state, clickX, clickY) for k, dxText in ipairs (getElementsByType("dxText")) do if isClickInsideDXElement(clickX, clickY, dxText) then triggerEvent("onClientDXClick", dxText, button, state, clickX, clickY) end end --[[ on pourra rajouter pour un dxButton: for k, dxButton in ipairs (getElementsByType("dxButton")) do if isClickInsideDXElement(clickX, clickY, dxButton) then triggerEvent("onClientDXClick", dxButton, button, state, clickX, clickY) end end]] end addEventHandler("onClientClick", root, onClientDXClickWatcher) -- Fonction qui retourne true si les coordonnées d'un clic correspond à la position de l'élément function isClickInsideDXElement(clickX, clickY, dxElem) local dxType = getElementType(dxElem) if dxType == "dxText" then local pos = getElementData(dxElem, "position") local size = getElementData(dxElem, "size") return isPosInsideBox(clickX, clickY, pos.x, pos.y, size.w, size.h) end --[[ on pourra rajouter pour un dxButton: if dxType == "dxButton" then ... return isPosInsideBox(...) end]] end -- Fonction qui retourne true si une coordonnées est à l'intérieur d'un rectangle définit function isPosInsideBox(posX, posY, boxX, boxY, boxW, boxH) return posX >= boxX && posX <= boxX + boxW && posY >= boxY && posY <= boxY + boxH end -- Fonction qui retourne true si un tableau contient une certaine key function table.hasKey(t, key) for k, _ in pairs (t) do if k == key then return true end end return false end Puis remplace exactement les lignes que tu m'as copiées par ceci: for numColonne, player in pairs(players) do --- hack if not _rankGrid then _rankGrid = {} -- Va juste nous aider à ne créer qu'un seul dxElement par ligne (et donc par player) vu qu'on est dans un onClientRender elseif #_rankGrid ~= #players then -- Si la liste de player à changée, il faut update for player, dxElem in pairs(_rankGrid) do destroyElement(dxElem) -- On supprime tout avant recréation pour ne pas avoir de doublons end _rankGrid = {} end --- local w, h = 880, 450; local x, y = (scr[1]/2)-(w/2)+155, (scr[2]/2)-(h/2)+110; ly = y + numColonne + 15 username = string.gsub(getPlayerName(player), "_", " ") local text = username -- de base on prend son username local rank = tonumber(getElementData(player, "rankfaction")) or 0 if rank == 6 then text = username.." (Leader)" -- mais s'il est rang 6, on rajoute " (Leader)" au username end -- Au lieu de draw directement, on crée un dxText -- dxDrawText(text, x+155, ly, left, top, white, 1.2, "default", "center", "center", false, false, true) if not table.hasKey(_rankGrid, player) then -- Une seule création du dxText avec son onClientDXClick handler local dxText = dxCreateText(text, x, ly, left-x, top-ly, white, 1.2, "default", "center", "center", false, false, true) setElementData(dxText, "player", player, false) -- On stock une donnée dans le dxText, ce qu'on ne pouvait pas faire avec un simple dxDrawText addEventHandler("onClientDXClick", dxElem, testHandler, false) --- hack _rankGrid[player] = dxText --- end end et enfin le testHandler auquel j'ai attaché l'event onClientDXClick: --- TEST --- function testHandler(button, state, clickX, clickY) if button ~= "left" then return end -- je fais rien si c'est pas le clic gauche de la souris qui a produit le trigger local text = getElementData(source, "text") local player = getElementData(source, "player") local realPlayerName = getPlayerName(player) outputChatBox("You clicked on \""..text.."\" (Real name: "..realPlayerName..")") -- Tu peux utiliser player comme bon te semblera end Cette solution est censée (sauf erreur dans mon code) faire exactement le même rendu que ton précédent code mais si tu auras maintenant un élément avec lequel tu pourras intéragir (en faisant un setElementData pas exemple) et si tu cliques gauche sur une ligne, tu devrais voir apparaître un message dans la chatbox qui contient le texte de la ligne ainsi que le nom original du player (parce que j'ai vu que tu replaçais les _ par des espaces au moment de l'affichage et surtout pour montrer que j'arrive bien à récupérer le joueur depuis la ligne cliquée sans faire de calcul ou de getPlayerFromName). Pour ton problème de positionnement vertical, il faut que tu définisses la hauteur d'une ligne en pixels (par exemple lineH = 40). Puis il faut que tu saches à quel Y de l'écran ta liste doit commencer (par exemple startY = 363). Une fois que tu as ces 2 donées, tu peux facilement calculer la position Y de chaque ligne dans ton for que tu m'as montré en faisant: local lineY = startY + (numColonne * lineH) (D'ailleurs numLigne serait un nom plus approprié, et pourrait éviter des erreurs à cause d'un mal entendu). Link to comment
Wumbaloo Posted October 21, 2015 Author Share Posted October 21, 2015 Un grand merci à toi une fois de plus! ça me fait plaisir que t'aies pris la peine de rédiger ce code. Merci de m'avoir réalisé le code, seulement, je me sens vraiment nul car je n'aurais pas pu le faire.. En fait, je comprends à 25% ton code que tu m'as envoyé, devrais-je aller relire mes cours de LUA ? Il y avait quelques erreurs dans ton code que j'ai su corrigé, seul, heureusement Y'a juste un problème avec le clickX et clickY, quand je clique sur mon écran, peut importe où, il m'affiche le testHandler. Et le name ne se destroy pas quand je removeEventHandler la fonction avec le username justement. Je vais continuer d'étudier ton code du coup, merci. Link to comment
Moderators Citizen Posted October 21, 2015 Moderators Share Posted October 21, 2015 En fait, je comprends à 25% ton code que tu m'as envoyé, devrais-je aller relire mes cours de LUA ? Si tu comprends pas la partie qui utilise le _rankGrid et table.hasKey, c'est pas grave parce j'ai dû pondre du code supplémentaire un peu hardcore pour que ça marche avec le seul bout de code que tu as montré. Si on prends l'exemple du système GUI, tu crées tes gui element que tu crèes, cache, montre et update selon tes besoins, et au moment où tu as besoin. En aucun cas tu auras des guiCreateXXX dans un onClientRender mais le code que tu avais était dans un onClientRender donc pour éviter de te demander d'autres parties de ton code qu'on aurait dû en plus changer pour faire propre, je me suis forcer à faire un peu de hack pour éviter de spammer le dxCreateText qui devait quand même se recréer si un joueur a quitté ou rejoins le serveur (donc si le nombre de players est différent du nombre de dxText qu'on a créé pour ça). Après avec tous les commentaires que j'ai placés, tu devrais normalement comprendre les fonctions suivantes: - dxCreateText - dxRenderEverything - isPosInsideBox - isClickInsideDXElement et - onClientDXClickWatcher Si ce n'est pas le cas, demande moi ici ce lesquels tu n'as pas compris, j'essayerai d'expliquer de façon plus détaillée. Y'a juste un problème avec le clickX et clickY, quand je clique sur mon écran, peut importe où, il m'affiche le testHandler. Ça j'en étais quasiment certains mais j'ai quand même laissé le bénéfice du doute. Enfait, les valeurs que tu as calculées pour x, ly, left et top ne sont pas corrects. Pour bien visualiser, un dxDrawText va tout d'abord créer un rectangle (ou aussi une bounding box) dont tu définis les coordonnées de son angle en haut à gauche (top et left sur le wiki) et les coordonnées de son angle en bas à droite (right et bottom sur le wiki). Ensuite une fois qu'il a créé son rectangle, il va placer son texte en fonction de l'alignement horizontal et vertical que tu lui as spécifié (alignX et alignY). Donc visuellement ton texte paraît bien placé et paraît ne pas occuper une grosse partie de ton écran, mais l'élément dans son entièreté en occupe une énorme. Et comme j'utilise les coordonnées et les dimensions de l'élément (donc les coordonnées et les dimensions de la bounding box) pour déterminer si un clic souris à été fait sur lui, si la bounding box prends tout l'écran, le onClientDXClick va être trigger sur tout l'écran. Pour corriger tout ça, il juste corriger la bounding box. Colle ce code n'importe où et tu pourras visualiser la bounding box de chaque dxDrawText réalisé dans ton script. local _dxDrawText = dxDrawText -- On copie la fonction originale de MTA local dxDrawText = function(text, left, top, right, bottom, color, scale, font, alignX, alignY, clip, wordBreak, postGUI) dxDrawRectangle(left, top, right-left, bottom-top, tocolor(200, 0, 0, 150)) -- on affiche la bounding box en rouge semi transparent _dxDrawText(text, left, top, right, bottom, color, scale, font, alignX, alignY, clip, wordBreak, postGUI) -- et on appelle normalement le vrai _dxDrawText end Je peux te faire un mini-cours sur skype, ça me sera plus simple et plus rapide pour t'expliquer et montrer des choses. Là je mets un temps fou à écrire toutes mes explications ^^. Ajoute-moi quand tu pourras (check tes MP). J'en profiterai pour t'expliquer dans le détail le process de mon code précédent (genre comment et pourquoi il fonctionne ). Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now