脚本不适用于多个相同的对象

时间:2018-08-10 10:09:19

标签: unity3d

我正在开发2D游戏。游戏中有不同的敌人,但我被其中之一困住了。敌人是手里拿着锤子的怪物。当玩家进入该范围内时,它会朝玩家奔跑并用锤子攻击他。一切正常。我对其进行了预制,并在其余的游戏中使用了它。但是后来我注意到敌人正在进攻,甚至脚本也在运行,因为我可以看到敌人进攻时的锤子对撞机。但是那个对撞机并没有伤害玩家。我检查了从脚本到标签和对撞机的所有内容,但没有任何效果。然后,我创建了一个单独的场景来解决问题。我只是将我的播放器和敌人从预制文件夹中拖到场景中,然后猜测它在这里起作用了。这意味着如果只有一个敌人(它的一个实例),那么一切都会起作用,但是当我使用相同的脚本以及其他所有东西创建相同敌人的第二个实例时,一切都不会起作用。只是无法解决问题。 Hammer Enemy

怪物脚本:

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;
    }
}

1 个答案:

答案 0 :(得分:1)

最有可能的问题在于:

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

GameObject.FindObjectOfType<Monster>();将始终返回描述中找到的as stated in the docs类型的第一个对象。

这意味着,当您向场景中添加多个Monsters时,变量instance将为所有实例(在您的层次结构中找到的第一个实例)填充相同的Monster。 / p>

现在,由于您尚未发布播放器脚本,因此我现在必须做一些假设: 您可能正在检查玩家脚本中某处的<Monster> instance,看它是否足够靠近玩家以攻击和伤害它。除了您的FindObjectOfType<Monster>()发现的单个怪兽之外,所有怪兽都会不是情况。您可以通过将每个怪物手动放置在玩家旁边来进行测试,例如,如果您的场景中有5个怪物,则很可能会攻击1个,而不会攻击4个。

要解决此问题,您可以:

  • 假设您想在instance中使用Monster脚本的当前实例,只需对其应用thisinstance = this

  • 使用FindObjectsOfType<Monster>()(注意对象后的 s )将所有怪物存储在一个数组中,这将返回怪物类型的所有实例。如docs

  • 中所示