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脚本的设置。
答案 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;
}
}
}
如果您仍然想使用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
}