3
\$\begingroup\$

First off I'm somewhat new to C# but I'm working on a game in C# Monogame and I'm trying to get timers working. There was a similar question answered around here a while back but I found that the solution doesn't work for me, perhaps an older version or I'm missing something, so I wrote similar timer and timer manager classes myself.

I ended up with a wait(time) function (that seems to work from looking through the debugger but not sure) now I'm wondering how can I get an action to be executed when the timer created by that expires.

Ideally I'd like something like

timerManager.Wait(10)
{
    //do stuff once done waiting
}

Here's my timer classes - Timer.cs and TimerManager.cs

TimerManager gets instantiated in my player class and wait is called in the update function by keyboard input.

if(keyState.IsKeyDown(Keys.Space))
{
    if(canJump)
    {
        vAccel = jumpSpeed * -1;
        stripManager.setCurrentAction(PlayerActions.jump);
        timerManager.Wait(1);
    }
}    

So my question is how can I get an action to trigger, ideally with a set of {} as shown above. I'm aiming to having a class I can reuse for any sort of delay I need in my game.

\$\endgroup\$
  • \$\begingroup\$ It is similar but I am more interested if it's possible to call an action from a custom code block rather than calling an existing method. It might be obvious but as I said I'm rather new to C# so I don't see how to achieve that. \$\endgroup\$ – Sergiu Nov 13 '15 at 15:13
  • \$\begingroup\$ Then you need to pass a lambda and call that once the timer times out. \$\endgroup\$ – ratchet freak Nov 13 '15 at 15:19
  • \$\begingroup\$ @Sergiu Please edit the question to explain the difference. \$\endgroup\$ – Anko Nov 18 '15 at 20:49
  • \$\begingroup\$ Looking at it again it is in fact too similar so I'll just mark it as a duplicate. \$\endgroup\$ – Sergiu Nov 19 '15 at 19:07
2
\$\begingroup\$

Perhaps something like the following might work for you or at least give you new ideas to handle your problem:

float delay = 0;
bool trigger = false;    

public Update()
{
    if(keyState.IsKeyDown(Keys.Space))
    {
         if(canJump) //this line is specific to the OP code
         { //this line is specific to the OP code
             vAccel = jumpSpeed * -1; //this line is specific to the OP code
             stripManager.setCurrentAction(PlayerActions.jump); //this line is specific to the OP code

             WaitTime(10);

         } //this line is specific to the OP code
    }

    if (delay > 0) delay -= Time.deltaTime;
    if (delay <= 0 && trigger)
    {
        DesiredActionAfterTimer();
        trigger = false;
    }
}

void WaitTime(float amountoftime)
{
     delay = amountoftime;
     trigger = true;
}

void DesiredActionAfterTimer()
{
    //Here you put the action you want to perform when time-waiting is over
}

What the above code does is the following.

When you call function WaitTime() passing a float value to it (let's call it X), that function only sets the delay variable to X and sets the trigger to "true". It is in the Update() loop function that the real timer works: every frame, if variable delays is greater than zero and trigger is "true", we subtract a Time.deltaTime from the delay variable. Then, when delay reaches zero, the function DesiredActionAfterTimer() is called to perform whatever action you want to be performed after the timer reaches zero. Also, the trigger variable is then set back to "false". Note that the trigger variable is important to assure that DesiredActionAfterTimer() is only called when WaitTime() was called first - not all the times delay is equal or lower than zero.

Lastly, for further ideas, does the question posted a couple of days ago help you a bit? See: How do I wait to execute code?

\$\endgroup\$
  • \$\begingroup\$ Sure. Let me know how it went. Also, notice that I've just edited the answer to correct some misspelling in the code explanation. \$\endgroup\$ – MAnd Nov 13 '15 at 21:18
1
\$\begingroup\$

A problem is that wait blocks. I suspect what you actually want to do is when the key is pressed store the total time in a variable and then decrement it every tick by your delta-t and check if it's less than or equal to zero.

\$\endgroup\$
1
\$\begingroup\$

I would use something like TaskScheduler, you can probably find dozen of implementations. If you insist on implementing it yourself here is rough sketch:

class PriorityQueue<T> where T: IComparable
{
   private List<T> _list;
   void Enqueue(T item) { _list.Add(item); }
   T Peek() { return _list.Min();}
   T Pop() { 
     var tmp = Peek(); 
     _list.Remove(tmp); 
     return tmp;
   }
}
class ScheduledTask : IComaparable
{
  public Action Action { get; set; }
  public TimeSpan Time { get; set; }
  //constructor, implementation of IComaparable, etc.
} 

class TaskScheduler {
  private PriorityQueue<ScheduledTask> _queue;
  public void Schedule(Action a, double seconds)
  { _queue.Enqueue(new ScheduledTask(a, gameTime.TotalGameTime.AddSeconds(seconds))); }

  public void InvokeAll()/*make sure you call this once each frame*/
  {
    while(_queue.peek().Time < gameTime.TotalGameTime )
     _queue.pop().Action.Invoke();
  }
}

Note that provided PriorityQueue is far from optimal, but I wont go into details of proper implementation of PriorityQueue as there are dozens implementations around, and it is well-defined ADT.

And usage:

TaskScheduler ts; //single instance is for all actions
if(keyState.IsKeyDown(Keys.Space))
{
    if(canJump) {
        ts.Schedule( ()=> 
          { 
              player.Jump(); /*or whatever code here*/
          }, 1.0 );
    }

    if(canFire) {
        ts.Schedule( ()=> 
          { 
              player.Fire();
          }, 0.5 );
    }
}

This is the closest you can probably get - to use lambda expression as Action - as far as I know you cannot implement own scopes (code blocks). Upside of this solution is you dont need add new named function for each action.
note: I did not checked syntax, if you see syntax error feel free to edit or comment the correction.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.