FindObjectOfType返回null

时间:2017-05-20 21:14:01

标签: c# unity3d polymorphism abstract-class base-class

我遇到的问题是丢弃的物品,我拿起弹药加枪。

使用所有方法和变量构建Gun类。 构建了一个源自Gun类的Rifle类 步枪完美无问题

我现在正在添加一个" PickUp"系统中x的敌人数量下降。

这是要拾取的项目上的脚本

public class AddARAmmo : MonoBehaviour
{
    private Rifle rifle;
    private void Awake()
    {
        rifle = FindObjectOfType<Rifle>();
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == string.Format("Player"))
        {
           rifle.AddAmmo(30);
            Destroy(gameObject);
        }

    }
}

步枪和枪的脚本有点长但是这里枪基类的相关内容是公共抽象类......

public int bulletsInStock;
 public void AddAmmo(int ammoToAdd)
{
    bulletsInStock += ammoToAdd; 
    UpdateAmmo();// updates on screen Ammo
}
......

然后在步枪类

 public override void Modifiers() // This is where the guns starts are stored
{
    bulletSpeed = 2777f;
    bulletsInStock = 200;
    bulletsInMag = 30;
    bulletPoolSize = 40;
    desiredRPS = 15;
    muzzleFlashPoolSize = 10;
}

我得到的对象引用未设置为实例

步枪脚本位于游戏层次结构的步枪上,因此它应该找到它。 有没有人看错了什么?

这是完整的Gun脚本

public abstract class Gun : MonoBehaviour
{
    [SerializeField] protected GameObject muzzleFlash;// spawns on barrelEnd
    [SerializeField] protected Transform muzzleFlashFolder;
    [SerializeField] protected Transform bulletFolder;// is the parent of bullets
    [SerializeField] protected Transform barrelEnd;// Gameobject at the end of barrel
    [SerializeField] protected Rigidbody bullet; // The bullet Prefab
    [SerializeField] protected Text ammo; // OSD
    [SerializeField] protected Text weaponType; // OSD
    [HideInInspector] protected float bulletSpeed;
    [HideInInspector] public int bulletsInStock;
    [HideInInspector] protected int bulletsInMag;
    [HideInInspector] protected float desiredRPS;// Rounds Per Second
    [HideInInspector] protected List<Rigidbody> poolOfBullets; // Make pool for bullets
    [HideInInspector] protected int bulletPoolSize; // The size off the buletpool 10 works really well
    [HideInInspector] protected List<GameObject> muzzleFlashPool;// pool for muzzleflash
    [HideInInspector] protected int muzzleFlashPoolSize; // size of the muzzle pool
    [HideInInspector] protected int bulletsLeft; // In mag
    [HideInInspector] protected bool isReloading = false;
    [HideInInspector] protected float timeLeft;// for fire speed
    [HideInInspector] protected float fireSpeedTimer;
    [HideInInspector] protected Weapons weaponsScript;
    [HideInInspector] protected PlayerController playerController;
    protected void FixedUpdateStuff()
    {
        if (playerController.canMove && Input.GetAxisRaw(string.Format("Fire1")) > 0)
        {
            FireSpeedControl();// call the fire timer controller
        }
        if (playerController.canMove && Input.GetAxisRaw(string.Format("Fire1")) == 0)
        {
            timeLeft = 0f;
        }
        if (playerController.canMove && Input.GetKeyDown(KeyCode.R) && !isReloading)
        {
            Reload();
        }
        UpdateAmmoOnInput();
    }
    protected void UpdateStuff()
    {
        if (gameObject.activeInHierarchy)// when a gun become active it updates OSD
        {
            UpdateWeaponType();// With its Name
        }
    }
    protected void RPSFinder()//  finds the Rounds Per Second the gun will fire
    {
        fireSpeedTimer = (100 / desiredRPS) / 100;
        timeLeft = fireSpeedTimer;
    }

    protected void Fire()// Instatiates a clone of the desired bullet and fires it at bulletSpeed
    {
        if (!Empty())
        {
            Rigidbody bulletClones = GetPooledBullet();
            if (bulletClones != null)
            {

bulletClones.transform.SetPositionAndRotation(barrelEnd.position, barrelEnd.rotation);
                bulletClones.gameObject.SetActive(true);
            }
            GameObject muzzleFlashClone = GetMuzzleFlash();
            if (muzzleFlashClone != null)
            {
                muzzleFlashClone.transform.position = barrelEnd.position;
                muzzleFlashClone.gameObject.SetActive(true);
            }
            bulletClones.AddForce(-bulletClones.transform.up * bulletSpeed * .304f); //add the force in FPS * .304 = MPS
            bulletsLeft--;// the holder to know how many bullets are left in the magazine
            isReloading = false;// Gun cannot reload unless it has been fired
            UpdateAmmo();// Updates the on screen ammo count and the stock usage
            return;
        }
    }

    protected void Reload()
    {// this removes full magazine from the stock and the stock can still go negitive FIX FIX FIX FIX FIX FIX FIX
        if (bulletsInStock > 0)
        {
            isReloading = true;
            bulletsInStock -= bulletsInMag;
            bulletsLeft = bulletsInMag;
            UpdateAmmo();
        }
    }

    protected bool Empty()// Checks the magazine to see if there are bullets in it
    {
        if (bulletsLeft == 0)
            return true;
        else
            return false;
}

    protected void FireSpeedControl()// controls the RPS fired by the gun Controled by Update() Input
    {
        if (timeLeft > 0f)
        {
            timeLeft -= Time.deltaTime;
        }
        else if (timeLeft <= 0f)
        {
            Fire();
            timeLeft = fireSpeedTimer;
        }
    }

    protected Rigidbody GetPooledBullet()// retrieve a preInstatiated bullet from the pool to use when shooting
    {
        for (int i = 0; i < poolOfBullets.Count; i++)
        {
            if (!poolOfBullets[i].gameObject.activeInHierarchy)
            {
                return poolOfBullets[i];
            }
        }
        return null;
    }

    protected GameObject GetMuzzleFlash()
    {
        for (int i = 0; i < muzzleFlashPool.Count; i++)
        {
            if (!muzzleFlashPool[i].gameObject.activeInHierarchy)
            {
                return muzzleFlashPool[i];
            }
        }
        return null;
    }

    protected void UpdateAmmo()// Update the on screen ammo information
    {
        ammo.text = bulletsLeft + string.Format( " : ") + bulletsInStock;
    }

    protected abstract void UpdateWeaponType();

    protected void UpdateAmmoOnInput()
    {
        if (weaponsScript.updateAmmo)
        {
            UpdateAmmo();
            weaponsScript.updateAmmo = false;
        }
    }


    public abstract void Modifiers();

    protected void StartStuff()
    {
        Modifiers();// Call first to store indvidual gun stats
        playerController = FindObjectOfType<PlayerController>();
        weaponsScript = FindObjectOfType<Weapons>();
        poolOfBullets = new List<Rigidbody>();
        for (int i = 0; i < bulletPoolSize; i++)
        {
            Rigidbody bulletClone = (Rigidbody)Instantiate(bullet);
            bulletClone.gameObject.SetActive(false);// Builds the Inspector list 
            poolOfBullets.Add(bulletClone); //and populates the elements with clones
            bulletClone.transform.parent = bulletFolder.transform;
        }
        muzzleFlashPool = new List<GameObject>();
        for (int i = 0; i < muzzleFlashPoolSize; i++)
        {
            GameObject muzzleFlashClone = (GameObject)Instantiate(muzzleFlash);
            muzzleFlashClone.gameObject.SetActive(false);
            muzzleFlashPool.Add(muzzleFlashClone);
            muzzleFlashClone.transform.parent = muzzleFlashFolder.transform;
        }
            bulletsLeft = bulletsInMag;
            ammo.text = string.Format( " 0 : 0 ");
            RPSFinder();// Run last to set the RPS of the gun
        }
        public void AddAmmo(int ammoToAdd)
        {
            bulletsInStock += ammoToAdd;
            UpdateAmmo();
        }

    }
}

这是完整的步枪脚本

public class Rifle : Gun
{
    //All variables are stored in the "Gun" Script 
    //Copy this onto guns 

    void Start()
    {
        StartStuff();
    }
    private void FixedUpdate()
    {
        FixedUpdateStuff();
    }

    void Update()
    {
        UpdateStuff();
    }

    public override void Modifiers() // This is where the guns starts are stored
    {
        bulletSpeed = 2777f;
        bulletsInStock = 200;
        bulletsInMag = 30;
        bulletPoolSize = 40;
        desiredRPS = 15;
        muzzleFlashPoolSize = 10;
    }

    protected override void UpdateWeaponType()
    {
        weaponType.text = string.Format("Assault Rifle");
    }


}

2 个答案:

答案 0 :(得分:3)

FindObjectOfType可能返回null有三个原因:

让我们说要查找的脚本名称为Rifle

FindObjectOfType<Rifle>()正在返回null

1 。附加Rifle脚本的GameObject处于非活动状态。您必须确保GameObject处于活动状态。 enter image description here

2 。步枪根本没有附加到任何GameObject。确保Rifle脚本附加到GameObject。enter image description here

如果启用或禁用脚本并不重要,只要它附加的GameObject处于活动状态,它就应该找到它。见#1

3 。加载新场景时:

使用SceneManager.LoadScene等功能触发场景加载时 并且Application.LoadLevelFindObjectOfType在加载完成后才能找到任何内容。

请参阅here了解如何检查场景何时加载。

如果您仍然遇到问题,那么只需找到GameObject,然后从中获取Rifle组件即可。假设GameObject的名称也是&#34; Rifle&#34;

GameObject.Find("Rifle").GetComponent<Rifle>();

答案 1 :(得分:0)

我想出了如何为遇到类似问题的人解决这个问题。  问题是当敌人放弃该项目时,Awake()方法运行。当它运行时,枪在场景中处于非活动状态,因此FindObjectOfType没有找到引用脚本,因为如上所述,它必须在要找到的场景中处于活动状态。

所以我做的是创建一个名为EnemyDrops的Holder脚本,这个脚本调用了枪的findobjectoftypes。这样就可以在最初的游戏开始时完成调用。

然后我更改了拾取器以找到EnemyDrops脚本(在空的游戏对象上)并将调用发送给它。

EnemyDrops Script

private Handgun handgun;

private void Awake()
{
    handgun = FindObjectOfType<Handgun>();
}

public void AddHandgunAmmo(int x)
{
    handgun.AddAmmo(x);
}  

和新的提货脚本

public class AddHandgunAmmo : MonoBehaviour
{
    private EnemyDrops enemyDrops;
    private void Awake()
    {
        enemyDrops = FindObjectOfType<EnemyDrops>();
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == string.Format("Player"))
        {
          enemyDrops.AddHandgunAmmo(50);
            Destroy(gameObject);
        }
    }
} 

正如你所看到的那样,通过这些方法传递价值仍然只需要一个中间人&#34;转发信息。但这很好用

感谢大家的反馈,我希望这有助于某人