[RESOLU] Boucle pour détruire GO par leurs nom

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Edrahil511
Messages : 19
Inscription : 13 Déc 2020 16:54

[RESOLU] Boucle pour détruire GO par leurs nom

Message par Edrahil511 » 08 Août 2021 07:58

Bonjour,

Je tiens à préciser que j'ai contourné mon problème et que je suis arrivé à mes fins en utilisant des TAG mais j'aurais voulu comprendre pourquoi ma première solution ne marche pas.

Les deux méthodes sont visible dans le code ci-dessous.
Je créé des gameObject avec mon premier if et mon but est de les détruire quand je passe dans mon else.
Je voulais dans un premier temps détruire tout les gameobject avec le même nom (DiceInPool) à l'aide d'une boucle mais cela ne détruit qu'un seul gameObject.

Je ne sais jamais trop comment exposer mes soucis sur le forum (trop en dire ou pas assez) mais la je pense que le code parle de lui même, sinon dites le moi et je développerai plus :mrgreen:

Code : Tout sélectionner

    public void PoolPanel(/*PlayerStat currentPlayer*/)
    {
        int sizeOfDice = 20; //Taille de l'image

        if(poolPannel.activeSelf == false)
        {
            poolPannel.SetActive(true);
            float decay = 0;
            foreach(SODice dice in currentPlayer.GetPool())
            {
                GameObject myGo = new GameObject();
                myGo.name = "DiceInPool";//Nommer des GO pour les détruire avec la 1ère méthode
                myGo.tag = "ToDestroy"; //Tag des GO pour les détruire avec la 2ème méthode
                myGo.transform.parent = poolPannel.transform;
                myGo.AddComponent<Image>();
               
                myGo.GetComponent<Image>().sprite = dice.GetMonstre().portrait;
              
                Debug.Log(decay);
                myGo.GetComponent<RectTransform>().sizeDelta = new Vector2(sizeOfDice, sizeOfDice);
                myGo.GetComponent<RectTransform>().localPosition = new Vector3(decay, -8, 0);

                decay *= -1;

                if(decay <= 0)
                {
                    decay -= myGo.GetComponent<RectTransform>().rect.width;
                }                
            }

            /*Ajustement de la taille de la fenêtre en fonction du nombre de dé en pool*/
            poolPannel.GetComponent<RectTransform>().sizeDelta = new Vector2((currentPlayer.GetPool().Count + 1) * sizeOfDice, poolPannel.GetComponent<RectTransform>().rect.height);          
        }
       
        else
        {
            //2EME METHODE	
            GameObject[] diceInPool;
            diceInPool = GameObject.FindGameObjectsWithTag("ToDestroy");

            foreach(GameObject dice in diceInPool)
            {
                Destroy(dice.gameObject);
            }
            
            //1ERE METHODE : NE DETRUIT QU'UN GAMEOBJECT
            /*  
            foreach (SODice dice in currentPlayer.GetPool())
            {
                Destroy(GameObject.Find("DiceInPool"));
            }
            */
            poolPannel.SetActive(false);
        }
    }
Dernière édition par Edrahil511 le 08 Août 2021 17:33, édité 1 fois.

Avatar de l’utilisateur
jmhoubre
Messages : 851
Inscription : 05 Oct 2019 22:05

Re: Boucle pour détruire GO par leurs nom

Message par jmhoubre » 08 Août 2021 13:04

Bonjour,

pour Destroy, la documentation précise :
The object obj is destroyed immediately after the current Update loop
Il est possible que ta boucle demande la destruction de l'objet, puis, dans la même frame, le "GameObject.Find("DiceInPool")" renvoie le même objet, qui est en instance de destruction, et ainsi de suite jusqu'à la fin de la boucle.

Comme tes objets ont été parentés avec poolPannel, pourquoi ne pas parcourir la boucle des enfants et les détruire ? Je te conseille de parcourir la liste des enfants depuis la fin.

Edrahil511
Messages : 19
Inscription : 13 Déc 2020 16:54

Re: Boucle pour détruire GO par leurs nom

Message par Edrahil511 » 08 Août 2021 13:58

jmhoubre a écrit :
08 Août 2021 13:04
Bonjour,

pour Destroy, la documentation précise :
The object obj is destroyed immediately after the current Update loop
Il est possible que ta boucle demande la destruction de l'objet, puis, dans la même frame, le "GameObject.Find("DiceInPool")" renvoie le même objet, qui est en instance de destruction, et ainsi de suite jusqu'à la fin de la boucle.
Ok je comprend bien ou été le problème. Je le savais en plus que la destruction d'un objet n'était pas immédiate mais se faisait à la fin de la frame mais c'est le genre de détail auquel je ne pense pas instinctivement.
jmhoubre a écrit :
08 Août 2021 13:04
Comme tes objets ont été parentés avec poolPannel, pourquoi ne pas parcourir la boucle des enfants et les détruire ? Je te conseille de parcourir la liste des enfants depuis la fin.
Mes objets sont tous enfant de poolPanel, mais peux tu développer ce que tu me dit la. Parcourir la boucle des enfants ? Tu me parle la d'utiliser d'utiliser des GetChild(index) ?

Avatar de l’utilisateur
jmhoubre
Messages : 851
Inscription : 05 Oct 2019 22:05

Re: Boucle pour détruire GO par leurs nom

Message par jmhoubre » 08 Août 2021 14:37

Oui, exactement. Les deux choses utiles sont childCount, la propriété qui donne le nombre d'enfants d'un parent, et GetChild, qui renvoie un enfant selon son index.
Cela donne quelque chose comme :

Code : Tout sélectionner

private void DestroyChildren()
{
    if (poolPanel != null)
    {
        for (int i = poolPanel.transform.childCount - 1; i >= 0; i--)
        {
            Destroy (poolPanel.transform.GetChild (i).gameObject);
        }
    }
}


Edrahil511
Messages : 19
Inscription : 13 Déc 2020 16:54

Re: Boucle pour détruire GO par leurs nom

Message par Edrahil511 » 08 Août 2021 16:00

Voila ce que ca donne et ca marche évidement. J'ai pas vraiment regardé ton morceau de code car étant en apprentissage j'essaye un maximum de trouver seul.

Code : Tout sélectionner

        else
        {

            for(int i = poolPannel.transform.childCount - 1 ; i > 0; i--)
            {
                Destroy(poolPannel.transform.GetChild(i).gameObject);
            }

            poolPannel.SetActive(false);
        }
Ma boucle ne prend pas en compte le premier enfant mais ce n'est pas une erreur c'est que celui ci n'est pas à détruire (il est toujours la et n'a rien avoir avec ceux que je créé dans mon if)

Du coup c'est pour toi la "meilleure" solution (mieux que d'utiliser des tags en tout cas) ? Personnellement j'ai pas du tout le réflexe d'utiliser les transform.Find() et ENCORE MOINS les transform.Getchild() car j'ai trop peur qu'en changeant un jour mon arborescence cela me casse tout et que je mette des heures à trouver l'erreur.

Une peur irrationnel peut être si j'utilise ces fonction de façon réfléchit pour des gameObject qui ne sont vraiment pas censé changer de hiérarchie ?

Avatar de l’utilisateur
jmhoubre
Messages : 851
Inscription : 05 Oct 2019 22:05

Re: Boucle pour détruire GO par leurs nom

Message par jmhoubre » 08 Août 2021 17:22

Les fonctions Findxxxx sont très consommatrices de ressources (je te renvoie aux différents articles de la doc si tu veux t'en convaincre). Il est généralement conseillé d'éviter de de les utiliser. Si on les utilise, il faut surtout éviter l'erreur de les utiliser au sein d'une fonction de la famille Update ().

On voit dans certains tutos des auteurs qui le font, sous prétexte que c'est un tuto, et que les performances ne sont pas un problème. Je trouve au contraire que montrer les bonnes pratiques à tous, y compris dans les tutos, est une très bonne chose, ou au moins signaler que ce n'est pas une bonne pratique.

Parfois, il n'y a pas de possibilité d'en utiliser une, mais cela reste quand même assez rare. On peut par exemple mettre le résultat en cache.

Donc oui, pour le cas que tu présentes, il me semble plus efficace d'appeler GetChild. Maintenant, pour en être sûr, il faut faire des mesures avec un outil comme StopWatch, ou quelque chose d'équivalent. J'ai une expérience limitée avec Unity.

N'oublie pas de passer ton post en [Résolu], à moins que tu n'aies encore des questions sur ce point.

Edrahil511
Messages : 19
Inscription : 13 Déc 2020 16:54

Re: Boucle pour détruire GO par leurs nom

Message par Edrahil511 » 08 Août 2021 17:33

Merci pour tout :super:

Répondre

Revenir vers « Scripting »