仅当发生更改时,如何从Update调用ShootingSettings方法?

时间:2019-05-05 01:18:58

标签: c# unity3d

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ShootingManager : MonoBehaviour
{
    [Header("Main")]
    public float launchForce = 700f;
    public bool automaticFire = false;
    public float bulletDestructionTime;

    [Space(5)]
    [Header("Slow Down")]
    public float maxDrag;
    public float bulletSpeed;
    public bool bulletsSlowDown = false;
    public bool overAllSlowdown = false;
    [Range(0, 1f)]
    public float slowdownAll = 1f;

    private List<GameObject> shooters = new List<GameObject>();
    private List<Shooting> shootingScripts = new List<Shooting>();


    // Start is called before the first frame update
    void Start()
    {
        shooters.AddRange(GameObject.FindGameObjectsWithTag("Shooter").ToList());
        ShootingSettings();
    }

    // Update is called once per frame
    void Update()
    {

    }

    private void ShootingSettings()
    {
        for (int i = 0; i < shooters.Count; i++)
        {
            shootingScripts.Add(shooters[i].GetComponent<Shooting>());
            shooters[i].GetComponent<Shooting>().launchForce = launchForce;
            shooters[i].GetComponent<Shooting>().automaticFire = automaticFire;
            shooters[i].GetComponent<Shooting>().bulletDestructionTime = bulletDestructionTime;
            shooters[i].GetComponent<Shooting>().maxDrag = maxDrag;
            shooters[i].GetComponent<Shooting>().bulletSpeed = bulletSpeed;
            shooters[i].GetComponent<Shooting>().bulletsSlowDown = bulletsSlowDown;
            shooters[i].GetComponent<Shooting>().overAllSlowdown = overAllSlowdown;
            shooters[i].GetComponent<Shooting>().slowdownAll = slowdownAll;
        }
    }
}

如果我从更新中调用ShootingSettings,它将一直保持循环。这取决于性能吗?还是我应该做一些IF并仅在其中一项设置有所更改时才调用该方法?

我在层次结构中有一些对象,并附加了相同的脚本:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shooting : MonoBehaviour
{
    [Header("Main")]
    public Rigidbody bulletPrefab;
    public float launchForce = 700f;
    public bool automaticFire = false;
    public float bulletDestructionTime;

    [Space(5)]
    [Header("Slow Down")]
    public float maxDrag;
    public float bulletSpeed;
    public bool bulletsSlowDown = false;
    public bool overAllSlowdown = false;
    [Range(0, 1f)]
    public float slowdownAll = 1f;

    private List<Transform> firePoints = new List<Transform>();
    private Animator anim;

    private void Start()
    {
        GatherAllChilds(transform);

        if (anim != null)
        {
            anim.SetBool("Shooting", true);
        }
    }

    public void Update()
    {
        if (overAllSlowdown == true)
        {
            Time.timeScale = slowdownAll;
        }

        if (firePoints.Count > 0 && anim != null)
        {
            for (int i = 0; i < firePoints.Count; i++)
            {
                if (isAnimationStatePlaying(anim, 0, "AIMING") == true)
                {
                    if (Input.GetButtonDown("Fire1") && automaticFire == false)
                    {
                        if (anim.GetBool("Shooting") == true)
                        {
                            anim.Play("SHOOTING");
                            LaunchProjectile(firePoints[i]);
                        }
                    }
                    else if (Input.GetButtonDown("Fire1") && automaticFire == true)
                    {
                        automaticFire = false;
                    }
                    else
                    {
                        if (Input.GetButtonDown("Fire2"))
                        {
                            automaticFire = true;
                        }
                        if (automaticFire == true)
                        {
                            anim.Play("SHOOTING");
                            LaunchProjectile(firePoints[i]);
                        }
                    }
                }
            }
        }
    }

    private void LaunchProjectile(Transform firePoint)
    {
        Rigidbody projectileInstance = Instantiate(
            bulletPrefab,
            firePoint.position,
            firePoint.rotation);

        projectileInstance.AddForce(new Vector3(0, 0, 1) * launchForce);

        if (bulletsSlowDown == true)
        {
            if (projectileInstance != null)
            {
                StartCoroutine(AddDrag(maxDrag, bulletSpeed, projectileInstance));
            }
        }

        if ((automaticFire == true || automaticFire == false) && bulletsSlowDown == false)
        {
            projectileInstance.gameObject.AddComponent<BulletDestruction>().destructionTime = bulletDestructionTime;
            projectileInstance.gameObject.GetComponent<BulletDestruction>().Init();
        }
    }

    IEnumerator AddDrag(float maxDrag, float bulletSpeed, Rigidbody rb)
    {
        if (rb != null)
        {
            float current_drag = 0;

            while (current_drag < maxDrag)
            {
                current_drag += Time.deltaTime * bulletSpeed;
                rb.drag = current_drag;
                yield return null;
            }

            rb.velocity = Vector3.zero;
            rb.angularVelocity = Vector3.zero;
            rb.drag = 0;

            rb.gameObject.AddComponent<BulletDestruction>().destructionTime = bulletDestructionTime;
            rb.gameObject.GetComponent<BulletDestruction>().Init();
        }
    }

    bool isAnimationStatePlaying(Animator anim, int animLayer, string stateName)
    {
        if (anim.GetCurrentAnimatorStateInfo(animLayer).IsName(stateName))
            return true;
        else
            return false;
    }

    private void GatherAllChilds(Transform parent)
    {
        for (int i = 0; i < parent.childCount; i++)
        {
            if (parent.GetChild(i).name == "Sci-Fi_Soldier")
            {
                anim = parent.GetChild(i).GetComponent<Animator>();
            }

            if (parent.GetChild(i).tag == "Fire Point")
            {
                firePoints.Add(parent.GetChild(i));
            }
            GatherAllChilds(parent.GetChild(i));
        }
    }
}

现在,在更改设置时以及在游戏运行时,此射击脚本都会影响每个对象。

我现在想在游戏运行时同时使用实时ShootingManager脚本来一次同时控制,效果和更改所有Shooting脚本的设置。

2 个答案:

答案 0 :(得分:1)

当您将这些更改保存在UnityEditor(Inspector)中时,其他答案无法同步这些更改。进行微调。

这听起来像是ScriptableObject的完美用例

[CreateAssetMenu (fileName = "new ShootingSettings", menuName = "ShootingSettings")]
public class ShootingSettings : ScriptableObject
{      
    [Header("Main")]
    public float launchForce = 700f;
    public bool automaticFire = false;
    public float bulletDestructionTime;

    [Space(5)]
    [Header("Slow Down")]
    public float maxDrag;
    public float bulletSpeed;
    public bool bulletsSlowDown = false;
    public bool overAllSlowdown = false;
    [Range(0, 1f)]
    public float slowdownAll = 1f;
}

通过右键单击资产->创建-> ShootingSettings创建实例,并为其命名。

现在更改您的Shooting类,而经理类改为一个

public ShootingSettings settings;

因此,从经理那里使用FindObjectsOfType会比使用FindObjectsWithTag和多次GetComponent效率更高!

private void Awake()
{
    // This is way more efficient than using find and GetComponent over and over again
    foreach(var shooting in FindObjectsOfType<Shooting>())
    {
        shooting.settings = settings;
    }
}

现在将您之前创建的资产引用到经理脚本的settings字段。

从现在开始,您对创建的资产所做的任何更改将应用​​于所有settings实例中的所有Shootig。因此,剩下要做的就是更改您的Shooting脚本以使用这些设置;)


或者,只要拥有类,您实际上也可以在没有ScriptableObject的情况下做同样的事情

[Serializable]
public class ShootingSettings
{      
    [Header("Main")]
    public float launchForce = 700f;
    public bool automaticFire = false;
    public float bulletDestructionTime;

    [Space(5)]
    [Header("Slow Down")]
    public float maxDrag;
    public float bulletSpeed;
    public bool bulletsSlowDown = false;
    public bool overAllSlowdown = false;
    [Range(0, 1f)]
    public float slowdownAll = 1f;
}

相反。在这种情况下,您可以直接在manager类中进行所有设置。由于所有Shooting实例都将使用相同的实例引用,因此以后在管理器中对settings进行的所有更改都是在您所有组件共享的同一settings实例上完成的。


=>您不需要任何方法或事件来使设置无处不在更新:)


在智能手机上键入内容,因此没有保修,但我希望这个想法会清楚

答案 1 :(得分:0)

总是最好将其称为事件,在这种情况下,它看起来好像不需要更新。

问题是,您的零钱来自哪里? 您可以将ShootingSettings(); 公开公开,并在每次更改时调用它。它可以解决您的问题吗?

另外,这里有一些建议

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ShootingManager : MonoBehaviour
{
    [Header("Main")]
    public float launchForce = 700f;
    public bool automaticFire = false;
    public float bulletDestructionTime;

    [Space(5)]
    [Header("Slow Down")]
    public float maxDrag;
    public float bulletSpeed;
    public bool bulletsSlowDown = false;
    public bool overAllSlowdown = false;
    [Range(0, 1f)]
    public float slowdownAll = 1f;

    //Making it public so you can drag and drop the   
    //references in the inspector
    public List<Shooting> shooters; 


    // Start is called before the first frame update
    void Start()
    {
        ShootingSettings();
    }

    // Update is called once per frame
    void Update()
    {

    }

    public void ShootingSettings()
    {
        for (int i = 0; i < shooters.Count; i++)
        {
            shooters[i].launchForce = launchForce;
            shooters[i].automaticFire = automaticFire;
            shooters[i].bulletDestructionTime = bulletDestructionTime;
            shooters[i].maxDrag = maxDrag;
            shooters[i].bulletSpeed = bulletSpeed;
            shooters[i].bulletsSlowDown = bulletsSlowDown;
            shooters[i].overAllSlowdown = overAllSlowdown;
            shooters[i].slowdownAll = slowdownAll;
        }
    }
}
  1. 在当前代码中,shotingScripts没有用。
  2. shooters可以是Shooting的列表,这样,您不需要每次都需要获取GetScript脚本时就执行GetComponent。并在需要时仍具有gameObject引用。
  3. 您可以公开“射击名单”并参考

如果您仍然想使用FindGameObjectsWithTag,则可以使用它,但是如果任何带有Shooter标签的gameObject没有附加Shooting脚本,则会引发错误。

编辑:正如@derHugo所建议的那样,与通过标签查找相比,FindObjectsOfType是更好的选择。

不使用 System.Linq

private List<Shooting> shooters;
    void Start() {
    Shooting[] shooterObjects = FindObjectsOfType<Shooting>();
    shooters = new List<Shooting>(shooterObjects.Length);
    for (int i = 0; i < shooterObjects.Length; i++)
    {
        shooters[i] = shooterObjects[i];
    }

    ShootingSettings();
}

使用 System.Linq

    private List<Shooting> shooters;

    void Start() {
    shooters = FindObjectsOfType<Shooting>().ToList();
    ShootingSettings();
    }

如果希望它在编辑器中工作(出于测试目的),则可以执行此操作。这仅在编辑器中起作用。如果要在运行时进行更新,则在进行更改时需要调用ShootingSettings();

    void Update()
    {
        #if UNITY_EDITOR
        ShootingSettings();
        #endif
    }