Panorama 用户界面
“Panorama”是Valve新开发的一个UI(用户界面)框架。它深受现代网页设计方式的影响,和HTML5/CSS/JS等框架非常相像。通过使用这个系统,用户可以快速开发出高质量的用户界面,包括流畅的游戏内容整合(如3D模型,粒子特效等)。
Panorama将完全取代原先的Scaleform的UI开发方式。在Workshop Tools Beta中,前端的自定义游戏用户界面都是使用Panorama开发的。虽然目前的Dota用户界面仍然采用Scaleform,但是最终也会被Panorama取代。起源2引擎有一些非常不同的需求,而它们仍然是由C++和Qt-实现的——这些语言不会被移植到Panorama中。
Panorama基本概念
标签元素 layout files
XML文件相当于其他文件的骨架。XML文件包含了UI中将要使用的板,以及它们的继承布局。XML文件可以从下列位置找到:
content/dota_addons/ADDON_NAME/panorama/layout/custom_game/*.xml
一个复杂的Panorama UI,为了保持简洁和清晰,往往具有多个XML文件(同时让多个元素可以被用在同一个位置)。比如说,一个比分牌可以拥有一个基本的XML文件,画好主要的布局,然后加上一个二级XML文件,具体画出队伍信息,再加上一个三级XML文件,画出玩家信息。
基础标签:panel
另见: Panorama-板
Panels 是Panorama中的组成部件。在网页开发的概念中,板相当于一个基本的HTML元素:<dir />。所有Panorama中可见的元素——标签、图片、按钮——都是板构成的。
样式表格 Style Sheets
CSS文件用来描述XML中的元素是通过怎样的方式被展现的。可以从下列位置找到:
content/dota_addons/ADDON_NAME/panorama/styles/custom_game/*.css
另有三个地方包含了所支持的CSS有关属性:
这一页Panorama Layout 也包含了关于Panorama布局系统的运行方式的资源。
脚本 𝐉𝐚𝐯𝐚𝐬𝐜𝐫𝐢𝐩𝐭
JS文件包含了𝐉𝐚𝐯𝐚𝐬𝐜𝐫𝐢𝐩𝐭代码,它们可以用来相应玩家输入,或者改变游戏状态。可以在下列位置找到:
content/dota_addons/ADDON_NAME/panorama/scripts/custom_game/*.js
事件 Events
另见: panorama事件
Panaroma事件是一种沟通多个板的方法。这些事件和javascript函数很像,但在发送信息方面有所不同。在制作UI时,事件可以用来简化一些普通的操作。
与网页设计的相像之处
如果你很熟悉网页设计的话,你会觉得一个Panorama XML文件很像HTML5,CSS文件几乎和网页中使用的一模一样(除了网页设计的复杂程度和浏览器兼容性),而JS文件和网页开发者们熟悉的也是一样(仅在函数功能的库上有些不同)。
就算你对网页设计不那么熟悉,这些相像之处也是很有用的。Panorama与网页设计具有相似的特点,这意味着你可以从网络上搜索到大量的相关资料。如果你想深入学习网页设计的话,这里有一个很好的网站: https://www.javascript.com
与网页的不同之处
- CSS代码的一些部分被调整过以变得更易用。
- 在javascript中,JQuery风格的“$”按键非常不好用,目前它只能通过ID来匹配单个按键。如果没有匹配的按键,会返回一个null值而不是空选择,这可能造成一些意外的错误。
- 某些网页设计的属性被省略了,因为实在是没有用或者太麻烦了。
用Panorama创作UI
迈出第一步
Manifest文件 是所有PanoramaUI的基础
content/dota_addons/ADDON_NAME/panorama/layout/custom_game/custom_ui_manifest.xml
工作流程
当运行Dota tool 的时候,content/folder下的XML、CSS和JS文件会和其他文件一样一起被监视,并且在用户做出改变的时候自动重新编译和加载(这个功能只有在UI被激活的时候才会生效,也就是说一个未被使用的XML文件只会在被用到的时候编译)
在面对一些动态变化的时候,Panorama通常都会很好地更新这些变化,但是一些太过“激烈”的变化就另当别论了。如果你看到了意外的结果,你需要重新加载你的地图(dota_launch_custom_game ADDON_NAME MAP_NAME
) 来确保UI完全刷新。
Panorama的Debugger
Panorama-Debugger 这是一个非常好用的工具,不仅能排错,还能让你了解现有的UI是如何组合在一起的。
注意
- 对于原型开发来说,行内格式并不是一个好的选择。
<Panel style="border: 1px solid red;" />
(记住在最后加上分号“;”! ) - 如果你一时半会找不到你要的板,不如先添加一个临时的“边框”-1px solid red; 或者具体的宽度/高度。
$.Msg( "In function foo():", some_data );
真的很好用。- 你也可以使用'dota_custom_ui_debug_panel <element_type>' 这条排错命令来强制让一种UI(比如说开局的UI和结束的UI就是两种UI)变的可见。 element_type 是一个数值,来自于DotaCustomUIType(比如说结束画面是 'dota_custom_ui_debug_panel 5')
方言
这里有关于Panaroma多语言支持的信息:方言
Valve提供的Panaroma UI
在Valve提供的模板RPG“乱战先锋”中有一些新的UI元素,它们可以被直接用到你的自定义游戏里。当然你也可以重头开始创建独特的用户界面。这些元素主要是用来解决多个队伍以及多个玩家的问题,因为传统的两个队伍5v5的用户界面已经不够用了。
更多信息请参阅:V爹的UI
附加主题
自定义载入界面
自定义载入界面不同于普通的UI设计,因为载入画面必须要在游戏前载入。
载入画面可以用一个简单的PanaromaXML文件解决,游戏会从下列位置载入XML文件:content/dota_addons/ADDON_NAME/panorama/layout/custom_game/custom_loading_screen.xml
自定义HUD元素
服务器的Lua代码里有些很简单也很强力的API可以用来在客户端上显示XML:
Function | Signature | Description |
---|---|---|
CustomUI.DynamicHud_Create | void DynamicHud_Create(int, string, string, handle)
|
为指定玩家(们)创建一个新的HUD元素。 ( int PlayerID /*-1 means everyone*/, string ElementID /* should be unique */, string LayoutFileName, table DialogVariables /* can be nil */ ) |
CustomUI.DynamicHud_Destroy | void DynamicHud_Destroy(int, string)
|
删除一个HUD元素 ( int PlayerID /*-1 means everyone*/, string ElementID ) |
CustomUI.DynamicHud_SetDialogVariables | void DynamicHud_SetDialogVariables(int, string, handle)
|
增加或改变已有的自定义HUD元素的会话变量 ( int PlayerID /*-1 means everyone*/, string ElementID, table DialogVariables ) |
CustomUI.DynamicHud_SetVisible | void DynamicHud_SetVisible(int, string, bool)
|
切换已有的HUD元素的可见性。 ( int PlayerID /*-1 means everyone*/, string ElementID, bool Visible ) |
响应鼠标
GameUI.SetMouseCallback这个API用来在游戏主代码之前注册一个函数,来响应鼠标。
示例 这一页内有一个关于这个功能的例子。
绑定按键
https://github.com/XavierCHN/EndlessDungeon/blob/master/content/ed/panorama/scripts/custom_game/key_binding.js key_binding https://www.jianshu.com/p/bdab22027ef8 按键绑定
常见错误
在你处理XML、CSS和JS代码的时候,你可能会遇到这些错误:
Relevant Area | Error | Solution |
---|---|---|
hud.xml
|
编译错误: "Found duplicate panel description" | 在<root> 元素里,只能有一个不带ID的panel元素。
|
game_info.xml
|
编译错误:"Found duplicate panel description" | 在<root> 元素里,只能有一个不带ID的panel元素。(这两条不是重复,注意XML文件)
|