Making a 2d top down zelda clone for college and encountered some problems...

Forgive me for not being specific in the title and for the long post but I have some multiple problems going on and I was hoping that someone might be able to help. Asking these after many hours of googling I haven’t managed to find solutions. I’ve also asked some questions on stack overflow, unity answers and in the unity group on Slack, but none answered. I’ll try my best to explain them well.

No.1: Colliders
It seems I don’t understand colliders well yet. I have multiple colliders on my player:

a) A trigger for Hitbox & item interractions on the main object (rigidbody2d is also on the main object).
b) A collider for colliding on the main object.
c) Different colliders on child objects (weapon upgrades) which only activate when the specific animation is played (one at a time can only be activated since there is a different animation for each weapon upgrade).

The problem is: that the onTriggerEnter function in my player attack script is activated by every collider the player has, even non-trigger colliders. Tried debugging by disabling them all and enabling them one at a time. Tried setting a) on a child object with and without a rigidbody. Did the same with b) (separately). At every case the onTriggerEnter is activated and my player is able to attack the enemy with every collider.

void OnTriggerEnter2D(Collider2D other)
    {
        foreach (GameObject enemy in enemies)
        {
            if (enemy == other.gameObject)
            {
                health = enemy.GetComponent<Health>();
                if (IsAttacking == true)
                {
                    inRange = true;
                }
                else
                {
                    inRange = false;
                }
            }
        }
    }

As you understand the player takes the health component of the enemy that entered the collider and damages it. It works well (except the fact that all colliders damage it).

No. 2 Projectile issue

The boss spawns and has some skills. One of them is throwing a fireball at the player. I have a child object on the boss which instantiates them and have the script in it.
Tried “LookAt” and everything works as intended except that the fireball rotates around Y (becomes “invisible” because the sprite rotates 90deg and it is perceived by the side, but the fireballs normally travel to the player’s position) and I need it to rotate around Z to look at the player.

So I tried something else to rotate it with Z (which you will see below in the script) and it works great but encountered another problem. The fireball won’t move. Here is the script, also have comments with the things I have tried (sorry for having so many comments, they are the things I have tried -not all of them together ofc).

public class BossAttack2 : MonoBehaviour {

    public GameObject fireball;
    public GameObject genericfireball;
    public GameObject player;
    public GameObject fire; //child object of boss

    public Rigidbody2D body;
    public Transform target;
    public Transform location;
    public Transform source; //transform of child object

    public float speed = 0.5f;
    //public Vector3 vector;

    // Use this for initialization
    void Start ()
    {
        player = GameObject.FindWithTag("Player");
        fire = GameObject.Find("fire");
        source = GetComponent<Transform>();
        location = source.transform;
    }
 
    // Update is called once per frame
    void Update ()
    {
        target = player.transform;

        //location.LookAt(target);

        //Vector3 difference = target.position - fire.transform.position;
        //float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
        //transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);

        //vector = new Vector3(0, 0, target.z);
        //location.position = vector;
     
        //I did this to rotate it on Z and it works but the object will not move when spawned
        float AngleRad = Mathf.Atan2(target.transform.position.y - source.transform.position.y, target.transform.position.x - source.transform.position.x);
        float AngleDeg = (180 / Mathf.PI) * AngleRad;
        location.rotation = Quaternion.Euler(0,0, AngleDeg +90);     
    }


    public void Fireball()
    {
        {
            genericfireball = Instantiate(fireball, location.position, location.rotation) as GameObject;
            //genericfireball.GetComponent<Rigidbody2D>();
            body = genericfireball.GetComponent<Rigidbody2D>();

            body.velocity = Vector2.MoveTowards(location.position, target.position, speed * Time.deltaTime).normalized;

            //body.velocity = new Vector2(target.position.x, target.position.y);

            //body.velocity = transform.forward * speed;

            //body.AddForce(body.velocity, (ForceMode2D.Force));
            //genericfireball.GetComponent<Rigidbody2D>().AddForce(player.transform.forward * speed * Time.deltaTime);
        }
    }
}

No.3 Problematic knockback

I’ve tried several different methods for knockback but none works as intended. The problem is most work on Y axis only and I just can’t figure out why. Here is the code with the things I’ve tried in comments (same as no.1, but I didn’t include the knockback code there since it was irrelevant).

    void OnTriggerEnter2D(Collider2D other)
    {
        foreach (GameObject enemy in enemies)
        {
            if (enemy == other.gameObject)
            {
                health = enemy.GetComponent<Health>();
                if (IsAttacking == true)
                {
                    inRange = true;

                    //problematic knockback attempts

                    Vector3 directionVector = other.transform.position - transform.position;
                    Rigidbody2D body = other.GetComponent<Rigidbody2D>();
                    if (body != null)
                    {
                        float forceMagnitude = 0.5f;
                        ForceMode2D mode = ForceMode2D.Impulse;
                        body.AddForce(directionVector * forceMagnitude, mode);
                    }
                    //Vector3 direction = (other.transform.position - transform.position).normalized;
                    //body = other.GetComponent<Rigidbody2D>();
                    //body.AddForce(direction * 10);

                    /*Vector2 directionVector = other.gameObject.transform.position - this.transform.position;
                    Rigidbody2D body = other.gameObject.GetComponent<Rigidbody2D>();
                    body.velocity = directionVector.normalized;*/
                }
                else
                {
                    inRange = false;
                }

1 - Create a variable reference for each collider, and when OnTriggerEnter is called, check which collider was hit by comparing to your variables.

2 - The “Fireball” function spawns a new fireball, and but the line where you set velocity doesn’t make sense. You’re setting velocity to a position, not a direction with magnitude. Try setting the velocity once when you spawn it like this:

body.velocity = (target.position - location.position).normalized * speed;

3 - In order for AddForce to work, you can’t be setting “velocity” in other places. Make sure you aren’t overriding your velocity with your movement code. Also, normalize your “directionVector” so that it multiplies correctly with “forceMagnitude”. Otherwise you’ll get a much larger force than you intended potentially.

1 Like

Thank you very much mate!

I solved my fireball problem with what you said.
I solved my colliders problem as well but with a more messy way. I moved this part of the script to the child objects, added kinematic rbs and thankfully the ontrigger in them detected their collider only. I tried to do what you said (which would be much better) but I couldn’t for some reason… Tried finding the children (which contained the colliders) by tag, then getting their colliders and putting an if statement in it. Tried comparing tags, the collider vars with the current one or if the enemy was on the specific colliders - it didn’t give me an error but it didn’t seem to work.
One of the methods I tried was: Specific trigger - Questions & Answers - Unity Discussions

About knockback, I still can’t solve it - the bat enemy for example moves like this and nothing else changes its velocity.

if (Vector2.Distance(batpos.position, playerpos.position) < aggroRange)
        {
            transform.position = Vector2.MoveTowards(transform.position, playerpos.position - playerpos.up * 0.01f, speed * Time.deltaTime);

(the -playerpos.up is because the object pivot is a little off, wasn’t there before)
The strange thing is that it works on Y but not at all on X.

An easy way to get the collider references is to create public variables and simply drag the correct ones to the variables in the inspector.

Your movement code is setting position, which overrides physics simulation. The physics system may be pushing the Bat, but that code will keep setting the position here. For a true physics knockback, you’ll either have to disable movement so physics can take effect, or move using AddForce.

1 Like