Wednesday, October 3, 2012

Cookbook: UDK timers

Timers in UDK are very useful if you want to call a postponed method (e.g. in 5seconds) or call something regularly (e.g. doing some statistics update each 10 seconds).

Syntax is very simple:


   1:  //set timer: (time to trigger,
   2:  //            true - repeated/false - once only,
   3:  //            method name to call in '')
   4:  SetTimer(2.0,,'MyTimerName');
   5:   
   6:  //stops timer execution
   7:  ClearTimer('MyTimerName');

Let's take a look at a simple example. Let's say we want to have a button that resets itself after given amount of time and additionally updates HUD with time left regularly (for HUD messaging see previous tutorial Cookbook: UDK cascading HUD messages, for kismet events see previous tutorial Cookbook: Triggering events, uscript -> kismet ).


   1:  class ButtonActorTimer extends ButtonActor;
   2:   
   3:  /** time for button to stay activated (then reset) */
   4:  var(Game) float fTimeToReset;
   5:   
   6:  /** time for tick (display message) */
   7:  var(Game) float fTimeToTick;
   8:   
   9:  var float fTimeLeft;
  10:   
  11:  //========================================================================
  12:  function TimeOut()
  13:  {
  14:      //trigger event with myself as instigator
  15:      self.TriggerEventClass(class'SeqEvent_ButtonReset', self);
  16:      Reset();
  17:  }
  18:   
  19:  //========================================================================
  20:  function TimeTick()
  21:  {
  22:      fTimeLeft -= fTimeToTick; //update time
  23:      Controller.StringToHUD(fTimeLeft$"..."); //show HUD message
  24:  }
  25:   
  26:  //========================================================================
  27:  function Set()
  28:  {
  29:      SetTimer(fTimeToReset,,'TimeOut'); //set new reset timer (called once)
  30:      fTimeLeft = fTimeToReset;
  31:      SetTimer(fTimeToTick,true,'TimeTick'); //ticking message (repeatedly)
  32:  }
  33:   
  34:  //========================================================================
  35:  function Reset()
  36:  {
  37:      ClearTimer('TimeOut'); //reset timer!
  38:      ClearTimer('TimeTick');
  39:  }

Button has two independent timers, one for reset (re-enable button, and send reset event to kismet) after time is up (door closes, etc.), second timer is for HUD update and sends time left message onto HUD.

Here is some ingame screenshot:


Tuesday, October 2, 2012

Cookbook: UDK cascading HUD messages

Many games have some messaging system on their HUDs (player picked up some power-up, have taken some damage, timer is ticking away, etc.). Using just the simple extension of HUD class, you can achieve similar results.

We'll use a simple structure to represent our message:


   1:  //message struct define
   2:  struct HUDMessage
   3:  {
   4:      var string sMessage;
   5:      var float fMessageTimer;
   6:  };

Simple method to display string on HUD (based on great vectorlab tutorial):


   1:  //========================================================================
   2:   function DrawString(string text, int X, int Y, int R, int G, int B, int A)
   3:   {
   4:      Canvas.SetPos(X, Y);
   5:      Canvas.SetDrawColor(R, G, B, A);
   6:      Canvas.Font = class'Engine'.static.GetMediumFont();    
   7:      Canvas.DrawText(text);
   8:   }

All messages are stored in a simple dynamic array and updated/displayed/removed each frame:


   1:  var array<HUDMessage> aMessages;
   2:   
   3:  //public method to be called from anywhere in game (your actors, etc.)
   4:  //========================================================================
   5:  function StringToHUD(string message, float timer = 0)
   6:  {
   7:      local HUDMessage newMessage;
   8:   
   9:      newMessage.sMessage = message;
  10:      newMessage.fMessageTimer = -timer; //make it appear longer, optional
  11:      
  12:      aMessages.InsertItem(0,newMessage); //insert at the beginning!
  13:  }
  14:   
  15:  //========================================================================
  16:  simulated event Tick(float DeltaTime)
  17:  {
  18:      local int i;
  19:   
  20:      //update message array
  21:      for (i = 0; i < aMessages.length; ++i)
  22:      {
  23:          aMessages[i].fMessageTimer += DeltaTime;
  24:      }
  25:  }
  26:   
  27:  //draw routine to display cascaded messages
  28:  //========================================================================
  29:  function DrawCustomMessage()
  30:  {
  31:      local HUDMessage message;
  32:      local offsetY = 200;
  33:          
  34:      foreach aMessages(message) //display all messages
  35:      {
  36:                  //message is still to be displayed
  37:          if (message.fMessageTimer < 2.0f)
  38:          {                                    
  39:              DrawString(message.sMessage,0,offsetY,255,255,255,255,true);
  40:              offsetY += 20; //update next message position
  41:          }
  42:          else //expired, remove
  43:          {
  44:              aMessages.RemoveItem(message);
  45:          }
  46:     }
  47:
  48:  }
  49:   
  50:  //========================================================================
  51:  function DrawHUD()
  52:  {
  53:      super.DrawHUD(); //don't forget to call parent method!
  54:      
  55:      DrawCustomMessage(); //our messaging routine
  56:   }

And here is an example screenshot directly from game: