[英]Bullet not getting Instantiated when destroyed - Unity2D
我是使用统一的新手,我仍在学习 C#。 因此,如果下面提到的问题看起来有点奇怪或容易解决,请多多包涵。
我正在创建一个项目以尝试从炮塔发射子弹,我在我的子弹脚本中包含了一个 function,它会在子弹越过某些边界后摧毁子弹,并在我的 bulletSpawner 脚本中包含一个 function 来实例化子弹,如果它被摧毁了。 出于某种原因,每当我播放和射击子弹并且它越过边界时,它都不会被克隆
这是子弹脚本;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
[SerializeField]
private float Power = 50f;
private Rigidbody2D myBody;
private SpriteRenderer sr;
private float posX;
private float posY;
private void Awake()
{
myBody = GetComponent<Rigidbody2D>();
sr = GetComponent<SpriteRenderer>();
}
void Update()
{
Shoot();
destroyBullet();
}
void Shoot()
{
if (Input.GetKeyDown(KeyCode.Space))
{
myBody.AddForce(new Vector2(Power, Power - myBody.gravityScale),
ForceMode2D.Impulse);
}
}
void destroyBullet()
{
posX = transform.position.x;
posY = transform.position.y;
if (posX > 100 || posX < -100 || posY > 100 || posY < -100)
Destroy(gameObject);
}
}//class
这是 BulletSpawner 脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSpawner : MonoBehaviour
{
public Transform bullet;
void Update()
{
StartCoroutine(SpawnBullet());
}
IEnumerator SpawnBullet()
{
while (!GameObject.FindWithTag("Bullet"))
{
yield return new WaitForSeconds(3);
Instantiate(bullet);
}//while
}//Ienum
}//class
注意:我已将 Bullet Prefab 附加到检查器面板中的项目符号上
每当子弹超出范围或被破坏时,我都会收到此错误:
MissingReferenceException:“Transform”类型的 object 已被破坏,但您仍在尝试访问它。
我知道它已被破坏,但我想找到一种方法来访问它,以便它可以克隆子弹(可以再次发射,破坏等等......)
请告知我可以做些什么来修复此代码或任何替代方法,以防止将来发生此类错误。 对于任何反馈,我们都表示感谢:)...
提前致谢!
因此,如前所述,主要问题是您使用原始场景实例作为Instantiate
的原始bullet
,但随后销毁了该原始项目。
如果您要使用销毁和实例化,您宁愿将预制资产作为bullet
原始资产。
然而,在 MickyD 提到之后:无论如何,你总是一次只有一颗子弹,所以你可能根本不需要摧毁它。 只需重用相同的项目符号实例。
然后关于Update
中的射击和你的协程,这是我宁愿做的
子弹本身根本不做任何事情,而只是被动的。
然后做
public class BulletSpawner : MonoBehaviour
{
// Now again the one from the Scene!
public Rigidbody2D bullet;
// Yes if Start is IEnumerator it is automatically run as Coroutine by Unity
IEnumerator Start ()
{
// Disable the Rigidbody of the bullet so it doesn't fall down
bullet.isKinematic = true;
// Huh?! This is okey in an IEnumerator as long as you yield inside
while(true)
{
// wait until Space is pressed
yield return new WaitUntil (() => Input.GetKeyDown(KeyCode.Space));
// enable the Rigidbody
bullet.isKinematic = false;
// shoot the bullet
bullet.AddForce(new Vector2(Power, Power - bullet.gravityScale), ForceMode2D.Impulse);
// Now wait until it is out of bounds
//TODO: .. or it hits something ;)
yield return new WaitUntil (() => bullet.position.magnitude > 100f /*TODO || hasHitSomething */);
// Then reset it's movement
bullet.velocity = Vector2.zero;
bullet.angularVelocity = 0;
// Reset position
bullet.position = Vector2.zero;
bullet.rotation = 0;
bullet.transform.position = Vector2.zero;
bullet.transform.rotation = Quaternion.identity;
// disable the Rigidbody for the next iteration
bullet.isKinematic = true;
// Disable the entire object
bullet.gameObject.SetActive(false);
// Wait for the cooldown
yield return new WaitForSeconds (3);
// enable the object (but not yet the Rigidbody)
bullet.gameObject.SetActive(true);
}
}
}
为了检查hasHitSomething
我会在子弹上放一个专用组件,例如
public class Bullet : MonoBehaviour
{
public bool hasCollided;
private void OnCollisionEnter2D(Collision2D collision)
{
hasCollided = true;
}
}
广告然后
yield return new WaitUntil (() => bullet.position.magnitude > 100f || bullet.GetComponent<Bullet>().hasCollided);
// reset the flag
bullet.GetComponent<Bullet>().hasCollided = false;
当然,您通常应该存储Bullet
引用而不是重复使用GetComponent
。
这个答案只是对 derHugo 上面写的代码稍作修正,
这是编辑后的版本,更改在下面的**中标记...
public class BulletSpawner : MonoBehaviour
{
public Rigidbody2D bullet;
public Transform bulletPos;//change**
[SerializeField]
private float Power = 50f;
void Start()
{
StartCoroutine(SpawnBullets());
}
void Update() {
}
IEnumerator SpawnBullets()
{
bullet.simulated = false;
while (true)
{
yield return new WaitUntil(() => Input.GetKeyDown(KeyCode.Space));
bullet.simulated = true;
bullet.AddForce(new Vector2(Power, Power - bullet.gravityScale),
ForceMode2D.Impulse);
yield return new WaitUntil(() => bullet.position.magnitude > 100f
|| hasHitSomething */);
bullet.velocity = Vector2.zero;
bullet.angularVelocity = 0;
bulletPos.position = Vector2.zero;//change**
bullet.rotation = 0;
bullet.simulated = false;
bullet.gameObject.SetActive(false);
yield return new WaitForSeconds(3);
bullet.gameObject.SetActive(true);
}
}
}
我已经完成了两项更改,因为当子弹被发射并出界时,子弹的 position 不会 go 回到原来的 position (因为这是代码,子弹被声明为)我的 Bullet object 的刚体(这意味着刚体将把它的 position 恢复到原点,而不是 Bullet object itelf 的刚体...声明组件没有意义。项目符号 object 并将项目符号更改为项目符号位置
bullet.position = Vector2.zero;
这是为了确保子弹 object 而不是子弹刚体将其 position 恢复到原点。
不要忘记在bulletSpawner中把子弹的transform组件附加到脚本上,这样就可以顺利运行了……
只是想包括这个,以免再次犯同样的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.