Bugs with adding the extra code

Hi Brain

I have been adding code to the project throughout, I saw you had posted a couple of helpful additions, things like moving to an item before picking it up, moving to a NPC to talk to them before talking, and moving to a shop before opening it. I added all three of them and some others, however I am running into issues with those three. I can’t escape moving to the object I click in those scenarios. I think that means my ActionScheduler is not cancelling the current action.

I also found an issue with dialogue where if you click on a npc and before you get to them click somewhere else it will cause an issue where you won’t be able to speak to that npc again or it may crash.

I would love to get your help to fix the 3, I am sure they all run into the same issue so if I can fix on I can fix the others.

These are the files for picking up the items.

public class Collector : MonoBehaviour, IAction
{
    Pickup target;
    Mover mover;
        private void Update()
        {

            if (target == null) return;
            //Vector3.Distance(tempShop.transform.position, transform.position) > 3
            //mover.CanMoveTo(target.transform.position);
            if (target != null && (Vector3.Distance(target.transform.position, transform.position) > 3))
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1f);
            }
            else
            {
                GetComponent<ActionScheduler>().StartAction(this);
                GetComponent<Mover>().Cancel();
                target.PickupItem();

            }
        }

    public void StartCollectionAction(Pickup pickup)
    {
        target = pickup;
    }

        public void Cancel()
        {
            Debug.Log("CANCEL CALLED");
            target = null;
            GetComponent<Mover>().Cancel();
        }
}
}

and this is in the Pickup to handle the raycast

public bool HandleRaycast(PlayerController callingController)
        {
            if (Input.GetMouseButtonDown(0))
            {
                callingController.GetComponent<Collector>().StartCollectionAction(pickup);
                //collector.StartCollectionAction(pickup);
                //pickup.PickupItem();
            }
            return true;
        }

Here is the one for shopping

 private void Update() {
            if(tempShop == null) return;
            if(tempShop)
            {
                if(Vector3.Distance(tempShop.transform.position, transform.position) > 3)
                {
                    GetComponent<Mover>().MoveTo(tempShop.transform.position, 1);
                }
                else
                {
                    if(!shopOpen)
                    {
                    GetComponent<Mover>().Cancel();
                    SetActiveShop();
                    }
                }
            }
        }

        public void OpenShop(Shop shop)
        {
            if(shop == null) return;
            GetComponent<ActionScheduler>().StartAction(this);
            tempShop = shop;
        }

        public void SetActiveShop()
        {
            playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
            playerController.enabled = false;
            shopOpen = true;
            if(activeShop != null)
            {
                Debug.Log("Active shop set shopper null");
                activeShop.SetShopper(null);
            }
            activeShop = tempShop;
            tempShop = null;
            if (activeShop != null)
            {
                Debug.Log("active shop set shopper this");
                activeShop.SetShopper(this);
            }
            if (activeShopChange != null)
            {
                Debug.Log("active shop change");
                activeShopChange();
            }
        }

        public void Quit()
        {
            playerController.enabled = true;
            activeShop = null;
            shopOpen = false;
            if (activeShop != null)
            {
                Debug.Log("Active shop set shopper null");
                activeShop.SetShopper(null);
            }

            if (activeShopChange != null)
            {
                Debug.Log("active shop change");
                activeShopChange();
            }
        }

        public void SetBoolShop(bool setStatus)
        {  
            shopOpen = setStatus;
        }

        public Shop GetActiveShop()
        {
            return activeShop;
        }

        public void Cancel()
        {
            GetComponent<Mover>().Cancel();
        }
    }
}

We’ll start with the Pickup. It looks like you’re not clearing the target after the pickup action itself. Add this line after target.PickupItem(); in Collector.Update()

target=null;

In StartCollectionAction, you’re not invoking the ActionScheduler, so it never registers to get cancelled.

public void StartCollectionAction(Pickup pickup)
{
    GetComponent<ActionScheduler>().StartAction(this);
    target=pickup;
}

Not all of the Shop.cs is shown, so I’m not sure if you’re calling Acitonschedular.StartAction() or not there. That would be the next thing to check.

Paste in your AIConversant.cs and PlayerConversant.cs and we’ll see if we can figure out what’s going on there.

Thanks for the reply, the lines helped the item pick up one work

this is the code for the shopper that gets called

 if(Input.GetMouseButtonDown(0))
            {
                callingController.GetComponent<Shopper>().OpenShop(this);
            }
            
            return true;
        }

than in the shopper you have openShop look like this, the rest of the shopper code is in the original post

 public void OpenShop(Shop shop)
        {
            if(shop == null) return;
            GetComponent<ActionScheduler>().StartAction(this);
            tempShop = shop;
        }

as for the Conversant here they are, there is more to this file, but I think I have given all the important parts.

public class PlayerConversant : MonoBehaviour, IAction
    {
        [SerializeField]
        string playerName;
        Dialogue currentDialogue;
        DialogueNode currentNode = null;
        AIConversant currentConversant = null;
        bool isChoosing = false;
        PlayerController playerController;
        AIConversant targetConversant;
        public event Action onConversationUpdated;
    
        public void StartDialogueAction(Dialogue dialogue, AIConversant speaker)
        {
            //Debug.Log($"StartDialogueAction {speaker}/{dialogue}");
            if(currentConversant != null && currentConversant == speaker) return;
            if(currentDialogue != null) Quit();
            if(dialogue == null)
            {
                return;
            }
            GetComponent<ActionScheduler>().StartAction(this);
            targetConversant = speaker;
            currentDialogue = dialogue;
        }
        
        
        private void Update() {
            assignPlayerController();
            if(targetConversant == null) return;
            if (targetConversant)
            {
                if (Vector3.Distance(targetConversant.transform.position, transform.position) > 3)
                {
                    GetComponent<Mover>().MoveTo(targetConversant.transform.position, 1);
                }
                else
                {
                    GetComponent<Mover>().Cancel();
                    StartDialogue();
                }
            }
        }

        private void StartDialogue()
        {
            //playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
            playerController.enabled = false;
            currentConversant = targetConversant;
            targetConversant = null;
            currentNode = currentDialogue.getRootNode();
            onConversationUpdated();
        }

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

        public void Quit()
        {
            playerController.enabled = true;
            currentDialogue = null;
            TriggerExitActions();
            currentNode = null;
            isChoosing = false;
            currentConversant = null;
            onConversationUpdated();
        }

  public void Cancel()
        {
            GetComponent<Mover>().Cancel();
            Quit();
        }

        public void assignPlayerController()
        {
            if(playerController != null) return;
            playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();

        }

This is the AI file

 public bool HandleRaycast(PlayerController callingController)
        {
            if(dialogue == null)
            {
                return false;
            }

            Health health = GetComponent<Health>();

            if (health && health.IsDead()) return false;

            if(Input.GetMouseButtonDown(0))
            {
               callingController.GetComponent<PlayerConversant>().StartDialogueAction(dialogue, this);
            }
            return true;
        }

Thanks for the help again

It’s quite possible that the issue is in the TriggerExitActions method (not posted)… by default, we’re not really doing a lot of error checking in the original code. In this case, we’re not setting currentConversant untll the player reaches the destination, but TriggerExitActions calls TriggerAction on the currentNode’s exit action string, which then calls every DialogueTrigger on the AIConversant…

The simplest fix here is to do a null check on the AIConversant at the beginning of TriggerAction

if(currentConversant==null) return;

I am curious in PlayerConversant and Shopper as to why you are setting the playerController value with a FindWithTag… The Player Controller should be on the same GameObject as the Player Conversant and Shopper, which means in Awake() you can set this value with

playerController = GetComponent<PlayerController>();

I can’t see any other reason that Shopper and PlayerConversant would continue to hold on to their targets when cancelled. Once the above fixes are applied, what is the status? At this point, (I probably should have asked sooner, would have led us right to the TriggerAction line) are there any error messages in the inspector?

So the reason it is set with FindWIthTag is that is what the tutorial videos tell you to do, unless I missed a video or something.

This the Trigger Exit Action method one in the player Conversant file.

    private void TriggerExitActions()
        {
            if (currentNode != null)
            {
                TriggerAction(currentNode.GetOnExitAction());
            }
        }

This is the GetonExitAction which is in the DialogueNode.cs file

 public string GetOnExitAction()
        {
            return onExitAction;
        }

The trigger exit method for Shopper just calls the quit function. All the // code is things that I have tried that usually cause crashes or errors along the way.

public void Close()
        {
            //shopper.SetBoolShop(false);
            //GetComponent<Shopper>().setShopStatus(false);
            //shopper.SetActiveShop(null);
           // GetComponent<Mover>().Cancel();
            shopper.Quit();
        }

Tried moving what you said to the Trigger action, still does not work

 private void TriggerAction(string action)
        {
            if (currentConversant == null) return;
            if (action == "") return;

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

As for errors, if you let the player walk up to the dialogue npc, than no there are no errors, however if you click away even though the player can’t escape walking up to the dialogue npc you will get an error there. The error will make it so no dialogue will show up.

There aren’t any errors with the shop though. That one runs fine besides the fact you can’t exit moving right towards them.

Line 64 is in this function, and it is the current node = currentDialogue.GetRootNode(); line.

 private void StartDialogue()
        {
            
            //playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
            playerController.enabled = false;
            currentConversant = targetConversant;
            targetConversant = null;
            currentNode = currentDialogue.getRootNode();
            onConversationUpdated();
        }

Sorry if I forgot any of the code you asked for, I think I posted the ones you asked for that I missed last time.

Hey I think I may have fixed the issues, both of them were fixed when I added the = null lines to both of them. I am hoping that there wont be any bugs so I will test and let you know if anything happens.

public void Cancel()
        {
            targetConversant = null;
            GetComponent<Mover>().Cancel();
            Quit();
        }
public void Cancel()
        {
            tempShop = null;
            GetComponent<Mover>().Cancel();
        }

For components on NPCs, this is the way to get the Player’s components. I.e. AIConversant, AIController, Shop
For components on the Player, you’re already on the player, so a simple GetComponent is the way to go. This includes PlayerConversant, Shopper, etc.

Pasting in just pieces of the code makes it very difficult to really see what’s going on (often times, the actual problem is hiding in a piece not yet posted, and tracing through the code in a script spread over 4 replies… It’s much better to paste in the entire script.

When you double click on the line in the error message, and it takes you to line 64 of PlayerConversant in the code editor, what is the specific line that it is telling you the null reference is on?

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms