VGUI文档

From Valve Developer Community
< Zh
Jump to navigation Jump to search
Info content.png
This page is Machine translated
It is not recommended to use machine translation without any corrections.
If the article is not corrected in the long term, it will be removed.
Also, please make sure the article complies with the alternate languages guide.(en)
English (en)Español (es)Polski (pl)Русский (ru)中文 (zh)Translate (Translate)
Info content.png
This page has not been fully translated.
You can help by finishing the translation.
If this page cannot be translated for some reason, or is left untranslated for an extended period of time after this notice is posted, the page should be requested to be deleted.
Also, please make sure the article complies with the alternate languages guide.(en)
This notice is put here by LanguageBar template and if you want to remove it after updating the translation you can do so on this page.


VGUI是Valve专有的图形用户界面(en)系统。所有或大多数起源 起源游戏以及早期的Steam Steam都使用VGUI来绘制窗口、对话框和菜单。它还处理本地化 ↓功能:以用户首选语言显示文本。

  • 对象架构采用层级结构,所有实现的元素均派生自VGUI基类。
  • 键盘/鼠标输入系统是事件驱动的,与其他GUI系统非常相似。
  • 最常见GUI元素(如按钮、文本字段或图像)的实现由VGUI控件库提供(vgui_controls.lib)。
  • 基础接口头文件位于\public\vgui\
  • 控件元素定义在\public\vgui_controls\

作为模组作者,您最可能通过client.dll项目使用VGUI来显示菜单、HUD元素或游戏内显示(如武器或计算机终端等)。

面板与层级结构

所有VGUI元素的基类均为vgui::Panel,它定义了屏幕上具有特定大小和位置的区域,可以自行绘制并处理输入事件。对话框窗口、文本字段和按钮都是具有父子层级关系的VGUI面板。最顶层的根面板由Source引擎提供。客户端根面板覆盖整个屏幕,但不可见。尽管可以直接使用客户端根面板,但大多数客户端面板使用共享的BaseViewport面板作为父级(g_pClientMode->GetViewport())。

下图展示了《反恐精英》中的VGUI面板层级结构:

VGUI客户端面板层级

您可以使用VGUI层级工具查看模组的面板结构。通过在开发者控制台(en)输入vgui_drawtree 1来开启该工具。

VGUI层级工具

面板名称采用颜色编码:

  • 可见
  • 隐藏
  • 弹出面板(框架)
  • 具有焦点

工具提供以下复选框选项:

显示可见
列出所有可见面板
显示隐藏
列出所有隐藏面板
仅弹窗
仅列出弹出面板(框架)
高亮鼠标悬停
当鼠标悬停时用彩色边框高亮面板,并展开树状图显示当前面板
冻结
锁定当前树状视图
显示地址
显示面板内存地址
显示透明度
显示面板透明度值(0为半透明,255为不透明)
按渲染顺序
按渲染顺序排列面板

Panel类

VGUI基类Panel派生出\public\vgui_controls\中定义的50多种控件。头文件通常详细说明了控件的特性与行为。下表展示常用元素的类层级:

Panel
EditablePanel Label TextEntry RichText ImagePanel
Frame Button ComboBox
MessageBox ToggleButton

由于所有VGUI类都派生自Panel类,我们需要深入了解其核心成员函数和属性。

最常用的面板构造函数是Panel(Panel* parent, const char* panelName),因为每个面板都需要指定父面板和同级唯一的名称。创建面板后,可通过SetVisible(bool state)控制可见性。

VGUI为每个新面板维护一个句柄,用于全局寻址而无需传递指针。许多事件消息函数使用这些VPANEL句柄标识源和目标面板。通过GetVPanel()可获取面板的VPANEL句柄。

使用SetPos(int x,int y)SetSize(int wide,int tall)设置面板位置和尺寸。尺寸以像素为单位,不会随屏幕分辨率自动缩放。位置始终相对于父面板的左上角(0,0)。

通过GetParent()GetVParent()可获取父面板或对应的VPANEL句柄。面板只能有一个父级,但可以有多个子级(通过GetChildCount()GetChild(int index)查询)。

要让面板响应输入事件(如按键或鼠标点击),需重写虚函数如OnMousePressed(MouseCode code)OnKeyCodePressed(KeyCode code)。通过SetMouseInputEnabled(bool state)SetKeyBoardInputEnabled(bool state)启用/禁用输入。

另一个有用的虚函数是OnThink(),在每次重绘面板时调用。若需降低更新频率,可使用OnTick()并通过ivgui()->AddTickSignal(VPANEL panel, int intervalMilliseconds)设置调用间隔。

窗口与弹窗

普通Panel始终是父面板的子区域,位置固定且绘制范围受限。通过MakePopup()可将面板解耦为独立窗口,但仍属于父级。通常使用Frame类实现弹窗功能,其封装了标题栏、系统菜单、拖拽调整等功能。

以下示例展示如何创建并激活框架(关闭时会自动销毁):

Frame* pFrame = new Frame( g_pClientMode->GetViewport(), "MyFrame" );
pFrame->SetScheme("ClientScheme.res");
pFrame->SetSize( 100, 100 );
pFrame->SetTitle("我的第一个框架", true );
pFrame->Activate(); // 设为可见、置顶并请求焦点

调整框架大小时会触发PerformLayout()以重新布局。可通过SetMoveable(bool state)SetSizeable(bool state)锁定位置和尺寸。

事件消息传递

VGUI面板通过消息系统进行通信。消息通过KeyValues对象传递,需指定发送方和接收方的VPANEL句柄。发送消息使用PostMessage(...)ivgui()->PostMessage(...),目标面板的OnMessage(...)会分派消息到预定义的处理器(通过MESSAGE_FUNC_*宏注册)。

示例消息处理:

class MyParentPanel  : public vgui::Panel
{
	...
private:
	MESSAGE_FUNC_PARAMS( OnMyMessage, "MyMessage", data );
}

void MyParentPanel::OnMyMessage (KeyValues* data)
{
	const char* text = data->GetString("text");
}

发送方代码:

void MyChildPanel::SomethingHappened()
{
	if ( GetVParent() )
	{
		KeyValues* msg = new KeyValues("MyMessage");
		msg->SetString("text", "有事件发生");
		PostMessage(GetVParent(), msg);
	}
}

通过PostActionSignal()发送通用事件,其他面板通过AddActionSignalTarget()注册监听。常用动作信号如"Command"消息,可重写OnCommand(const char* command)处理。

方案

VGUI方案(scheme)通过资源文件定义控件的颜色、字体和图标。默认继承父级方案,可通过SetScheme(HScheme scheme)切换。使用LoadControlSettings()加载布局资源文件(需继承自EditablePanel)。

资源文件示例:

MyControlName
{
	ControlName	Label
	fieldName	MyControlName
	xpos		8
	ypos		72
	wide		160
	tall		24
	visible		1
	enabled		1
	labelText	"你好世界"
	textAlignment	west
}

构建模式

VGUI构建模式面板

通过SHIFT+CTRL+ALT+B开启构建模式,实时编辑面板布局并保存到资源文件。

绘制与表面

重写Paint()PaintBackground()自定义绘制。使用ISurface接口绘制图形、文本和纹理。示例绘制红色方块:

void MyPanel::Paint(void)
{
	BaseClass::Paint();  
	surface()->DrawSetColor(255, 0, 0, 255);
	surface()->DrawFilledRect(0, 0, 20, 20);
}

文本绘制需设置字体:

void MyPanel::Paint(void)
{
	wchar_t* pText = L"你好世界!";
	vgui::IScheme* pScheme = vgui::scheme()->GetIScheme(GetScheme());
	vgui::HFont hFont = pScheme->GetFont("DefaultSmall");
	surface()->DrawSetTextFont(hFont);
	surface()->DrawSetTextColor(255, 0, 0, 255);
	surface()->DrawSetTextPos(10, 10);
	surface()->DrawPrintText(pText, wcslen(pText));
}

加载并绘制纹理:

MyPanel::MyPanel(void)
{
	m_nTextureID = vgui::surface()->CreateNewTextureID();
	vgui::surface()->DrawSetTextureFile(m_nTextureID, "vgui/your_folder/mylogo", true, false);
}

void MyPanel::Paint(void)
{
	vgui::surface()->DrawSetTexture(m_nTextureID);
	vgui::surface()->DrawSetColor(50,50,50,100);
	vgui::surface()->DrawTexturedRect(0, 0, 100, 100);
}

比例缩放

在配置文件中使用比例值(基于640x480分辨率),通过SetProportional(true)自动缩放。代码中可使用scheme()->GetProportionalScaledValue()转换坐标。

Tip.png提示:xposypos中使用c-<wide/tall>实现不同宽高比下的居中。

本地化

使用#开头的令牌实现多语言支持。例如SetText("#MyMod_HelloWorld"),并在资源文件(如mymod_english.txt)中定义翻译:

"MyMod_HelloWorld"		"Hello world."

通过g_pVGuiLocalize->Find("#Token")获取本地化文本。注意文件需保存为UCS2-Little Endian格式。

另见

教程