Interaction Script help

So I am fairly new at scripting; and have looked up several ways to do this but so far am not having any luck. I want to be able to interact with an item/npc once entering a radius around it (sphere collider most likely) with a single button press (lets use C for simplicity sake) but am finding no help online for something like this. Can anyone give me pointers???

Not sure it matters but movment is using the WASD keys, and I want the end product to be a Fable like game.

Have a collider around the target, set up a ontriggerenter for when you enter the collider, you set a bool to true. Then you can display something like “hit c to talk”. Then when they hit c, check the bool and trigger your dialog. If the bool is false, you do nothing.

Use OnTriggerExit to set bool to false when the player leaves the trigger.

Thank you. I am a little rusty on my scripting knowledge, took a two year break from game design thanks to life, and now trying to play catchup.The terms you gave me should help me piece it together though.

Would love a sample script though…lol i know its kind of cheating and unfair of me to ask. Just something to show the basic setup of the script.

Give your player the collider, and when it hits something, then do something. It should be a Trigger, and I think you need a kinematic Rigidbody component attached too. Even better, it would be a box in front of your player, so you can only interact when facing the correct direction.

Everything that is interactable would have an Interactable script, or be on the Interactable layer. If a script, it would be on the same gameobject that has the collider.

You also need a script to store the current interactable that you are colliding with, because their might be 5, so you need the most recently hit one.

Goes on every collider you want to interact with.

using UnityEngine;
using System.Collections;
using UnityEngine.Events;

public class InteractableS : MonoBehaviour {

   [Header("Events")]
   public InteractableEvent onInteract;

   [System.Serializable]
   public class InteractableEvent : UnityEvent<InteractableS> { }

   public void Interact()
   {
       onInteract.Invoke(this);
   }

}

Goes on collider attached to your player. Detects collisions and checks if they are an InteractableS. Does other checks like “is the collider we exited our Current one? Then clear it”.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;

public class InteractableDetectorS : MonoBehaviour {

   [Header("Info")]
   public InteractableS _current;

   [Header("Events")]
   public EventCurrentInteractableChanged onCurrentInteractableChanged;
   public UnityEvent onCurrentInteractableLost;

   [System.Serializable]
   public class EventCurrentInteractableChanged : UnityEvent<InteractableS> { }

   //============================================
   // UNITY FUNCTIONS
   //============================================

   public void OnColliderEntered(Collider collider)
   {
       // Collided object has an InteractableS script?
       InteractableS interactable = collider.GetComponent<InteractableS>();
       if (interactable == null) return; // If not, stop

       if (!HasCurrent())
       {
           Current = interactable;
       }
   }

   public void OnColliderExited(Collider collider)
   {
       InteractableS interactable = collider.GetComponent<InteractableS>();
       if (interactable == null) return;

       if (HasCurrent(interactable))
       {
           Current = null;
       }
   }

   //============================================
   // HELPER FUNCTIONS
   //============================================

   public bool HasCurrent()
   {
       return Current != null;
   }

   bool HasCurrent(InteractableS interactable)
   {
       return Current == interactable;
   }

   //============================================
   // PROPERTIES
   //============================================

   public InteractableS Current
   {
       get { return _current; }
       set
       {
           if (value == null)
           {
               _current = value;

               onCurrentInteractableLost.Invoke();
               onCurrentInteractableChanged.Invoke(_current);
           }
           else if (value != _current)
           {
               _current = value;

               onCurrentInteractableChanged.Invoke(_current);
           }
       }
   }

}

A test input script would be like this on your player:

public class PlayerInput : MonoBehaviour {

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.C))
        {
            InteractableDetectorS detector = GetComponent<InteractableDetectorS>();

            if (detector != null)
            {
                if (detector.HasCurrent())
                    detector.Current.Interact();
            }
    }

}

Thanks a lot man. The tips are great and I can’t wait to dive into this and see if I can get my NPC’s to respond to my PC in the project.

Now, unless I am missing something, I need to tie a third script to any object after its been interacted with, bringing up what they say right?

You should hook up the onInteract event in the inspector to a script that starts a dialog system, or shows a GUI or something.

That is actually what I was thinking. Seriously, I was taught all this once and fell like such a dumb ass for forgetting it all.

Ok as annoying as this is, nothing I try works. Looking online for ways to call up dialogue after interacting and none of it seems to be functioning the right way. Tried the Simple RPG tutorials which are highly recommended and they didn’t help either.
Have my character moving (although his running animation isn’t working right, work on that later), camera following him at right height, paths mostly correct to allow movement.
The hardest thing so far for me is intractability at all. Can’t get him to interact with any items or the NPCs.

Hey there, if you’re still lost/not got this working, could you post the code that you’re using for interacting? That might help for further assistance. :slight_smile:

Well still can not get the code given above to work. Not sure what I am doing wrong, but it seems to do nothing after being attached to the NPC and then to my PC. Only thing I can think of is I am not adding something I should have.
I am a noob at this, sorry. Actually if anyone would be willing to Skype and teach me a little, it would be appreciated. Tutorials seem to be hit or miss, with a lot more being a miss.

The code i am using is presented above, although i have now been sent another code by a friend of mine that should work a little differently. I can’t get either to work and it is starting to get irritating. I have tried tons of tutorials and none of them seem to get it right either.
Honestly if people would stop sending me code and explain why the code isn’t working it would be helpful. Can’t learn with new options thrown at me without explanation of why the old didn’t work.

When in doubt, throw print statements everywhere!

When debugging in general, it’s a process of elimination. Is the OnColliderEntered being called? Is it doing what you’re expecting it to do? No? The code must be taking a different path.

It might help to work backwards from the very last event you’re expecting to happen. In this case:

        if (Input.GetKeyDown(KeyCode.C))
        {
            InteractableDetectorS detector = GetComponent<InteractableDetectorS>();

            if (detector != null)
            {
                if (detector.HasCurrent())
                {
                    detector.Current.Interact();
                }
            }
    }

Is the detector.Current.Interact(); line ever reached? Add a print statement and see if it fires. If it does, then you know the problem is not in the player script, it’s in the detector/interactable scripts. If it doesn’t fire, then the variables are clearly not what you’re expecting them to be. Here if the detector doesn’t have a current interactable paired with it, the detector is null, or the Input is bugged (unlikely) then it wont fire.

I thank you greatly. I will get back into it and see what the problem is. Had problems with camera and movement earlier when i reopened my scene after a break so that took up a chunk of time i wasn’t expecting.

Oh, I did forget to add, the collider’s not triggering and all that stuff doesnt matter at the moment because the compiling errors in this script will not let me play the scene.

Is there any way to cross your text out on here???
Also…all three errors i had were caused by a simple misplaced }

However now i have a new error:
Assets/Scripts/InteractableDetectors.cs(9,30): error CS1519: Unexpected symbol `;’ in class, struct, or interface member declaration

The KeyCode bug is because KeyCode.internal doesn’t exist.

The void update line is because it thinks you’re declaring a property instead of a method (which is what Update is).
You should probably need to know about them and what they do:
Bunch o’ stuff about scripts

    // Property:
    public int NumCakes
    {
        get
        {
            return chocCakes + vanillaCakes;
        }
    }

    // Fields
    int chocCakes = 4;
    int vanillaCakes = 2;


    // Method
    public int GetCakes()
    {
        return chocCakes + vanillaCakes;
    }

Properties are like fields and methods squished together. They can move data around and can do other functions like trigger an event when accessed. You use them like normal fields though, what they do under the hood is invisible to the caller.
Fields are your standard variables that sit there and get either assigned to or read. They can’t do anything except store a value and be used by other code.
Methods are the workhorses that move data, operate on data, and produce data.

The interactables line is because it doesn’t have a type. It doesn’t know what the interactables_current variable is. To declare it you’d do this:

public InteractableS interactable_current;

Typically variable declaration in C# follows the convention [modifiers] [type] [name];

Where modifiers are public, private, static, protected, abstract, etc.

Well that didn’t get rid of that error oddly.
As…the correct placement of the following code is where?

if (Input.GetKeyDown(KeyCode.C))
[*]        {
[*]            InteractableDetectorS detector = GetComponent<InteractableDetectorS>();
[*]            if (detector != null)
[*]            {
[*]                if (detector.HasCurrent())
[*]                {
[*]                    detector.Current.Interact();
[*]                }
[*]            }
[*]    }

Can you copy/paste the code? Preferably with code tags

I thank you for the code tag link lmao. At one time I was well versed in properties and methods, but its been awhile. I want to apologize if this error is so blatantly obvious i look like a moron right now…

Also, its still saying _current is not defined. Not sure why it didn’t flag it earlier but it’s now all over the place.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;

public class InteractableDetectors : MonoBehaviour {
    public Interactables interactable_current;

    [Header("Info")]
    public interactable_current;


    [Header("Events")]
    public EventCurrentInteractableChanged onCurrentInteractableChanged;
    public UnityEvent onCurrentInteractableLost;

    [System.Serializable]
    public class EventCurrentInteractableChanged : UnityEvent<Interactables> { }

    //============================================
    // UNITY FUNCTIONS
    //============================================

    public void OnColliderEntered(Collider collider)
    {
        // Collided object has an InteractableS script?
        Interactables interactable = collider.GetComponent<Interactables>();
        if (interactable == null) return; // If not, stop

        if (!HasCurrent())
        {
            Current = interactable;
        }
    }

    public void OnColliderExited(Collider collider)
    {
        Interactables interactable = collider.GetComponent<Interactables>();
        if (interactable == null) return;

        if (HasCurrent(interactable))
        {
            Current = null;
        }
    }

    //============================================
    // HELPER FUNCTIONS
    //============================================

    public bool HasCurrent()
    {
        return Current != null;
    }

    bool HasCurrent(Interactables interactable)
    {
        return Current == interactable;
    }

    //============================================
    // PROPERTIES
    //============================================

    public Interactables Current
    {
        get { return _current; }
        set
        {
            if (value == null)
            {
                _current = value;

                onCurrentInteractableLost.Invoke();
                onCurrentInteractableChanged.Invoke(_current);
            }
            else if (value != _current)
            {
                _current = value;

                onCurrentInteractableChanged.Invoke(_current);
            }
        }
    }

because it’s not defined :stuck_out_tongue_winking_eye:

The original script:

[Header("Info")]
public InteractableS _current;

The one you posted:

[Header("Info")]
public interactable_current;

First it should have a space between interactable and _current, and “interactable” should be “InteractableS”.

Modifiers, type, name.