统一的新事物。
所以我创建了一个简单的枪口闪光粒子动画,该动画应该在玩家靠近他时显示在敌人的枪上,模拟没有实际子弹的射击。但是我在这部分muzzleFlash.Play();
中得到了一个空引用异常,我相信这是因为我实际上并没有使用我拥有的代码在start函数中获得枪口Flash组件,实际上我知道这是在调试之后的结果我发现的模式。我很难弄清楚如何访问该组件。下面是我的代码,我还发布了我的层次结构图。预先感谢。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StaticShootingEnemy : MonoBehaviour
{
[SerializeField] private float _range = 12f;
private Transform _player;
private bool _alive;
private float _distance;
private ParticleSystem muzzleFlash;
// Use this for initialization
void Start()
{
_player = GameObject.Find("Player").transform;
_alive = true;
muzzleFlash = (ParticleSystem)this.gameObject.GetComponent("muzzleFLash");
}
// Update is called once per frame
void Update()
{
_distance = Vector3.Distance(this.transform.position, _player.transform.position);
if (_alive && _distance < _range)
AttackPlayer();
}
private void AttackPlayer()
{
//Turning enemy to look at player
transform.LookAt(_player);
Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
if (Physics.SphereCast(ray, 0.75f, out hit))
{
//TODO: Fix enemy shooting fast when gettting close to him.
GameObject hitObject = hit.transform.gameObject;
if (hitObject.GetComponent<PlayerController>())
{
muzzleFlash.Play();
Debug.Log("Player Hit!");
}
else
muzzleFlash.Stop();
}
}
public void SetAlive(bool alive)
{
_alive = alive;
}
}
答案 0 :(得分:1)
您可能将对象“ muzzleFlash”作为子对象来附加脚本。因此,在这种情况下,最好有一个对您的ParticleSystem对象的引用,称为muzzleFlash。
[SerializeField] private ParticleSystem muzzleFlash; // drag and drop your ParticleSystem muzzleFlash in inspector
或者至少您可以找到像这样的muzzleFlash
GameObject muzzleFlashObj = GameObject.Find("muzzleFlash");
ParticleSystem muzzleFlash = muzzleFlashObj.GetComponent<ParticleSystem>();
在您的情况下,它为null,因为该对象上可能没有称为MuzzleFlash的组件。您要获取的组件是ParticleSystem。
答案 1 :(得分:1)
staticshootingenemy脚本位于哪个组件上?如果它与粒子系统不在同一个组件上,则找不到它,因为this.gameObject.GetComponent(“ muzzleFLash”)在该组件上不存在。您可以使用GameObject.Find(“ muzzleFLash”)搜索粒子系统。
答案 2 :(得分:1)
因此,回到您的评论中,您可以为枪口闪烁实现类似池的功能。
public class MuzzleFlashEffect : MonoBehaviour
{
[SerializeField] private ParticleSystem particleEffect;
private Queue<MuzzleFlashEffect> poolQueue;
public void SetPoolQueue(Queue<MuzzleFlashEffect> queue)
{
poolQueue = queue;
}
public void Play()
{
StartCoroutine(Playing());
}
private IEnumerator Playing()
{
particleEffect.Play();
while (particleEffect.isPlaying)
{
yield return null; // wait until particle animation is done, then recycle effect
}
particleEffect.Stop();
poolQueue.Enqueue(this); // recycle this effect
}
// you can do the same thing for Animation as well, or even write some abstract PoolableVFX class that would be usefull for Animation , ParticleSystems etc..
}
//assume you have some game controller that manage what is going on in the scene
public class GameController : MonoBehaviour
{
[SerializeField] private MuzzleFlashEffect muzzleFlashPrefab;
private Queue<MuzzleFlashEffect> poolQueue = new Queue<MuzzleFlashEffect>(10); // 10 is enough i guess and it's good to set it at instantiation to avoid memory fragmentation
private MuzzleFlashEffect GetMuzzleFlash(Vector3 pos, Quaternion rot)
{
MuzzleFlashEffect muzzleFlash;
// if we already have some effects, then play them, otherwise make a new one and recycle it then
if (poolQueue.Count > 0)
{
muzzleFlash = poolQueue.Dequeue();
}
else
{
muzzleFlash = Instantiate(muzzleFlashPrefab);
muzzleFlash.SetPoolQueue(poolQueue);
}
muzzleFlash.transform.position = pos;
muzzleFlash.transform.rotation = rot;
return muzzleFlash;
}
void Update()
{
// your fancy logic ...
GameObject mutantGunEnd = new GameObject("mutant");
//assume that here you want your muzzle flash effect, so you do:
var muzzleFlash = GetMuzzleFlash(mutantGunEnd.transform.position, mutantGunEnd.transform.rotation); // or you might want to pass mutantGunEnd.transform.forward instead, it depends...
muzzleFlash.Play();
// your fancy logic ...
}
}
因此,在这种情况下,您仅具有所需数量的ParticleEffect实例,并节省了一些资源。您也可以为要回收的任何类型的对象创建通用通用池。 (您想回收而不是实例化,因为cuz实例化是cpu昂贵的)。 M.b,这在这里有点矫but过正,但我只是想分享一下我对此的看法