Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Group of gameObjects react to event, but how do I make only specific one?

Discussion in 'Scripting' started by krist101, May 1, 2022.

  1. krist101

    krist101

    Joined:
    Jul 19, 2019
    Posts:
    3
    Hello.
    So I am having a bit of a problem in Unity2D.
    I understand the why is this happening, but I cannot get it to work.
    Basically, I have a NPC that's a prefab (npcPrefab) and I make copies of that NPC so that they randomly spawn.
    When the newly created NPC enters the restaurant, the waiter comes and takes order, chef cooks... It all works.

    Problem is, when there is more than 1 NPC on screen.
    Let's say that there are 5 NPCs and one of them was served food, so therefore they should eat (do animation) & leave.
    The problem is that all 5 NPC will do that (do animation & leave).
    This is because I call an event when the food is served, and of course every NPC has the same script and listens to that event and therefore executes that method (to eat & leave).

    Here is a part of the code I use on all my tables to check who collided (so I know if NPC came, table is full, when should waiter come...):

    Code (CSharp):
    1. public class AtTheTable : MonoBehaviour {
    2.     public static event Action<Vector3> atTable;
    3.     public static event Action<ScriptableObjectsFood> atTableEmployee;
    4.     public static event Action foodBrought;
    5.     private bool firstTime = true;
    6.     private ScriptableObjectsFood fd;
    7.     public bool isHere = false;
    8.  
    9.     private void OnTriggerEnter2D(Collider2D other) {
    10.         if (Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.x, 3) == Math.Round(this.GetComponent<Transform>().position.x, 3)
    11.             && Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.y, 3) == Math.Round(this.GetComponent<Transform>().position.y + 0.3f, 3)) {
    12.             print("npc came to table");
    13.             atTable?.Invoke(GetComponent<Transform>().position);
    14.             fd = other.gameObject.GetComponent<WhatToEat>().foodToEat;//get object "food" from sript attached to NPC
    15.             isHere = true;
    16.         }//NPC
    17.         if (Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.x, 3) == Math.Round(this.GetComponent<Transform>().position.x + 0.6f, 3)
    18.             && Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.y, 3) == Math.Round(this.GetComponent<Transform>().position.y, 3) && firstTime) {
    19.             firstTime = false;
    20.             print("waiter came to table");
    21.             atTableEmployee?.Invoke(fd);
    22.         }//EMPLOYEE 1st time
    23.  
    24.         else if (Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.x, 3) == Math.Round(this.GetComponent<Transform>().position.x + 0.6f, 3)
    25.             && Math.Round(other.gameObject.GetComponent<NavMeshAgent>().destination.y, 3) == Math.Round(this.GetComponent<Transform>().position.y, 3) && !firstTime) {
    26.             print("waiter brought food");
    27.             firstTime = true;
    28.             foodBrought?.Invoke(); //<-here is where food is served, all NPCs are listening, but I want only specific one
    29.         }//EMPLOYEE 2nd time
    30.  
    31.     }
    32. }
    And here is the code from the NPCs:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. using System;
    6.  
    7.  
    8. public class NPCMove : MonoBehaviour
    9. {
    10.     private Animator animator;
    11.     public NavMeshAgent agent;
    12.  
    13.     void Start(){
    14.         animator = GetComponent<Animator>();
    15.         agent = GetComponent<NavMeshAgent>();
    16.         agent.updateRotation = false;
    17.         agent.updateUpAxis = false;
    18.      
    19.     }
    20.  
    21.     void OnEnable() {
    22.         AtTheTable.foodBrought += eatFood;
    23.     }
    24.     void OnDisable() {
    25.         AtTheTable.foodBrought -= eatFood;
    26.     }
    27.  
    28.     void Update(){
    29.         animator.SetFloat("Horizontal", agent.velocity.x);
    30.         animator.SetFloat("Vertical", agent.velocity.y);
    31.     }
    32.  
    33.     protected async void eatFood() { //part of code they all execute beause they all listen to it
    34.         animator.gameObject.SetActive(false);
    35.         animator.gameObject.SetActive(true);
    36.         animator.Play("NPC_Cook"); // This is the "eat animation" - temp.
    37.  
    38.         await MainManager.HoldUpForSeconds(3);
    39.         Transform ofTheEnd = GameObject.FindGameObjectWithTag("adios").transform;
    40.         agent.SetDestination(ofTheEnd.position);
    41.     }
    42.  
    43.  
    44. }
    45.  
    46.  
    Or have I completely missed? Is this happening because my Event is static (or all of them)? If so, how could I fix it?
    Thanks!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,735
    Well you're using a static event. That means there's only one event.

    You should probably have the event be specific to a specific table. That way the customers can listen to events only at the table they are sitting at, and the waiter can fire the events specifically for that table. To do this you'd have the events not be static, and you'd subscribe to the events as you sit at the table, and unsubscribe as you leave the table.
     
    krist101 likes this.
  3. krist101

    krist101

    Joined:
    Jul 19, 2019
    Posts:
    3
    Hello, and thanks for your answer.
    If I understand this correctly, I should ?.Invoke() events from Employees and subscribe/unsubscribe from Table scripts (basically opposite of what I was doing now)?
    Because then I am still not sure how to do it without being static to access it from other classes (without singletons).
    Because then I would have to call (if I make event to fire from waiter) - from my AtTheTable ex.
    EmployeeMove.theNewEvent += newMethod

    when I recognise a guest has arrived and unsubscribe when I notice the guest has left.
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,735
    You don't need singletons or anything like that. When you get an OnTriggerEnter2D callback from the customer or the employee overlapping the table, you can get a reference to the table script from there and either subscribe to or invoke the event.

    Likewise you can invoke or unsubscribe from events in OnTriggerExit2D.
     
    krist101 likes this.
  5. krist101

    krist101

    Joined:
    Jul 19, 2019
    Posts:
    3
    Oh okay, I understand now.
    Thank you very much!