Page 1 sur 2

[RESOLU] Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 19 Sep 2019 18:02
par Chandala
Bonjour, bonsoir à toutes et à tous ! :cote:

Je reviens à vous encore une fois pour un nouveau souci avec ma Visual Novel. C'est un souci que je rencontre depuis un long moment à présent et la console n'indique aucune erreur pouvant donner une idée de sa résolution.

Mon projet actuel comporte deux scènes (MainMenu et Novel) qui permettent toutes les deux d'accéder au panel Save/Load pour sauvegarder, charger ou même supprimer des données de sauvegardes. La scène MainMenu y accède grâce à un bouton "Continuer" tandis que la scène Novel (la partie jeu) y accède grâce à un clic droit.

L'écran MainMenu en mode Game :
Image


En cliquant sur Continuer, le panel Save/Load suivant s'affiche bien :
Image
(oui j'ai deux boutons "retour" mais je voulais tester voir si ça venait de TMPro et/ou des images/RawImage mais avec ou sans, ça ne fonctionne en aucun cas :pascontent2: ).

Les boutons à gauche de l'écran sont reconnus comme tels (cliquer dessus fonctionne et le highlighted color aussi, d'où le orange pétant sur le 2ème bouton retour ::d ) mais pas les autres, cliquer dessus ne donne rien du tout.

Depuis la scène Novel, ces mêmes boutons sont aussi reconnus en plus des petits 1, 2, 3, ..., 7 qui changent le numéro des "N empty file..." juste en dessous. Mais encore une fois, les boutons comprenant les images toutes blanches et les textes ne sont pas reconnus comme des boutons (pas de highlight dessus, ni de clic chargeant les données).

J'ai lu plusieurs fois que le problème venait d'un EventSystem absent mais dans les deux scènes il est bien présent et en dehors des Canvas comme montré ci dessous :
ImageImage

L'EventSystem est strictement identique dans les deux cas :
Image

Aussi, j'ai bien placé tous les OnClick qu'il fallait sur les boutons, la cible étant à chaque fois le Panel dans lequel ils se trouvaient, permettant ainsi d'appeler la fonction pour fermer le panel, charger les données etc. Un petit exemple ici :
Image

Et voici le GameSavePanel.cs qui appelle ces fonctions :

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class GameSavePanel : MonoBehaviour
{
    public List<BUTTON> buttons = new List<BUTTON>();

    [HideInInspector]
    public int currentSaveLoadPage = 1;

    public CanvasGroup canvasGroup;

    public Button loadButton;
    public Button saveButton;
    public Button deleteButton;

    public enum TASK
    {
        saveToSlot,
        loadFromSlot,
        deleteSlot
    }
    public TASK slotTask = TASK.loadFromSlot;

    public void LoadFilesOntoScreen(int page = 1)
    {
        currentSaveLoadPage = page;

        string directory = FileManager.savPath + "savData/gameFiles/" + page.ToString() + "/";

        if (System.IO.Directory.Exists(directory))
        {
            for(int i = 0; i < buttons.Count; i++)
            {
                BUTTON b = buttons[i];
                string expectedFile = directory + (i + 1).ToString() + ".txt";
                if (System.IO.File.Exists(expectedFile))
                {
                    GAMEFILE file = FileManager.LoadEncryptedJSON<GAMEFILE>(expectedFile, FileManager.keys);

                    b.button.interactable = true;
                    byte[] previewImageData = FileManager.LoadComposingBytes(directory + (i + 1).ToString() + ".png");
                    Texture2D previewImage = new Texture2D(2, 2);
                    ImageConversion.LoadImage(previewImage, previewImageData);
                    file.previewImage = previewImage;
                    b.previewDisplay.texture = file.previewImage;

                    //need to read date and time information from file.
                    b.dateTimeText.text = page.ToString() + "\n" + file.modificationDate;
                }
                else
                {
                    b.button.interactable = allowSavingFromThisScreen;
                    b.previewDisplay.texture = Resources.Load<Texture2D>("Images/UI/EmptyGameFile");
                    b.dateTimeText.text = page.ToString() + "\n" + "empty file...";
                }
            }
        }
        else
        {
            for (int i = 0; i < buttons.Count; i++)
            {
                BUTTON b = buttons[i];
                b.button.interactable = allowSavingFromThisScreen;
                b.previewDisplay.texture = Resources.Load<Texture2D>("Images/UI/EmptyGameFile");
                b.dateTimeText.text = page.ToString() + "\n" + "empty file...";
            }
        }
    }

    [HideInInspector]
    public BUTTON selectedButton = null;
    string selectedGameFile = "";
    string selectedFilePath = "";
    public bool allowLoadingFromThisScreen = true;
    public bool allowSavingFromThisScreen = true;
    public bool allowDeletingFromThisScreen = true;

    public void ClickOnSaveSlot(Button button)
    {
        foreach (BUTTON B in buttons)
        {
            if (B.button == button)
                selectedButton = B;
        }

        selectedGameFile = currentSaveLoadPage.ToString() + "/" + (buttons.IndexOf(selectedButton) + 1).ToString();
        selectedFilePath = FileManager.savPath + "savData/gameFiles/" + selectedGameFile + ".txt";

        //Run an error check just to be sure the file has not been removed since load.
        if (System.IO.File.Exists(selectedFilePath))
        {
            loadButton.interactable = allowLoadingFromThisScreen;
            saveButton.interactable = allowSavingFromThisScreen;
            deleteButton.interactable = allowDeletingFromThisScreen;
        }
        else
        {
            selectedButton.dateTimeText.text = "<color=red>FILE NOT FOUND!";
            loadButton.interactable = false;
            saveButton.interactable = allowSavingFromThisScreen;
            deleteButton.interactable = true;
        }
    }

    public void LoadFromSelectedSlot()
    {
        //we need to load the data from this slot to know what to do.
        GAMEFILE file = FileManager.LoadEncryptedJSON<GAMEFILE>(selectedFilePath, FileManager.keys);

        //save the name of the file that we will be loading in the visual novel. carries over to next scene.
        FileManager.SaveFile(FileManager.savPath + "savData/file", selectedGameFile);

        UnityEngine.SceneManagement.SceneManager.LoadScene("Novel");

        gameObject.SetActive(false);//deactivate the panel after loading.
    }

    public void ClosePanel()
    {
        if (gameObject.activeInHierarchy)
            GetComponent<Animator>().SetTrigger("deactivate");
    }

    public void SaveToSelectedSlot()
    {
        //save the open game file to this slot.
        if (NovelController.instance != null)
        {
            savingFile = StartCoroutine(SavingFile());
        }
    }

    Coroutine savingFile = null;
    IEnumerator SavingFile()
    {
        NovelController.instance.activeGameFileName = selectedGameFile;

        //render this part of the screen invisible so we get a clear snapshot of the visual novel.
        GetComponent<Animator>().SetTrigger("instantInvisible");
        yield return new WaitForEndOfFrame();

        // a screen shot is made during this point.
        NovelController.instance.SaveGameFile();

        selectedButton.dateTimeText.text = currentSaveLoadPage.ToString() + "\n" + GAMEFILE.activeFile.modificationDate;
        selectedButton.previewDisplay.texture = GAMEFILE.activeFile.previewImage;

        yield return new WaitForEndOfFrame();

        //render this part of the screen visible again after the screenshot is taken.
        GetComponent<Animator>().SetTrigger("instantVisible");

        savingFile = null;
    }

    public void DeleteSlot()
    {
        print("We'll do this later.");
    }

    [System.Serializable]
    public class BUTTON
    {
        public Button button;
        public RawImage previewDisplay;
        public TextMeshProUGUI dateTimeText;
    }
}
Voilà, si quelqu'un voit d'où peut provenir le problème, je serais ravie qu'il me le signale car je suis vraiment à court d'idées à présent :triste1:
Merci beaucoup d'avance pour votre attention ! :merci: :coeur:

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 19 Sep 2019 21:55
par Max
Bonsoir,

as-tu essayé de mettre en tête de tes méthodes de ta classe GameSavePanel un Debug.Log pour voir si malgré tout tu ne rentres pas dedans lors de chaque click ?

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 20 Sep 2019 10:13
par boubouk50
N'y aurait-il pas tout simplement un panel ou autre élément d'UI qui bloquerait le raycast?

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 20 Sep 2019 15:53
par Chandala
Merci tous les deux pour vos réponses !

Et non Max, je n'y avais pas pensé, j'ai encore du mal à comprendre comment on demande au Debug.Log ce genre de vérification plus spécifique :gene: Comment peut-on lui demander de détecter si on rentre bien dans une méthode ? :0 Les articles que j'ai lus dessus proposent carrément de créer son propre Debug Script ou d'utiliser un Debug.DrawRay qui ne me semble pas approprié du coup...

C'est bien possible Boubouk ! Maintenant que tu le dis, il y a des choses un peu curieuses dans ma hiérarchie...

Concernant ma Scène MainMenu :

Le Canvas a un Graphic Raycaster (Script) avec un Ignore Reversed Graphics coché.
Le Background a une RawImage avec un Raycast Target coché.

Le Main Panel a une Image avec Raycast Target coché aussi, mais aussi un Canvas Group avec Interactable et Blocks Raycasts cochés, mais avec un Ignore Parent Group décoché.
Dans le Main Panel, il y a un Title avec une RawImage qui a le Raycast Target coché aussi.
Il y a le GameObject Button Bar qui lui contient les boutons du Main Menu, soit New Game - Continue - Options et Quit. Tous ont l'Interactable coché mais seul le bouton New Game a un Raycast Target décoché. Le bouton New Game fonctionne bien et lance le jeu quand on clique dessus, le bouton Continue redirige bien vers le (prefab) SaveAndLoadGameFilePanel.

Le FadeIn a une Image qui a le Raycast Target décoché.
Le SettingsPanel a une Image avec le Raycast Target coché. Il a aussi un Canvas Group avec un Canvas Group avec Interactable et Blocks Raycasts cochés, mais avec un Ignore Parent Group décoché.

Enfin, le fameux SaveAndLoadGameFilePanel qui a le même Canvas Group que précédemment ainsi qu'une Image avec un Raycast Target coché.
A l'intérieur du SaveAndLoadGameFilePanel, un GameObject Image avec toujours un Raycast Target coché.
Et à l'intérieur de cette Image, les 6 boutons "Game Select" (carrés blancs + empty file) qui ont tous un Raycast Target et un Interactable cochés.
Il en va de même pour les 7 petits boutons au dessus qui ne sont pas dans l'Image.
Enfin, un dernier GameObject Image avec un Raycast Target coché contenant les 5 boutons à gauche (Button, Retour, Save, Load et Delete). Tous ont un Raycast Target coché mais seulement les Button et Retour ont un Interactable coché (car pour le moment c'est inutile d’interagir avec les trois autres boutons).

Navrée pour la redondance mais j'espère que c'est tout de même clair ainsi :gene: ;) Est-ce que quelque chose semble contradictoire parmi tous ces Raycast Target cochés ?
Aussi j'ai décoché le Raycast Target du Main Panel pour tester, Unity s'est fermé aussitôt. BON ! xD

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 20 Sep 2019 19:01
par Max
Bonsoir,
Chandala a écrit :
20 Sep 2019 15:53
Et non Max, je n'y avais pas pensé, j'ai encore du mal à comprendre comment on demande au Debug.Log ce genre de vérification plus spécifique
Les Debugs permettent juste l'affichage dans la console (et dans le fichier log) de messages. Par exemple, si lors d'un click sur un de tes boutons, la fonction ClickOnSaveSlot() est appelée, alors tu peux lui demander d'afficher un simple texte signifiant qu'effectivement (ou pas) l'appel est effectué. Si message tu as, c'est que ton soucis est du coté script (la fonction est appelée mais ne réagit pas comme attendue), si message tu n'as pas, alors c'est que le soucis vient du coté UI.

Exemple

Code : Tout sélectionner

    public void ClickOnSaveSlot(Button button)
    {
    	Debug.Log("ClickOnSaveSlot click enter");
    	...
   }
    
Chandala a écrit :
20 Sep 2019 15:53
C'est bien possible Boubouk ! Maintenant que tu le dis, il y a des choses un peu curieuses dans ma hiérarchie...
Il faut rester simple. En gros, la solution suggérer consiste simplement à désactiver tous les panels de ton UI, sauf celui qui pose problème. Si dans ce cas cela fonctionne, alors c'est que très certainement un des autres panels fiche le bazar et vient parasiter celui qui ne fonctionne pas.

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 21 Sep 2019 05:19
par Chandala
Bon matin à tous :cote:

Okay donc le Debug.Log ne sert bien qu'à ça, je me disais aussi que je n'avais vu nulle part des utilisations plus précises.

Parmi les méthodes que j'ai testées avec le Debug.Log, la LoadFilesOntoScreen est bien reconnue par la console lorsqu'on clique sur "Continue" pour passer du Main Menu au SaveAndLoad Panel.

Suivant ton exemple Max, j'obtiens un "ClosePanel click enter" en appuyant sur le bouton "Retour", un "LoadFromSelectedSlot click enter" pour le bouton "Load" avec une erreur car il n'y a pas de données à charger encore, et enfin un "We'll do this later" bien présent dans le tuto pour le bouton "Delete" xD

Aussi j'ai mis le SaveAndLoad Panel seul dans une scène à part, à l'intérieur d'un Canvas, et le souci persiste :pascontent:

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 21 Sep 2019 10:35
par Max
Bonjour,

Donc si je suis ce que tu dis, le soucis viendrait bien du coté script dans ce cas ?

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 21 Sep 2019 20:00
par Chandala
Alors là, aucune idée...

Je suis partie en éclaireur sur le Discord voir si d'autres avaient eu ce souci avec ce tutoriel mais pas de réponse pour le moment et dans les archives des questions, rien à signaler non plus à ce sujet.

Après les boutons fonctionnent mieux en partie dans la scène Novel (le texte "empty file" dans les boutons GameSelect change lorsqu'on clique sur les petits boutons 1, 2, ..., 7 mais on ne peut toujours pas cliquer sur les boutons GameSelect en eux-mêmes).

Autrement, il y a ceci dans l'Animator pour permettre les transitions :
Image

Le Any state donne ceci :
Image

Tous les autres n'ont aucune transition ('List is Empty') sauf le loadGameToInactive et le loadGameToActive qui ont les conditions suivantes :
ImageImage

J'ai vérifié et ils sont identiques dans le projet du tutoriel, maintenant la différence que j'ai pu noter, c'est au niveau du poids des animations. Au total, le dossier les contenant dispose de 16 fichiers que voici :
Image

Les miens font 30,5ko au total tandis que ceux du tuto font 88,8ko... Je vais enquêter sur le pourquoi du comment d'une telle différence et voir si je peux les remplacer ou les rendre strictement identiques (même si je les avais déjà vérifiés y'a un bon moment de ça :0 )

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 21 Sep 2019 20:55
par Max
Chandala a écrit :
21 Sep 2019 20:00
Alors là, aucune idée...
Ben si on essais de rester logique et au vue de se que tu rapportes après tes essais, je pense qu'il serait bon de commencer par là.
Après tu pars sur les Animator, je ne vois pas trop pourquoi. Tes boutons ont des Animator en componant ? C'est pas présent sur les screens que tu as fournis.

Re: Boutons de panel reconnus mais qui ne fonctionnent pas

Publié : 21 Sep 2019 21:33
par Chandala
Je vais voir pour le script ce que je peux faire alors, comparer ses méthodes avec d'autres similaires notamment.

Pour les Animators ils ne sont pas attachés aux boutons mais ils sont sur 3 panels (FadeIn, SettingsPanel et SaveAndLoadGameFilePanel) du coup je pensais qu'une erreur supposée à ce niveau-là aurait peut-être pu interférer avec les boutons à l'intérieur du panel mais il semblerait que non.

Enfin, je vais examiner tout ça pour le moment !