Panorama-Javascript

From Valve Developer Community
Jump to: navigation, search
English (en)中文 (zh)Translate (Translate)

Pnorama将Javascript作为编程语言之一以便动态地相应用户输入和游戏事件。客户端上执行的Javascript代码可以和服务器上的代码进行沟通(需要在LUA内执行)。

JS代码API

Panorama(en)JS的API基本上是大部分Scaleform和ActionScript的API扩展。

API记录在这里:Dota 2 Workshop_Tools/Panorama/Javascript/API(en)

工作流程

连接起代码

通过'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(en)

    function OnFoo( data ) { $.Msg( "foo_event: ", data ); }
    var handle = GameEvents.Subscribe( "foo_event_name", OnFoo );
    GameEvents.Unsubscribe( handle );

自定义网络传输表

自定义网络传输表用来从服务器向客户端传输一些持续状态。 另见: 自定义网表(en)

Best Practices and Javascript Gotchas

"use strict"

我们的JS代码范例使用了http://www.w3schools.com/js/js_strict.asp "use strict"(en)功能来增加代码d安全性、稳定性和清晰性。

奇怪的匿名函数That Weird Anonymous Function Thing (IIFE)

在我们的JS代码范例中,你可能会发现很多地方都用到了https://en.wikipedia.org/wiki/Immediately-invoked_function_expression Immediately-invoked Function Expression (IIFE)(en)模式。 In our example Javascript, you may see use of the https://en.wikipedia.org/wiki/Immediately-invoked_function_expression Immediately-invoked Function Expression (IIFE)(en) 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(en)或自行于网络搜索。

变量捕获

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引擎处理执行。