Player speak first but it's the NPC name who is displaying

Hello.
Normally if I want to say something to someone, I’m the fisrt to talk.
I built my Dialogue like that. Yellow nodes are player node and blue nodes are NPC nodes :
image

the first node with “Bonjour” is correctly stting to player speaking:
image

But when I talk to the NPC, it’s his name displayed in the first Dialogue panel.
image

Do I have missed something?
The rest of the dialogue go on normally with correct name displaying.

Thanks

François

Check the inspector for the player conversant. Do you have the wrong name in the Player Name field? If it is correct in the inspector, check the DialogueUI script to see if the correct get name method is being used.

Hello edc237.
My inspector Player Conversant in the Player Object I’ve the right Player Name :
image
but I think the error come from the GetCurrentConversantName:

public string GetCurrentConversantName()

        {

            if(isChoosing)

            {

                return playerName;

            }

            else

            {

                return currentConversant.GetName();

            }

        }

There is no Choosing when my player say Hello.
Only Next.
So I think it explain (the else) it displays NPC name.
If I put a ! in front of the isChoosing test, it’s the player name wich appear first but after all the sequence is inverted…
Any Idea?
Hera are my code but I checked 2 or 3 time…

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using RPG.Dialogue;

using TMPro;

using UnityEngine.UI;

namespace RPG.UI

{

    public class DialogueUI : MonoBehaviour

    {

        PlayerConversant playerConversant;

        [SerializeField] TextMeshProUGUI AIText;

        [SerializeField] Button nextButton;

        [SerializeField] GameObject AIResponse;

        [SerializeField] Transform choiceRoot;

        [SerializeField] GameObject choicePrefab;

        [SerializeField] Button quitCross;

        [SerializeField] Button exitButton;//New ref to add for the exit button

        [SerializeField] TextMeshProUGUI conversantName;

        void Start()

        {

            playerConversant = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerConversant>();

            playerConversant.onConversationUpdate += UpdateUI;

            nextButton.onClick.AddListener(() => playerConversant.Next());

            quitCross.onClick.AddListener(() => playerConversant.Quit());

            exitButton.onClick.AddListener(() => playerConversant.Quit());// New line to add for the Exit Button

            UpdateUI();

        }

        void UpdateUI()

        {

            gameObject.SetActive(playerConversant.isActive());

            if(!playerConversant.isActive())

            {

                return;

            }

            conversantName.text = playerConversant.GetCurrentConversantName();

            AIResponse.SetActive(!playerConversant.IsChoosing());

            choiceRoot.gameObject.SetActive(playerConversant.IsChoosing());  

            //choiceRoot.DetachChildren();

            if(playerConversant.IsChoosing())

            {

                BuildChoiceList();

            }

            else

            {

                AIText.text = playerConversant.GetText();

                nextButton.gameObject.SetActive(playerConversant.HasNext());

                exitButton.gameObject.SetActive(false);//For exit bouton

            }

            if(!playerConversant.HasNext())

            {

                exitButton.gameObject.SetActive(true);//For exit bouton

            }

        }

        private void BuildChoiceList()

        {

            choiceRoot.DetachChildren();

            foreach (DialogueNode choice in playerConversant.GetChoices())

            {

                GameObject choiceInstance = Instantiate(choicePrefab, choiceRoot);

                var textComp = choiceInstance.GetComponentInChildren<TextMeshProUGUI>();

                textComp.text = choice.GetText();

                Button button = choiceInstance.GetComponentInChildren<Button>();

                button.onClick.AddListener(() =>

                {

                    playerConversant.SelectChoice(choice);

                });

            }

        }

    }

}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace RPG.Dialogue
{
    public class PlayerConversant : MonoBehaviour
    {
        [SerializeField] string playerName;

        Dialogue currentDialogue;
        DialogueNode currentNode = null;
        AIConversant currentConversant = null;
        bool isChoosing = false;

        public event Action onConversationUpdate;

        public void StartDialogue(AIConversant newConversant, Dialogue newDialogue)
        {
            currentConversant = newConversant;
            currentDialogue = newDialogue;
            currentNode = currentDialogue.GetRootNode();
            TriggerEnterAction();
            onConversationUpdate();//lancement de l'évent conversation
        }

        public void Quit()
        {
            currentDialogue = null;
            TriggerExitAction();
            currentNode = null;
            isChoosing = false;
            currentConversant = null;
            onConversationUpdate();
        }

        public bool isActive()
        {
            return currentDialogue != null;
        }

        public bool IsChoosing()
        {
            return isChoosing;
        }

        public string GetText()
        {
            if (currentNode == null)
            {
                return "";
            }

            return currentNode.GetText();
        }

        public string GetCurrentConversantName()
        {
            if(isChoosing)
            {
                return playerName;
            }
            else
            {
                return currentConversant.GetName();
            }
        }

        public IEnumerable<DialogueNode> GetChoices()
        {
            return currentDialogue.GetPlayerChildren(currentNode);
        }

        public void SelectChoice(DialogueNode chosenNode)
        {            
            currentNode = chosenNode;
            TriggerEnterAction();
            isChoosing = false;
            Next();    
        }

        public void Next()
        {
            int numPlayerResponsives = currentDialogue.GetPlayerChildren(currentNode).Count();
            if(numPlayerResponsives > 0)
            {
                isChoosing = true;
                TriggerExitAction();
                onConversationUpdate();
                return;
            }

            DialogueNode[] children = currentDialogue.GetAIChildren(currentNode).ToArray();
            int randomIndex = UnityEngine.Random.Range(0, children.Count());
            TriggerExitAction();
            currentNode = children[randomIndex];
            TriggerEnterAction();
            onConversationUpdate();
        }

        public bool HasNext()
        {
            return currentDialogue.GetAllChildren(currentNode).Count() > 0;
        }

        private void TriggerEnterAction()
        {
            if(currentNode != null)
            {
                TriggerAction(currentNode.GetOnEnterAction());
            }
        }

        private void TriggerExitAction()
        {
            if(currentNode != null)
            {
                TriggerAction(currentNode.GetOnExitAction());
            }
            
        }
        private void TriggerAction (string action)
        {
            if(action == "") return;

            foreach(DialogueTrigger trigger in currentConversant.GetComponents<DialogueTrigger>())
            {
                trigger.Trigger(action);
            }
        }
    }
} 

Thanks.
François

The issue is that you are starting a conversation with the player talking first and the course assumes the NCP will speak first. Go to where StartDialogue is called and add a line that sets the conversant name to the player. I can not test this myself due to some changes I made in the project. My clean copy from the RPG series is archived. Try it and let me know if it works.

Hello.
I think I have no choice in StartDialogue methode in the PlayerConversant script. it’s necessarily the NPC. (AIConversant)

        public void StartDialogue(AIConversant newConversant,  Dialogue newDialogue)
        {
            currentConversant = newConversant;
            currentDialogue = newDialogue;
            currentNode = currentDialogue.GetRootNode();
            TriggerEnterAction();
            onConversationUpdate();//lancement de l'évent conversation
        }

I’ve no idea the way to force Player name displaying…
Thanks
François

The course design assumes that the first node will always be the speaker.

Later tonight, I’ll look at what adjustments would be needed to test for and then start with the Player (in the event that PlayerSpeaking is selected.

I think the easiest fix for this is to make that opening Dialogue “skip” if it’s IsPlayer… Then the next set of nodes can be the Player greeting (because now we’ll have a DialogueNode to use as a basis for the Next() method.

I’ll have to dig around in the code and find the most efficient solution. Believe it or not, this is the first time I recall anyone asking for the conversation to start with the Player.

1 Like

Lol, thank you Brian, I’m totally fond of your sentence :wink:
Maybe in France we think differently :smiley: :smiley:
Thanks a lot for your support you, and all the community.
François

PS: After discussing with my kids the notice me that in all game when you click in the npc, he’s the one we speak first.
It could be cool to start a dialogue with the Player and propose directly 2 our 3 sentences.
Why not.
But thnaks to spend some time to see how to do :wink:

1 Like

My solution was actually quite easy, and requires just a tidbit of code and a slight change to the way we set up or starting node…

First, head into PlayerConversant.cs and we’re going to borrow a little code from Next()

        public void StartDialogue(AIConversant newConversant, Dialogue newDialogue)
        {
            currentConversant = newConversant;
            currentDialogue = newDialogue;
            currentNode = currentDialogue.GetRootNode();
            TriggerEnterAction();
            if (currentNode.IsPlayerSpeaking())
            {
                int numPlayerResponses = FilterOnCondition(currentDialogue.GetPlayerChildren(currentNode)).Count();
                if (numPlayerResponses > 0)
                {
                    isChoosing = true;
                    TriggerExitAction();
                }
            }
            onConversationUpdated?.Invoke();
        }

Now… go into your Dialogue… Set it up as normal, but don’t worry about the root node’s text. Get those player choices in there, and then you can change the root node’s dialogue to be Is Player Speaking.

So here’s how this works… when we enter a conversation, we check to see if that root node is a player node. If it is, then we check to see if there are valid player nodes as children (much like we do in Next). If there are, then set IsChoosing to true and the system will display the player choices (the three in the above illustration) and compltely ignore displaying the root node.

It’s important to have at least on valid player choice, or that root node will end up being displayed as the speaker.

Hello Brian.
Thanks for this smart adaptation :slight_smile:
I suppose FilterOnCondition is a “futur” method we implement later ?
I actually attack quest chapter.
Thanks again having spent time for me :slight_smile:
Have a nice day.
Take care.
François

Yes, the FilterOnCondition will make a lot more sense once you get to the Quests section.

Thank you Brian :slight_smile:

Privacy & Terms