Panorama-Javascript
You can help by adding links to this article from other relevant articles.
January 2024
Pnorama将Javascript作为编程语言之一以便动态地相应用户输入和游戏事件。客户端上执行的Javascript代码可以和服务器上的代码进行沟通(需要在LUA内执行)。
JS代码API
Panorama JS的API基本上是大部分Scaleform和ActionScript的API扩展。
API记录在这里:Dota 2 Workshop_Tools/Panorama/Javascript/API
工作流程
连接起代码
通过'scripts'
代码块,Panorama中的XML文件可以参考JS文件。也可以直接在'script'
内包含行内格式的JS代码(只适用于少量代码)。
<root>
<scripts>
<!--
This is a reference to a script file located here:
content/dota_addons/ADDON_NAME/scripts/custom_game/my_script_name.js
-->
<include src="file://{resources}/scripts/custom_game/my_script_name.js" />
</scripts>
<script>
// This is an inline Javascript (XML experts: Panorama automatically wraps your script block inside a CDATA section.)
$.Msg( "Hello, world!" );
</script>
<Panel>
<!-- (Panel hierarchy goes here.) -->
</Panel>
</root>
(上述代码会被自动编译到如下目录:game/dota_addons/ADDON_NAME/scripts/custom_game/my_script_name.vjs_c
。也可以用资源编译器手动编译)。
重新加载行为
当板被重新加载的时候,与其相关的JS代码也会被重新执行。重新执行的结果一般都是正常的,不过有些时候也会很奇怪。在一个复杂的UI中进行迭代的时候,最好确保你的代码在重新加载的时候不会出现错误。过期的已登记回调会被自动忽略,所以重新登记它们是不会出错的。不过,当你在动态地创建板时,最好考虑一下这些板在之前的重载时是不是已经创建过了。一点点细心的检查可以大大地加快你的迭代速度。
Panels
创建板
代码的强大功能之一,是它能够动态地创建很多板元素。什么叫动态?看下面这个例子:假设一个多队伍记分板要为每个队伍创建一个子板元素,相应地每个队伍的板又要为每个玩家创建一个子版元素,那么UI就可以“动态”地适应玩家数量和队伍数量,只需要一个XML/CSS/JS 代码来创建一个“例子”。
var parentPanel = $.GetContextPanel(); // the root panel of the current XML context
var newChildPanel = $.CreatePanel( "Panel", parentPanel, "ChildPanelID" );
newChildPanel.BLoadLayout( "file://{resources}/layout/custom_game/new_panel.xml", false, false );
从JS代码中获取CSS属性
很多CSS属性,都可以通过MyPanel.style.property
来获取。因为两种语言的语法不同,所以JS代码中的名称和CSS代码中的对应名称是不一样的(在网页设计中也是如此)。不过就算不同,它们也很好认:连字符格式的词语转变成驼峰式(或者相反)即可。比如说,CSS中的background-color
相当于JS中的 style.backgroundColor
。
$ (dollar符号)
$
global object包含了一些重要的全局常规。
类JQuery选择
在用JQuery的时候,你会发现有些板使用了$( "#PanelID" )
这样的代码。但是注意,这种用法目前有着明显的限制,即只能使用单一ID来索引板,而如果没有找到板的话,函数会返回一个null值而不是一个空选,这有可能造成意外的JS代码错误(而且剩下的代码都无法执行了)。
$( "#MyLabel" ).text = "hello";
Msg
For simple logging, use $.Msg()
- it supports all Javascript types and any number of arguments. (It will print all the arguments consecutively on a single line.)
// This will print: Hello {"who":"world"}!
$.Msg( "Hello ", { "who": "world" }, "!" );
获取内容板
$.GetContextPanel()
会返回当前正在运行的“内容板”(和其他语言内的“this”和“self”很像)。这是加载这段代码的XML文件内的“根”板元素。
<root>
<script>
$.GetContextPanel().SetHasClass( "context_panel", true ); // after this it will have both "context_panel" and "root_panel" classes
</script>
<Panel class="root_panel">
<Label text="Hi" />
</Panel>
</root>
游戏内API
游戏内事件
Javascript可以登记一些函数,在游戏事件被触发的时候响应事件。可以响应的事件包括引擎内置事件和新的Custom Game Events 。
function OnFoo( data ) { $.Msg( "foo_event: ", data ); }
var handle = GameEvents.Subscribe( "foo_event_name", OnFoo );
GameEvents.Unsubscribe( handle );
自定义网络传输表
自定义网络传输表用来从服务器向客户端传输一些持续状态。 另见: 自定义网表
Best Practices and Javascript Gotchas
"use strict"
我们的JS代码范例使用了http://www.w3schools.com/js/js_strict.asp "use strict" 功能来增加代码d安全性、稳定性和清晰性。
奇怪的匿名函数That Weird Anonymous Function Thing (IIFE)
在我们的JS代码范例中,你可能会发现很多地方都用到了https://en.wikipedia.org/wiki/Immediately-invoked_function_expression Immediately-invoked Function Expression (IIFE) 模式。 In our example Javascript, you may see use of the https://en.wikipedia.org/wiki/Immediately-invoked_function_expression Immediately-invoked Function Expression (IIFE) pattern.
(function () {
$.Msg( "The panel associated with this javascript just got loaded or reloaded!" );
})();
三等号
如果你对C-系列语言很熟悉的话,你可能会惊奇地发现JS代码里有两种“等于”操作符:“==”和“===”。
更多信息请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness here 或自行于网络搜索。
变量捕获
If you're coming to Javascript from another language, you should know that nested functions capture their enclosing scope by reference, which can lead to unexpected results:
var closures_bad = [];
var closures_good = [];
function create()
{
for (var i = 0; i < 5; i++)
{
closures_bad[i] = function()
{
$.Msg( "i = ", i );
};
closures_good[i] = (function( j ){return function()
{
$.Msg( "i = ", j );
}}(i));
}
}
function run()
{
// prints "5 5 5 5 5" because loop variable 'i' is captured by reference above
for (var k = 0; k < 5; k++)
{
closures_bad[k]();
}
// prints "0 1 2 3 4" because each value of loop 'i' is captured by a different function parameter 'j'
for (var k = 0; k < 5; k++)
{
closures_good[k]();
}
}
create();
run();
Misc
Parnoma中的JS代码由Google V8 Javascript引擎处理执行。