- Home /
Press f to interact with NPC or objects
How do I change the method used for initiating the interaction. Instead of clicking object, check if within a certain radius of an object when you hit a key on your keyboard.
If within 1 unit, the player gets a message that they can press f to interact. When f is pressd, get the object they're close to and handle the interaction the same way.
PS. I'm using box collider.
Here are the script that I found. I tried this but once I start the game and press F key, its working. But I want the player to press the F key once the character is inside the collider of an object.
WorldInteraction
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class WorldInteraction : MonoBehaviour {
NavMeshAgent playerAgent;
void Start() {
playerAgent = GetComponent<NavMeshAgent>();
}
void Update() {
if (Input.GetMouseButtonDown(0) && !UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) {
GetInteraction();
}
}
void GetInteraction() {
Ray interactionRay = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit interactionInfo;
if(Physics.Raycast(interactionRay, out interactionInfo, Mathf.Infinity)) {
GameObject interactedObject = interactionInfo.collider.gameObject;
if (interactedObject.tag == "Interactable Object") {
interactedObject.GetComponent<Interactable>().MoveToInteraction(playerAgent);
} else {
playerAgent.destination = interactionInfo.point;
}
}
}
}
Interactable
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Interactable : MonoBehaviour {
public NavMeshAgent playerAgent;
public virtual void MoveToInteraction(NavMeshAgent playerAgent) {
this.playerAgent = playerAgent;
playerAgent.destination = this.transform.position;
Interact();
}
public virtual void Interact() {
Debug.Log ("Interacting with base class.");
}
}
NPC
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPC : Interactable {
public override void Interact() {
Debug.Log ("Interacting with NPC.");
}
}
Yeah there's a way to do that, use OverlapSphere to find coliders with respect to your specified position, radius, and layer.
public class YourScript : $$anonymous$$onoBehaviour
{
private float myRadius = 20;
public Layer$$anonymous$$ask myLayers;
private void Update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.F))
{
Collider[] objectToDetect = Physics.OverlapSphere(transform.position, myRadius, myLayers);
if (objectToDetect.Length > 0)
{
if (objectToDetect[0].gameObject.tag == "tagYouLookingFor")
{
//Do your thing
}
}
}
}
}
Well, I have two object tags to be interact by the player. Portal and NPC (Interactable Object). On Portal tag, the player will press the Enter button to select locations and for the NPC the player needs to press the F key to interact with NPC. I'm just confused. Are these correct? Correct me if I'm wrong.
private void Update()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.F))
{
Collider[] objectToDetect = Physics.OverlapSphere(transform.position, myRadius, myLayers);
if (objectToDetect.Length > 0)
{
if (objectToDetect[0].gameObject.tag == "Portal")
{
//Do your thing
}
}
}
else if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.F))
{
Collider[] objectToDetect = Physics.OverlapSphere(transform.position, myRadius, myLayers);
if (objectToDetect.Length > 0)
{
if (objectToDetect[0].gameObject.tag == "Interactable Object")
{
//Do your thing
}
}
}
}
What if I have 2 different tags to be interact like Portal and Interactable Objects? Can you check my code above? @nicholasw1816
What If I have 2 different tags? Lets say I have Portal and Interactable Objects tag. On the Portal tag, the player needs to hit the Enter $$anonymous$$ey to select locations while on the Interactable Objects or anything, the player needs to hit the F key. How would I do that on your code? Thanks.
What If I have 2 different tags? Lets say I have Portal and Interactable Objects tag. On the Portal tag, the player needs to hit the Enter $$anonymous$$ey to select locations while on the Interactable Objects or anything, the player needs to hit the F key. How would I do that on your code? Thanks.
Answer by dan_wipf · Dec 08, 2018 at 11:31 AM
well instead of this:
void Update() {
if (Input.GetKeyDown(KeyCode.F)&& !UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) {
GetInteraction();
}
}
you could use your box collider as trigger. then check if the plyaer is inside the collider.
//like this
void OnTriggerStay(Collider other){
if (other.tag == “Player” && Input.GetKeyDown(KeyCode.F)){
//your code
}
You need to have a rigidbody on one of the objects (you or the npc) and have isTriggered set to true on yourself ;)
$$anonymous$$y character has rigidbody and the isTriggered also checked.
well i dont know your experience with unity, but what you want is a trigger zone which if you, the player is inside can interract with what ever throught pressing f. this is achieved by a collider set to trigger, and then inside a script look for the player if he is inside and pressed the key. am i right if this is what you want?
Ins$$anonymous$$d of object.tag == "Player" can I use object.tag == Interactable Object" ?
Answer by Username801 · Feb 20, 2020 at 02:08 PM
I am a complete noob to unity. However, found a tutorial that seems good: link text.
Answer by berndunity · Dec 12, 2018 at 06:51 AM
You should set a bool to true when the player collides, as dan_wipf said, and use that bool inside update like.
public bool open = false;
if (other.tag == “Player”){
open = true;
}
Update(){
if (Input.GetKeyDown(KeyCode.F)){
//your code.
}
}
I think you get the idea, because OnTriggerStay is called once and update every frame.
Sorry for my late answer, but I would use OnTriggerEnter(){}
well then you cant call onkeydown, them you have to set a bool to true and inside the update part, call onkeydown
Its working now, but the problem is when I pressed the f key it doesn't call the GetInteraction method.
Can you send the updated code, because now I can't know how it looks like.
P.S. you haven't put the Update() in OnTriggerEnter()
Here's what I did. On the Portal tag there's a little problem. Why I got too much selection buttons of location? I just console the hasInteracted boolean and I got 18 response of "True". See screenshot below.
//World Interaction
void OnTriggerStay(Collider interactedObject) {
if (interactedObject.gameObject.tag == "Interactable Object" && Input.Get$$anonymous$$eyDown ($$anonymous$$eyCode.F))
{
GetInteraction(interactedObject);
}
else if (interactedObject.gameObject.tag == "Pickupable Object" && Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.LeftControl))
{
GetInteraction(interactedObject);
}
else if(interactedObject.gameObject.tag == "Portal" && Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Return))
{
GetInteraction(interactedObject);
}
}
void GetInteraction(Collider interactedObject)
{
hasInteracted = true;
interactedObject.GetComponent<Interactable>().Interact();
messagePanel.SetActive(false);
}
//Portal
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Portal : ActionItem {
public Vector3 TeleportLocation { get; set; }
[SerializeField]
private Portal[] linkedPortals;
private PortalController portalController { get; set; }
void Start () {
portalController = FindObjectOfType<PortalController>();
TeleportLocation = new Vector3(transform.position.x + 5f, transform.position.y, transform.position.z);
}
public override void Interact() {
portalController.ActivatePortal(linkedPortals);
}
}
//PortalController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PortalController : $$anonymous$$onoBehaviour {
[SerializeField]
private Button button;
private Portal[] portal;
private Player player;
private GameObject panel;
void Start() {
player = FindObjectOfType<Player> ();
panel = transform.Find ("PanelPortals").gameObject;
}
public void ActivatePortal(Portal[] portals) {
panel.SetActive (true);
for (int i = 0; i < portals.Length; i++) {
Button portalButton = Instantiate (button, panel.transform);
portalButton.GetComponentInChildren<Text> ().text = portals [i].name;
int x = i;
portalButton.onClick.AddListener (delegate {
OnPortalButtonClick (x, portals [x]);
});
}
}
void OnPortalButtonClick(int portalIndex, Portal portal) {
player.transform.position = portal.TeleportLocation;
foreach (Button button in GetComponentsInChildren<Button>()) {
Destroy (button.gameObject);
}
panel.SetActive (false);
}
}
public void ActivatePortal(Portal[] portals) {
panel.SetActive (true);
for (int i = 0; i < portals.Length; i++) {
Button portalButton = Instantiate (button, panel.transform);
portalButton.GetComponentInChildren<Text> ().text = portals [i].name;
int x = i;
for ( int p = 0; p < portals.Lenght; p++){
if (p.name == i.name ){
` Destroy(p.gameObject);
}
}
portalButton.onClick.AddListener (delegate {
OnPortalButtonClick (x, portals [x]);
});
}
}
$$anonymous$$ake a for loop inside the other for loop to check if there aren't any double buttons, if there are then destroy it.(I can't check if this will work).