首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >单位:闪光频率可变的开关比

单位:闪光频率可变的开关比
EN

Stack Overflow用户
提问于 2018-10-22 13:57:50
回答 2查看 203关注 0票数 1

我希望能以一定的频率闪光。举个例子,比如说2Hz。我也希望能够指定一个比率,在这里,我可以显示这个循环的2/3,并将它隐藏在1/3中,所以这个比率是2:1。这是一堆疯狂的闪烁,所以我需要保持灵活的方式。可能有一些闪烁的比例为3:5,频率为2Hz,其他一些闪烁在4Hz,比1:1,以此类推。

另外,我需要能够同步闪光。因此,如果一个对象已经在闪烁,而我开始闪烁另一个对象,则它们需要同步(或者更确切地说,它们的周期需要同步,闪存可能会随着比率的不同而变化)。但如果在相同的频率,他们需要“打开”在同一时间,即使他们的比率是不同的。而且,他们都需要同时打开最慢的开关。

我目前的方法是:我有一个GameObject FlashCycle,在它的更新方法中,计算出我拥有的3个频率(2Hz、4Hz和8Hz)的进度。

代码语言:javascript
运行
复制
 float time = Time.time;
 twoHerzProgress = (time % twoHerzInSeconds) / twoHerzInSeconds;
 fourHerzProgress = (time % fourHerzInSeconds) / fourHerzInSeconds;
 eightHerzProgress = (time % eightHerzInSeconds) / eightHerzInSeconds;

我尝试过不同的time,但这并不重要,所以如果您不认为这是个坏主意,那么让我们继续使用它吧!

现在,每当我想要闪现一个对象时,在它自己的Update()中,我会这样做:

代码语言:javascript
运行
复制
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;
    }

然后继续,如果是show == true,则显示该对象。

不幸的是,这并没有在一个很好的,平滑和规则的间隔对象闪现。我测量了2Hz的间隔,得到了高达48毫秒的差值,虽然看起来不太大,但在屏幕上确实有很大的不同。

因此,问题归结为:如何在保持灵活性(比率和频率)的同时,获得快速、可调整的闪光灯,并具有同步闪存?

谢谢你的帮忙!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-22 14:30:42

您可以使用协同线WaitForSeconds来实现这一点。

代码语言:javascript
运行
复制
// 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赫兹的频率来称呼它

代码语言:javascript
运行
复制
StartCoroutine(Flash(8.0f));

这实际上等于设置onRatio = offRatio的任何调用。

代码语言:javascript
运行
复制
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 1));

StartCoroutine(Flash(8.0f, onRatio = 2, offRatio = 2));

....

或具有频率和比率,例如1(on):2(off)和8Hz

代码语言:javascript
运行
复制
StartCoroutine(Flash(8.0f, onRatio = 1, offRatio = 2));

通过这种设置,Coroutine在while(true)-loop中“永远”运行。因此,在启动具有不同参数的新Coroutine之前,不要忘记

代码语言:javascript
运行
复制
 StopAllCoroutines();

现在,如果要在Update方法中动态地更改这个值,则必须在roder中添加一些控制标志和附加变量,以确保只有在发生更改时才会调用新的Coroutine:

代码语言:javascript
运行
复制
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;
    }
}

备注:

  1. 我不知道你的FlashRateInterval,但如果你出于某种原因需要使用它,你可以让它 公共枚举FlashRateInterval { AllwaysOn,twoHerz = 2,fourHerz = 4,eightHerz =8} 以便直接使用正确的值。
  2. 我会叫一个频率变量flashRate.herz。您也不会调用size值cube.meters。我建议把它重命名为flashRate.frequency

为了证明同步,你将需要访问所有行为并比较它们的价值(所以我要说一些static List<YourBehavior>),而不是在Coroutine中,等待所有的bools被设置为真,然后再继续自己的行为。为此,您需要额外的bool,因为可能show在一个组件上是永久的。

代码语言:javascript
运行
复制
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>() (有点慢)不同,您还可以做一些类似的事情

代码语言:javascript
运行
复制
public static List<YOUR_COMPONENT> Components = new List<YOUR_COMPONENT>();

private void Awake()
{
    if(!Components.Contains(this)){
        Components.Add(this);
    }
}

因此,您现在还禁用了组件和对象。

票数 3
EN

Stack Overflow用户

发布于 2018-10-22 14:19:18

您得到了一些差异,因为您正在使用<=条件在Update()循环中执行所有操作。在较慢/更快的机器上,您将有更多/更少的差异,因为帧的持续时间永远不会等于您的频率。

尝试在Corotine中做所有的事情:统一协同工作文档

代码语言:javascript
运行
复制
//bad code below but i think its more understandable like this
IEnumerator Flash() 
{
   while(true)
   {
     BlinkOn();
     Sync();//sync here another cicle if you want to sync when on starts
     yield return new WaitForSeconds(yourDuration);// yourDuration*multiplier/something+0.5f....ecc

     BlinkOff()
     Sync();//sync here another cicle if you want to sync when of starts
     yield return new WaitForSeconds(yourDuration);
   }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52931177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档