Mel*_*lsy 4 c# polymorphism abstract-class base-class unity-game-engine
我遇到的问题是我捡起一个掉落的物品,给枪添加弹药。
使用所有方法和变量构建了一个 Gun 类。构建了一个从 Gun 类派生的 Rifle 类 The Rifle 完美无缺
我现在正在添加一个“拾取”系统,其中 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
步枪和枪的脚本有点长,但这里是枪基类中的相关内容是公共抽象类......
public int bulletsInStock;
public void AddAmmo(int ammoToAdd)
{
bulletsInStock += ammoToAdd;
UpdateAmmo();// updates on screen Ammo
}
......
Run Code Online (Sandbox Code Playgroud)
然后在步枪班
public override void Modifiers() // This is where the guns starts are stored
{
bulletSpeed = 2777f;
bulletsInStock = 200;
bulletsInMag = 30;
bulletPoolSize = 40;
desiredRPS = 15;
muzzleFlashPoolSize = 10;
}
Run Code Online (Sandbox Code Playgroud)
我收到了一个未设置为实例的对象引用
步枪脚本位于游戏层次结构中的步枪上,因此它应该会找到它。有人看到有什么不对吗?
这是完整的枪脚本
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是完整的步枪脚本
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");
}
}
Run Code Online (Sandbox Code Playgroud)
FindObjectOfType 可能返回 null 的三个原因:
假设要查找的脚本名称是Rifle
:
并且FindObjectOfType<Rifle>()
正在返回null
。
1 .Rifle
脚本附加到的游戏对象处于非活动状态。您必须确保游戏对象处于活动状态。
2 .The Rifle 根本没有附加到任何游戏对象上。确保步枪脚本附加到游戏对象。.
脚本是启用还是禁用并不重要,只要它附加到的 GameObject 处于活动状态,它就会找到它。见#1。
3.加载新场景时:
当你触发场景加载与功能,如SceneManager.LoadScene
和Application.LoadLevel
,FindObjectOfType
就无法找到任何东西,直到现场装载完成它。
请参阅此处了解如何检查场景何时完成加载。
如果您仍然遇到不应该出现的问题,只需找到 GameObject,然后从中获取Rifle
组件即可。假设 GameObject 的名称也是“Rifle”。
GameObject.Find("Rifle").GetComponent<Rifle>();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3443 次 |
最近记录: |