Universal Projectile Script

So I see that Rick actually went ahead and hardcoded in that the projectile damages only attackers. I personally wanted to make the projectile script universal so it could be thrown easily onto either an ally or an enemy projectile. I was wondering if this was the most efficient format for doing so. I created dummy scripts called “Ally” and “Enemy” that were simply used for classification purposes.

When the projectile is instantiated, it checks to see if it is an ally or enemy. If it is an ally, it sets the bool “ally” to true. During TriggerEnter2D, it then checks the other collider to see if it is an ally. If it is an ally, it sets the bool “other” to true. If both bools match, then the CheckIfOtherIsAlly condition will be true, which disables the if statement in TriggerEnter2D.

    bool ally = false;

    private void Start()
    {
        CheckIfAlly();
    }

    private void CheckIfAlly()
    {
        if (GetComponent<Ally>())
        {
            ally = true;
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        // If it is not an ally, deal damage.
        if (!CheckIfOtherIsAlly(other))
        {
            DamageHandler damageHandler = GetComponent<DamageHandler>();
            Health healthOfOther = other.GetComponent<Health>();
            healthOfOther.DealDamage(damageHandler.GetDamage());
            Destroy(gameObject);
        }
    }


 // This checks to see if the colliding creature is an ally or enemy. If it's an ally, it will return true.
    private bool CheckIfOtherIsAlly(Collider2D other)
    {
        bool otherIsAlly = false;
        //Find if there is enemy or ally script on it.
        if (other.GetComponent<Ally>())
            { otherIsAlly = true;}

        if (ally == otherIsAlly)
        { return true; }
        else
        { return false; }
    }

Hi.
Learned a new thing from your code; private bool CheckIfOtherIsAlly(Collider2D other) actually never considered using Collider2D as a parameter in a function other than OnTriggerEnter/OnCollisionEnter functions. And it is a fine use of passing parameters, which i still find it a bit hard to cover.

1 Like

Yup, it works to pull the information off the other object through collision! Only requirement to call the collision data is to actually have a collision, so it might not be the best thing to try to call it without a Trigger or Collision function checking first.

I figured it would be much easier to read and a lot tidier to call a function rather than throwing it all in one TriggerEnter2D function. With my code I like having only extremely simple things in my code, so I find every reason to create a new function.

Hi Terra.

So this code is like blue team vs red team in the forest, using laser tag and friendly fire is off.

I have been trying to figure out the lines. I have couple of questions, would you be so kind to answer?

First of all, did you give any references on the projectile? How did you call GetComponent() in the CheckIfAlly() function?

You declared a local variable of type bool in CheckIfOtherIsAlly() and took the argument to make compare. I know that you do not need to give any reference if you are using Collider2D parameter as you did in the if statement. So you checked if the other gameObject has the Ally.cs attached on it. And see if they match or not. Then you took the bool type function to see if you can make damage to the target.

I crossed this page on a GetComponent related question. That’s why I am trying to understand your approach.

I hope you do not find this bothering.

So the way I have my game set up is that any object having to do with the player with an “Ally” component, regardless of if it is a character, a projectile, or an empty with a collider on it. For anything that an ally is supposed to be able to hit, I give it the “Enemy” component. I rarely call “Enemy” as there are currently only two teams, but I like to be prepared in case I wanted to add a third.

Explaining my “private bool CheckIfOtherIsAlly()” a bit more:
I declare a private bool “otherIsAlly” as false.

The if statement uses "other.GetComponent() to check if there is an ally component on the object my projectile collides with. In this case, it will return true if it finds an “Ally” component. This will declare that “otherIsAlly” is true.

The next if/else statement checks to see if the projectile and the colliding object are on the same side. If they are, then CheckIfOtherIsAlly will return true. It will return false if they are on opposing sides.
This does this by taking the “ally” bool declared in Start(), which references the projectile
and comparing it to the bool “otherIsAlly”, declared in CheckIfOtherIsAlly(), which references the colliding object.

CheckIfOtherIsAlly()'s purpose it to check if the colliding object is an ally of the projectile. If both have the Ally component, then they are allies. But this is also true if both have the Enemy component.

This then sends this bool to the if statement in OnTriggerEnter2D().
In this if statement, I placed an exclamation point before the condition CheckIfOtherIsAlly(other). This exclamation point means that it is checking to see if the other is NOT an Ally. If the other is NOT an ally, then DealDamage() will be called, as well as the necessary components to call DealDamage().
The projectile object will then be destroyed, as it has served its purpose.

Thanks for the detailed explanaion.

Could you please explain how this function not turning into an error message? Because i thoguht this projectile gameObject had to have Ally.cs or Enemy.cs attached on it. It didn’t use Collider2D paramter like in CheckIfOtherIsAlly(Collider2D other) or OnTriggerEnter2D(Collider2D other) . The rest is crystal clear.

private void CheckIfAlly()
{
    if (GetComponent<Ally>())
    {
        ally = true;
    }
}

Thank you again.

By the way, this is my projectile code after combining with yours. I implemented your CheckOfOtherIsAlly() funciton, and its extension into my OnTriggerEnter2D()

[SerializeField] private float spinner = 360;
[SerializeField] private float projectileSpeed = 2f;
private DamageDealer damageDealer;

private bool ally = false;

private void Start()
{
    damageDealer = GetComponent<DamageDealer>();
    CheckIfAlly();
}

private void Update()
{
    transform.Rotate(0, 0, -spinner * Time.deltaTime);
    GetComponent<Rigidbody2D>().velocity = new Vector2(projectileSpeed, 0);
}

private void OnTriggerEnter2D(Collider2D target)
{
    // If it is not an ally, deal damage.
    if (!CheckIfOtherIsAlly(target))
    {
        Debug.Log(target);
        var health = target.GetComponent<Health>();
        var damage = damageDealer.GetDamage();
        health.DamageDealt(damage);
        Destroy(gameObject);
    }
}

private void CheckIfAlly()
{
    if (GetComponent<Defender>())
    {
        ally = true;
    }
}

// This checks to see if the colliding object is an ally or enemy. If it's an ally, it will return true.
private bool CheckIfOtherIsAlly(Collider2D target)
{
    bool otherIsAlly = false;
    //Find if there is enemy or ally script on it.
    if (target.GetComponent<Defender>())
    { otherIsAlly = true; }

    if (ally = otherIsAlly)
    { return true; }
    else
    { return false; }
}

I believe it is not returning an error because I use an if statement. If there is no code to call in a void function, it just returns void, to my understanding. I’m not 100% positive though.

It’s good that you implemented it with the Defender component, just watch that you might have unnecessary coding in Defender.cs or code that gives you trouble with the projectile. To remedy it myself, I have classes of characters. Allies and Enemies are side classifications, and then I have Shooter(ranged), Fighter(melee), Generator(makes currency), Projectile(ranged ammo), and Hitter(melee weapon).

Also, I found a bug within my code. It was simple. This new version includes the change as well as a Debug to make sure you know when it fails.

I forgot that when comparing two variables, to make sure they are exactly the same, the operator is “==”, and I was using “=”

private bool CheckIfOtherIsAlly(Collider2D other)
    {
        bool otherIsAlly = false;
        //Find if there is enemy or ally script on it.
        if (other.GetComponent<Ally>())
            { otherIsAlly = true;}

        if (ally == otherIsAlly)
        { return true; }
        else if (ally != otherIsAlly)
        { return false; }
        else { Debug.Log("CheckIfOtherIsAlly() not returning properly"); return true;  } 
    }

In the end, you need to return something out of the function, so I return it as true, but after I send an error message to the console via Debug.Log()

This one please. This fucntion is bugging me badly =(
Don’t you need to attach the script itself on the gameObject to initialize it by GetComponent in another script? It is not a cached reference also. According to what i know; you want to check this gameObject has Ally.cs attached on it or not. But the projectile has only DamageHandler.cs on it and a movement script of your choice. Should not it be FindObjectOfType<Ally>()?

private void CheckIfAlly() 
{ 
    if (GetComponent<Ally>()) 
    { 
        ally = true; 
    } 
}

I tested this code by making every gameObject on Default layer and the projectile destroyed the defender itself. Then I changed the GetComponent with FindObjectOfType and it worked like miracle.

You don’t want to use FindObjectOfType() because it will search the entire scene for the first object that has Defender attached to it, meaning that if there is an Defender on the map, bool ally will always be true. GetComponent() brings it into the scope of the single object we’re targeting.

I would make the alteration that I made to CheckIfOtherIsAlly(), as well as ensure that the Defender Component is applied to both the Projectile prefab as well as your Shooter.

I have Defender.cs and Enemy.cs fully coded as well as attached on the respected gameObjects. So your IFF (identification friend or foe, using by fighter planes in modern age) type of code if huge help.

This is the reason I created an Ally.cs and separated it from Defender.cs

You want to have the classification on every single prefab that is coded as an Ally, including projectiles, defenders, even detection areas.

I filled the core game area with cactuses and they don’t destroy any friend, just killing enemy spawns. I made every gameObject Default layer to see if your IFF works. And it works, but i had to change GetComponent with FindObjectOfType. There are 2 scripts attached on my projectile, defender and attacker; DamageDealer.cs and Projectile.cs (with your IFF code) on my projectile, Defender.cs and Health.cs on my defenders, Attacker.cs and Health.cs on my enemies.

You need to add Defender.cs or a new Ally.cs to your projectile prefab to make it work as intended.

Your code as it is will not work on Enemies if you use FindObjectOfType(). As I said, that will make it search for any defender and if there is one defender, it will classify the projectile as an Ally, even if it is supposed to be an Enemy.

FindObjectOfType() is a function that will go through every object in your scene searching for any object of the type you are trying to find.

If you use FindObjectOfType() as a condition for an if statement, it will return true if there is one or more GameObjects of that type in your entire scene.

GameObject.GetComponent() is a function that will search a single object for the component.

If you use GameObject.GetComponent() as a condition for an if statement, it will return true if the GameObject in question has that component attached to it.

Yes, now it is clear. But this time another question popped in my mind. What happens if you give your enemies ability to shoot? They have Enemy.cs, so they should selfdestruct. Right? Ma be we should also add Enemy.cs and initialize it.

It is already initialized as an enemy.

At the top of the script, bool ally is assigned as false.

At the beginning of CheckIfOtherIsAlly, otherIsAlly is assigned as false.

These bools being set to false assigns a classification as “enemy” to them, even if they dont technically have the Enemy.cs script on them.

Since they are being initialized as false (enemies, in other words), you don’t need to have a function to set the ally bools to false.

Hmm…

So at the bottom of the code your 2nd bool is also set to false, which will be equal when the both bools are false.

Cool aproach.

Yeah, last thing. I wanna make sure you changed the final part of CheckIfOtherIsAlly().
It’s really important that it reads:

if (ally == otherIsAlly)
{return true;}

My complete function is as follows.

private bool CheckIfOtherIsAlly(Collider2D other)
    {
        bool otherIsAlly = false;
        //Find if there is enemy or ally script on it.
        if (other.GetComponent<Ally>())
            { otherIsAlly = true;}

        if (ally == otherIsAlly)
        { return true; }
        else if (ally != otherIsAlly)
        { return false; }
        else { Debug.Log("CheckIfOtherIsAlly() not returning properly"); return true;  } 
    }

People might think the state of being true should be a result of just being true, but it only needs to be equal on either sides.

Privacy & Terms