C# 单位:以可变开/关比的频率闪烁
我希望能够以一定的频率闪现东西。例如,假设为2Hz。我还希望能够指定一个比率,在这个比率中,我可以显示周期的2/3,并将其隐藏1/3,因此比率为2:1。这是一个疯狂的一串闪烁,所以我需要保持灵活的方式,我这样做。可能会有一些比为3:5、频率为2Hz的闪烁,还有一些比为1:1、频率为4Hz的闪烁,以此类推 此外,我需要能够同步闪烁。因此,如果一个对象已经在闪烁,我开始闪烁另一个对象,它们需要同步(或者说,它们的周期需要同步,闪烁可能会随着比率的不同而变化)。但如果频率相同,它们需要同时“打开”,即使它们的比率不同。此外,它们都需要在最慢的开关打开的同时打开 我目前的方法是:我有一个游戏对象FlashCycle,它的更新方法基本上计算了我拥有的3个频率(2Hz、4Hz和8Hz)的进度 我尝试过不同的C# 单位:以可变开/关比的频率闪烁,c#,unity3d,flashing,C#,Unity3d,Flashing,我希望能够以一定的频率闪现东西。例如,假设为2Hz。我还希望能够指定一个比率,在这个比率中,我可以显示周期的2/3,并将其隐藏1/3,因此比率为2:1。这是一个疯狂的一串闪烁,所以我需要保持灵活的方式,我这样做。可能会有一些比为3:5、频率为2Hz的闪烁,还有一些比为1:1、频率为4Hz的闪烁,以此类推 此外,我需要能够同步闪烁。因此,如果一个对象已经在闪烁,我开始闪烁另一个对象,它们需要同步(或者说,它们的周期需要同步,闪烁可能会随着比率的不同而变化)。但如果频率相同,它们需要同时“打开”,即
time
s,但这并不重要,所以如果你不认为这是个坏主意的话,我们还是坚持使用它吧
现在,每当我想刷新一个对象时,在它自己的Update()
中,我会这样做:
switch (flashRate.herz)
{
case FlashRateInterval.twoHerz:
show = flashCycle.oneHerzProgress <= onTimePercentage;
case FlashRateInterval.fourHerz:
show =flashCycle.twoHerzProgress <= onTimePercentage;
case FlashRateInterval.eightHerz:
show =flashCycle.fourHerzProgress <= onTimePercentage;
default:
show =true;
}
开关(flashRate.herz)
{
案例FlashRateInterval.twoHerz:
show=flashCycle.oneHerzProgress您有一些不同之处,因为您在一个更新()周期中用完成所有事情,您可以使用并实现这一点
// 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);
}
}
因此,您可以使用频率(例如8Hz)调用它
StartCoroutine(Flash(8.0f));
这实际上等于您设置onRatio=offRatio
的任何调用
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 1));
StartCoroutine(Flash(8.0f, onRatio = 2, offRatio = 2));
....
或使用频率和比率,例如1(开):2(关)和8Hz
使用此设置,协程将在while(true)
-循环中“永远”运行。因此,在启动具有不同参数的新协程之前,不要忘记首先停止所有具有
StopAllCoroutines();
现在,如果您想在更新方法中动态更改,您必须在roder中添加一些控制标志和其他变量,以确保只有在发生更改时才调用新的协同程序:
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;
}
}
以便直接使用正确的值
我会调用频率变量flashRate.herz
。您也不会调用大小值cube.meters
。我建议将其重命名为flashRate.frequency
要归档同步,您需要访问所有行为并比较它们的值(因此我要说的是一些静态列表
)然后,例如,在协同程序中,等待所有布尔值都设置为真,然后再继续使用您自己的布尔值。为此,您需要额外的布尔值,因为在一个组件上,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)
{
.........
public bool正在闪烁;
IEnumerator闪烁(浮动频率,浮动接通比率=1,浮动断开比率=1)
{
//todo:在更新中不闪烁->时,必须将此设置为false
isBlinking=true;
浮动循环率=1.0f/频率;
浮点数持续时间=(onRatio/(onRatio+offRatio))*循环次数;
浮动关闭持续时间=(关闭比率/(打开比率+关闭比率))*循环关闭;
//开始时同步
show=false;
//等到所有显示都变为假
foreach(FindObjectsOfType()中的var组件)
{
//跳过检查此组件
如果(组件==此)继续;
//如果组件未运行协同路由,则跳过
如果(!component.isBlinking)继续;
//现在等到节目变假
while(component.show)
{
//WaitUntilEndOfFrame使之成为可能
//让我们在之前再次检查该值
//下一帧
返回新的WaitForEndOfFrame;
}
}
//=>当所有显示均为false时,到达此行
//现在,让我们做同样的事情,但这一次等待的是真实的
//等到所有显示都变为假
foreach(FindObjectsOfType()中的var组件)
{
//跳过检查此组件
如果(组件==此)继续;
//如果组件未运行协同路由,则跳过
如果(!component.isBlinking)继续;
//现在等到节目变假
而(!component.show)
{
//WaitUntilEndOfFrame使之成为可能
//让我们在之前再次检查该值
//下一帧
返回新的WaitForEndOfFrame;
}
}
//当所有显示再次变为真=>循环开始时,达到此行
while(true)
{
.........
除了使用有点慢的FindObjectsOfType()
,您还可以执行以下操作
public static List<YOUR_COMPONENT> Components = new List<YOUR_COMPONENT>();
private void Awake()
{
if(!Components.Contains(this)){
Components.Add(this);
}
}
公共静态列表组件=新列表();
私人空间
{
如果(!Components.Contains(this)){
增加(本);
}
}
因此,您也会得到当前禁用的组件和对象您可能希望使用屈服返回
,否则您的协同程序将在第一帧后结束。如果我使用的协同程序以最快的速度“启动”(在我的情况下为8Hz),这是否明智/是否有效对于4Hz和2Hz,四分之三跳过一次?我有点喜欢在一个集中的地方进行闪烁,并考虑拥有这段代码(即使重写到所有可能的美!)在每个游戏对象中运行都很糟糕?啊,好吧,所以你建议的问题是,我很难让多个对象同步闪烁,同时拥有不同的闪烁比率,除非我为每个对象运行一个协同进程(即使这样,它们也可能在某个时候关闭)。即使它们有不同的闪烁比率,我也需要它们同时“打开”所有对象(aka具有相同的周期开始)。我试图用sync
解释的是,当我使另一个对象闪烁时,它应该
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;
}
}
public enum FlashRateInterval
{
AllwaysOn,
twoHerz = 2,
fourHerz = 4,
eightHerz = 8
}
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)
{
.........
public static List<YOUR_COMPONENT> Components = new List<YOUR_COMPONENT>();
private void Awake()
{
if(!Components.Contains(this)){
Components.Add(this);
}
}