0

I am developing a 2D game. There are different enemies in the game, but I am being stuck with one of them. The enemy is a monster with a hammer in the hand. When the player enters in it's range, it runs towards the player and attacks him with the hammer. Everything worked fine. I made a prefab of it and used it in the rest of my game. But then I noticed that enemy is attacking and even the script is working as I can see the hammer collider at the time of enemy attack. But that collider was not damaging the player. I checked everything from script to tags and colliders, but nothing worked. Then I created a separate scene to sort out the issue. I just dragged my player and the enemy from prefab folder to the scene and guess what it was working there. Which mean that if there was only one enemy (one instance of it), everything worked but not when I created the second instance of the same enemy with the same scripts and everything else. Just can't sort out the issue. Hammer Enemy

Monster script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Monster : MonoBehaviour {

    private static Monster instance;

    public static Monster Instance
    {
        get {
            if (instance == null) {
                instance = GameObject.FindObjectOfType<Monster> ();
            }
            return instance;
        }
    }

    //Movement Variables
    public float movementSpeed;
    private IMonsterState currentState;
    public Animator MyAnimator{ get; set;}
    public GameObject Target{ get; set;}
    bool facingRight;
    public bool Attack{ get; set;}
    public bool TakingDamage{ get; set;}
    public float meleeRange;

    public Transform leftEdge;
    public Transform rightEdge;

    public float pushBackForce;

    public EdgeCollider2D attackCollider{ get; set;}

    //public EdgeCollider2D monsterhammer;


    public bool InMeleeRange
    {
        get{
            if (Target != null) {
                return Vector2.Distance (transform.position, Target.transform.position) <= meleeRange;
            }
            return false;
        }
    }

    // Use this for initialization
    void Start () {

        ChangeState(new IdleState());
        MyAnimator = GetComponent<Animator> ();
        attackCollider = GetComponentInChildren<EdgeCollider2D> ();
        //attackCollider=monsterhammer;
        facingRight = true;
    }

    // Update is called once per frame
    void FixedUpdate () {

        if (!Attack) {
            attackCollider.enabled = false;
        }

        if (!TakingDamage) {
            currentState.Execute ();
        }
        LookAtTarget ();
    }

    private void LookAtTarget()
    {
        if (Target != null) {
            float xDir = Target.transform.position.x - transform.position.x;

            if (xDir < 0 && facingRight || xDir > 0 && !facingRight) {
                ChangeDirection ();
            }
        }
    }

    public void ChangeState(IMonsterState newState)
    {
        if (currentState != null) {
            currentState.Exit ();
        }

        currentState = newState;
        currentState.Enter (this);
    }

    public void Move()
    {
        if (!Attack) {
            if ((GetDirection ().x > 0 && transform.position.x < rightEdge.position.x) || (GetDirection ().x < 0 && transform.position.x > leftEdge.position.x)) {
                MyAnimator.SetFloat ("speed", 1);
                transform.Translate (GetDirection () * (movementSpeed * Time.deltaTime));
            } 
            else if (currentState is MonsterPatrol) 
            {
                ChangeDirection ();
            }
        }
    }

    public Vector2 GetDirection()
    {
        return facingRight ? Vector2.right : Vector2.left;
    }

    public void ChangeDirection()
    {
        facingRight = !facingRight;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }

    public void MoveLeft()
    {
        facingRight = false;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }

    public void MoveRight()
    {
        facingRight = true;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        currentState.OnTriggerEnter (other);
    }

    void OnCollisionStay2D(Collision2D other)
    {
        if (other.gameObject.tag == "Player") {

            playerHealth thePlayerHealth = other.gameObject.GetComponent<playerHealth> ();
            thePlayerHealth.addDamage (2);

            //if (playerHealth.damaged) {
            pushBack (other.transform);
            //}
        }
    }

    void pushBack(Transform pushedObject)
    {
        //Vector2 pushDirection = new Vector2 (0, (pushedObject.position.y - transform.position.y)).normalized;
        //pushDirection *= pushBackForce;
        Rigidbody2D pushRB = pushedObject.gameObject.GetComponent<Rigidbody2D> ();
        pushRB.velocity = Vector2.zero;

        if (pushedObject.position.x > transform.position.x) {
            pushRB.AddRelativeForce (Vector3.right * pushBackForce);
        } else {
            pushRB.AddRelativeForce (Vector3.left * pushBackForce);
        }
    }

    public void MeleeAttack()
    {
        attackCollider.enabled = true;
    }
}
3
  • 1
    Please include the scripts in question aswel so we can take a look at it and help you debug it Commented Aug 10, 2018 at 10:13
  • Show the minimal code reproducing your problem. Commented Aug 10, 2018 at 10:13
  • 1
    Please edit your question instead of using answers Commented Aug 10, 2018 at 10:48

1 Answer 1

1

The problem most likely lies with:

get {
        if (instance == null) {
            instance = GameObject.FindObjectOfType<Monster> ();
        }
        return instance;
    }

GameObject.FindObjectOfType<Monster>(); Will always return the first object found of this type as stated in the docs under description.

This means that when you add multiple Monsters into your scene your variable instance will get filled with the same Monster for all instances (the first one it finds in your hierarchy)

Now since you havn't posted your Player script I'll have to do some assuming now: You are probably checking your <Monster> instance somewhere in your player script to see if it is near enough to the player to attack and hurt it. This will not be the case for all monsters except the single monster found by your FindObjectOfType<Monster>() . You could test this by manually placing each monster right next to your player, and most likely if for example you have 5 monsters in your scene 1 will attack, and 4 won't.

To fix this you can:

  • Assuming you want the current instance of the Monster script in instance simply apply this to it (instance = this)

  • store all your monsters in an array using FindObjectsOfType<Monster>() (notice the s after object) which will return all instances of the type monster. as found in the docs

Sign up to request clarification or add additional context in comments.

2 Comments

that's a very valid point, but the problem is that none of the 5 attack, and as you said about the find object stuff. Every enemy is associated with a separate script, which should not cause the problem. And it is creating the instance of a script to set the properties from outside.
The same script was used initially at the time of creation of enemy. Everything worked fine. Even it is working good now but only with a single instance, when there are more than one, the attack of enemy just makes no damage.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.