Timer improvements

If there is something important you think is missing in the current version of ZGameEditor then you can post a feature request here!

Moderator: Moderators

Post Reply
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Timer improvements

Post by rrTea »

OnExpire
It'd be great if there was an automatic option to trigger something after the Timer has finished... I guess it's pretty obvious (I'd use it for bombs and similar situations). Similar to how AnimatorGroup has OnStop basically.

Of course the same effect can already be achieved in various clumsy ways, but they are all ugly...
Last edited by rrTea on Mon Aug 08, 2016 12:59 pm, edited 5 times in total.
User avatar
VilleK
Site Admin
Posts: 2318
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Timer / OnExpire

Post by VilleK »

I would probably just set the Timer.Interval=0 to disable it in a ZExpression in the Timer.OnTimer event. Is there a problem with that approach?
Imerion
Posts: 200
Joined: Sun Feb 09, 2014 4:42 pm

Re: Timer / OnExpire

Post by Imerion »

That is smart. I haven't used timers much, instead doing them myself in code. But that should work well now that I know about it. :)
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Timer / OnExpire

Post by rrTea »

VilleK wrote:I would probably just set the Timer.Interval=0 to disable it in a ZExpression in the Timer.OnTimer event. Is there a problem with that approach?
But wouldn't that just stop the timer?

...I just saw that the Timer in the newest build has a "CurrentRelativeTime", so looks like this can be used in a condition (something like return (Countdown.CurrentRelativeTime == 0); + also check a flag to stop it from looping) so I tested it in

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnUpdate>
    <Timer Name="Countdown" Interval="1" RepeatCount="0"/>
    <Condition>
      <Expression>
<![CDATA[return (
Countdown.CurrentRelativeTime == 0);]]>
      </Expression>
      <OnTrue>
        <ZExpression Expression="trace ("Here it is!");"/>
      </OnTrue>
    </Condition>
  </OnUpdate>
  <Content>
    <ZExpression>
      <Expression>
<![CDATA[trace (
intToStr(Countdown.CurrentRelativeTime*100)
);]]>
      </Expression>
    </ZExpression>
  </Content>
</ZApplication>
...but this never completes? Even though the other ZExpression (that is currently in Content, after moving it to OnUpdate) does report that the CurrentRelativeTime reaches 0... Did I misunderstand how it works?
User avatar
Rado1
Posts: 775
Joined: Wed May 05, 2010 12:16 pm

Re: Timer / OnExpire

Post by Rado1 »

I would not use RepeatCount == 0 in condition, but rather put the desired behavior to OnTimer; it's more explicit. However, RepeatCount can be used for other things, see the following example:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZExpression Comment="Init">
      <Expression>
<![CDATA[Countdown.RepeatCount = -1;
Countdown.CurrentRelativeTime = 0;]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <Timer Name="Countdown" Interval="5" RepeatCount="0">
      <OnTimer>
        <ZExpression>
          <Expression>
<![CDATA[trace ("Here it is!");
Countdown.RepeatCount = 0;
Countdown.CurrentRelativeTime = 6;]]>
          </Expression>
        </ZExpression>
      </OnTimer>
    </Timer>
  </OnUpdate>
  <OnRender>
    <RenderText TextFloatRef="6 - Countdown.CurrentRelativeTime;"/>
  </OnRender>
</ZApplication>
User avatar
Kjell
Posts: 1910
Joined: Sat Feb 23, 2008 11:15 pm

Re: Timer / OnExpire

Post by Kjell »

Hi guys,

The CurrentRelativeTime property indicates how long ago the Timer has hit its interval. This is relevant because the moment when a interval has been completed usually doesn't match up exactly with the moment a frame is being executed.

For instance, imagine a Timer that spawns a model every second which has a Velocity.X of 1, a random Position.Y and renders a semi-transparent sprite. When you don't take CurrentRelativeTime in consideration and simply spawn a clone in OnTimer, you'll notice that the sprites are sometimes slightly apart or overlap slightly. But using CurrentRelativeTime you can correct this ( by offsetting the starting position ) almost perfectly.

Image

Obviously you could also treat this kind of situation as a type of animation, to get it 100% right .. but the CurrentRelativeTime method is very useful for accurately spawning high-speed bullets at a set interval and such.

K
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Timer / OnExpire

Post by rrTea »

Rado: Yes you're right, it's better to put it like in your example.

Kjell: Thanks for clarification, so that's what it's for!

In any case, just to attempt to clarify what I was talking about in the opening post: I was trying to say that adding the equivalent of AnimatorGroup's "OnStop" to Timer component would make Timer even more useful. (Edit: I added it to the old post.)
Last edited by rrTea on Mon Aug 08, 2016 1:02 pm, edited 1 time in total.
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Timer improvements

Post by rrTea »

"Retrigger" timer
The name is a bit misleading but here is the situation I'm working on:
Player can do some stuff that adds to ComboCounter. As soon as the ComboCounter is bigger than 0, it should start falling every 1 second. Right now I'm dealing with it like this (from my main project):

Code: Select all

ZZDC<?xml version="1.0" encoding="iso-8859-1" ?>
<Condition Comment="Any combo?">
  <Expression>
<![CDATA[return (
ComboCounter > 0
);]]>
  </Expression>
  <OnTrue>
    <Timer Name="timer_ComboCountdown" Interval="0.2">
      <OnTimer>
        <ZExpression Expression="ComboCounter--;"/>
        <Condition Comment="More than 40?">
          <Expression>
<![CDATA[return (
ComboCounter > 40
);]]>
          </Expression>
          <OnTrue>
            <PlaySound Sound="sfx_ComboCountdown" NoteNr="96"/>
          </OnTrue>
        </Condition>
      </OnTimer>
    </Timer>
  </OnTrue>
</Condition>
The problem arises when the Player (it's encouraged actually) adds more Combo points before that 1 second expires. In such cases it looks bad when the counter first jumps up and immediately back down if it so happened that the Timer was at, say 0.2 when the new combo points got collected. What should happen is that the new addition of a combo point resets the Timer, but I can't find a way to do it. Is that even possible?

I tried a few things but nothing works.

Edit: Oh I just found an old topic that sounds similar to this:
viewtopic.php?p=5086#p5086
From what I understood of Kjell's explanation resetting the CurrentRelativeTime shouldn't do what I'm after?... I'll keep on poking tomorrow.
Last edited by rrTea on Mon Aug 08, 2016 1:36 pm, edited 1 time in total.
User avatar
Kjell
Posts: 1910
Joined: Sat Feb 23, 2008 11:15 pm

Re: Timer improvements

Post by Kjell »

Hi rrTea,
rrTea wrote:What should happen is that the new addition of a combo point resets the Timer, but I can't find a way to do it.
I'd recommend using a DIY-timer in these kind of situations.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" ClearColor="0.502 0.502 0.502 1" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[// Reset the DIY-timer and combo-counter.

Timer = 0;
Combo = 0;]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <ZExpression>
      <Expression>
<![CDATA[// Drive DIY-timer

Timer += App.DeltaTime;

// Check if 1 second has passed

while(Timer > 1)
{
  Timer--;
  Combo++;
}

// Update combo string

RenderCombo.Text = intToStr(Combo);]]>
      </Expression>
    </ZExpression>
    <KeyPress Keys="{" RepeatDelay="0.1">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[// Reset the DIY-timer

Timer = 0;]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <OnRender>
    <UseMaterial Material="DigitsMaterial"/>
    <RenderText Name="RenderCombo" Text="0" Scale="5" RenderCharExpression="//"/>
  </OnRender>
  <Content>
    <Variable Name="Timer"/>
    <Variable Name="Combo"/>
    <Group Comment="Digits">
      <Children>
        <Font Name="Digits" Bitmap="DigitsBitmap" FirstChar="48" CharPixelWidth="4" CharPixelHeight="5"/>
        <Bitmap Name="DigitsBitmap" Width="20" Height="10" Filter="1">
          <Producers>
            <BitmapFromFile Transparency="2" HasAlphaLayer="1" DataWidth="20" DataHeight="10">
              <BitmapFile>
<![CDATA[78DAFBFF1F011880E03F1A1F0670C913A31E9926479E9AEEC3A50F1DE0721F369A907D94F0D1DD488DF0C7C5C6172EA49887CDFD84E283909B88750FA5E1874E030044C69678]]>
              </BitmapFile>
            </BitmapFromFile>
          </Producers>
        </Bitmap>
        <Material Name="DigitsMaterial" Shading="1" Light="0" Blend="1" ZBuffer="0" Font="Digits"/>
      </Children>
    </Group>
  </Content>
</ZApplication>
K
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Re: Timer improvements

Post by rrTea »

Too bad Timer can't be used for that at the moment but this works too, thanks! I implemented it and it works. I'm planning to use it for other things too so I guess I'll just make all those timers like this.
User avatar
Kjell
Posts: 1910
Joined: Sat Feb 23, 2008 11:15 pm

Re: Timer improvements

Post by Kjell »

Hi rrTea,
rrTea wrote:I'm planning to use it for other things too so I guess I'll just make all those timers like this.
In that case you might want to wrap it into a ZLibrary ..

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZLibrary Comment="Timer">
      <Source>
<![CDATA[//

const int _INF = 0xFF800000;

//

const int TIMER_PAUSE = 0x0,
          TIMER_RESET = 0x1;

void timerAction(ref float timer, int action)
{
  switch(action)
  {
    case TIMER_PAUSE:
      if(timer != reinterpret_cast<float>(_INF))timer = 0-timer;
      break;

    case TIMER_RESET:
      timer = 0;
      break;
  }
}

byte timerExecute(ref float timer, float interval, int repeat)
{
  if(timer >= 0)
  {
    float t = floor(timer);
    timer += interval > 0 ? App.DeltaTime/interval : 1;

    if(floor(timer) != t)
    {
      if(repeat != -1)
      {
        if(t > repeat)
        {
          timer = reinterpret_cast<float>(_INF);
          return 0;
        }
      }

      return 1;
    }
  }

  return 0;
}]]>
      </Source>
    </ZLibrary>
  </OnLoaded>
  <OnUpdate>
    <Condition Expression="return timerExecute(Timer, 1, 2);">
      <OnTrue>
        <ZExpression Expression="trace(intToStr(Timer));"/>
      </OnTrue>
    </Condition>
  </OnUpdate>
  <Content>
    <Variable Name="Timer"/>
  </Content>
</ZApplication>
It's modeled after the Timer component, so ..

- When you use a interval of 1 second, the first time the timer is triggered is 1 second after the timer has started.
- When you use a repeat count of 2, the timer will trigger 3 times in total.
- When you use a interval that fits in the duration of a frame more than once, the timer still only triggers once per frame.

Make sure to call timerExecute every frame, and use timerAction to (UN)PAUSE or RESET the timer. If you want more ( or fewer ) features, want things to work differently or have any questions .. let me know :wink:

K
User avatar
rrTea
Posts: 475
Joined: Sat Feb 15, 2014 9:54 am

Excellent!

Post by rrTea »

Hey Kjell, thanks so much! You're right it's probably best to have it in a library - it'll come in handy for combos, time trials and all the other things. I'll try to implement it as soon as I'm done with the video.
Post Reply