【问题标题】:Script not working with multiple same objects脚本不适用于多个相同的对象
【发布时间】:2018-08-10 10:09:19
【问题描述】:

我正在开发一款 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;
    }
}

【问题讨论】:

  • 请同时包含有问题的脚本,以便我们查看并帮助您调试
  • 显示重现问题的最少代码。
  • 请编辑您的问题而不是使用答案

标签: unity3d


【解决方案1】:

问题很可能在于:

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

GameObject.FindObjectOfType&lt;Monster&gt;(); 将始终返回在描述下找到的第一个 as stated in the docs 类型的对象。

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

既然你还没有发布你的播放器脚本,我现在必须做一些假设: 您可能正在您的播放器脚本中的某处检查您的&lt;Monster&gt; instance,以查看它是否足够靠近播放器来攻击和伤害它。除了您的FindObjectOfType&lt;Monster&gt;() 找到的单个 怪物之外,所有怪物并非都是这种情况。您可以通过手动将每个怪物放置在您的玩家旁边来测试这一点,例如,如果您的场景中有 5 个怪物,很可能 1 会攻击,而 4 不会。

要解决此问题,您可以:

  • 假设您想要 instance 中的 Monster 脚本的当前实例,只需将 this 应用于它 (instance = this)

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

【讨论】:

  • 这是一个非常有效的观点,但问题是 5 次攻击都没有,正如你所说的 find object 东西。每个敌人都与一个单独的脚本相关联,这不会导致问题。它正在创建脚本实例以从外部设置属性。
  • 在创建敌人时最初使用了相同的脚本。一切正常。即使现在效果很好但只有一个实例,当有多个时,敌人的攻击只是没有伤害。
猜你喜欢
  • 1970-01-01
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多