HGE教程翻译(6)

来源:互联网 发布:合肥市行知学校排名 编辑:程序博客网 时间:2024/06/11 17:46

Tutorial 06 – 创建菜单

 

这个教程显示如何创建通用的GUI控制和菜单。

创建通用控制

首先我们定义控制类,从hgeGUIObject继承:

 

class hgeGUIMenuItem : public hgeGUIObject
{
public:
  hgeGUIMenuItem(int id, hgeFont *fnt, HEFFECT snd,
          float x, float y, float delay, char *title);
 
  virtual void  Render();
  virtual void  Update(float dt);
 
  virtual void  Enter();
  virtual void  Leave();
  virtual bool  IsDone();
  virtual void  Focus(bool bFocused);
  virtual void  MouseOver(bool bOver);
 
  virtual bool  MouseLButton(bool bDown);
  virtual bool  KeyClick(int key, int chr);
 
private:
  hgeFont       *fnt;
  HEFFECT       snd;
  float         delay;
  char          *title;
 
  hgeColor      scolor, dcolor, scolor2, dcolor2, color;
  hgeColor      sshadow, dshadow, shadow;
  float         soffset, doffset, offset;
  float         timer, timer2;
};

 

构造函数初始化数据成员id, bStatic, bVisible, bEnabled rect

 

hgeGUIMenuItem::hgeGUIMenuItem(int _id, hgeFont *_fnt,
                HEFFECT _snd, float _x, float _y,
                float _delay, char *_title)
{
  id=_id;
  fnt=_fnt;
  snd=_snd;
  delay=_delay;
  title=_title;
 
  color.SetHWColor(0xFFFFE060);
  shadow.SetHWColor(0x30000000);
  offset=0.0f; timer=-1.0f; timer2=-1.0f;
 
  bStatic=false; bVisible=true; bEnabled=true;
 
  float w=fnt->GetStringWidth(title);
  rect.Set(_x-w/2, _y, _x+w/2, _y+fnt->GetHeight());
}

 

Render函数是重点,每个控制都要定义它。

 

void hgeGUIMenuItem::Render()
{
  fnt->SetColor(shadow.GetHWColor());
  fnt->Render(rect.x1+offset+3, rect.y1+3, HGETEXT_LEFT, title);
  fnt->SetColor(color.GetHWColor());
  fnt->Render(rect.x1-offset, rect.y1-offset, HGETEXT_LEFT, title);
}

 

所有其他方法都是可选的,你可以不定义。


Update在每次GUI更新并需要渲染时调用。在这例子中我们有两个定时器根据时间调节颜色和位置,

 

void hgeGUIMenuItem::Update(float dt)
{
  if(timer2 != -1.0f)
  {
    timer2+=dt;
    if(timer2 >= delay+0.1f)
    {
      color=scolor2+dcolor2;
      shadow=sshadow+dshadow;
      offset=0.0f;
      timer2=-1.0f;
    }
    else
    {
      if(timer2 < delay) { color=scolor2; shadow=sshadow; }
      else {
        color=scolor2+dcolor2*(timer2-delay)*10;
        shadow=sshadow+dshadow*(timer2-delay)*10;
      }
    }
  }
  else if(timer != -1.0f)
  {
    timer+=dt;
    if(timer >= 0.2f)
    {
      color=scolor+dcolor;
      offset=soffset+doffset;
      timer=-1.0f;
    }
    else
    {
      color=scolor+dcolor*timer*5;
      offset=soffset+doffset*timer*5;
    }
  }
}

 

EnterGUI将要出现在屏幕上时调用。一个控制动画应该在这里进入:

 

void hgeGUIMenuItem::Enter()
{
  hgeColor tcolor2;
 
  scolor2.SetHWColor(0x00FFE060);
  tcolor2.SetHWColor(0xFFFFE060);
  dcolor2=tcolor2-scolor2;
 
  sshadow.SetHWColor(0x00000000);
  tcolor2.SetHWColor(0x30000000);
  dshadow=tcolor2-sshadow;
 
  timer2=0.0f;
}

 

LeaveGUI要从屏幕消失时调用。

 

void hgeGUIMenuItem::Leave()
{
  hgeColor tcolor2;
 
  scolor2.SetHWColor(0xFFFFE060);
  tcolor2.SetHWColor(0x00FFE060);
  dcolor2=tcolor2-scolor2;
 
  sshadow.SetHWColor(0x30000000);
  tcolor2.SetHWColor(0x00000000);
  dshadow=tcolor2-sshadow;
 
  timer2=0.0f;
}

 

IsDone用来检测这个控制是否完成Enter/Leave动画。完成返回true

 

bool hgeGUIMenuItem::IsDone()
{
  if(timer2==-1.0f) return true;
  else return false;
}

 

Focus当控制获得或失去键盘输入焦点时调用。

 

void hgeGUIMenuItem::Focus(bool bFocused)
{
  hgeColor tcolor;
 
  if(bFocused)
  {
    hge->Effect_Play(snd);
    scolor.SetHWColor(0xFFFFE060);
    tcolor.SetHWColor(0xFFFFFFFF);
    soffset=0;
    doffset=4;
  }
  else
  {
    scolor.SetHWColor(0xFFFFFFFF);
    tcolor.SetHWColor(0xFFFFE060);
    soffset=4;
    doffset=-4;
  }
 
  dcolor=tcolor-scolor;
  timer=0.0f;
}

 

MouseOver用来通知鼠标指针进入或离开它的区域。这里我们只设置输入焦点到控制当鼠标经过它时。

 

void hgeGUIMenuItem::MouseOver(bool bOver)
{
  if(bOver) gui->SetFocus(id);
}

 

MouseLButton当左键状态改变时调用。如果控制改变它的状态并希望通知调用者,应该返回true

 

bool hgeGUIMenuItem::MouseLButton(bool bDown)
{
  if(!bDown)
  {
    offset=4;
    return true;
  }
  else 
  {
    hge->Effect_Play(snd);
    offset=0;
    return false;
  }
}

 

KeyClick用来通知控制一个键被点击。如果控制改变它的状态并希望通知调用者,应返回true

 

bool hgeGUIMenuItem::KeyClick(int key, int chr)
{
  if(key==HGEK_ENTER || key==HGEK_SPACE)
  {
    MouseLButton(true);
    return MouseLButton(false);
  }
 
  return false;
}

 

现在我们有通用的控制行为定义了。

使用GUI

这里是简单部分。首先我们需要资源变量:

 

HEFFECT    snd;
HTEXTURE   tex;
 
hgeGUI     *gui;
hgeFont    *fnt;
hgeSprite  *spr;

 

WinMain中,在初始化过程中载入资源:

 

  snd=hge->Effect_Load("menu.wav");
  tex=hge->Texture_Load("cursor.png");
 
  fnt=new hgeFont("font1.fnt");
  spr=new hgeSprite(tex,0,0,32,32);

 

现在创建GUI并添加菜单部件。GUI控制在内部处理,你不需要关心。

 

  gui=new hgeGUI();
 
  gui->AddCtrl(new hgeGUIMenuItem(
               1,fnt,snd,400,200,0.0f,"Play"));
  gui->AddCtrl(new hgeGUIMenuItem(
               2,fnt,snd,400,240,0.1f,"Options"));
  gui->AddCtrl(new hgeGUIMenuItem(
               3,fnt,snd,400,280,0.2f,"Instructions"));
  gui->AddCtrl(new hgeGUIMenuItem(
               4,fnt,snd,400,320,0.3f,"Credits"));
  gui->AddCtrl(new hgeGUIMenuItem(
               5,fnt,snd,400,360,0.4f,"Exit"));

 

现在我们设置GUI模式,鼠标图象和默认键盘焦点,然后开始进入动画:

 

  gui->SetNavMode(HGEGUI_UPDOWN | HGEGUI_CYCLED);
  gui->SetCursor(spr);
  gui->SetFocus(1);
  gui->Enter();

 

现在看看我们如何更新菜单和接收通知。在FrameFunc中我们调用hgeGUI::Update来更新状态,它返回控制的鉴定值。如果所有的控制都完成离开动画,它返回-1。如果没有事情发生返回0

 

  int id;
  static int lastid=0;
  float dt=hge->Timer_GetDelta();
 
  id=gui->Update(dt);
  if(id == -1)
  {
    switch(lastid)
    {
      case 1:
      case 2:
      case 3:
      case 4:
        gui->SetFocus(1);
        gui->Enter();
        break;
 
      case 5: return true;
    }
  }
  else if(id) { lastid=id; gui->Leave(); }

 

RenderFunc中调用hgeGUI::Render来渲染菜单:

 

  hge->Gfx_BeginScene();
  gui->Render();
  hge->Gfx_EndScene();

 

菜单出现并运行。现在来到WinMain。程序结束时删除GUI并释放资源。

 

  delete gui;
  delete fnt;
  delete spr;
  hge->Texture_Free(tex);
  hge->Effect_Free(snd);