Вы можете использовать Сопрограммы и WaitForSeconds
, чтобы достичь этого
// onRatio and offRatio are "optional" parameters
// If not provided, they will simply have their default value 1
IEnumerator Flash(float frequency ,float onRatio = 1, float offRatio = 1)
{
float cycleDuration = 1.0f / frequency;
float onDuration = (onRatio/ (onRatio + offRatio)) * cycleDuration;
float offDuration = (offRatio/ (onRatio + offRatio)) * cycleDuration;
while(true)
{
show = true;
yield return new WatForSeconds(onDuration);
show = false;
yield return new WatForSeconds(offDuration);
}
}
, чтобы вы могли вызывать его с частотой, например, 8 Гц
StartCoroutine(Flash(8.0f));
это фактически равно любому вызову, для которого вы установили onRatio = offRatio
например
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 1));
StartCoroutine(Flash(8.0f, onRatio = 2, offRatio = 2));
....
или с частотой и отношениями, например, 1 (вкл): 2 (выкл) с 8 Гц
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 2));
При этой настройке сопрограмма работает «навсегда» в while(true)
-цикле.Поэтому не забудьте перед запуском новой Coroutine с другими параметрами сначала остановить все процедуры с помощью
StopAllCoroutines();
Теперь, если вы хотите изменить это динамически в методе Update, вам придетсядобавьте некоторые управляющие флаги и дополнительные переменные в roder, чтобы новый Coroutine вызывался только при изменении:
FlashRateInterval currentInterval;
float currentOnRatio = -1;
float currentOffRatio = -1;
void Update()
{
// if nothing changed do nothing
if(flashRate.herz == currentInterval
//todo && Mathf.Approximately(<yourOnRatio>, currentOnRatio)
//todo && Mathf.Approximately(<yourOffRatio>, currentOffRatio)
) return;
StopAllCoroutines();
currentInterval = flashRate.herz;
//todo currentOnRatio = <yourOnRatio>;
//todo currentOffRatio = <yourOffRatio>;
switch (flashRate.herz)
{
case FlashRateInterval.twoHerz:
StartCoroutine(2.0f);
//todo StartCoroutine(2.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
case FlashRateInterval.fourHerz:
StartCoroutine(4.0f);
//todo StartCoroutine(4.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
case FlashRateInterval.eightHerz:
StartCoroutine(8.0f);
//todo StartCoroutine(8.0f, onRatio = <yournRatio>, offRatio = <yourOffRatio>);
default:
show =true;
}
}
Примечания:
Я не знаю ваш FlashRateInterval
, но если вам нужно по какой-то причине использовать его, вы можете сделать его похожим на
public enum FlashRateInterval
{
AllwaysOn,
twoHerz = 2,
fourHerz = 4,
eightHerz = 8
}
, чтобы напрямую использовать правильные значения.
Я бы назвал частотную переменную flashRate.herz
.Вы также не назвали бы значение размера cube.meters
.Я бы порекомендовал переименовать его в flashRate.frequency
.
Для того, чтобы обеспечить синхронизацию, вам каким-то образом понадобится доступ ко всем поведениям и сравнить их значения (так что я бы сказал, что некоторыеstatic List<YourBehavior>
) и, например, в Coroutine дождитесь, пока все bools, например, не установятся в true, прежде чем продолжить с вашим собственным.Для этого вам понадобится дополнительный bool, поскольку вполне возможно, что show
верно для одного компонента.
public bool isBlinking;
IEnumerator Flash(float frequency ,float onRatio = 1, float offRatio = 1)
{
//todo: You'll have to set this false when not blinking -> in Update
isBlinking = true;
float cycleDuration = 1.0f / frequency;
float onDuration = (onRatio/ (onRatio + offRatio)) * cycleDuration;
float offDuration = (offRatio/ (onRatio + offRatio)) * cycleDuration;
// SYNC AT START
show = false;
// wait until all show get false
foreach(var component in FindObjectsOfType<YOUR_COMPONENT>())
{
// skip checking this component
if(component == this) continue;
// if the component is not running a coroutine skip
if(!component.isBlinking) continue;
// Now wait until show gets false
while(component.show)
{
// WaitUntilEndOfFrame makes it possible
// for us to check the value again already before
// the next frame
yield return new WaitForEndOfFrame;
}
}
// => this line is reached when all show are false
// Now lets just do the same but this time wating for true
// wait until all show get false
foreach(var component in FindObjectsOfType<YOUR_COMPONENT>())
{
// skip checking this component
if(component == this) continue;
// if the component is not running a coroutine skip
if(!component.isBlinking) continue;
// Now wait until show gets false
while(!component.show)
{
// WaitUntilEndOfFrame makes it possible
// for us to check the value again already before
// the next frame
yield return new WaitForEndOfFrame;
}
}
// this line is reached when all show are getting true again => begin of loop
while(true)
{
.........
Вместо использования FindObjectsOfType<YOUR_COMPONENT>()
, что довольно медленно, вы также можете сделать что-то вроде
public static List<YOUR_COMPONENT> Components = new List<YOUR_COMPONENT>();
private void Awake()
{
if(!Components.Contains(this)){
Components.Add(this);
}
}
, поэтому вы также получаете в настоящее время отключенные компоненты и объекты