Access event through other GameObject

In my design, NPC prefabs cannot have GameObject dependencies that have to be dragged and dropped – at least not if I’m going to procedurally spawn the NPCs. My problem is that I have a few player animation events which I would like to pass to procedurally spawned NPCs. It doesn’t matter if they all get the message at the same time, since I have other bool checks as well.

My problem is that the event can only be sent to player. It’s not practical to drag the player GameObject to every single spawned NPC. I checked out UnityEvents, but you need to assign a GameObject in the inspector too, or am I misunderstanding? So, how can I reference the player animation event within a script on the NPC? Thanks.

I’ve never used an animation event, but just thinking out loud… could you have the game object that spawns your NPCs have the method that the animation event calls? You could either keep a collection of spawn enemies and call a method on each when the event happens, or get them to register to an event on the spawner for the same purpose, perhaps.

That’s a nice idea, but I’ll be using DunGen for most of the spawning, and I’d rather not monkey with someone else’s code. Also, the spawns wouldn’t necessarily be at runtime. But, even if I drag and drop an NPC in the scene, I want to drag it in there and be done with it.

I’ve already wired them for AI and dealing damage to player. In that case, I use animation event, but do a Find(“player”) search OnEnable(), so NPC knows to test whether player is in fact the object which is hit and damage is recorded in player’s Game Control. Unfortunately, the opposite will not work, even if there are only two NPCs, that is one too many. This is what I want to pass to NPC:

    private void Defend()
    {
        if (got_hit && hit_enemy_window && !already_got_hit && !blocking)
        {
            already_got_hit = true;
            if (Character_Sheet.control.which_weapon_equipped == 1)
                enemy_health -= (player_damage * player_damage_multiplier) * (1 + Character_Sheet.control.weapon_index);
            else enemy_health -= player_damage * player_damage_multiplier;
        }

        else if (!hit_enemy_window)
            already_got_hit = false;

        if(enemy_health <= 0)
        {
            anim_golem.SetTrigger("die");
            Destroy(gameObject, 10f);
        }

    }

The bool got_hit is set to true when triggered on the player, where anything tagged “enemy” will do the following:

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Enemy")
        {
            other.gameObject.GetComponent<Enemy_Attack>().got_hit = true;
        }
    }

The other condition which must be true is the “hit_enemy_window.” This is the one which needs to be determined by the animation event as follows:

    private void Can_Attack(int can_hit)
    {
        if (can_hit != 0)
        {
            hit_player_window = true;
            damage_multiplier = can_hit;
        }

        else if (can_hit == 0)
            hit_player_window = false;
    }

Is there some “trick” I can use to set a global event without using Inspector? UnityEvent is not documented very well, and I could only get it to work in inspector. I suspect this will solve my problem, but how to make it work at runtime through script?

Well, I will offer an alternative suggestion and ask you a question.

First, the question: Can you explain in a few words what the animation event is doing for your game?
I know you posted the code, you said, but it would just be easier to hear a clear, and concise explanation from you (in case there are any alternatives that come to mind, I mean).

Okay, the first time I suggested that the spawner do the adding to the list, but I didn’t realize you were using some asset that you didn’t want to mess with.
In that case, you could have the enemies add themselves to a list on some other game object’s script. You could do this with a singleton, for example. In fact,you could probably keep a static list on a script on the enemy, also.
In either of those situations, the animation event could call a method, on a game object that you have in the scene, which could in turn : call a method on the game object (singleton), or simply execute a series of calls across the static list on the script on the enemy.

Those are a couple of ideas I could think up. If you share your goals about what this is doing for you, perhaps I (or someone else) could offer other options. :slight_smile:

Thanks for the help. I guess I wasn’t too clear earlier. I have a trigger attached to the player which is always active. It sets a bool to true if an object tagged “enemy” enters the trigger. Secondly, I have another bool which is only true at certain frames of the animation. For example, for a sword swing, the bool is only true for the frames when the sword is extended the most.

Both of these bools must check to true in order for the attack to register as damaging. The purpose of this is so that timing and positioning are important game mechanics – both must be fulfilled. The enemy NPC works this way with the two bools, and player can roll out of the way to dodge, etc.

It has to go both ways though. I have to use animation events, because coding different timings with WaitForSeconds() or something for all of the different attack animations would be a nightmare. There are a lot of them, and I’m trying to make the code as generic as possible.

It all fits together just as I envisioned, except for the animation event of the player attacking. Handling player damage from the enemy NPC is not so difficult, due to being able to Find the player, which is always active. I don’t want to have to do Find all the time though, and it would be better if the bool evaluated to true for only the enemy NPC that was attacked when the animation event triggered. All of the enemies in the scene have the script attached though.

I’m not so familiar with singletons, but if the same script is on each enemy, wouldn’t that be a problem? I see how keeping a list or array of the enemies would work, and I may have to go that route, but I’d rather not have to bookkeep the enemies in the scene. Maybe I’ll give it a try. Thanks for the suggestions. If you have more, now that I’ve explained the problem, I’d be glad to hear them.

I patched it together, but it’s really sloppy. I have a GameObject whose sole purpose is to Find(“player”). That way I can detect the animation event in one of the player scripts, set the bool there, and access it in the enemy_attack script as if(player_script.bool == true), if that makes sense. I’m still open to suggestions though, and I’ll be looking into the methods you mentioned earlier.

Okay, so that explanation made a lot more sense to me. I can be slow sometimes. :slight_smile:
If you set the bool with the animation event, and you only want only the attacked NPC (or NPCs, if more than 1 can be there), then I would change my answer to this:
Keep a reference of the attacked NPC(s), and when you get the animation event, set the bool using that.
No need to keep a list of them all, or anything else I suggested.

  • at first, I thought you wanted this event to reach every NPC at once. :slight_smile: Sorry.

That sounds good, yeah?

The idea you posted just before I hit ‘post’ sounds okay, too. If you track the variable in 1 script and the enemies involved in the attack can access it easily, sounds okay. :slight_smile: