Bladeren bron

Chinese Translation (#73)

CocosGames 5 jaren geleden
bovenliggende
commit
f14db8ecb0
100 gewijzigde bestanden met toevoegingen van 7067 en 0 verwijderingen
  1. 6 0
      docs/languages.json
  2. 9 0
      docs/zh/manuals/2dgraphics.md
  3. 8 0
      docs/zh/manuals/3dgraphics.md
  4. 120 0
      docs/zh/manuals/adapting-graphics-to-screen-size.md
  5. 261 0
      docs/zh/manuals/addressing.md
  6. 143 0
      docs/zh/manuals/android.md
  7. 509 0
      docs/zh/manuals/animation.md
  8. 120 0
      docs/zh/manuals/application-lifecycle.md
  9. BIN
      docs/zh/manuals/assets/Vector_Math_Library-Overview.pdf
  10. 98 0
      docs/zh/manuals/atlas.md
  11. 153 0
      docs/zh/manuals/bob.md
  12. 110 0
      docs/zh/manuals/building-blocks.md
  13. 62 0
      docs/zh/manuals/bundling.md
  14. 143 0
      docs/zh/manuals/camera.md
  15. 150 0
      docs/zh/manuals/collection-factory.md
  16. 179 0
      docs/zh/manuals/collection-proxy.md
  17. 92 0
      docs/zh/manuals/components.md
  18. 179 0
      docs/zh/manuals/debugging.md
  19. 24 0
      docs/zh/manuals/design.md
  20. 87 0
      docs/zh/manuals/dev-app.md
  21. 204 0
      docs/zh/manuals/editor-scripts.md
  22. 140 0
      docs/zh/manuals/editor.md
  23. 124 0
      docs/zh/manuals/extensions-best-practices.md
  24. 155 0
      docs/zh/manuals/extensions-build-variants.md
  25. 82 0
      docs/zh/manuals/extensions-debugging-android.md
  26. 136 0
      docs/zh/manuals/extensions-debugging-ios.md
  27. 148 0
      docs/zh/manuals/extensions-debugging.md
  28. 31 0
      docs/zh/manuals/extensions-defold-sdk.md
  29. 61 0
      docs/zh/manuals/extensions-details.md
  30. 270 0
      docs/zh/manuals/extensions-manifest-merge-tool.md
  31. 54 0
      docs/zh/manuals/extensions-script-api.md
  32. 238 0
      docs/zh/manuals/extensions.md
  33. 212 0
      docs/zh/manuals/facebook.md
  34. 217 0
      docs/zh/manuals/factory.md
  35. 355 0
      docs/zh/manuals/flash.md
  36. 164 0
      docs/zh/manuals/font.md
  37. 69 0
      docs/zh/manuals/getting-help.md
  38. 180 0
      docs/zh/manuals/glossary.md
  39. 191 0
      docs/zh/manuals/graphics.md
  40. 48 0
      docs/zh/manuals/gui-box.md
  41. 73 0
      docs/zh/manuals/gui-clipping.md
  42. 102 0
      docs/zh/manuals/gui-layouts.md
  43. 34 0
      docs/zh/manuals/gui-particlefx.md
  44. 56 0
      docs/zh/manuals/gui-pie.md
  45. 149 0
      docs/zh/manuals/gui-script.md
  46. 68 0
      docs/zh/manuals/gui-spine.md
  47. 62 0
      docs/zh/manuals/gui-template.md
  48. 58 0
      docs/zh/manuals/gui-text.md
  49. 351 0
      docs/zh/manuals/gui.md
  50. 122 0
      docs/zh/manuals/hot-reload.md
  51. 214 0
      docs/zh/manuals/html5.md
  52. 44 0
      docs/zh/manuals/iac.md
  53. 202 0
      docs/zh/manuals/iap.md
  54. BIN
      docs/zh/manuals/images/3dgraphics/add_animation.png
  55. BIN
      docs/zh/manuals/images/3dgraphics/animationset.png
  56. BIN
      docs/zh/manuals/images/addressing/absolute.png
  57. BIN
      docs/zh/manuals/images/addressing/bean.png
  58. BIN
      docs/zh/manuals/images/addressing/bean_buddy.png
  59. BIN
      docs/zh/manuals/images/addressing/bean_editor.png
  60. BIN
      docs/zh/manuals/images/addressing/bean_shield.png
  61. BIN
      docs/zh/manuals/images/addressing/bean_shield_editor.png
  62. BIN
      docs/zh/manuals/images/addressing/collection_team.png
  63. BIN
      docs/zh/manuals/images/addressing/manager_editor.png
  64. BIN
      docs/zh/manuals/images/addressing/name_collision.png
  65. BIN
      docs/zh/manuals/images/addressing/relative_same.png
  66. BIN
      docs/zh/manuals/images/addressing/team_editor.png
  67. BIN
      docs/zh/manuals/images/addressing/teams_editor.png
  68. BIN
      docs/zh/manuals/images/addressing/teams_manager.png
  69. BIN
      docs/zh/manuals/images/android/apk_file.png
  70. BIN
      docs/zh/manuals/images/android/sign_bundle.png
  71. BIN
      docs/zh/manuals/images/android/sign_bundle2.png
  72. BIN
      docs/zh/manuals/images/android/usb_debugging.png
  73. BIN
      docs/zh/manuals/images/animation/animsheet.png
  74. BIN
      docs/zh/manuals/images/animation/blender_animation.png
  75. BIN
      docs/zh/manuals/images/animation/[email protected]
  76. BIN
      docs/zh/manuals/images/animation/bounce.gif
  77. BIN
      docs/zh/manuals/images/animation/custom_curve.png
  78. BIN
      docs/zh/manuals/images/animation/frog_runloop.gif
  79. BIN
      docs/zh/manuals/images/animation/model_hierarchy.png
  80. BIN
      docs/zh/manuals/images/animation/property_animation.png
  81. BIN
      docs/zh/manuals/images/animation/[email protected]
  82. BIN
      docs/zh/manuals/images/animation/runloop.gif
  83. BIN
      docs/zh/manuals/images/animation/spine_animation.png
  84. BIN
      docs/zh/manuals/images/animation/spine_bones.png
  85. BIN
      docs/zh/manuals/images/animation/[email protected]
  86. BIN
      docs/zh/manuals/images/animation/spine_events.png
  87. BIN
      docs/zh/manuals/images/animation/spine_ingame.png
  88. BIN
      docs/zh/manuals/images/animation/[email protected]
  89. BIN
      docs/zh/manuals/images/animation/square_curve.png
  90. BIN
      docs/zh/manuals/images/animation/suzanne.gif
  91. BIN
      docs/zh/manuals/images/animation/wiggle.gif
  92. BIN
      docs/zh/manuals/images/application_lifecycle/application_lifecycle_final.png
  93. BIN
      docs/zh/manuals/images/application_lifecycle/application_lifecycle_init.png
  94. BIN
      docs/zh/manuals/images/application_lifecycle/application_lifecycle_overview.png
  95. BIN
      docs/zh/manuals/images/application_lifecycle/application_lifecycle_update.png
  96. BIN
      docs/zh/manuals/images/atlas/add.png
  97. BIN
      docs/zh/manuals/images/atlas/[email protected]
  98. BIN
      docs/zh/manuals/images/atlas/add_animation.png
  99. BIN
      docs/zh/manuals/images/atlas/[email protected]
  100. BIN
      docs/zh/manuals/images/atlas/animation_group.png

+ 6 - 0
docs/languages.json

@@ -11,6 +11,12 @@
             "name": "한국어 (Korean)",
             "translation": "Translation by Kiman Kim",
             "active": false
+        },
+        "zh":
+        {
+            "name": "中文 (Chinese)",
+            "translation": "Translation by cocosgames.com",
+            "active": false
         }
     }
 }

+ 9 - 0
docs/zh/manuals/2dgraphics.md

@@ -0,0 +1,9 @@
+---
+title: Defold 2D 图像教程
+brief: 本教程已过时
+---
+
+# 2D Graphics
+
+详见 [图像教程](/manuals/graphics).
+

+ 8 - 0
docs/zh/manuals/3dgraphics.md

@@ -0,0 +1,8 @@
+---
+title: Defold 3D 图像教程
+brief: 本教程已过时
+---
+
+# 3D graphics
+
+详见 [图像教程](/manuals/graphics).

+ 120 - 0
docs/zh/manuals/adapting-graphics-to-screen-size.md

@@ -0,0 +1,120 @@
+---
+title: 适配游戏图像到不同的屏幕尺寸
+brief: 本教程解释了如何适配游戏和图像到不同的屏幕尺寸.
+---
+
+# 介绍
+
+当适配游戏和图像到不同的屏幕尺寸时, 要考虑一些事情:
+
+* 这是个低分辨率的像素对齐的复古游戏还是高分辨率的现代游戏?
+* 不同屏幕全屏模式下玩的时候游戏应该如何应对?
+  * 玩家应该在高分辨率屏幕中看到更多的游戏内容还是图像自适应缩放来显示同样多的内容?
+* 要是屏幕的长宽比跟在game.project中设置的不一样游戏该怎么办?
+  * 玩家看到更多的游戏内容? 还是显示黑边? 还是重新调整GUI大小?
+* 你需要什么样的菜单和屏幕gui组件, 他们怎么适应各种屏幕大小与方向?
+  * 当屏幕方向改变, 菜单和屏幕gui组件应该改变布局还是不管什么方向都不动?
+
+本教程将探讨这些事情然后提供建议.
+
+
+## 内容渲染的方法如何改变
+
+Defold 渲染脚本提供整个渲染流程的控制. 渲染脚本控制着显示什么, 怎么显示以及显示的顺序. 默认渲染脚本总是显示 *game.project* 文件里定义的长, 宽的一块区域, 不管窗口缩放和屏幕大小匹配. 如果窗口大小, 比例改变, 将会造成内容的拉伸. 有些游戏可能能接受, 但通常当屏幕分辨率或比例改变, 应该适当让游戏内容显示的多些或少些, 或者至少在不改变窗口比例的条件下缩放游戏内容. 要改变内容拉伸的现象详情请见 [渲染教程](https://www.defold.com/manuals/render/#默认视口映射).
+
+
+## 复古/8比特图像
+
+复古/8比特图像游戏模拟了老式游戏机或者低分辨率低调色盘的电脑游戏. 比如任天堂红白机 (NES) 就是分辨率 256x240 的, Commodore 64 是 320x200 的,  Gameboy 是 160x144 的, 这些屏幕分辨率赶不上当前屏幕的零头. 为了在当今高分辨率屏幕上模拟这种风格的游戏需要把屏幕缩放好几倍. 一个简单的方法是先显示低分辨率图像然后再在渲染时放大. 这在Defold中使用渲染脚本就能做到, [固定映射](/manuals/render/#固定映射) 可以设置一个合适的放大值.
+
+比如使用这个瓷砖图源和角色 ([source](https://ansimuz.itch.io/grotto-escape-game-art-pack)) 来模拟一个8位 320x200 分辨率游戏:
+
+![](images/screen_size/retro-player.png)
+
+![](images/screen_size/retro-tiles.png)
+
+在 *game.project* 文件中设置分辨率 320x200  然后编译, 游戏看起来是这样:
+
+![](images/screen_size/retro-original_320x200.png)
+
+对于现代分辨率屏幕来说窗口也太小了! 把窗口拖动放大到 1280x800 还舒服些:
+
+![](images/screen_size/retro-original_1280x800.png)
+
+现在窗口感觉好多了, 我们还需调整图像, 因为太小了难以看清游戏内容. 我们用渲染脚本来设置一个固定放大的映射:
+
+```Lua
+msg.post("@render:", "use_fixed_projection", { zoom = 4 })
+```
+
+结果会变成这样:
+
+![](images/screen_size/retro-zoomed_1280x800.png)
+
+好多了. 窗口和图像都可以, 但是仔细看会发现一个明显的问题:
+
+![](images/screen_size/retro-zoomed_linear.png)
+
+图像模糊了! 因为GPU渲染纹理时放大了图形采样. 默认 *game.project* 文件里 Graphics 部分设置是 *linear*:
+
+![](images/screen_size/retro-settings_linear.png)
+
+现在改成 *nearest* 试试:
+
+![](images/screen_size/retro-settings_nearest.png)
+
+![](images/screen_size/retro-zoomed_nearest.png)
+
+现在我们的游戏图像是像素对齐的了. 还可以想想其他办法, 比如在*game.project*的sprite里关闭 sub-pixels:
+
+![](images/screen_size/retro-subpixels.png)
+
+当Subpixels选项关闭后所有 sprites 就不会渲染在半个像素上而是永远像素对齐.
+
+## 高分辨率图像
+
+处理高分辨率图像我们需要使用复古游戏不同的方法. 做位图时就要做成高分辨率屏幕下 1:1 大小的图.
+
+同样也需要更改渲染脚本. 这次我们需要按原始比例显示图像:
+
+```Lua
+msg.post("@render:", "use_fixed_fit_projection")
+```
+
+这样就确保了游戏像 *game.project* 设置的那样始终显示等比的内容, 如果宽高比与设置不符, 游戏边缘可能会显示出额外的内容.
+
+在 *game.project* 文件中可以设置设计时屏幕宽和高.
+
+### 高分辨率视网膜屏幕
+
+想要支持高分辨率视网膜屏幕可以在 *game.project* 文件里打开这个选项:
+
+![](images/screen_size/highdpi-enabled.png)
+
+选中这个选项就打开了高分辨率后台缓冲. 游戏会以设置好的宽高双倍比例渲染, 但是游戏分辨率不变. 也就是说游戏内容是1倍大小的就照常显示. 但是如果内容是双倍大小再在游戏里缩小为1倍的话就是高清渲染了.
+
+
+## 创建可适配性 GUI
+
+系统的 GUI 组件由各种元素组成, 或称作 [节点](/manuals/gui/#节点类型), 虽然看起来很简单却能创造出从按钮到复杂的菜单和弹框等各种界面. GUI 可以设计成自动适配屏幕尺寸和方向的. 比如让节点保持在屏幕顶部, 底部或边上而不改变自身的大小. 也可以设置成对于不同屏幕尺寸和方向自动调整节点关系大小与形态.
+
+### 节点属性
+
+gui中的节点包含锚点, 横轴纵轴以及一个调整模式.
+
+* 锚点定义了节点的中心.
+* 锚点模式控制着当屏幕边界或者其父节点边界在适配物理屏幕时拉伸的话, 节点自身在水平和垂直方向位置如何修改.
+* 调整模式控制着当屏幕边界或者其父节点边界在适配物理屏幕时, 节点自身该怎样做.
+
+详情请见 [GUI教程](/manuals/gui/#节点属性).
+
+### 布局
+
+Defold支持GUI在手机上自动适配屏幕方向. 此功能让你能把GUI设计成适配各种各样屏幕比例和方向的. 也可以用来创建特定设备上的界面布局. 详情请见 [GUI 布局教程](/manuals/gui-layouts/)
+
+
+## 测试不同的屏幕尺寸
+
+Debug 菜单有用来模拟特定设备分辨率或者自定义分辨率的选项. 当应用运行时你可以通过选择 <kbd>Debug->Simulate Resolution</kbd> 然后从列表中选择一个模拟设备. 运行中的应用会自动缩放来测试游戏运行在不同分辨率和屏幕比例的设备上的样子.
+
+![](images/screen_size/simulate-resolution.png)

+ 261 - 0
docs/zh/manuals/addressing.md

@@ -0,0 +1,261 @@
+---
+title: Defold 定位
+brief: 本教程解释了 Defold 如何实现地址定位功能.
+---
+
+# 定位
+
+为了让代码能够控制每个对象和组件的移动, 缩放, 播放动画或者添加删除各种视听元素, Defold 提供了地址定位机制.
+
+## 标志
+
+Defold 使用地址 (称为 URL, 暂且不表) 来引用游戏对象和组件. 地址里包含各种标志. 下面列举了 Defold 使用地址的例子. 本教程将详述地址的用法:
+
+```lua
+local id = factory.create("#enemy_factory")
+label.set_text("my_gameobject#my_label", "Hello World!")
+
+local pos = go.get_position("my_gameobject")
+go.set_position(pos, "/level/stuff/other_gameobject")
+
+msg.post("#", "hello_there")
+local id = go.get_id(".")
+```
+
+先看一个简单的例子. 比如你有一个含有Sprite的游戏对象. 然后附加一个脚本来控制这个对象. 在编辑器里的设置就差不多这样:
+
+![bean in editor](images/addressing/bean_editor.png)
+
+你想开始先关闭这个sprite, 留待以后显示. 我们来简单创建一个脚本 "controller.script":
+
+```lua
+function init(self)
+    msg.post("#body", "disable") -- <1>
+end
+```
+1. 不知道 '#' 是什么意思没关系, 一会儿就谈到.
+
+就像设计的那样, 游戏一开始脚本组件 *定位* 到了sprite组件 "body" 对其地址发出了一个  "disable" 的 *消息* . 这个消息的结果就是把sprite隐藏了. 也就是说, 整个流程是这样的:
+
+![bean](images/addressing/bean.png)
+
+id可以随意设置. 当前我们对游戏对象设置了一个id "bean", sprite组件叫做 "body", 控制这个对象的脚本组件叫做 "controller".
+
+::: 注意
+如果你不手动命名, 编辑器会自动设置一个命名. 每当新建一个游戏对象或组件, 系统会将唯一 *Id* 赋值给它.
+
+- 游戏对象就是go后面跟一个数字 ("go2", "go3" 以此类推).
+- 组件就是组件名后面跟一个数字 ("sprite", "sprite2" 以此类推).
+
+自动命名虽然能用, 但是我们鼓励你自己将命名设计的更好, 更有意义.
+:::
+
+现在, 再增加一个sprite来给豆子先生添加一个盾牌:
+
+![bean](images/addressing/bean_shield_editor.png)
+
+每个游戏对象的组件id必须唯一. 再叫 "body" 的话脚本就不知道该给谁发送 "disable" 信息了. 所以我们选择了 (更具意义的) id "shield". 这样不管是 "body" 还是 "shield" 我们都能自由控制了.
+
+![bean](images/addressing/bean_shield.png)
+
+::: 注意
+如果你非要设置成一样的id, 系统会提示错误阻止你这样做:
+
+![bean](images/addressing/name_collision.png)
+:::
+
+现在再多加一些游戏对象进来试试. 假设你要让两个 "豆子先生" 组个队. 一个叫 "bean" 另一个叫 "buddy". 然后, 当 "bean" 等待一段时间后, 它就让 "buddy" 开始跳舞. 也就是从 "bean" 的脚本组件 "controller" 发送一个自定义消息 "dance" 到 "buddy" 的 "controller" :
+
+![bean](images/addressing/bean_buddy.png)
+
+::: 注意
+这两个脚本组件都叫 "controller", 但是由于唯一性是对每个游戏对象来说的, 所以这样做是可以的.
+:::
+
+这次的消息是发给本游戏对象 ("bean") 之外的地方, 代码需要知道哪个 "controller" 来接收这个消息. 既需要对象id也需要组件id. 完整的地址是 `"buddy#controller"` 它包含两个方面内容.
+
+- 首先需要指定目标对象的id ("buddy"),
+- 然后是对象/组件分隔符 ("#"),
+- 组后是组件的id ("controller").
+
+回过头来看上个例子我们没有指定对象的id, 系统默认对象就是脚本所在的 *当前游戏对象*.
+
+比如, `"#body"` 就是在当前游戏对象里找 "body" 组件. 这就很方便因为脚本可以在 *任何* 游戏对象上运行, 只要它有 "body" 组件.
+
+## 集合
+
+集合可以用来创建一组游戏对象, 或者嵌套游戏对象然后在需要的时候使用它们. 当你在编辑器里做实例化操作时集合文件就可作为模板 (有的叫 "prototypes" 有的叫 "prefabs").
+
+比如你想建立许多 bean/buddy 二人组. 最好把它们做成 *集合文件* (命名为 "team.collection"). 编译并保存好. 然后在引导启动集合里就可以实例化并命名 (比如 "team_1"):
+
+![bean](images/addressing/team_editor.png)
+
+这种结构下, "bean" 游戏对象依旧可以使用地址 `"buddy#controller"` 来引用"buddy"的"controller"组件.
+
+![bean](images/addressing/collection_team.png)
+
+如果你再实例化一个 "team.collection" (命名 "team_2"), 那么 "team_2" 的脚本也能顺利运行. "team_2"中的"bean" 对象同样使用地址 `"buddy#controller"` 来引用"buddy"的"controller"组件.
+
+![bean](images/addressing/teams_editor.png)
+
+## 相对地址
+
+地址 `"buddy#controller"` 在两组实例下都能运行因为它是一个 *相对* 地址. 集合 "team_1" 和 "team_2" 都有自己的上下文, 或者叫做 "命名空间". Defold 认为集合内这样的相对地址与命名是合理的:
+
+![relative id](images/addressing/relative_same.png)
+
+- "team_1"的命名空间里 "bean" 和 "buddy" 都是唯一id.
+- 同样在"team_2"的命名空间里 "bean" 和 "buddy" 也都是唯一id.
+
+实际上相对地址在后台已经把上下文考虑在内. 这同样很方便因为你可以用同样的代码创建很多个集合的实例.
+
+简化符
+: Defold 支持如下相对地址简化符:
+
+  `.`
+  : 代表本游戏对象.
+
+  `#`
+  : 代表本组件.
+
+  举例:
+
+  ```lua
+   -- Let this game object acquire input focus
+   msg.post(".", "acquire_input_focus")
+  ```
+
+  ```lua
+   -- Post "reset" to the current script
+   msg.post("#", "reset")
+  ```
+
+## 游戏对象路径
+
+为了正确理解命名机制, 我们来看看游戏编译运行时发生了什么:
+
+1. 编辑器读取引导启动集合 ("main.collection") 与其所有内容 (游戏对象和其他集合).
+2. 对于每个静态的游戏对象, 编译器分配唯一id. 游戏对象 "路径" 从引导启动集合根节点起, 到嵌套关系里找到这个对象为止. 每个 '/' 符号代表嵌套的每一层.
+
+如上示例, 游戏里就有四个游戏对象路径:
+
+- /team_1/bean
+- /team_1/buddy
+- /team_2/bean
+- /team_2/buddy
+
+::: 注意
+游戏里的各种id存储为哈希值. 包括集合里的相对路径也哈希成绝对路径.
+:::
+
+运行时, 不存在集合的概念. 编译前, 对象是不属于集合的. 也无法对集合本身施加操作. 有必要的话, 需要用代码维护集合里的对象. 每个对象id都是静态的, 并且在它们的生命周期中都保持不变. 所以保存一个对象的id后总可以使用此id引用它.
+
+## 绝对地址
+
+定位的时候完全可以使用绝对地址. 多数情况下相对地址有助于代码重用, 但是有些情况下还得使用绝对地址定位.
+
+比如, 你需要一个 AI 管理器管理每个豆子先生. 豆子先生要向管理器报告自身的激活状态, 管理器根据它们的状态决定它们的排序. 这就需要创建一个带脚本的管理器对象然后把它放在引导启动集合的根目录下.
+
+![manager object](images/addressing/manager_editor.png)
+
+Each bean is then responsible for sending status messages to the manager: "contact" if it spots an enemy or "ouch!" if it is hit and takes damage. For this to work, the bean controller scrips use absolute addressing to send messages to the component "controller" in "manager".
+
+Any address that starts with a '/' will be resolved from the root of the game world. This corresponds to the root of the *bootstrap collection* that is loaded on game start.
+
+The absolute address of the manager script is `"/manager#controller"` and this absolute address will resolve to the right component no matter where it is used.
+
+![teams and manager](images/addressing/teams_manager.png)
+
+![absolute addressing](images/addressing/absolute.png)
+
+## Hashed identifiers
+
+The engine stores all identifiers as hashed values. All functions that take as argument a component or a game object accepts a string, hash or an URL object. We have seen how to use strings for addressing above.
+
+When you get the identifier of a game object, the engine will always return an absolute path identifier that is hashed:
+
+```lua
+local my_id = go.get_id()
+print(my_id) --> hash: [/path/to/the/object]
+
+local spawned_id = factory.create("#some_factory")
+print(spawned_id) --> hash: [/instance42]
+```
+
+You can use such an identifier in place of a string id, or construct one yourself. Note though that a hashed id corresponds to the path to the object, i.e. an absolute address:
+
+::: sidenote
+The reason relative addresses must be given as strings is because the engine will compute a new hash id based on the hash state of the current naming context (collection) with the given string added to the hash.
+:::
+
+```lua
+local spawned_id = factory.create("#some_factory")
+local pos = vmath.vector3(100, 100, 0)
+go.set_position(pos, spawned_id)
+
+local other_id = hash("/path/to/the/object")
+go.set_position(pos, other_id)
+
+-- This will not work! Relative addresses must be given as strings.
+local relative_id = hash("my_object")
+go.set_position(pos, relative_id)
+```
+
+## URLs
+
+To complete the picture, let's look at the full format of Defold addresses: the URL.
+
+An URL is an object, usually written as specially formatted strings. A generic URL consists of three parts:
+
+`[socket:][path][#fragment]`
+
+socket
+: Identifies the game world of the target. This is important when working with [Collection Proxies](/manuals/collection-proxy) and is then used to identify the _dynamically loaded collection_.
+
+path
+: This part of the URL contains the full id of the target game object.
+
+fragment
+: The identity of the target component within the specified game object.
+
+As we have seen above, you can leave out some, or most of this information in the majority of cases. You almost never need to specify the socket, and you often, but not always, have to specify the path. In those cases when you do need to address things in another game world then you need to specify the socket part of the URL. For instance, the full URL string for the "controller" script in the "manager" game object above is:
+
+`"main:/manager#controller"`
+
+and the buddy controller in team_2 is:
+
+`"main:/team_2/buddy#controller"`
+
+We can send messages to them:
+
+```lua
+-- Send "hello" to the manager script and team buddy bean
+msg.post("main:/manager#controller", "hello_manager")
+msg.post("main:/team_2/buddy#controller", "hello_buddy")
+```
+
+## Constructing URL objects
+
+URL objects can also be constructed programmatically in Lua code:
+
+```lua
+-- Construct URL object from a string:
+local my_url = msg.url("main:/manager#controller")
+print(my_url) --> url: [main:/manager#controller]
+print(my_url.socket) --> 786443 (internal numeric value)
+print(my_url.path) --> hash: [/manager]
+print(my_url.fragment) --> hash: [controller]
+
+-- Construct URL from parameters:
+local my_url = msg.url("main", "/manager", "controller")
+print(my_url) --> url: [main:/manager#controller]
+
+-- Build from empty URL object:
+local my_url = msg.url()
+my_url.socket = "main" -- specify by valid name
+my_url.path = hash("/manager") -- specify as string or hash
+my_url.fragment = "controller" -- specify as string or hash
+
+-- Post to target specified by URL
+msg.post(my_url, "hello_manager!")
+```

+ 143 - 0
docs/zh/manuals/android.md

@@ -0,0 +1,143 @@
+---
+title: Defold 的 Android 平台开发
+brief: 本教程介绍了如何在 Defold 中进行 Android 设备应用的开发
+---
+
+# Android 开发
+
+Android 设备允许自由允许你开发的应用. 可以很容易地编译好游戏拷贝到 Android 设备上. 本手册介绍了对于 Android 游戏的打包步骤. 推荐开发时, 从 [开发应用](/manuals/dev-app) 上运行游戏因为可以通过无线连接设备进行代码和内容的热重载.
+
+## Android 和 Google Play 签名
+
+Android 需要安装的应用都进行数字签名. 不像 iOS 证书都需要由 Apple 签发, Android 允许开发者自己创建证书和密匙来对应用签名.
+
+创建证书和密匙的过程看似复杂但是开发阶段 Defold 对此有自动化功能.你可以在打包 Android应用时指定证书和密匙. 不指定的话, Defold 会自动创建证书和密匙打包 *.apk* (Android Application Package) 文件.
+
+注意如果要把应用上传至 Google Play, 就需要用自己的证书和密匙签名应用. 因为后续应用更新时, _新版本 *.apk* 文件签名需要与老版本保持一致_. 如果不一致, Google Play 会拒绝 *.apk* 更新上架, 除非作为全新应用发布.
+
+详情请见 [Google Play 开发者中心](https://play.google.com/apps/publish/).
+
+## 创建证书和密匙
+
+基于 *.pem*-格式创建证书, 基于 *.pk8*-格式创建密匙. 二者的创建都可以使用 `openssl` 工具:
+
+```sh
+$ openssl genrsa -out key.pem 2048
+$ openssl req -new -key key.pem -out request.pem
+$ openssl x509 -req -days 9999 -in request.pem -signkey key.pem -out certificate.pem
+$ openssl pkcs8 -topk8 -outform DER -in key.pem -inform PEM -out key.pk8 -nocrypt
+```
+
+这样就生成了 *certificate.pem* 和 *key.pk8* 文件可以用来签名应用包.
+
+::: 注意
+注意保存好证书和密匙文件. 一点丢失就 _不能_ 上传 *.apk* 更新文件到 Google Play 了.
+:::
+
+## 创建 Android 应用包
+
+使用编辑器可以很容易地进行应用打包.打包前可以在  "game.project" [项目配置文件](/manuals/project-settings/#android) 里为应用设置图标, 版本号之类的. 菜单选择 <kbd>Project ▸ Bundle... ▸ Android Application...</kbd> 来进行打包.
+
+如果希望编辑器自动生成调试用证书, 把 *Certificate* 和 *Private key* 置空即可:
+
+![Signing Android bundle](images/android/sign_bundle.png)
+
+如果希望使用自己的证书和密匙, 配置 *.pem* 和 *.pk8* 文件即可:
+
+![Signing Android bundle](images/android/sign_bundle2.png)
+
+点击 <kbd>Create Bundle</kbd> 会提示选择打包文件存放位置.
+
+![Android Application Package file](images/android/apk_file.png)
+
+### 安装 Android 应用包
+
+编辑器生成 Android 应用包 *.apk* 文件. 应用包可以通过 `adb` 工具 (见下文), 或者通过 Google Play 的 [Google Play 开发者控制台](https://play.google.com/apps/publish/) 安装到设备上.
+
+```
+$ adb install Defold\ examples.apk
+4826 KB/s (18774344 bytes in 3.798s)
+  pkg: /data/local/tmp/my_app.apk
+Success
+```
+
+## 权限
+
+Defold 引擎需要一些权限来运行各种功能. 权限在 `AndroidManifest.xml` 文件中定义, 并在 "game.project" [项目配置文件](/manuals/project-settings/#android) 中配置. 关于 Android 权限详见 [官方文档](https://developer.android.com/guide/topics/permissions/overview). 默认配置需要如下权限:
+
+### android.permission.INTERNET and android.permission.ACCESS_NETWORK_STATE (Protection level: normal)
+允许应用打开网络连接访问互联网. 需要上网时需要此权限. 见 ([Android 官方文档-网络](https://developer.android.com/reference/android/Manifest.permission#INTERNET)) 和 ([Android 官方文档-网络状态](https://developer.android.com/reference/android/Manifest.permission#ACCESS_NETWORK_STATE)).
+
+### android.permission.WRITE_EXTERNAL_STORAGE (Protection level: dangerous)
+允许应用写入外部存储器. 从 API level 19 开始, 读写 Context.getExternalFilesDir(String) 和 Context.getExternalCacheDir() 返回的应用目录不需要此权限. 需要 (使用 io.* 或 sys.save/load) 读写 [sys.get_save_file()](/ref/sys/#sys.get_save_file:application_id-file_name) 之外的目录文件以及 Android manifest 里设置 `android:minSdkVersion` 小于 19 时需要此权限. ([[Android 官方文档-外存写入](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE)).
+
+### android.permission.WAKE_LOCK (Protection level: normal)
+允许应用阻止屏幕息屏和调光. 接收通知保持亮屏时需要此权限. ([[Android 官方文档-亮屏锁定](https://developer.android.com/reference/android/Manifest.permission#WAKE_LOCK))
+
+
+## Android Debug Bridge
+
+`adb` 命令行工具是一个多功能易使用的用来与 Android 设备进行交互的工具. 可以在 Mac, Linux 或者 Windows 上下载 Android SDK Platform-Tools 来安装 `adb`.
+
+下载 Android SDK Platform-Tools 地址: https://developer.android.com/studio/releases/platform-tools. *adb* 工具就在 */platform-tools/* 里. 或者, 也通过各个平台的软件包管理器下载安装.
+
+Ubuntu Linux:
+
+```
+$ sudo apt-get install android-tools-adb
+```
+
+Fedora 18/19:
+
+```
+$ sudo yum install android-tools
+```
+
+Mac OS X (Homebrew)
+
+```
+$ brew cask install android-platform-tools
+```
+
+通过如下代码让 `adb` 通过电脑 USB 与 Android 设备进行连接:
+
+```
+$ adb devices
+List of devices attached
+31002535c90ef000    device
+```
+
+如果连接不上, 确保在 Android 设备上开启了 *USB debugging*. 在设备 *设置* 里找 *开发者选项* (或称 *开发选项*).
+
+![Enable USB debugging](images/android/usb_debugging.png)
+
+## 应用包调试
+
+使用调试版引擎打包的应用 (即打包时选择 "Debug" 变体) 会把控制台信息全部发送至 Android 系统日志上. 使用 `adb` 工具的 `logcat` 命令访问日志. 使用标签 (`-s [标签名]`) 可以对日志信息进行过滤:
+
+```
+$ adb logcat -s "defold"
+--------- beginning of /dev/log/system
+--------- beginning of /dev/log/main
+I/defold  ( 6210): INFO:DLIB: SSDP started (ssdp://192.168.0.97:58089, http://0.0.0.0:38637)
+I/defold  ( 6210): INFO:ENGINE: Defold Engine 1.2.50 (8d1b912)
+I/defold  ( 6210): INFO:ENGINE: Loading data from:
+I/defold  ( 6210): INFO:ENGINE: Initialised sound device 'default'
+I/defold  ( 6210):
+D/defold  ( 6210): DEBUG:SCRIPT: Hello there, log!
+...
+```
+
+## 常见问题
+
+安装时报 "Failure [INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES]" 错误
+: Android 发现了你使用不同的证书安装应用. 编译调试包时, 使用的是临时证书. 安装前先卸载旧应用:
+
+  ```
+  $ adb uninstall com.defold.examples
+  Success
+  $ adb install Defold\ examples.apk
+  4826 KB/s (18774344 bytes in 3.798s)
+          pkg: /data/local/tmp/Defold examples.apk
+  Success
+  ```

+ 509 - 0
docs/zh/manuals/animation.md

@@ -0,0 +1,509 @@
+---
+title: Defold 动画教程
+brief: 本教程介绍了 Defold 的动画支持.
+---
+
+# 动画
+
+Defold 内置支持多种动画:
+
+* 逐帧动画
+* Spine 动画
+* 3D 蒙皮动画
+* 属性动画
+
+## 逐帧动画
+
+逐帧动画就是由一些列静态图片轮流显示生成的动画. 这种技术类似于老式翻页动画 (详见 http://en.wikipedia.org/wiki/Traditional_animation). 由于每帧的独立性使得这种技术很自由. 但是每帧一张图片会很耗费内存. 相似图片越多动画过渡越平滑同时也带来了巨大的工作量. Defold 逐帧动画使用来自于 [图集](/manuals/atlas), 或者 [瓷砖图源](/manuals/tilesource) 里水平排列的图片.
+
+  ![Animation sheet](images/animation/animsheet.png){.inline}
+  ![Run loop](images/animation/runloop.gif){.inline}
+
+## Spine 动画
+
+Spine 动画提供 2D _骨骼动画_ 支持 (详见 http://en.wikipedia.org/wiki/Skeletal_animation). 这是一种类似于剪裁动画的技术. 剪裁动画把对象分成各部分 (比如身体, 眼睛, 嘴巴之类的) 在每帧上独立运动. Spine 动画可以建立隐藏的, 树形关联的虚拟 _骨骼_. 骨架, 或称 _绑定_, 来为骨骼上添加的图片单独做动画. Defold 支持以 [Spine JSON 格式](http://esotericsoftware.com/spine-json-format) 输出的动画. Skeletal 动画都很平滑因为骨骼动画关键帧之间可以自动进行插值.
+
+  关于导入 Spine 数据作为 Spine 模型和动画, 详见 [Spine 教程](/manuals/spine).
+
+  ![Spine animation](images/animation/spine_animation.png){.inline}
+  ![Run loop](images/animation/frog_runloop.gif){.inline}
+
+## 3D 蒙皮动画
+
+3D 模型的骨骼动画和 Spine 动画类似但是是针对于 3D 空间的. 3D 模型不是像剪裁动画那样先分成各个部分然后用骨骼连起来做动画. 而是使用骨骼精细控制模型上各个三角形如何移动.
+
+  关于如何导入 3D 模型动画, 详情请见 [模型教程](/manuals/model).
+
+  ![Blender animation](images/animation/blender_animation.png){.inline srcset="images/animation/[email protected] 2x"}
+  ![Wiggle loop](images/animation/suzanne.gif){.inline}
+
+## 属性动画
+
+数值类的属性 (numbers, vector3, vector4 和 quaterions) 以及着色器常量都可以由内置的属性动画系统制作属性动画, 即使用 `go.animate()` 函数. 引擎会在属性值之间进行 "补间" 依照指定的播放和缓动模式进行播放. 你也可以自定义缓动函数.
+
+  ![Property animation](images/animation/property_animation.png){.inline srcset="images/animation/[email protected] 2x"}
+  ![Bounce loop](images/animation/bounce.gif){.inline}
+
+## 播放逐帧动画
+
+Sprite 和 GUI 方块节点可以用来播放逐帧动画而且可以在运行时进行控制.
+
+Sprites
+: 通过调用 [`sprite.play_flipbook()`](/ref/sprite/?q=play_flipbook#sprite.play_flipbook:url-id-[complete_function]-[play_properties]) 函数播放逐帧动画. 示例见下文.
+
+GUI 方块节点
+: 通过调用 [`gui.play_flipbook()`](/ref/gui/?q=play_flipbook#gui.play_flipbook:node-animation-[complete_function]-[play_properties]) 函数播放逐帧动画. 示例见下文.
+
+::: 注意
+ping-pong 播放模式把动画从第一帧播放到最后一帧再反向播放到 **第二帧** , 而不是第一帧. 这样便于连续播放的衔接.
+:::
+
+### Sprite 示例
+
+假设你的游戏有个 "dodge" 功能, 按下指定的键主角就进行闪避动作. 为此你建立了四组动画:
+
+"idle"
+: 主角待机的循环动画.
+
+"dodge_idle"
+: 主角闪避动作的循环动画.
+
+"start_dodge"
+: 主角从站立姿态到闪避动作的一次性动画.
+
+"stop_dodge"
+: 主角从闪避动作到站立姿态的一次性动画.
+
+逻辑代码如下:
+
+```lua
+
+local function play_idle_animation(self)
+    if self.dodge then
+        sprite.play_flipbook("#sprite", hash("dodge_idle"))
+    else
+        sprite.play_flipbook("#sprite", hash("idle"))
+    end
+end
+
+function on_input(self, action_id, action)
+    -- "dodge" 就是输入动作
+    if action_id == hash("dodge") then
+        if action.pressed then
+            sprite.play_flipbook("#sprite", hash("start_dodge"), play_idle_animation)
+            -- 记录闪避动作已开始
+            self.dodge = true
+        elseif action.released then
+            sprite.play_flipbook("#sprite", hash("stop_dodge"), play_idle_animation)
+            -- 记录闪避动作完成
+            self.dodge = false
+        end
+    end
+end
+```
+
+### GUI 方块节点示例
+
+给节点选择图片或者动画时, 实际上也同时指定了图片来源 (图集或者瓷砖图源) 以及默认动画. 节点图源是静态的, 但是当前播放的动画是可以在运行时指定的. 静态图片被视作单帧动画, 所以运行时切换图片相当于播放另一个动画:
+
+```lua
+local function flipbook_done(self)
+    msg.post("#", "jump_completed")
+end
+
+function init(self)
+    local character_node = gui.get_node("character")
+    -- 新动画/图片播放时
+    -- 节点图源要存在默认动画.
+    gui.play_flipbook(character_node, "jump_left", flipbook_done)
+end
+```
+
+动画播放完成时可以提供一个回调函数. 如果动画是以 `ONCE_*` 模式播放, 播放完成后会调用这个回调函数.
+
+## Spine model 动画
+
+在 Spine 模型上播放动画, 只需调用 [`spine.play_anim()`](/ref/spine#spine.play_anim) 函数:
+
+```lua
+local function anim_done(self)
+    -- 动画播放完成, 做其他事情...
+end
+
+function init(self)
+    -- 在 "spinemodel" 组件上播放 "walk" 动画同时与上一个动画
+    -- 在前 0.1 内混合, 然后进行回调.
+    local anim_props = { blend_duration = 0.1 }
+    spine.play_anim("#spinemodel", "run", go.PLAYBACK_LOOP_FORWARD, anim_props, anim_done)
+end
+```
+
+![Spine model in game](images/animation/spine_ingame.png){srcset="images/animation/[email protected] 2x"}
+
+如果动画是以 `go.PLAYBACK_ONCE_*` 模式播放, 然后在 `spine.play_anim()` 里指定回调函数, 则动画播放完成后会调用回调函数. 关于回调函数详见下文.
+
+### Spine model - 播放头
+
+除了 `spine.play_anim()` 还有更高级的方法, *Spine Model* 组件暴露了一个 "cursor" 属性可以通过 `go.animate()` 进行控制:
+
+```lua
+-- 设置 spine model 动画但是不播放.
+spine.play_anim("#spinemodel", "run_right", go.PLAYBACK_NONE)
+
+-- 设置播放头为 0
+go.set("#spinemodel", "cursor", 0)
+
+-- 基于 in-out quad 缓动慢慢对播放头进行从 0 到 1 的 pingpong 补间.
+go.animate("#spinemodel", "cursor", go.PLAYBACK_LOOP_PINGPONG, 1, go.EASING_INOUTQUAD, 6)
+```
+
+::: 注意
+补间和设置播放头时, 时间轴事件不会被触发.
+:::
+
+### Spine model - 骨骼层级
+
+Spine 骨架的各个骨骼实例在游戏对象内展示出来. 在 Spine model 组件的 *Outline* 视图内, 可以看到完整的嵌套关系. 在此层级嵌套关系中你可以看到骨骼的名称和其所在的位置.
+
+![Spine model hierarchy](images/animation/spine_bones.png){srcset="images/animation/[email protected] 2x"}
+
+通过骨骼名称, 就可以在运行时得到骨骼实例. 函数 [`spine.get_go()`](/ref/spine#spine.get_go) 返回指定骨骼的 id, 然后就可以用来进行设置父级之类的操作:
+
+```lua
+-- 把手枪绑定到英雄手上
+local hand = spine.get_go("heroine#spinemodel", "front_hand")
+msg.post("pistol", "set_parent", { parent_id = hand })
+```
+
+### Spine model - 时间轴事件
+
+Spine 动画可以基于精确的时间触发事件. 对于需要做同步行为的功能非常有帮助, 例如播放走路声音, 场景粒子效果, 在骨骼层级上进行绑定和解绑或者实现你需要的其他功能.
+
+在 Spine 软件里可以使用时间轴设置事件:
+
+![Spine events](images/animation/spine_events.png)
+
+各种事件由事件 id 表示 (上例中是 "bump") 而且时间轴上的事件可以包含一些数据:
+
+Integer
+: 整数值.
+
+Float
+: 浮点数值.
+
+String
+: 字符串值.
+
+动画播放遇到事件时, `spine_event` 消息会被发回到调用 `spine.play()` 函数的脚本上. 消息数据参数就是事件附带的数据, 连同其他一些有用的数据:
+
+`t`
+: 自动画播放第一帧开始经过的时间.
+
+`animation_id`
+: 动画名, 哈希值.
+
+`string`
+: 事件附带字符串值, 哈希值.
+
+`float`
+: 事件附带浮点数值.
+
+`integer`
+: 事件附带整数值.
+
+`event_id`
+: 事件 id, 哈希值.
+
+`blend_weight`
+: 此时动画混合情况. 0 表示动画还没有被混合, 1 当前动画混合 100%.
+
+```lua
+-- Spine 动画包含与动画同步的音效.
+-- 作为消息传到这里.
+function on_message(self, message_id, message, sender)
+  if message_id == hash("spine_event") and message.event_id == hash("play_sound") then
+    -- 播放动画音效. 事件数据包括声音组件和声音增益.
+    local url = msg.url("sounds")
+    url.fragment = message.string
+    sound.play(url, { gain = message.float })
+  end
+end
+```
+
+## 3D Model 动画
+
+通过调用 [`model.play_anim()`](/ref/model#model.play_anim) 函数播放模型动画:
+
+```lua
+function init(self)
+    -- 在 #model 上来回播放 "wiggle" 动画
+    model.play_anim("#model", "wiggle", go.PLAYBACK_LOOP_PINGPONG)
+end
+```
+
+::: 注意
+Defold 目前只支持烘焙动画. 动画每个骨骼每一帧都要有矩阵数据, 而不是单独的位置, 旋转和缩放数据.
+
+动画是线性插值的. 如果需要曲线插值动画要在输出时烘焙.
+
+不支持 Collada 中的动画剪辑. 想要一个模型多个动画, 就要分别导出为 *.dae* 文件然后在 Defold 里组成 *.animationset* 文件.
+:::
+
+### 3D Model - 骨骼层级
+
+模型骨骼作为游戏对象展示出来.
+
+通过骨骼名称, 就可以在运行时得到骨骼实例. 函数 [`model.get_go()`](/ref/model#model.get_go) 返回指定骨骼的 id.
+
+```lua
+-- 得到 wiggler 模型的中央骨骼
+local bone_go = model.get_go("#wiggler", "Bone_002")
+
+-- 然后可以任意操作该游戏对象...
+```
+
+### 3D Model - 播放头
+
+像 Spine 模型一样, 3D 模型也可以通过控制 `cursor` 属性播放动画:
+
+```lua
+-- 设置 #model 上的动画但不播放
+model.play_anim("#model", "wiggle", go.PLAYBACK_NONE)
+-- 把播放头设置为动画起始位置
+go.set("#model", "cursor", 0)
+-- 基于 in-out quad 缓动对播放头进行从 0 到 1 的 pingpong 补间.
+go.animate("#model", "cursor", go.PLAYBACK_LOOP_PINGPONG, 1, go.EASING_INOUTQUAD, 3)
+```
+
+## 属性动画
+
+制作游戏对象或者组件的属性动画, 可以使用函数 `go.animate()`. 对于 GUI 节点属性, 可以使用函数 `gui.animate()`.
+
+```lua
+-- 设置 y 轴位置为 200
+go.set(".", "position.y", 200)
+-- 制作动画
+go.animate(".", "position.y", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_OUTBOUNCE, 2)
+```
+
+停止某个属性的所有动画, 调用 `go.cancel_animations()`, 对于 GUI 节点, 调用 `gui.cancel_animation()`:
+
+```lua
+-- 停止当前游戏对象欧拉 z 轴旋转动画
+go.cancel_animation(".", "euler.z")
+```
+
+如果取消组合属性的动画, 例如 `position`, 其所有子属性 (`position.x`, `position.y` 和 `position.z`) 动画也会一同取消.
+
+[属性教程](/manuals/properties) 涵盖游戏对象, 组件和 GUI 节点的所有属性.
+
+## GUI 节点属性动画
+
+几乎所有 GUI 节点属性都可以制作动画. 比如说, 把一个节点的 `color` 设置成透明看不见然后制作属性动画到全白使其可见 (也就是没有染色).
+
+```lua
+local node = gui.get_node("button")
+local color = gui.get_color(node)
+-- 节点白色动画
+gui.animate(node, gui.PROP_COLOR, vmath.vector4(1, 1, 1, 1), gui.EASING_INOUTQUAD, 0.5)
+-- 边框红色动画
+gui.animate(node, "outline.x", 1, gui.EASING_INOUTQUAD, 0.5)
+-- 位置延 x 轴移动 100 像素动画
+gui.animate(node, hash("position.x"), 100, gui.EASING_INOUTQUAD, 0.5)
+```
+
+## 播放模式
+
+动画可以单次播放也可以循环播放. 取决于播放模式:
+
+* go.PLAYBACK_NONE
+* go.PLAYBACK_ONCE_FORWARD
+* go.PLAYBACK_ONCE_BACKWARD
+* go.PLAYBACK_ONCE_PINGPONG
+* go.PLAYBACK_LOOP_FORWARD
+* go.PLAYBACK_LOOP_BACKWARD
+* go.PLAYBACK_LOOP_PINGPONG
+
+pingpong 模式先正向播放, 再反向播放. GUI 属性动画也有这些播放模式:
+
+* gui.PLAYBACK_NONE
+* gui.PLAYBACK_ONCE_FORWARD
+* gui.PLAYBACK_ONCE_BACKWARD
+* gui.PLAYBACK_ONCE_PINGPONG
+* gui.PLAYBACK_LOOP_FORWARD
+* gui.PLAYBACK_LOOP_BACKWARD
+* gui.PLAYBACK_LOOP_PINGPONG
+
+## 缓动
+
+缓动决定动画基于时间的变化. 下面列出了内置的缓动函数.
+
+以下可用于 `go.animate()` 函数:
+
+|---|---|
+| go.EASING_LINEAR | |
+| go.EASING_INBACK | go.EASING_OUTBACK |
+| go.EASING_INOUTBACK | go.EASING_OUTINBACK |
+| go.EASING_INBOUNCE | go.EASING_OUTBOUNCE |
+| go.EASING_INOUTBOUNCE | go.EASING_OUTINBOUNCE |
+| go.EASING_INELASTIC | go.EASING_OUTELASTIC |
+| go.EASING_INOUTELASTIC | go.EASING_OUTINELASTIC |
+| go.EASING_INSINE | go.EASING_OUTSINE |
+| go.EASING_INOUTSINE | go.EASING_OUTINSINE |
+| go.EASING_INEXPO | go.EASING_OUTEXPO |
+| go.EASING_INOUTEXPO | go.EASING_OUTINEXPO |
+| go.EASING_INCIRC | go.EASING_OUTCIRC |
+| go.EASING_INOUTCIRC | go.EASING_OUTINCIRC |
+| go.EASING_INQUAD | go.EASING_OUTQUAD |
+| go.EASING_INOUTQUAD | go.EASING_OUTINQUAD |
+| go.EASING_INCUBIC | go.EASING_OUTCUBIC |
+| go.EASING_INOUTCUBIC | go.EASING_OUTINCUBIC |
+| go.EASING_INQUART | go.EASING_OUTQUART |
+| go.EASING_INOUTQUART | go.EASING_OUTINQUART |
+| go.EASING_INQUINT | go.EASING_OUTQUINT |
+| go.EASING_INOUTQUINT | go.EASING_OUTINQUINT |
+
+以下可用于 `gui.animate()` 函数:
+
+|---|---|
+| gui.EASING_LINEAR | |
+| gui.EASING_INBACK | gui.EASING_OUTBACK |
+| gui.EASING_INOUTBACK | gui.EASING_OUTINBACK |
+| gui.EASING_INBOUNCE | gui.EASING_OUTBOUNCE |
+| gui.EASING_INOUTBOUNCE | gui.EASING_OUTINBOUNCE |
+| gui.EASING_INELASTIC | gui.EASING_OUTELASTIC |
+| gui.EASING_INOUTELASTIC | gui.EASING_OUTINELASTIC |
+| gui.EASING_INSINE | gui.EASING_OUTSINE |
+| gui.EASING_INOUTSINE | gui.EASING_OUTINSINE |
+| gui.EASING_INEXPO | gui.EASING_OUTEXPO |
+| gui.EASING_INOUTEXPO | gui.EASING_OUTINEXPO |
+| gui.EASING_INCIRC | gui.EASING_OUTCIRC |
+| gui.EASING_INOUTCIRC | gui.EASING_OUTINCIRC |
+| gui.EASING_INQUAD | gui.EASING_OUTQUAD |
+| gui.EASING_INOUTQUAD | gui.EASING_OUTINQUAD |
+| gui.EASING_INCUBIC | gui.EASING_OUTCUBIC |
+| gui.EASING_INOUTCUBIC | gui.EASING_OUTINCUBIC |
+| gui.EASING_INQUART | gui.EASING_OUTQUART |
+| gui.EASING_INOUTQUART | gui.EASING_OUTINQUART |
+| gui.EASING_INQUINT | gui.EASING_OUTQUINT |
+| gui.EASING_INOUTQUINT | gui.EASING_OUTINQUINT |
+
+<div id="game-container" class="game-container">
+<canvas id="game-canvas" tabindex="1" width="640" height="512"></canvas>
+<script src="//storage.googleapis.com/defold-doc/assets/easier/dmloader.js"></script>
+<script>
+  var extra_params = {
+   archive_location_filter: function( path ) { return ('//storage.googleapis.com/defold-doc/assets/easier/archive' + path + ''); },
+   splash_image: '//storage.googleapis.com/defold-doc/assets/easier/preview.jpg',
+   custom_heap_size: 268435456,
+   disable_context_menu: true,
+   game_start: function() {}
+  };
+  Module['onRuntimeInitialized'] = function() { Module.runApp("game-canvas", extra_params); };
+  Module['locateFile'] = function(path, scriptDirectory) {
+   if (path == "dmengine.wasm" || path == "dmengine_release.wasm" || path == "dmengine_headless.wasm") { path = "easier.wasm"; }
+   return scriptDirectory + path;
+  };
+  function load_engine() {
+   var engineJS = document.createElement('script');
+   engineJS.type = 'text/javascript';
+   if (Module['isWASMSupported']) {
+   engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_wasm.js';
+   } else {
+   engineJS.src = '//storage.googleapis.com/defold-doc/assets/easier/easier_asmjs.js';
+   }
+   document.head.appendChild(engineJS);
+  }
+  load_engine();
+</script>
+</div>
+
+![Linear interpolation](images/properties/easing_linear.png){.inline}
+![In back](images/properties/easing_inback.png){.inline}
+![Out back](images/properties/easing_outback.png){.inline}
+![In-out back](images/properties/easing_inoutback.png){.inline}
+![Out-in back](images/properties/easing_outinback.png){.inline}
+![In bounce](images/properties/easing_inbounce.png){.inline}
+![Out bounce](images/properties/easing_outbounce.png){.inline}
+![In-out bounce](images/properties/easing_inoutbounce.png){.inline}
+![Out-in bounce](images/properties/easing_outinbounce.png){.inline}
+![In elastic](images/properties/easing_inelastic.png){.inline}
+![Out elastic](images/properties/easing_outelastic.png){.inline}
+![In-out elastic](images/properties/easing_inoutelastic.png){.inline}
+![Out-in elastic](images/properties/easing_outinelastic.png){.inline}
+![In sine](images/properties/easing_insine.png){.inline}
+![Out sine](images/properties/easing_outsine.png){.inline}
+![In-out sine](images/properties/easing_inoutsine.png){.inline}
+![Out-in sine](images/properties/easing_outinsine.png){.inline}
+![In exponential](images/properties/easing_inexpo.png){.inline}
+![Out exponential](images/properties/easing_outexpo.png){.inline}
+![In-out exponential](images/properties/easing_inoutexpo.png){.inline}
+![Out-in exponential](images/properties/easing_outinexpo.png){.inline}
+![In circlic](images/properties/easing_incirc.png){.inline}
+![Out circlic](images/properties/easing_outcirc.png){.inline}
+![In-out circlic](images/properties/easing_inoutcirc.png){.inline}
+![Out-in circlic](images/properties/easing_outincirc.png){.inline}
+![In quadratic](images/properties/easing_inquad.png){.inline}
+![Out quadratic](images/properties/easing_outquad.png){.inline}
+![In-out quadratic](images/properties/easing_inoutquad.png){.inline}
+![Out-in quadratic](images/properties/easing_outinquad.png){.inline}
+![In cubic](images/properties/easing_incubic.png){.inline}
+![Out cubic](images/properties/easing_outcubic.png){.inline}
+![In-out cubic](images/properties/easing_inoutcubic.png){.inline}
+![Out-in cubic](images/properties/easing_outincubic.png){.inline}
+![In quartic](images/properties/easing_inquart.png){.inline}
+![Out quartic](images/properties/easing_outquart.png){.inline}
+![In-out quartic](images/properties/easing_inoutquart.png){.inline}
+![Out-in quartic](images/properties/easing_outinquart.png){.inline}
+![In quintic](images/properties/easing_inquint.png){.inline}
+![Out quintic](images/properties/easing_outquint.png){.inline}
+![In-out quintic](images/properties/easing_inoutquint.png){.inline}
+![Out-in quintic](images/properties/easing_outinquint.png){.inline}
+
+## 自定义缓动
+
+可以使用 `vector` 和其中的一系列值代替预置缓动函数. 矢量值从 (`0`) 过渡到 (`1`). 引擎会从矢量中取样并自动线性插值生成缓动曲线.
+
+示例如下:
+
+```lua
+local values = { 0, 0.4, 0.2, 0.2, 0.5. 1 }
+local my_easing = vmath.vector(values)
+```
+
+生成的缓动曲线如下:
+
+![Custom curve](images/animation/custom_curve.png)
+
+下面的例子是让游戏对象的 y 轴位置依照自定义曲线从当前位置到 200 来回跳跃:
+
+```lua
+local values = { 0, 0, 0, 0, 0, 0, 0, 0,
+                 1, 1, 1, 1, 1, 1, 1, 1,
+                 0, 0, 0, 0, 0, 0, 0, 0,
+                 1, 1, 1, 1, 1, 1, 1, 1,
+                 0, 0, 0, 0, 0, 0, 0, 0,
+                 1, 1, 1, 1, 1, 1, 1, 1,
+                 0, 0, 0, 0, 0, 0, 0, 0,
+                 1, 1, 1, 1, 1, 1, 1, 1 }
+local square_easing = vmath.vector(values)
+go.animate("go", "position.y", go.PLAYBACK_LOOP_PINGPONG, 200, square_easing, 2.0)
+```
+
+![Square curve](images/animation/square_curve.png)
+
+## 播放完成回调函数
+
+所有动画函数 (`go.animate()`, `gui.animate()`, `gui.play_flipbook()`, `gui.play_spine_anim()`, `sprite.play_flipbook()`, `spine.play_anim()` 和 `model.play_anim()`) 可以在最后一个参数上传入Lua回调函数. 当动画播放完成时会调用这个函数. 对于循环动画, 和使用 `go.cancel_animations()` 手动取消播放的动画, 不会调用回调函数. 动画播放完成的回调函数里可以发送消息或者继续播放其他动画.
+
+不同动画函数的回调函数参数有些许区别. 具体请参照动画函数的 API 文档.
+
+```lua
+local function done_bouncing(self, url, property)
+    -- 动画播放完成. 进行各种处理...
+end
+
+function init(self)
+    go.animate(".", "position.y", go.PLAYBACK_ONCE_FORWARD, 100, go.EASING_OUTBOUNCE, 2, 0, done_bouncing)
+end
+```

+ 120 - 0
docs/zh/manuals/application-lifecycle.md

@@ -0,0 +1,120 @@
+---
+title: Defold 应用生命周期教程
+brief: 本教程详述了 Defold 游戏的生命周期.
+---
+
+# 应用生命周期
+
+Defold 应用或者游戏的生命周期相当简单. 引擎切换运行三种状态: 初始化, 更新循环 (游戏主要耗时状态) 以及析构.
+
+![Lifecycle overview](images/application_lifecycle/application_lifecycle_overview.png)
+
+通常对于 Defold 的内部运作机制稍作了解就足够了. 然而, 有时了解 Defold 内部的运行顺序还是有必要的. 本教程介绍了 Defold 应用从始至终是按什么顺序运行的.
+
+引擎一开始进行初始化操作. 载入启动集合然后在所有组件上调用 [`init()`](/ref/go#init) 函数 (包括脚本组件和GUI脚本). 这个函数用于进行用户自定义初始化操作.
+
+接下来就是应用主要耗时环节更新循环. 每一帧, 每个游戏对象及其组件都会进行更新操作. 脚本和GUI脚本的 [`update()`](/ref/go#update) 函数被调用. 与此同时消息机制开始运作, 播放声音和渲染图像的程序开始运行.
+
+应用最后会结束运行. 应用退出之前引擎会退出更新循环进入析构阶段. 准备删除所有被加载的游戏对象. 所有对象的 [`final()`](/ref/go#final) 函数被调用, 用于进行用户自定义析构操作. 然后删除所有游戏对象以及启动集合.
+
+## 初始化
+
+下图包含了初始化的分解步骤. 其中 "dispatch messages" 阶段 (在 "spawn dynamic objects" 上方) 单独在右侧图表进行详细分解.
+
+![Lifecycle overview](images/application_lifecycle/application_lifecycle_init.png)
+
+其实初始化阶段启动集合被加载之前引擎还做了许多别的工作. 内存分析, 接口, 图像, HID (输入设备), 声音, 物理等等的初始化. 应用配置文件 ("game.project") 也在此时被加载.
+
+最开始的用户可控的操作, 是在引擎初始化结束后, 对于渲染脚本 `init()` 函数的调用.
+
+然后启动集合被加载和初始化. 对其中所有游戏对象及其子对象设置位移 (位置, 旋转和缩放). 所有组件的 `init()` 函数被调用.
+
+::: 注意
+每个 `init()` 函数调用顺序不确定. 调用顺序和集合里所处位置无关.
+:::
+
+因为 `init()` 代码里可以有消息发布, 工厂创建对象, 删除对象等等操作, 引擎接下来会进入 "post-update" 阶段. 此时消息被发布出去, 工厂实际创建对象, 需要删除的对象进行删除操作. 注意 post-update 阶段包含的 "dispatch messages" 序列不仅发送消息队列还会处理发送给集合代理的消息. 代理子队列 (开启关闭, 载入和标记卸载) 等步骤在此时进行处理.
+
+也就是说在 `init()` 里进行 [集合工厂](/manuals/collection-proxy) 加载操作是完全可行的, 集合初始化, 从代理卸载集合---这些都能在第一个 `update()` 被调用之前进行, 也就是在引擎退出初始化进入更新循环之前进行:
+
+```lua
+function init(self)
+    print("init()")
+    msg.post("#collectionproxy", "load")
+end
+
+function update(self, dt)
+    -- 运行到这里时代理集合已经被卸载了.
+    print("update()")
+end
+
+function on_message(self, message_id, message, sender)
+    if message_id == hash("proxy_loaded") then
+        print("proxy_loaded. Init, enable and then unload.")
+        msg.post("#collectionproxy", "init")
+        msg.post("#collectionproxy", "enable")
+        msg.post("#collectionproxy", "unload")
+        -- 代理集合 init() 和 final() 函数
+        -- 会在 update() 调用之前完成
+    end
+end
+```
+
+## 更新循环
+
+每帧都会循环更新长长的序列. 下图展示了更新循环的详细步骤. "Dispatch messages" 阶段还是单独在右侧独立详细展示:
+
+![Update loop](images/application_lifecycle/application_lifecycle_update.png)
+
+## 输入
+
+从可用设备中读取输入数据, 通过映射 [输入绑定表](/manuals/input) 把输入派发出去. 获得输入焦点的游戏对象里每个组件的 `on_input()` 函数都会获得输入数据. 不管是脚本组件还是GUI脚本 `on_input()` 函数都会被调用---只要它们被定义了而且获得了输入焦点.
+
+获得输入焦点并且包含集合代理组件的游戏对象会把输入发送到代理集合内部去. 这个过程在被开启的代理间递归进行下去.
+
+## 更新
+
+启动集合每个游戏对象组件都会被遍历到. 只要它们定义了 `update()` 函数, 就会在更新时被调用. 对于集合代理组件, 其内部 "update" 过程会递归进行下去.
+
+::: 注意
+每个 `update()` 函数调用顺序不确定. 调用顺序和集合里所处位置无关.
+:::
+
+下个阶段所有消息被发送出去. 接收者的 `on_message()` 代码也可能包含消息发送, 所以消息会持续发送直至全部发送完成. 但是, 有一个发送消息最大轮数的限制. 详见 [消息传递教程](/manuals/message-passing).
+
+对于碰撞对象组件, 物理消息 (collisions, triggers, ray_cast 响应等) 会被发送给所有含有 `on_message()` 函数的组件.
+
+然后进行位移操作, 对每个游戏对象及其子对象应用位置移动, 旋转和缩放.
+
+## 渲染更新
+
+渲染更新阶段发送消息到 `@render` 接口 (摄像机组件 `set_view_projection` 消息, `set_clear_color` 消息等). 渲染脚本的 `update()` 函数被调用.
+
+## 后更新
+
+更新过程结束后, 一个后更新过程开始启动. 此时被标记为卸载的集合代理会从内存中卸载 (在 "dispatch messages" 阶段). 被标记为删除的游戏对象调用 `final()` 函数. 通常 `final()` 还包含消息发送代码所以接下来又是一轮 "dispatch messages" 阶段.
+
+然后工厂实际创建对象. 最后, 被标记为删除的游戏对象被删除.
+
+更新循环的最后一步是向 `@system` 发送消息 (`exit`, `reboot` 消息, 开关分析器, 开始结束视频捕获等等). 图像开始渲染. 与此同时, 视频捕获完成, 可视分析器渲染完成 (见 [调试教程](/manuals/debugging).)
+
+## 帧率和集合时间步
+
+每秒帧数 (即每秒更新循环运行次数) 可以在项目配置里设置, 或者通过发送 `set_update_frequency` 消息到 `@system` 接口手动设置. 而且, 可以通过发送 `set_time_step` 消息给代理来为集合单独设置 _时间步_. 修改集合时间步不影响帧率. 它影响的是物理时间步与发送到 `update()` 函数中的 `dt` 值. 注意修改时间步不影响 `update()` 调用的频率---永远是每帧调用一次.
+
+(See the [Collection proxy manual](/manuals/collection-proxy) and [`set_time_step`](/ref/collection-proxy#set-time-step) for details)
+
+## 析构
+
+应用退出时, 完成最后一次更新循环, 卸载所有集合代理: 析构和删除集合代理里的所有游戏对象.
+
+然后引擎进入析构阶段处理启动集合里的内容:
+
+![Finalization](images/application_lifecycle/application_lifecycle_final.png)
+
+组件的 `final()` 函数被调用. 后跟一轮消息传递. 最后, 所有游戏对象被删除, 启动集合被卸载.
+
+引擎还会继续做后续子系统处理: 删除项目配置, 关闭内存分析, 等等.
+
+至此应用正式退出.
+

BIN
docs/zh/manuals/assets/Vector_Math_Library-Overview.pdf


+ 98 - 0
docs/zh/manuals/atlas.md

@@ -0,0 +1,98 @@
+---
+title: 图集教程
+brief: 本教程介绍了 Defold 中图集资源是如何工作的.
+---
+
+# Atlas
+
+sprites 通常使用单个的小图片, 但是处于性能考虑, 最好把小图片合并成大图, 称为图集. 相比桌面设备和游戏机, 手机这种性能不太高的地方, 合并小图的做法就十分必要了.
+
+在 Defold 中, 图集资源由一系列单个图片组成, 这些小图最终会自动合并成大图.
+
+## 创建图集
+
+在 *Assets* 浏览器右键菜单中选择 <kbd>New... ▸ Atlas</kbd>. 命名图集文件. 图集编辑器会自动打开.
+*Properties* 面板会显示出图集的可编辑属性 (详见下文).
+
+先要向图集里填入图片或者动画才能在 Sprites 和 ParticleFX 之类的可视组件里使用.
+
+确保你需要的图片都存在项目里 (把图片文件拖放到 *Assets* 浏览器的适当位置).
+
+加入单张图片
+: 在 *Outline* 面板上 <kbd>右键点击</kbd> 图集根节点.
+  
+  从弹出菜单中选择 <kbd>Add Images</kbd> 来加入单张图片.
+
+  此时会弹出选择图片的菜单. 注意此菜单支持文件名过滤和多选功能.
+
+  ![Creating an atlas, adding images](images/atlas/add.png){srcset="images/atlas/[email protected] 2x"}
+
+  被加入的图片会显示在 *Outline* 列表里, 而且编辑器里也会显示出图片合成的图集. 可以按 <kbd>F键</kbd> (菜单栏 <kbd>View ▸ Frame Selection</kbd>) 来居中显示.
+
+  ![Images added](images/atlas/single_images.png){srcset="images/atlas/[email protected] 2x"}
+
+加入逐帧动画
+: 在 *Outline* 面板上 <kbd>右键点击</kbd> 图集根节点.
+
+  从弹出菜单中选择 <kbd>Add Animation Group</kbd> 来加入逐帧动画.
+
+  一个默认命名为 ("New Animation") 的新建空动画组就被加入图集了.
+
+  <kbd>右键点击</kbd> 动画组, 选择 <kbd>Add Images</kbd> 加入来图片.
+
+  同样会弹出选择图片菜单, 选择的图片都会被加入到动画组.
+  
+  ![Creating an atlas, adding images](images/atlas/add_animation.png){srcset="images/atlas/[email protected] 2x"}
+
+  选中动画组后按 <kbd>空格键</kbd> 即可预览动画. 动画 *Properties* 可以自由修改 (见下文).
+
+  ![Animation group](images/atlas/animation_group.png){srcset="images/atlas/[email protected] 2x"}
+
+选中图片后按 <kbd>Alt + Up/down</kbd> 可以更改顺序. 也可以拷贝粘贴任意图片 (通过 <kbd>Edit</kbd> 菜单栏, 右键菜单或者快捷键).
+
+## 图集属性
+
+图集资源有一系列属性. 在 *Outline* 视图中选中图集后属性出现在 *Properties* 面板中.
+
+Size
+: 图集空间占用大小. 宽高取2的整数幂. 注意如果开启了纹理压缩, 某些格式需要纹理为正方形. 非正方形纹理将加入空白以建立正方形. 详情请见 [Texture profiles 教程](/manuals/texture-profiles/).
+
+Margin
+: 每两个图片之间的间隙.
+
+Inner Padding
+: 每个图片四周加入的空白.
+
+Extrude Borders
+: 每个图片四周的边缘挤出. 片元着色器采样图片边缘的时候, 相邻图片 (同个图集) 边缘可能会被采集到. 挤出边缘就可以解决这个问题.
+
+这里用四个 64x64 正方形图片做图集不同属性设置的演示. 注意这里图集一旦超过 128x128 就会跳到 256x256, 从而造成了资源浪费.
+
+![Atlas properties](images/atlas/atlas_properties.png){srcset="images/atlas/[email protected] 2x"}
+
+## 动画属性
+
+动画组除了组成动画的图片, 还提供了一些属性:
+
+Id
+: 动画名称.
+
+Fps
+: 动画播放速率, 以帧每秒 (FPS) 表示.
+
+Flip horizontal
+: 动画水平翻转.
+
+Flip vertical
+: 动画垂直翻转.
+
+Playback
+: 设置动画播放方式:
+
+  - `None` 不播放, 只显示第一张图片.
+  - `Once Forward` 从第一张图片到最后一张图片播放一次.
+  - `Once Backward` 从最后一张图片到第一张图片播放一次.
+  - `Once Ping Pong` 从第一张图片播放到最后一张图片再反向播放一次.
+  - `Loop Forward` 从第一张图片到最后一张图片循环播放.
+  - `Loop Backward` 从最后一张图片到第一张图片循环播放.
+  - `Loop Ping Pong` 从第一张图片播放到最后一张图片再反向循环播放.

+ 153 - 0
docs/zh/manuals/bob.md

@@ -0,0 +1,153 @@
+---
+title: Defold 项目编译教程
+brief: Bob 是用于 Defold 项目的命令行编译工具. 本教程详述如何使用这个工具.
+---
+
+# 编译器 Bob
+
+Bob 是一个用于Defold项目编辑器之外的命令行编译工具.
+
+Bob 用来编译操作 (对应编辑器里的 <kbd>Project ▸ Build And Launch</kbd>), 来创建数据档或者创建可独立发布的应用 (对应编辑器里的 <kbd>Project ▸ Bundle ▸ ...</kbd> 选项)
+
+Bob 集合了编译所需的一切, 作为Java包 _JAR_ 发布. 你可以在其发布地址 http://d.defold.com 里下载到 *bob.jar* . 先选择版本, 再下载 *bob/bob.jar*. 要运行 Bob 工具, 你需要 [安装OpenJDK 11](https://openjdk.java.net/projects/jdk/11/).
+
+## 用法
+
+Bob 运行于命令行界面 `java` (再Windows上是 `java.exe`) 后跟bob的jar包作为参数:
+
+```text
+$ java -jar bob.jar --help
+usage: bob [options] [commands]
+ -a,--archive                        编译数据包
+ -ar,--architectures <arg>           逗号分割发布架构
+                                     
+    --binary-output <arg>            指定可执行文件存放地址
+                                     默认地址是
+                                     "<build-output>/<platform>/"
+ -bo,--bundle-output <arg>           打包输出目录
+ -br,--build-report <arg>            指定编译报告的存放存放地址
+                                     报告为JSON格式
+ -brhtml,--build-report-html <arg>   指定编译报告的存放存放地址
+                                     报告为HTML格式
+    --build-server <arg>             编译服务器 (当使用原生扩展
+                                     时使用)
+ -ce,--certificate <arg>             指定证书 (Android)
+ -d,--debug                          使用dmengine的debug版本(当
+                                     编译时). 弃用, 使用--variant
+                                     代替
+    --defoldsdk <arg>                指定defold sdk (sha1)
+                                     使用版本
+ -e,--email <arg>                    用户电邮
+ -h,--help                           帮助文档
+ -i,--input <arg>                    指定源目录, 默认是当前
+                                     目录
+    --identity <arg>                 指定签名 (iOS)
+ -k,--keep-unused                    指定未使用资源仍然打包
+                                     输出
+ -l,--liveupdate <arg>               要在发布后使用热更新功能
+                                     参数填yes
+ -mp,--mobileprovisioning <arg>      指定mobileprovisioning profile (iOS)
+ -o,--output <arg>                   输出目录. 默认是
+                                     "build/default"
+ -p,--platform <arg>                 发布平台 (打包时)
+ -pk,--private-key <arg>             指定私匙 (Android)
+ -r,--root <arg>                     指定编译目录. 默认是
+                                     当前目录
+    --settings <arg>                 指定项目设置文件的
+                                     路径. 可以使用多个
+                                     文件. 设置根据文件
+                                     从左到右应用.
+    --strip-executable               去掉dmengine的debug信息
+                                     (编译 iOS 或 Android时)
+ -tc,--texture-compression <arg>     使用纹理档中指定的
+                                     纹理压缩
+ -tp,--texture-profiles <arg>        使用纹理压缩档 (弃用)
+ -u,--auth <arg>                     用户auth符
+    --use-vanilla-lua                只使用 vanilla 源代码 (即
+                                     不要字节码)
+ -v,--verbose                        冗余输出
+    --variant <arg>                  指定使用 debug, release 或者 headless
+                                     dmengine的版本 (编译时)
+    --version                        打印输出
+                                     版本号
+    --with-symbols                   生成标记文件 (如果
+                                     可用)
+```
+
+支持的命令:
+
+`clean`
+: 清空编译目录下的编译文件.
+
+`distclean`
+: 清空编译目录下的所有文件.
+
+`build`
+: 编译所有项目文件. 加入 `--archive` 选项可生成编译数据包 (编译目录下生成 "game.darc" 文件).
+
+`bundle`
+: 指定平台打包. 打包需要数据包已经编译生成 (`build` 加入 `--archive` 选项) 然后指定打包平台 (使用 `--platform` 选项). Bob 会把应用打包到编译目录下, 除非使用 `--bundle-output` 选项手动指定打包输出目录. 包名根据 *game.project* 文件中设置的项目名命名. 使用 `--variant` 指定打何种运行类型的包, 连同 `--strip-executable` 选项代替了老的 `--debug` 选项. 如果 `--variant` 没有指定, 默认时release类型的 (去除 Android 和 iOS 的debug信息). 把 `--variant` 设置为 debug 而省略 `--strip-executable` 选项, 就相当于老的 `--debug`选项.
+
+`resolve`
+: 解析所有外部依赖库.
+
+可用平台:
+
+`x86_64-darwin`
+: Mac OSX 64 bit
+
+`x86_64-win32`
+: Windows 64 bit
+
+`x86-win32`
+: Windows 32 bit
+
+`x86_64-linux`
+: Linux 64 bit
+
+`arm64-darwin`
+: iOS 64 bit
+
+`armv7-darwin`
+: iOS 32 bit
+
+`x86_64-ios`
+: iOS Mac OSX 64 bit (iOS Simulator)
+
+`armv7-android`
+: Android 32 bit
+
+`js-web`
+: HTML5
+
+默认情况下, Bob 在当前目录下寻找项目来编译. 切换到 Defold 项目目录下使用 bob, 它会把数据编译到默认输出 *build/default* 目录下.
+
+```sh
+$ cd /Applications/Defold-beta/branches/14/4/main
+$ java -jar bob.jar
+100%
+$
+```
+
+还可以把命令连成一行一起执行. 下面的例子包含了解析库, 清理编译目录, 编译数据包然后打包成 OSX 应用 (命名为 *My Game.app*):
+
+```sh
+$ java -jar bob.jar --archive --platform x86-darwin resolve distclean build bundle
+100%
+$ ls -al build/default/
+total 70784
+drwxr-xr-x   13 sicher  staff       442  1 Dec 10:15 .
+drwxr-xr-x    3 sicher  staff       102  1 Dec 10:15 ..
+drwxr-xr-x    3 sicher  staff       102  1 Dec 10:15 My Game.app
+drwxr-xr-x    8 sicher  staff       272  1 Dec 10:15 builtins
+-rw-r--r--    1 sicher  staff    140459  1 Dec 10:15 digest_cache
+drwxr-xr-x    4 sicher  staff       136  1 Dec 10:15 fonts
+-rw-r--r--    1 sicher  staff  35956340  1 Dec 10:15 game.darc
+-rw-r--r--    1 sicher  staff       735  1 Dec 10:15 game.projectc
+drwxr-xr-x  223 sicher  staff      7582  1 Dec 10:15 graphics
+drwxr-xr-x    3 sicher  staff       102  1 Dec 10:15 input
+drwxr-xr-x   20 sicher  staff       680  1 Dec 10:15 logic
+drwxr-xr-x   27 sicher  staff       918  1 Dec 10:15 sound
+-rw-r--r--    1 sicher  staff    131926  1 Dec 10:15 state
+$
+```

+ 110 - 0
docs/zh/manuals/building-blocks.md

@@ -0,0 +1,110 @@
+---
+title: Defold 构成
+brief: 本教程详述游戏对象, 组件和集合是如何工作的.
+---
+
+#  构成
+
+Defold 核心设计中的一些概念可能一时不容易理解. 本教程介绍了 Defold 游戏的各个组成部分. 看完本教程后, 可以去参考 [定位教程](/manuals/addressing) 和 [消息传递教程](/manuals/message-passing). 编辑器中提供了一些 [教程](/tutorials/getting-started) 也可以帮助学习理解.
+
+![Building blocks](images/building_blocks/building_blocks.png){srcset="images/building_blocks/[email protected] 2x"}
+
+Defold 游戏主要由三大部分组成:
+
+Collection
+: 集合文件构成了你的游戏. 集合可以包含具有嵌套关系的游戏对象与其他集合. 可以用来构建诸如关卡, 敌人队伍, 多个游戏对象嵌套组成的一个角色之类的各种内容.
+
+Game object
+: 游戏对象是一个带 id 的容器, 具有位置, 旋转和缩放. 用来容纳组件. 可以用来构建主角, 子弹, 游戏逻辑或者资源加载/卸载程序.
+
+Component
+: 组件被放置在游戏对象中用来产生游戏里可视, 可听, 可运行的东西. 可以用来构建 sprite, 脚本, 音效或者粒子特效.
+
+## 集合
+
+集合是包含嵌套游戏对象和其他集合的树形结构. 通常集合作为文件保存于项目中.
+
+Defold 游戏引擎启动时, 首先导入一个 "game.project" 配置文件中指定的 _启动集合_. 启动集合一般叫做 "main.collection",  当然也可以根据喜好随意设置.
+
+集合可以包含游戏对象和其他集合 (通过引用子集合文件), 它们可以随意嵌套. 下面是一个 "main.collection" 集合示例. 它包含了一个游戏对象 (id 叫做 "can") 和一个子集合 (id 叫做 "bean"). 这个子集合, 又包含了两个游戏对象: "bean" 和 "shield".
+
+![Collection](images/building_blocks/collection.png){srcset="images/building_blocks/[email protected] 2x"}
+
+注意这个 id 叫做 "bean" 的子集合也是一个集合文件, 路径是 "/main/bean.collection", 这个文件被 "main.collection" 引用:
+
+![Bean collection](images/building_blocks/bean_collection.png){srcset="images/building_blocks/[email protected] 2x"}
+
+运行时无法用集合的 id 对 "main" 和 "bean" 这样的集合定位. 但是, 使用 _路径_ 引用游戏对象时可能会用到集合的 id (详情请见 [定位教程](/manuals/addressing)):
+
+```lua
+-- file: can.script
+-- 定位 "bean" 集合的 "bean" 对象
+local pos = go.get_position("bean/bean")
+```
+
+集合只能用文件引用的方式添加到其他集合中:
+
+在 *Outline* 视图中 <kbd>右键点击</kbd> 选择 <kbd>Add Collection File</kbd>.
+
+## 游戏对象
+
+游戏对象在游戏运行时有自己的生命周期. 游戏对象有位置, 旋转和缩放. 这些属性可以在运行时进行控制也可用于属性动画.
+
+```lua
+-- 将 "can" 游戏对象的 X 坐标位置创建属性动画 
+go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR, 1.0)
+```
+
+游戏对象可以是空的 (比如作为位置标记) 但通常包含各种组件, 比如 sprite, 声音, 脚本, 模型, 工厂什么的. 游戏对象可以使用编辑器进行创建, 放入集合, 或者在运行时使用 _factory_ 组件动态生成.
+
+游戏对象可以直接放入集合, 或者作为文件被集合引用:
+
+在 *Outline* 视图中 <kbd>右键点击</kbd> 集合选择 <kbd>Add Game Object</kbd> (直接放入) 或者 <kbd>Add Game Object File</kbd> (作为文件引用).
+
+
+## 组件
+
+:[components](../shared/components.md)
+
+可用组件列表详见 [组件概述](/manuals/components/).
+
+## 直接放入还是作为文件引用
+
+创建集合, 游戏对象或者组件 _文件_ 的时候, 实际上是创建了一个蓝图, 或者称为原型. 原型文件保存于项目中, 而不是游戏里. 要在游戏里使用这些原型的实例就需要在集合中把原型实例化.
+
+在大纲视图中可以看到各个实例是基于哪个原型的. 下例中 "main.collection" 包含了3个基于文件的实例:
+
+1. "bean" 子集合.
+2. "bean" 子集合里 "bean" 对象的 "bean" 脚本组件.
+3. "can" 游戏对象的 "can" 脚本组件.
+
+![Instance](images/building_blocks/instance.png){srcset="images/building_blocks/[email protected] 2x"}
+
+如果你有许多游戏对象或者集合的实例, 这种基于文件的设计就很方便:
+
+![GO instances](images/building_blocks/go_instance.png){srcset="images/building_blocks/[email protected] 2x"}
+
+修改了原型文件, 那么它的所有实例都能一同被修改.
+
+![GO instances updated](images/building_blocks/go_instance2.png){srcset="images/building_blocks/[email protected] 2x"}
+
+## 游戏对象层级
+
+在集合文件中, 可以将游戏对象设置成父子层级关系. 只需要 <kbd>拖拽</kbd> 游戏对象到父级对象 <kbd>放开鼠标</kbd> 即可完成父子层级的建立:
+
+![Childing game objects](images/building_blocks/childing.png){srcset="images/building_blocks/[email protected] 2x"}
+
+这种动态的父子关系影响了它们的变化方式. 不论是在编辑器还是运行时, 父级的各种变化 (包括位置, 旋转和缩放) 都会自动应用到它的所有子级上:
+
+![Child transform](images/building_blocks/child_transform.png){srcset="images/building_blocks/[email protected] 2x"}
+
+反过来说, 子级的变化都基于父级的坐标空间. 在编辑器中, 你可以使用 <kbd>Edit ▸ World Space</kbd> (默认设置) 或者 <kbd>Edit ▸ Local Space</kbd> 来设置一个对象变化基于的坐标空间.
+
+运行时可以通过发送 `set_parent` 消息改变对象的父级.
+
+```lua
+local parent = go.get_id("bean")
+msg.post("child_bean", "set_parent", { parent_id = parent })
+```
+
+一个常见的误解是对象层级改变了那么它的定位地址也会改变. 但是, 这其实是两码事. 父子关系改变的是场景的层级. 集合嵌套关系才决定对象地址. 在对象整个生命周期中, 地址是不会变化的.

+ 62 - 0
docs/zh/manuals/bundling.md

@@ -0,0 +1,62 @@
+---
+title: 打包应用
+brief: 本教程介绍了如何打包应用.
+---
+
+# 打包应用
+
+开发项目时常常需要在目标平台上进行测试. 开发中越早发现性能问题越好解决. 同样鼓励在各平台间做测试以便发现诸如shader之类的兼容问题. 在做手机开发时可以使用 [手机开发应用](/manuals/dev-app/) 把内容推送到手机上, 避免反复的安装和卸载.
+
+你可以在 Defold 编辑器中生成其支持的所有平台应用, 不需要外界工具辅助. 也可以在控制台使用命令行工具打包应用. 如果应用里包含 [原生扩展](/manuals/extensions) 的话打包时需要网络连接.
+
+## 从编辑器中打包
+
+使用 Project 菜单的 Bundle 选项进行打包:
+
+![](images/bundling/bundle_menu.png)
+
+选择不同的打包平台会出现不同的对话窗.
+
+### 编译报告
+
+有一个编译选项控制编译时是否生成报告. 从报告中可以方便检查游戏包中各个资源占用的空间. 在编译时打开 *Generate build report* 选项即可.
+
+![build report](images/profiling/build_report.png){srcset="images/profiling/[email protected] 2x"}
+
+To learn more about build reports please refer to the [Profiling manual](/manuals/profiling/#编译报告).
+
+### Android
+
+打包安卓应用 (.apk 文件) 及其准备工作详见 [Android 教程](/manuals/android/#打包Android应用).
+
+### iOS
+
+打包ios应用 (.ipa 文件) 及其准备工作详见 [iOS 教程](/manuals/ios/#打包ios应用).
+
+### OSX
+
+打包 OSX 应用 (.app 文件) 无需什么准备, 但是要在 "game.project" 文件中做相应设置, 详见 [项目配置文件](/manuals/project-settings/#macos--os-x).
+
+### Linux
+
+打包 Linux 应用无需什么准备, 但是要在 "game.project" 文件中做相应设置, 详见 [项目配置文件](/manuals/project-settings/).
+
+### Windows
+
+打包 Windows 应用 (.exe file) 无需什么准备, 但是要在 "game.project" 文件中做相应设置, 详见但是要在 "game.project" 文件中做相应设置, 详见 [项目配置文件](/manuals/project-settings/#windows).
+
+#### Facebook Gameroom
+
+可以为 Facebook Gameroom 打包成 Windows 应用的一种特殊版本. 这一过程详见 [Facebook Gameroom 教程](/manuals/gameroom/).
+
+### HTML5
+
+打包 HTML5 应用及其参数设置详见 [HTML5 教程](/manuals/html5/#打包html5应用).
+
+#### Facebook Instant Games
+
+可以为 Facebook Instant Games 打包成 HTML5 应用的一种特殊版本. 这一过程详见 [Facebook Instant Games 教程](/manuals/instant-games/).
+
+## 命令行打包
+
+日常开发中一般使用 Defold 编辑器编译和打包应用. 如果需要自动生成机制, 比如发布新版本时批处理所有平台或者使用持续集成环境持续生成最新版本. 可以使用 [Bob 命令行工具](/manuals/bob/) 编译和打包.

+ 143 - 0
docs/zh/manuals/camera.md

@@ -0,0 +1,143 @@
+---
+title: 摄像机组件教程
+brief: 本教程介绍了 Defold 摄像机组件的功能.
+---
+
+# 摄像机
+
+Defold 的摄像机组件控制游戏世界的视口与映射. 摄像机组件定义了透视和平视的视口与映射矩阵用于渲染脚本进行渲染. 透视摄像机一般服务于 3D 游戏, 平视摄像机一般服务员 2D 游戏. 如果需要摄像机追随, 缩放, 震动之类的功能需要自己来实现 (可以参考下面的 [第三方摄像机解决方案](https://www.defold.com/manuals/camera/#third-party-camera-solutions)).
+
+## 创建摄像机
+
+要创建摄像机, 在游戏对象上 <kbd>右键点击</kbd> 选择 <kbd>Add Component ▸ Camera</kbd>. 或者先创建组件文件再链接到游戏对象上.
+
+![create camera component](images/camera/create.png){srcset="images/camera/[email protected] 2x"}
+
+摄像机有以下属性用以建立 *视锥* (透视摄像机可用):
+
+![camera settings](images/camera/settings.png){srcset="images/camera/[email protected] 2x"}
+
+Id
+: 组件id
+
+Aspect Ratio
+: (**透视摄像机可用**) - 视锥宽高比. 1.0 代表正方形视口.  4:3 显示器 1024x768 这样的分辨率用 1.33. 16:9 的显示器用 1.78. 如果设置了 *Auto Aspect Ratio* 则此属性无效.
+
+Fov
+: (**透视摄像机可用**) - 以 _弧度_ 表示的摄像机 *垂直* 视域. 视域越宽, 摄像机看到的内容越多. 注意目前默认值 (45) 有点误导. 要 45 度的视域, 要设置值为 0.785 ($\pi / 4$).
+
+Near Z
+: (**透视摄像机可用**) - 近端裁剪平面z值.
+
+Far Z
+: (**透视摄像机可用**) - 远端裁剪平面z值.
+
+Auto Aspect Ratio
+: (**透视摄像机可用**) - 自动设置宽高比.
+
+## 使用摄像机
+
+通过发送 acquire_camera_focus 消息, 激活摄像机并填充视口同时向渲染脚本提供映射矩阵:
+
+```lua
+msg.post("#camera", "acquire_camera_focus")
+```
+
+被激活的摄像机, 会在每一帧向 "@render" 接口发送 `"set_view_projection"` 消息, 也就是说渲染脚本会接收此消息:
+
+```lua
+-- builtins/render/default.render_script
+--
+function on_message(self, message_id, message)
+    if message_id == hash("set_view_projection") then
+        self.view = message.view                    -- [1]
+        self.projection = message.projection
+    end
+end
+```
+1. 这个消息中包含一个视口矩阵和一个映射矩阵.
+
+### 摄像机平移
+
+平移摄像机所在游戏对象就相当于平移摄像机. 摄像机会根据当前x和y坐标更新视口矩阵.
+
+### 摄像机缩放
+
+延 z 轴移动透视摄像机所在游戏对象就相当于缩放摄像机. 摄像机会根据当前z坐标更新视口矩阵.
+
+对于平视摄像机只有将其映射类型设置为 `Fixed` 才可以进行视口缩放, 此时要向 "@render" 接口发送缩放等级进行视口缩放:
+
+```Lua
+msg.post("@render:", "use_fixed_projection", { zoom = 2, near = -1, far = 1 })
+```
+
+### 摄像机跟随
+
+把摄像机对象放在要跟随的游戏对象子级就能实现摄像机跟随:
+
+![follow game object](images/camera/follow.png)
+
+或者自己写脚本每帧更新摄像机位置也可以.
+
+### 鼠标位置转换为世界坐标
+
+摄像机平移缩放后 on_input() 函数提供的鼠标位置就不再与世界坐标匹配了. 此时需要进行手动矫正. 默认渲染脚本里把鼠标/屏幕坐标转换为世界坐标的代码如下:
+
+::: 注意
+[本教程第三方摄像机解决方案部分](/manuals/camera/#第三方摄像机解决方案) 提供了坐标转换方法.
+:::
+
+```Lua
+-- builtins/render/default.render_script
+--
+local function screen_to_world(x, y, z)
+	local inv = vmath.inv(self.projection * self.view)
+	x = (2 * x / render.get_width()) - 1
+	y = (2 * y / render.get_height()) - 1
+	z = (2 * z) - 1
+	local x1 = x * inv.m00 + y * inv.m01 + z * inv.m02 + inv.m03
+	local y1 = x * inv.m10 + y * inv.m11 + z * inv.m12 + inv.m13
+	local z1 = x * inv.m20 + y * inv.m21 + z * inv.m22 + inv.m23
+	return x1, y1, z1
+end
+```
+
+## 映射
+
+摄像机提供了用于透视映射的渲染脚本. 非常适合 3D 游戏. 对于 2D 游戏, 通常使用的是 *平视映射*. 这种摄像机的视口不是视锥, 而是方盒. 平视口没有近大远小. 同样大小的东西无论离摄像机远还是近映射出来都一样大.
+
+![projections](images/camera/projections.png){srcset="images/camera/[email protected] 2x"}
+
+### 平视映射 (2D)
+平视映射的渲染脚本不采用摄像机发来的映射矩阵自己实现渲染算法. 默认提供三种适配方式: `Stretch`, `Fixed` 和 `Fixed Fit`. 可以通过发送消息设置适配方式:
+
+```lua
+msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
+```
+
+::: 注意
+消息里近远端裁剪平面深度还是需要的. 但是摄像机属性里的近远端裁剪平面设置只在透视摄像机里有效.
+:::
+
+::: 注意
+平时摄像机渲染视口的左下角对应摄像机所在游戏对象的位置.
+:::
+
+渲染脚本及适配方式详情请见 [渲染手册](/manuals/render/#默认视口映射).
+
+### 透视映射 (3D)
+透视映射渲染脚本采用摄像机发来的视口与映射矩阵信息实现渲染. 通过发送如下消息使渲染脚本使用来自摄像机的映射信息:
+
+```lua
+msg.post("@render:", "use_camera_projection")
+```
+
+渲染脚本详情请见 [渲染手册](/manuals/render/#透视映射).
+
+
+## 第三方摄像机解决方案
+
+有一些第三方库实现了诸如游戏对象跟随, 坐标转换等摄像机功能. 可以在 Defold 社区资源库找到:
+
+- [Rendercam](https://defold.com/assets/rendercam/) (2D 和 3D) 由 Ross Grams 开发.
+- [Ortographic camera](https://defold.com/assets/orthographic/) (仅 2D) 由 Björn Ritzl 开发.

+ 150 - 0
docs/zh/manuals/collection-factory.md

@@ -0,0 +1,150 @@
+---
+title: 集合工厂教程
+brief: 本教程介绍了如何使用集合工厂创建一组嵌套的游戏对象.
+---
+
+# 集合工厂
+
+集合工厂组件用于在游戏运行时创建一组保存于集合之中的嵌套的游戏对象.
+
+Defold 提供了集合或者称为 "prefabs" 的可重用模板机制 . 关于集合概述, 请见 [Defold 组成](/manuals/building-blocks#collections). 使用集合可以在编辑器, 或者在运行时动态插入游戏内容.
+
+使用集合工厂可以依照一个集合文件向游戏世界插入内容. 这与游戏对象工厂的做法类似只不过集合工厂能创建一组含有父子嵌套层级关系的游戏对象. 典型用法比如动态生成一组敌人 (敌人对象和其武器对象的组合).
+
+## 新建集合
+
+假设有一个角色对象, 在它的子集有个盾牌对象. 我们就可以把这种含嵌套层级关系的组合保存为一个集合文件 "bean.collection".
+
+::: 注意
+*集合代理* 组件用于创建基于集合的游戏世界, 里面可以包含独立的物理世界. 通过新建一个接口, 集合中的所有内容通过集合代理加载. 这样可以实现诸如切换关卡之类的功能. 游戏世界通常包含很多东西, 如果加载少量内容, 不要使用集合代理. 详情请见 [集合代理教程](/manuals/collection-proxy).
+:::
+
+![Collection to spawn](images/collection_factory/collection.png)
+
+把 *集合工厂* 加入游戏对象然后设置其 *原型* 为 "bean.collection":
+
+![Collection factory](images/collection_factory/factory.png)
+
+这样只需调用 `collectionfactory.create()` 函数即可创建角色加盾牌的组合了:
+
+```lua
+local bean_ids = collectionfactory.create("#bean_factory")
+```
+
+此函数有5个参数:
+
+`url`
+: 要使用的集合工厂组件的id.
+
+`[position]`
+: (可选) 新建游戏对象组合的世界坐标位置. 以 `vector3` 表示. 如果不指定位置, 默认位置是集合工厂所在游戏对象的位置.
+
+`[rotation]`
+: (可选) 新创建游戏对象组合的世界坐标旋转. 以 `quat` 表示.
+
+`[properties]`
+: (可选) 新创建游戏对象组合的 `id`-`table` 属性初始化 Lua 表. 关于此表结果见下文.
+
+`[scale]`
+: (可选) 新创建游戏对象组合的等比缩放. 以 `number` (大于 0) 表示. 或者以 `vector3` 表示每个坐标轴上的非等比缩放.
+
+`collectionfactory.create()` 返回一个包含每个新建对象id的表. 表的内容是集合内每个对象id对应运行时每个对象id:
+
+::: 注意
+"bean" 与 "shield" 的父子层级关系 *不会* 在表里反应出来. 只能从运行时画面看出这种层级关系, 即做变化时两个对象同时变化. 改变层级关系与游戏对象id无关.
+:::
+
+```lua
+local bean_ids = collectionfactory.create("#bean_factory")
+go.set_scale(0.5, bean_ids[hash("/bean")])
+pprint(bean_ids)
+-- DEBUG:SCRIPT:
+-- {
+--   hash: [/shield] = hash: [/collection0/shield], -- <1>
+--   hash: [/bean] = hash: [/collection0/bean],
+-- }
+```
+1. 前缀 `/collection[N]/` 中, `[N]` 是计数器, 以确保每个id的唯一性:
+
+## 属性
+
+创建集合的对象时, 可以把属性表作为参数传给集合工厂. 表里的键是对象id, 值是这个对象需要设置的属性表.
+
+```lua
+local props = {}
+props[hash("/bean")] = { shield = false }
+local ids = collectionfactory.create("#bean_factory", nil, nil, props)
+```
+
+假设 "bean.collection" 里的 "bean" 对象有一个叫 "shield" 的脚本属性. 关于脚本属性详情请见 [脚本属性教程](/manuals/script-properties).
+
+```lua
+-- bean/controller.script
+go.property("shield", true)
+
+function init(self)
+    if not self.shield then
+        go.delete("shield")
+    end     
+end
+```
+
+## 工厂资源的动态加载
+
+开启工厂属性的 *Load Dynamically*, 工厂资源将会被延迟加载.
+
+![Load dynamically](images/collection_factory/load_dynamically.png)
+
+关闭动态加载, 则加载集合工厂组件时会同时加载其需要的资源以便工厂可以尽快创建新游戏对象.
+
+开启动态加载, 有两种用法:
+
+同步加载
+: 调用 [`collectionfactory.create()`](/ref/collectionfactory/#collectionfactory.create:url-[position]-[rotation]-[properties]-[scale]) 函数创建新对象时. 资源会同步加载, 这意味着游戏可能会卡一下, 加载完成后再创建新对象.
+
+  ```lua
+  function init(self)
+      -- 集合工厂父级集合加载时
+      -- 集合工厂资源不会被加载. 调用 create 函数
+      -- 会把资源进行同步加载.
+      self.go_ids = collecionfactory.create("#collectionfactory")
+  end
+
+  function final(self)  
+      -- 删掉游戏对象, 资源引用计数减少
+      -- 本例中集合工厂资源也会被卸载
+      -- 因为集合工厂组件不包含对资源的引用.
+      go.delete_all(self.go_ids)
+
+      -- 因为集合工厂组件不包含对资源的引用
+      -- 所以对集合工厂调用 unload 没有意义
+      collectionfactory.unload("#factory")
+  end
+  ```
+
+异步加载
+: 调用 [`collectionfactory.load()`](/ref/collectionfactory/#collectionfactory.load:[url]-[complete_function]) 函数进行资源的异步加载. 资源加载完毕后, 回调用回调函数.
+
+  ```lua
+  function load_complete(self, url, result)
+      -- 资源加载完成, 可以新建对象
+      self.go_ids = collectionfactory.create(url)
+  end
+
+  function init(self)
+      -- 集合工厂父级集合加载时
+      -- 集合工厂资源不被加载. 调用 load 函数进行资源异步加载.
+      collectionfactory.load("#factory", load_complete)
+  end
+
+  function final(self)
+      -- 删掉游戏对象, 资源引用计数减少
+      -- 本例中集合工厂资源不会被卸载
+      -- 因为集合工厂组件包含对资源的引用.
+      go.delete_all(self.go_ids)
+
+      -- 调用 unload 函数, 集合工厂对资源引用被释放,
+      -- 这样资源才会被卸载.
+      collectionfactory.unload("#factory")
+  end
+  ```

+ 179 - 0
docs/zh/manuals/collection-proxy.md

@@ -0,0 +1,179 @@
+---
+title: 集合代理教程
+brief: 本教程介绍了如何动态创建新游戏世界以及在游戏世界间进行切换.
+---
+
+# 集合代理
+
+集合代理组件用于基于集合文件内容动态加载卸载新的游戏 "世界". 可以用来实现切换关卡, GUI 屏幕, 在关卡里加载卸载插播 "场景", 加载卸载迷你游戏等等功能.
+
+Defold 把所有游戏对象组织在集合里. 集合可以包含游戏对象和其他集合 (即子集合). 集合代理可以让你把内容拆分到各个集合然后用脚本动态加载卸载这些集合.
+
+集合代理不像 [集合工厂组件](/manuals/collection-factory/). 集合工厂用于在当前游戏世界创建集合. 集合代理用于运行时创建全新游戏世界, 它们用处不同.
+
+## 创建集合代理组件
+
+1. 把一个集合代理组件加入到游戏对象上 <kbd>右键点击</kbd> 并从上下文菜单中选择 <kbd>Add Component ▸ Collection Proxy</kbd>.
+
+2. 设置 *Collection* 属性来引用一个集合, 就是你希望动态加载进运行环境的集合. 这些引用是静态的, 所以确保把游戏所需的各个部分都通过集合引用到.
+
+![add proxy component](images/collection-proxy/create_proxy.png){srcset="images/collection-proxy/[email protected] 2x"}
+
+(也可以编译时排除一部分内容需要的时候用代码下载而不使用 *Exclude* 选项和 [热更新功能](/manuals/live-update/).)
+
+## 启动集合
+
+当 Defold 引擎开始工作最先把 *启动集合* 导入运行环境并对其中的所有游戏对象进行初始化. 然后开启游戏对象和它们的组件. 在 [项目配置](/manuals/project-settings) 里设置把哪个集合作为启动集合使用. 依照惯例启动集合都叫做 "main.collection".
+
+![bootstrap](images/collection-proxy/bootstrap.png){srcset="images/collection-proxy/[email protected] 2x"}
+
+To fit the game objects and their components the engine allocates the memory needed for the whole "game world" into which the contents of the bootstrap collection are instanciated. A separate physics world is also created for any collision objects and physics simulation.
+
+Since script components need to be able to address all objects in the game, even from outside the bootstrap world, it is given a unique name: the *Name* property that you set in the collection file:
+
+![bootstrap](images/collection-proxy/collection_id.png){srcset="images/collection-proxy/[email protected] 2x"}
+
+If the collection that is loaded contains collection proxy components, the collections that those refer to are *not* loaded automatically. You need to control the loading of these resources through scripts.
+
+## Loading a collection
+
+Dynamically loading a collection via proxy is done by sending a message called `"load"` to the proxy component from a script:
+
+```lua
+-- Tell the proxy "myproxy" to start loading.
+msg.post("#myproxy", "load")
+```
+
+![load](images/collection-proxy/proxy_load.png){srcset="images/collection-proxy/[email protected] 2x"}
+
+The proxy component will instruct the engine to allocate space for a new world. A separate runtime physics world is also created and all the game objects in the collection "mylevel.collection" are instantiated.
+
+The new world gets its name from the *Name* property in the collection file, in this example it is set to "mylevel". The name has to be unique. If the *Name* set in the collection file is already used for a loaded world, the engine will signal a name collision error:
+
+```txt
+ERROR:GAMEOBJECT: The collection 'default' could not be created since there is already a socket with the same name.
+WARNING:RESOURCE: Unable to create resource: build/default/mylevel.collectionc
+ERROR:GAMESYS: The collection /mylevel.collectionc could not be loaded.
+```
+
+When the engine has finished loading the collection, the collection proxy component will send a message named `"proxy_loaded"` back to the script that sent the `"load"` message. The script can then initialize and enable the collection as a reaction to the message:
+
+```lua
+function on_message(self, message_id, message, sender)
+    if message_id == hash("proxy_loaded") then
+        -- New world is loaded. Init and enable it.
+        msg.post(sender, "init")
+        msg.post(sender, "enable")
+        ...
+    end
+end
+```
+
+`"load"`
+: This message tells the collection proxy component to start loading its collection into a new world. The proxy will send back a message called `"proxy_loaded"` when it's done.
+
+`"async_load"`
+: This message tells the collection proxy component to start background loading its collection into a new world. The proxy will send back a message called `"proxy_loaded"` when it's done.
+
+`"init"`
+: This message tells the collection proxy component that all the game objects and components that has been instantiated should be initialized. All script `init()` functions are called at this stage.
+
+`"enable"`
+: This message tells the collection proxy component that all the game objects and components should be enabled. All sprite components begin to draw when enabled, for instance.
+
+## Addressing into the new world
+
+The *Name* set in the collection file properties is used to address game objects and components in the loaded world. If you, for instance, create a loader object in the bootstrap collection you may need to communicate with it from any loaded collection:
+
+```lua
+-- tell the loader to load the next level:
+msg.post("main:/loader#script", "load_level", { level_id = 2 })
+```
+
+![load](images/collection-proxy/message_passing.png){srcset="images/collection-proxy/[email protected] 2x"}
+
+## Unloading a world
+
+To unload a loaded collection, you send messages corresponding to the converse steps of the loading:
+
+```lua
+-- unload the level
+msg.post("#myproxy", "disable")
+msg.post("#myproxy", "final")
+msg.post("#myproxy", "unload")
+```
+
+`"disable"`
+: This message tells the collection proxy component to disable all the game object and components in the world. Sprites stop being rendered at this stage.
+
+`"final"`
+: This message tells the collection proxy component to finalize all the game object and components in the world. All scripts' `final()` functions are called at this stage.
+
+`"unload"`
+: This message tells the collection proxy to remove the world completely from memory.
+
+If you don’t need the finer grained control, you can send the `"unload"` message directly without first disabling and finalizing the collection. The proxy will then automatically disable and finalize the collection before it’s unloaded.
+
+When the collection proxy has finished unloading the collection it will send a `"proxy_unloaded"` message back to the script that sent the `"unload"` message:
+
+```lua
+function on_message(self, message_id, message, sender)
+    if message_id == hash("proxy_unloaded") then
+        -- Ok, the world is unloaded...
+        ...
+    end
+end
+```
+
+
+## Time step
+
+Collection proxy updates can be scaled by altering the _time step_. This means that even though the game ticks at a steady 60 FPS, a proxy can update at a higher or lower pace, affecting physics and the `dt` variable passed to `update()`. You can also set the update mode, which allows you to control if the scaling should be performed discretely (which only makes sense with a scale factor below 1.0) or continuously.
+
+You control the scale factor and the scaling mode by sending the proxy a `set_time_step` message:
+
+```lua
+-- update loaded world at one-fifth-speed.
+msg.post("#myproxy", "set_time_step", {factor = 0.2, mode = 1}
+```
+
+To see what's happening when changing the time step, we can create an object with the following code in a script component and put it in the collection we're altering the timestep of:
+
+```lua
+function update(self, dt)
+    print("update() with timestep (dt) " .. dt)
+end
+```
+
+With a time step of 0.2, we get the following result in the console:
+
+```txt
+INFO:DLIB: SSDP started (ssdp://192.168.0.102:54967, http://0.0.0.0:62162)
+INFO:ENGINE: Defold Engine 1.2.37 (6b3ae27)
+INFO:ENGINE: Loading data from: build/default
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0
+DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
+```
+
+`update()` is still called 60 times a second, but the value of `dt` changes. We see that only 1/5 (0.2) of the calls to `update()` will have a `dt` of 1/60 (corresponding to 60 FPS)---the rest is zero. All physics simulations will also be updated according to that dt and advance only in one fifth of the frames.
+
+See [`set_time_step`](/ref/collectionproxy#set_time_step) for more details.
+
+## Caveats and common issues
+
+Physics
+: Through collection proxies it is possible to load more than one top level collection, or *game world* into the engine. When doing so it is important to know that each top level collection is a separate physical world. Physics interactions (collisions, triggers, ray-casts) only happen between objects belonging to the same world. So even if the collision objects from two worlds visually sits right on top of each other, there cannot be any physics interaction between them.
+
+Memory
+: Each loaded collection creates a new game world which comes with a relatively large memory footprint. If you load dozens of collections simultaneously through proxies, you might want to reconsider your design. To spawn many instances of game object hierarchies, [collection factories](/manuals/collection-factory) are more suitable.
+
+Input
+: If you have objects in your loaded collection that require input actions, you need to make sure that the game object that contains the collection proxy acquires input. When the game object receives input messages these are propagated to the components of that object, i.e. the collection proxies. The input actions are sent via the proxy into the loaded collection.

+ 92 - 0
docs/zh/manuals/components.md

@@ -0,0 +1,92 @@
+---
+title: 游戏对象组件
+brief: 本教程提供了游戏对象组件概览及其使用方法.
+---
+
+#  组件
+
+:[组件](../shared/components.md)
+
+## 组件类型
+
+Defold 提供以下组件类型:
+
+* [Collection factory](/manuals/collection-factory) - 创建集合实例
+* [Collection proxy](/manuals/collection-proxy) - 加载卸载集合
+* [Collision object](/manuals/physics) - 2D 和 3D 物理
+* [Camera](/manuals/camera) - 修改游戏世界的视口和映射
+* [Factory](/manuals/factory) - 创建游戏对象实例
+* [GUI](/manuals/gui) - 渲染图形用户界面
+* [Label](/manuals/label) - 渲染文本
+* [Model](/manuals/model) 显示3D模型 (可以带动画)
+* [Particle FX](/manuals/particlefx) -  创建粒子
+* [Script](/manuals/script) - 添加游戏逻辑
+* [Sound](/manuals/sound) - 播放音效音乐
+* [Spine model](/manuals/spine-model) - 渲染spine动画
+* [Sprite](/manuals/sprite) - 显示2D图像 (可以带逐帧动画)
+* [Tilemap](/manuals/tilemap) - 显示一组瓷砖图
+
+## 开启关闭组件
+
+游戏对象在创建时其组件是开启的. 如果需要关闭组件可以给组件发送 [`disable`](/ref/go/#disable) 消息:
+
+```lua
+-- 把此脚本所在的游戏对象上 id 为 'weapon' 的组件关闭
+msg.post("#weapon", "disable")
+
+-- 关闭 'enemy' 游戏对象上 id 为 'shield' 的所有组件
+msg.post("enemy#shield", "disable")
+
+-- 关闭当前游戏对象上的所有组件
+msg.post(".", "disable")
+
+-- 关闭 'enemy' 游戏对象上的所有组件
+msg.post("enemy", "disable")
+```
+
+需要开启组件可以给组件发送 [`enable`](/ref/go/#enable) 消息:
+
+```lua
+-- 开启 id 为 'weapon' 的组件
+msg.post("#weapon", "enable")
+```
+
+## 组件属性
+
+Defold 组件属性各不相同.在 [Outline 视图](/manuals/editor/#编辑器视图) 中当前选中的组件属性会显示在编辑器的 [Properties 面板](/manuals/editor/#the-editor-views) 中. 可用组件的详细属性详情请见API教程.
+
+## 位置, 旋转和缩放
+
+可视组件通常含有位置, 旋转以及缩放属性. 这些属性可以在编辑器里修改但是绝大多数情况下不能在运行时修改 (sprite 和 label 的缩放属性是例外情况).
+
+如果需要在运行时修改组件的而不是组件所在游戏对象的位置, 旋转和缩放. 有个副作用就是游戏对象所有组件都会受影响. 如果你想维护游戏对象上的一个组件而不是多个, 建议将该组件移入另一个游戏对象并作为原来那个游戏对象的子对象.
+
+## 组件渲染顺序
+
+可视组件的渲染顺序取决于两个方面:
+
+### 渲染脚本的渲染优先级
+每个组件都有 [材质](/manuals/material/) 而且每个材质都有一个或多个标签. 渲染脚本依次定义一系列优先级, 每个优先级匹配一个或多个材质标签. 渲染脚本在 *update()* 函数里 [按优先级依次渲染](/manuals/render/#render-predicates) , 匹配优先级标签的组件会被显示出来. 默认渲染脚本先绘制 sprites 和 tilemaps, 再渲染粒子特效, 二者都使用世界坐标系. 最后渲染脚本会在屏幕坐标系中渲染 GUI 组件.
+
+### 组件z值
+匹配某个优先级的组件在一起渲染, 它们之间的渲染顺序取决于组件的 z 值. 组件的最终z值是由组件的z值, 游戏对象和其父级游戏对象的z值之和.
+
+::: 注意
+各个 GUI 组件的渲染顺序 **不是** 由 GUI 组件的z值决定的. GUI 组件的渲染顺序由 [gui.set_render_order()](/ref/gui/#gui.set_render_order:order) 函数控制.
+:::
+
+例如: 两个游戏对象 A 和 B. B 是 A 的子集. B 有一个sprite组件.
+
+| 元素     | z值      |
+|----------|---------|
+| A        | 2       |
+| B        | 1       |
+| B#sprite | 0.5     |
+
+在上述定义中 B 的sprite组件最终z值是 2 + 1 + 0.5 = 3.5.
+
+::: 注意
+如果两个组件 z 值相同则可能造成两个组件来回穿梭闪烁或者不同平台顺序不同的结果.
+
+渲染脚本为 z 值定义了极近端和极远端平面. z值在此范围之外的组件不会被渲染. 默认范围是 -1 到 1 但是 [可以任意修改](/manuals/render/#默认视口映射).
+:::

+ 179 - 0
docs/zh/manuals/debugging.md

@@ -0,0 +1,179 @@
+---
+title: Defold 调试
+brief: 本教程介绍了 Defold 预置的调试功能.
+---
+
+# 调试
+
+Defold 包含了一个集成 Lua 调试和检视的功能. 连同内置 [性能分析工具](/manuals/profiling) 能够帮助你找到问题根源和性能瓶颈.
+
+## 输出和可视调试
+
+Defold 里最简单的调试方法是用 [print 调试](http://en.wikipedia.org/wiki/Debugging#Techniques). 使用 `print()` 或者 [`pprint()`](/ref/builtins#pprint) 语句观察变量或者定位执行流程. 如果有个游戏对象行为与预料不符, 就可以在它上面加个脚本以便进行调试. 使用打印函数能把内容输出到编辑器内的 *控制台* 上.  除了打印函数, 引擎还提供了在屏幕上画调试文字和直线的功能. 发送消息到 `@render` 接口即可:
+
+```lua
+-- 在屏幕上画 "my_val" 的值以及一些调试文字
+msg.post("@render:", "draw_text", { text = "My value: " .. my_val, position = vmath.vector3(200, 200, 0) })
+
+-- 在屏幕上玩家和敌人之间画调试直线
+local start_p = go.get_position("player")
+local end_p = go.get_position("enemy")
+local color_red = vmath.vector4(1, 0, 0, 1)
+msg.post("@render:", "draw_line", { start_point = start_p, end_point = end_p, color = color_red })
+```
+
+可视调试信息把数据加入渲染流程以便进行常规渲染.
+
+* `"draw_line"` 加入的数据在渲染脚本 `render.draw_debug3d()` 函数里渲染.
+* `"draw_text"` 使用 "/builtins/fonts/system_font.font" 以及 "/builtins/fonts/system_font.material" 材质进行渲染.
+
+注意如果需要每帧都进行渲染, 把消息发送放在 `update()` 函数里是个好主意.
+
+## 运行调试器
+
+要运行调试器, 或者选择 <kbd>Debug ▸ Run with Debugger</kbd> 即可打开带调试器的游戏, 或者选择 <kbd>Debug ▸ Attach Debugger</kbd> 把调试器附加的已经运行着的游戏上.
+
+![overview](images/debugging/overview.png){srcset="images/debugging/[email protected] 2x"}
+
+调试器一旦附加到游戏上, 你就可以通过控制台调试器面板按钮或者从 <kbd>Debug</kbd> 菜单来控制游戏运行了:
+
+Break
+: ![pause](images/debugging/pause.svg){width=60px .left}
+  立即停止游戏执行. 游戏会在断点处停止运行. 此时可以查看游戏状态, 步进游戏, 或者继续运行直到下一个断点. 编辑器上表明了当前运行的点:
+
+  ![script](images/debugging/script.png){srcset="images/debugging/[email protected] 2x"}
+
+Continue
+: ![play](images/debugging/play.svg){width=60px .left}
+  Continue running the game. The game code will continue to run until you either press pause or the execution hits a breakpoint that you have set. If execution breaks at a set breakpoint, the the execution point is marked in the code editor on top of the breakpoint marker:
+
+  ![break](images/debugging/break.png){srcset="images/debugging/[email protected] 2x"}
+
+Stop
+: ![stop](images/debugging/stop.svg){width=60px .left}
+  Stop the debugger. Pressing this button will immediately stop the debugger, detach it from the game and terminate the running game.
+
+Step Over
+: ![step over](images/debugging/step_over.svg){width=60px .left}
+  Advance execution of the program one step. If the execution involves running another Lua function, the execution _will not step into the function_ but continue running and stop on the next line below the function call. In this example, if the user presses "step over", the debugger will execute code and stop at the `end` statement below the line with the call to the function `nextspawn()`:
+
+  ![step](images/debugging/step.png){srcset="images/debugging/[email protected] 2x"}
+
+::: sidenote
+A line of Lua code does not correspond to a single expression. Stepping in the debugger moves ahead one expression at a time, meaning that currently you may have to hit the step button more than once to advance to the next line.
+:::
+
+Step Into
+: ![step in](images/debugging/step_in.svg){width=60px .left}
+  Advance execution of the program one step. If the execution involves running another Lua function, the execution _will step into the function_. Calling the function adds an entry to the call stack. You can click each entry in the call stack list to view the entry point and the content of all variables in that closure. Here, the user has stepped into the function `nextspawn()`:
+
+  ![step into](images/debugging/step_into.png){srcset="images/debugging/[email protected] 2x"}
+
+Step Out
+: ![step out](images/debugging/step_out.svg){width=60px .left}
+  Continue execution until it returns from the current function. If you have stepped execution into a function, pressing the button "step out" will continue execution until the function returns.
+
+Setting and clearing breakpoints
+: You can set an arbitrary number of breakpoints in your Lua code. When the game runs with the debugger attached, it will stop execution at the next breakpoint it encounters and wait for further interaction from you.
+
+  ![add breakpoint](images/debugging/add_breakpoint.png){srcset="images/debugging/[email protected] 2x"}
+
+  To set or clear a breakpoint, click in the column just right of the line numbers in the code editor. You can also select <kbd>Edit ▸ Toggle Breakpoint</kbd> from the menu.
+
+Evaluating Lua expressions
+: With the debugger attached and the game stopped at a breakpoint, a Lua runtime is available with the current context. Type Lua expressions in the bottom of the console and press <kbd>Enter</kbd> to evaluate them:
+
+  ![console](images/debugging/console.png){srcset="images/debugging/[email protected] 2x"}
+
+  It is currently not possible to modify variables through the evaluator.
+
+Detaching the debugger
+: Select <kbd>Debug ▸ Detach Debugger</kbd> to detach the debugger from the game. It will continue running immediately.
+
+## Debugging on mobile devices
+
+Some issues can be hard to debug with the editor debugger. Diagnosing problems such as native crashes and out of memory issues may need you to connect to the devices with USB cable and make use of a terminal.
+
+Android
+: Once your game is launched on your Android device, you can view all program output and crash stacktraces using the "adb" tool, which is part of the Android SDK. Documentation for "adb" and installation links can be found here: https://developer.android.com/studio/command-line/adb.html
+
+  Once installed and setup, connect your device with USB, open a terminal and run:
+
+  ```txt
+  cd <path_to_android_sdk>/platform-tools/
+  adb logcat
+  ```
+
+  The device will then dump all the output to the current terminal, along with any prints from the game.
+
+  If you want to see only Defold application outputs use next command:
+  ```txt
+  cd <path_to_android_sdk>/platform-tools/
+  adb logcat -s defold
+  ```
+
+iOS
+: On iOS you can attach the LLDB debugger to a game running on device. To debug a game it needs to be signed with a “Apple Developer Provisioning Profile” that include the device you want to debug on. Bundle the game from the editor and supply the provisioning profile in the bundle dialog (bundling for iOS is only available on macOS).
+
+  To launch the game and attach the debugger you will need a tool called [ios-deploy](https://github.com/phonegap/ios-deploy). Install and debug your game by running the following in a terminal:
+
+  ```txt
+  ios-deploy --debug --bundle <path_to_game.app> # NOTE: not the .ipa file
+  ```
+
+  This will install the app on your device, start it and automatically attach a LLDB debugger to it. If you are new to LLDB, read [Getting Started with LLDB](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-basics.html).
+
+
+## Extracting the log.txt file
+
+If you enable the *Write Log* setting in "game.project", any game output will be written to disk, to a file called "log.txt". Here is how you extract the file if you run the game on device:
+
+iOS
+: Connect your device to a computer with macOS and Xcode installed.
+
+  Open Xcode and go to <kbd>Window ▸ Devices and Simulators</kbd>.
+
+  Select your device in the list, then select the relevant app in the *Installed Apps* list.
+
+  Click the cog icon below the list and select <kbd>Download Container...</kbd>.
+
+  ![download container](images/debugging/download_container.png){srcset="images/debugging/[email protected] 2x"}
+
+  Once the container has been extracted it will be shown in *Finder*. Right click the container and select <kbd>Show Package Content</kbd>. Locate the file "log.txt", which should be located in "AppData/Documents/".
+
+Android
+: The ability to extract the "log.txt" depends on OS version and manufacturer. Here is a short and simple step by step guide: https://stackoverflow.com/a/48077004/129360
+
+## Lua debug library
+
+Lua comes with a debug library that is useful in some situations, particularly if you need to inspect the innards of your Lua environment. You can find more information about it here: http://www.lua.org/pil/contents.html#23.
+
+## Debugging checklist
+
+If you encounter an error or if your game does not behave like expected, here is a debugging checklist:
+
+1. Check the console output and verify that there are no runtime errors.
+
+2. Add `print` statements to your code to verify that the code is actually running.
+
+3. If it's not running, check that you have done the proper setup in the editor required for the code to run. Is the script added to the right game object? Have your script acquired input focus? Are the input-triggers correct? Is the shader code added to the material? Etc.
+
+4. If your code is depending on the values of variables (in an if-statement, for example), either `print` those values where they are used or checked, or inspect them with the debugger.
+
+Sometimes finding a bug can be a hard and time consuming process, requiring you to go through your code bit by bit, checking everything and narrowing down the faulty code and eliminating sources of error. This is best done by a method called "divide and conquer":
+
+1. Figure out which half (or less) of the code that must contain the bug.
+2. Again, figure out which half, of that half, must contain the bug.
+3. Continue narrowing down the code that must cause the bug until you find it.
+
+Happy hunting!
+
+## Debugging problems with physics
+
+If you have problems with physics and collisions aren't working as expected it is recommended to enable physics debugging. Check the *Debug* checkbox in the *Physics* section of the *game.project* file:
+
+![physics debug setting](images/debugging/physics_debug_setting.png)
+
+When this checkbox is enabled Defold will draw all collision shapes and contact points of collisions:
+
+![physics debug visualisation](images/debugging/physics_debug_visualisation.png)

+ 24 - 0
docs/zh/manuals/design.md

@@ -0,0 +1,24 @@
+---
+title: Defold 设计理念
+brief: Defold 设计幕后理念
+---
+
+# Defold 的设计理念
+
+Defold 为以下目的而创建:
+
+- 为游戏团队提供专业的迭代开发平台.
+- 简单明了, 提供可视化解决方案和游戏常用功能与开发流程.
+- 提供极轻量级的游戏开发平台.
+- 提供高性能运行环境.
+- 真正跨平台.
+
+Defold编辑器与引擎就是为了实现上述目的而精心打造的. 如果你从其他平台转来, 可能会有点不习惯, 比如:
+
+- 资源树与各种命名需要静态指定. 开始可能麻烦, 随着项目深入你就会觉得很方便.
+- 我们鼓励简单封装的实体间互相传递消息.
+- 没有面向对象的思想.
+- API都是异步的.
+- 渲染流程是可程式化可自定义的.
+- 所有资源文件都是直白文本文件, 为了最大化适应 Git merge , 也为了方便用外部工具编辑.
+- 资源可以实时修改然后在运行中的游戏里热重载, 这样特别方便开发迭代和做测试.

+ 87 - 0
docs/zh/manuals/dev-app.md

@@ -0,0 +1,87 @@
+---
+title: 在设备上运行开发用app
+brief: 本教程介绍了如何在设备上安装开发用app以方便开发流程.
+---
+
+# 移动端开发用app
+
+开发用app 让你可以通过wifi把内容推送到设备上. 这样进行修改测试的时候就不用反复打包安装了. 只需要在设备上安装开发用app, 打开app然后在编辑器里选择设备作为推送目标即可.
+
+## 安装开发用app
+
+使用引擎Debug打包的应用都可以用作开发用app. Android 上我们以及提供了 Defold 引擎的开发用app,  但是在 iOS 上的开发用app需要你使用自己的 signing identity 和 provisioning profile 手动打包并签名.
+
+### 在 iOS 上安装
+
+打包成 Debug 变体的 iOS 应用可以用作开发用app. 推荐就使用你当前的项目打包成 Debug 变体就好. 这样可以保证你的应用使用了正确的项目设置和 [原生扩展](/manuals/extensions/). 关于如何打包ios应用详情请见 [iOS 教程](/manuals/ios/#creating-an-ios-application-bundle). 记得使用 Debug 变体!
+
+### 在 Android 上安装
+
+对ios的建议同样适用于 Android. 然而我们已经编译好了一个开发用 *.apk* 文件.
+
+::: 注意
+只有在不使用 [原生扩展](/manuals/extensions/) 的项目可以使用我们提供的开发用apk. 否则你需要自己手动打debug包并且加入你所使用的原生扩展.
+:::
+* 访问 http://d.defold.com Defold下载网站.
+* 从列表中选择所需引擎版本.
+* 选择 *engine/armv7-android/dmengine.apk* Android开发用app (Armv7).
+
+![Download dmengine](images/dev-app/download_dmengine.png)
+
+下载此文件, 在下载存放目录下输入以下 `adb` 命令安装 *.apk*:
+
+```sh
+$ adb install dmengine.apk
+4445 KB/s (8706017 bytes in 1.912s)
+    pkg: /data/local/tmp/dmengine.apk
+Success
+```
+
+此时 "dmengine" 应用已安装好.
+
+![dmengine on the device](images/dev-app/dmengine_on_device.png)
+
+## 启动游戏
+
+要在设备上启动游戏, 应用与编辑器之间需要互联, 可以使用 wifi 也可以使用 USB 线缆 (见下文).
+
+1. 确保编辑器处于运行中.
+2. 在设备上启动开发用app.
+3. 在编辑器的 <kbd>Project ▸ Targets</kbd> 中选择设备.
+4. 选择 <kbd>Project ▸ Build And Launch</kbd> 运行游戏. 如果用网络连接的话可能需要等一小会儿.
+5. 游戏运行时, 就可以照常使用 [热重载](/manuals/hot-reload/) 功能了.
+
+![launch](images/dev-app/launch.png)
+
+### 在 Windows 上使用 USB 连接 iOS 设备
+
+要在 Windows 上使用 USB 连接运行于 iOS 设备上的app, 首先 [安装 iTunes](https://www.apple.com/lae/itunes/download/). 安装完之后还需从iOS设备的设置菜单里 [开启 Personal Hotspot](https://support.apple.com/en-us/HT204023). 如果跳出 "Trust This Computer?" 则选择 Trust. 这样设备就会出现在 <kbd>Project ▸ Targets</kbd> 列表中了.
+
+### 在 Linux 上使用 USB 连接 iOS 设备
+
+Linux 上同样开启 Personal Hotspot 然后 "Trust This Computer".
+
+### 在 OSX 上使用 USB 连接 iOS 设备
+
+当设备与 OSX 通过 USB 连线时, 新版本 iOS 能自动开启连接,  <kbd>Project ▸ Targets</kbd> 会自动显示出设备.
+
+老iOS设备还是同样开启 Personal Hotspot 然后 "Trust This Computer".
+
+### 在 OSX 上使用 USB 连接 Android 设备
+
+当设备处于 USB 共享模式时,  可以通过 USB 连接设备与 OSX. 在 MacOS 上需要安装 [HoRNDIS](https://joshuawise.com/horndis#available_versions) 这类的第三方驱动程序. 当 HoRNDIS 安装好后还需要在 Security & Privacy 设置里允许其运行. 设备上开启 USB 共享模式后就会出现在 <kbd>Project ▸ Targets</kbd> 列表中了.
+
+### 在 Windows 或 Linux 上使用 USB 连接 Android 设备
+
+同样在设备上开启 USB 共享模式后就会出现在 <kbd>Project ▸ Targets</kbd> 列表中了.
+
+## 故障排除
+
+无法下载应用
+: 确保你的设备 UDID 包含在手机应用签名 provisioning 中.
+
+Targets 菜单没有设备
+: 无线连接时确保设备和计算机处于相同子网.
+
+弹出消息说版本不匹配
+: 这是由于更新了编辑器没更新应用. 用新编辑器重新编译安装应用即可.

+ 204 - 0
docs/zh/manuals/editor-scripts.md

@@ -0,0 +1,204 @@
+---
+title: 编辑器脚本
+brief: 本教程介绍了如何使用 Lua 扩展编辑器功能
+---
+
+# 编辑器脚本
+
+只需使用: `.editor_script` 扩展名的 Lua 脚本就可以创建自定义菜单项和编辑器生命周期回调. 使用这种方法, 你可以调整编辑器创建适合自己的开发流.
+
+## 编辑器脚本运行环境
+
+编辑器脚本运行于编辑器中, 在一个Java虚拟机下的Lua虚拟机下运行. 所有脚本共享一个环境, 也就是说它们能彼此访问. 你可以导入Lua模块, 就像 `.script` 文件一样, 但是编辑器内lua运行版本不同, 所以要注意代码兼容性. 编辑器使用 Lua 版本 5.2.x, 具体来说就是 [luaj](https://github.com/luaj/luaj) 运行时, 目前只有这个运行时能运行在Java虚拟机下. 除了这些, 还有一些限制:
+- 没有 `debug` 和 `coroutine` 包;
+- 没有 `os.execute` — 我们在 [actions](#actions) 部分提供了更有效安全的方法;
+- 没有 `os.tmpname` 和 `io.tmpfile` — 目前编辑器可存取文件仅限于项目文件夹内的文件;
+- 目前没有 `os.rename`, 以后可能加入;
+- 没有 `os.exit` 和 `os.setlocale`.
+
+用编辑器脚本定义的编辑器扩展会在打开项目时加载. 获取依赖库时, 扩展会重新加载, 因为依赖库里有可能有扩展脚本存在. 重新加载时, 不会改变当前扩展脚本, 因为此时也许你正在编辑它们. 要完全重新加载, 可以使用 Project → Reload 编辑器命令.
+
+## `.editor_script` 构成
+
+每个编辑器脚本需要返回一个模块, 如下:
+```lua
+local M = {}
+
+function M.get_commands()
+  -- TODO
+end
+
+return M
+```
+然后编辑器会收集项目中和共享库里的所有的编辑器脚本, 把它们加载到Lua虚拟机中并在需要的时候调用它们 (详情请见 [commands](#commands) 和 [lifecycle hooks](#lifecycle-hooks) 部分).
+
+## Editor API
+
+可以使用API中 `editor` 包与编辑器进行交互:
+- `editor.platform` —字符串, 在Windows上是 `"x86_64-win32"`, 在macOS上是 `"x86_64-darwin"`, 在Linux上是 `"x86_64-linux"`.
+- `editor.get(node_id, property)` — 得到编辑器里某些节点的值. 编辑器里的节点是可变实体, 比如脚本或者集合文件, 集合中的游戏对象, 作为资源加载的 json 文件, 等等. `node_id` is a userdata that is passed to the editor script by the editor. Alternatively, you can pass resource path instead of node id, for example `"/main/game.script"`. `property` is a string. Currently these properties are supported:
+  - `"path"` — file path from the project folder for *resources* — entities that exist as files. Example of returned value: `"/main/game.script"`
+  - `"text"` — text content of a resource editable as text (such as script files or json). Example of returned value: `"function init(self)\nend"`. Please note that this is not the same as reading file with `io.open()`, because you can edit a file without saving it, and these edits are available only when accessing `"text"` property.
+  - some properties that are shown in the Properties view when you have selected something in the Outline view. These types of outline properties supported:
+    - strings
+    - booleans
+    - numbers
+    - vec2/vec3/vec4
+    - resources
+
+    Please note that some of these properties might be read-only, and some might be unavailable in different contexts, so you should use `editor.can_get` before reading them and `editor.can_set` before making editor set them. Hover over property name in Properties view to see a tooltip with information about how this property is named in editor scripts. You can set resource properties to nil by supplying `""` value.
+- `editor.can_get(node_id, property)` — check if you can get this property so `editor.get()` won't throw an error
+- `editor.can_set(node_id, property)` — check if `"set"` action with this property won't throw an error
+
+## Commands
+
+If editor script module defines function `get_commands`, it will be called on extension reload, and returned commands will be available for use inside the editor in menu bar or in context menus in Assets and Outline panes. Example:
+```lua
+local M = {}
+
+function M.get_commands()
+  return {
+    {
+      label = "Remove Comments",
+      locations = {"Edit", "Assets"},
+      query = {
+        selection = {type = "resource", cardinality = "one"}
+      },
+      active = function(opts)
+        local path = editor.get(opts.selection, "path")
+        return ends_with(path, ".lua") or ends_with(path, ".script")
+      end,
+      run = function(opts)
+        local text = editor.get(opts.selection, "text")
+        return {
+          {
+            action = "set",
+            node_id = opts.selection,
+            property = "text",
+            value = strip_comments(text)
+          }
+        }
+      end
+    },
+    {
+      label = "Minify JSON"
+      locations = {"Assets"},
+      query = {
+        selection = {type = "resource", cardinality = "one"}
+      },
+      active = function(opts)
+        return ends_with(editor.get(opts.selection, "path"), ".json")
+      end,
+      run = function(opts)
+        local path = editor.get(opts.selection, "path")
+        return {
+          {
+            action = "shell",
+            command = {"./scripts/minify-json.sh", path:sub(2)}
+          }
+        }
+      end
+    }
+  }
+end
+
+return M
+```
+Editor expects `get_commands()` to return an array of tables, each describing a separate command. Command description consists of:
+
+- `label` (required) — text on a menu item that will be displayed to the user
+- `locations` (required) — an array of either `"Edit"`, `"View"`, `"Assets"` or `"Outline"`, describes a place where this command should be available. `"Edit"` and `"View"` mean menu bar at the top, `"Assets"` means context menu in Assets pane, and `"Outline"` means context menu in Outline pane.
+- `query` — a way for command to ask editor for relevant information and define what data it operates on. For every key in `query` table there will be corresponding key in `opts` table that `active` and `run` callbacks receive as argument. Supported keys:
+  - `selection` means this command is valid when there is something selected, and it operates on this selection.
+    - `type` is a type of selected nodes command is interested in, currently these types are allowed:
+      - `"resource"` — in Assets and Outline, resource is selected item that has a corresponding file. In menu bar (Edit or View), resource is a currently open file;
+      - `"outline"` — something that can be shown in the Outline. In Outline it's a selected item, in menu bar it's a currently open file;
+    - `cardinality` defines how many selected items there should be. If `"one"`, selection passed to command callback will be a single node id. If `"many"`, selection passed to command callback will be an array of one or more node ids.
+- `active` - a callback that is executed to check that command is active, expected to return boolean. If `locations` include `"Assets"` or `"Outline"`, `active` will be called when showing context menu. If locations include `"Edit"` or `"View"`, active will be called on every user interaction, such as typing on keyboard or clicking with mouse, so be sure that `active` is relatively fast.
+- `run` - a callback that is executed when user selects menu item, expected to return an array of [actions](#actions).
+
+## Actions
+
+Action is a table describing what editor should do. Every action has an `action` key. Actions come in 2 flavors: undoable and non-undoable.
+
+### Undoable actions
+
+Undoable action can be undone after it is executed. If a command returns multiple undoable actions, they are performed together, and get undone together. You should use undoable actions if you can. Their downside is that they are more limited.
+
+Existing undoable actions:
+- `"set"` — set a property of a node in the editor to some value. Example:
+  ```lua
+  {
+    action = "set",
+    node_id = opts.selection,
+    property = "text",
+    value = "current time is " .. os.date()
+  }
+  ```
+  `"set"` action requires these keys:
+  - `node_id` — node id userdata. Alternatively, you can use resource path here instead of node id you received from the editor, for example `"/main/game.script"`;
+  - `property` — a property of a node to set, currently only `"text"` is supported;
+  - `value` — new value for a property. For `"text"` property it should be a string.
+
+### Non-undoable actions
+
+Non-undoable action clears undo history, so if you want to undo such action, you will have to use other means, such as version control.
+
+Existing non-undoable actions:
+- `"shell"` — execute a shell script. Example:
+  ```lua
+  {
+    action = "shell",
+    command = {
+      "./scripts/minify-json.sh",
+      editor.get(opts.selection, "path"):sub(2) -- trim leading "/"
+    }
+  }
+  ```
+  `"shell"` action requires `command` key, which is an array of command and it's arguments. Main difference with `os.execute` is that since this is a potentially dangerous operation, editor will show a confirmation dialog asking user if they want to execute this command. It will remember each command that user already allowed.
+
+### Mixing actions and side effects
+
+You can mix undoable and non-undoable actions. Actions are executed sequentially, hence depending on an order of actions you will end up losing ability to undo parts of that command.
+
+Instead of returning actions from functions that expect them, you can just read and write to files directly using `io.open()`. This will trigger a resource reload that will clear undo history.
+
+## Lifecycle hooks
+
+There is a specially treated editor script file: `hooks.editor_script`, located in a root of your project, in the same directory as `game.project`. This and only this editor script will receive lifecycle events from the editor. Example of such file:
+```lua
+local M = {}
+
+function M.on_build_started(opts)
+  local file = io.open("assets/build.json", "w")
+  file:write("{\"build_time\": \"".. os.date() .."\"}")
+  file:close()
+end
+
+return M
+```
+We decided to limit lifecycle hooks to single editor script file because order in which build hooks happen is more important than how easy it is to add another build step. Commands are independent from each other, so it does not really matter in what order they are shown in the menu, in the end user executes a particular command they selected. If it was possible to specify build hooks in different editor scripts, it would create a problem: in which order do hooks execute? You probably want to create a checksums of content after you compress it... And having a single file that establishes order of build steps by calling each step function explicitly is a way to solve this problem.
+
+Every lifecycle hook can return actions or write to files in project directory.
+
+Existing lifecycle hooks that `/hooks.editor_script` may specify:
+- `on_build_started(opts)` — executed when game is Built to run locally or on some remote target. Your changes, be it returned actions or updated file contents, will appear in a built game. Raising an error from this hook will abort a build. `opts` is a table that contains following keys:
+  - `platform` — a string in `%arch%-%os%` format describing what platform it's built for, currently always the same value as in `editor.platform`.
+- `on_build_finished(opts)` — executed when build is finished, be at successful or failed. `opts` is a table with following keys:
+  - `platform` — same as in `on_build_started`
+  - `success` — whether build is successful, either `true` or `false`
+- `on_bundle_started(opts)` — executed when you create a bundle or Build HTML5 version of a game. As with `on_build_started`, changes triggered by this hook will appear in a bundle, and errors will abort a bundle. `opts` will have these keys:
+  - `output_directory` — a file path pointing to a directory with bundle output, for example `"/path/to/project/build/default/__htmlLaunchDir"`
+  - `platform` — platform the game is bundled for. See a list of possible platform values in [Bob manual](/manuals/bob).
+  - `variant` — bundle variant, either `"debug"`, `"release"` or `"headless"`
+- `on_bundle_finished(opts)` — executed when bundle is finished, be it successful or not. `opts` is a table with the same data as `opts` in `on_bundle_started`, plus `success` key indicating whether build is successful.
+- `on_target_launched(opts)` — executed when user launched a game and it successfully started. `opts` contains an `url` key pointing to a launched engine service, for example, `"http://127.0.0.1:35405"`
+- `on_target_terminated(opts)` — executed when launched game is closed, has same opts as `on_target_launched`
+
+Please note that lifecycle hooks currently are an editor-only feature, and they are not executed by Bob when bundling from command line.
+
+## Editor scripts in libraries
+
+You can publish libraries for other people to use that contain commands, and they will be automatically picked up by editor. Hooks, on the other hand, can't be picked up automatically, since they have to be defined in a file that is in a root folder of a project, but libraries expose only subfolders. This is intended to give more control over build process: you still can create lifecycle hooks as simple functions in `.lua` files, so users of your library can require and use them in their `/hooks.editor_script`.
+
+Also note that although dependencies are shown in Assets view, they do not exist as files (they are entries in a zip archive), so there is currently no easy way to execute a shell script you provide in a dependency. If you absolutely need it, you'll have to extract provided scripts by getting their text using `editor.get()` and then writing them somewhere with `file:write()`, for example in a `build/editor-scripts/your-extension-name` folder.

+ 140 - 0
docs/zh/manuals/editor.md

@@ -0,0 +1,140 @@
+---
+title: 编辑器概述
+brief: This manual gives an overview on how the Defold editor look and works, and how to navigate in it.
+---
+
+# Editor overview
+
+The editor allows you to browse and manipulate all files in your game project in an efficient manner. Editing files brings up a suitable editor and shows all relevant information about the file in separate views.
+
+## Starting the editor
+
+When you run the Defold editor, you are presented with a project selection and creation screen. On the left side there are three main views available. Click to select what you want to do:
+
+Home
+: Click to show a lists your recently opened projects so you can quickly access them. This is the default view.
+
+New
+: Click if you want to create a new Defold project, then select if you want to base your project on a basic template (from the *From Template* tab), if you would like to follow a tutorial (the *From Tutorial* tab), or try one of the sample projects (the *From Sample* tab).
+
+  ![new project](images/editor/new_project.png){srcset="images/editor/[email protected] 2x"}
+
+  When you create a new project it is stored on your local drive and any edits you do are saved locally. To share the project with members of your team, use the *Synchronize* feature in the editor. It creates a Defold cloud Git storage project for you through which you and your team can synchronize work.
+
+Import project
+: Create a working copy from an existing project from you Defold cloud Git storage account. The local copy is linked to the cloud Git project so it's ready for team synchronization.
+
+  ![import project](images/editor/import_project.png){srcset="images/editor/[email protected] 2x"}
+
+  Access to the Defold cloud git storage requires that you provide your Defold account credentials.
+
+You can learn more about the different options in the [Project Setup manual](https://www.defold.com/manuals/project-setup/).
+
+## The editor views
+
+The Defold editor is separated into a set of panes, or views, that display specific information.
+
+![Editor 2](images/editor/editor2_overview.png)
+
+The *Assets* view
+: Lists all the files that are part of your project. Click and scroll to navigate the list. All file oriented operations can be made in this view:
+
+   - <kbd>Double click</kbd> a file to open it in an editor for that file type.
+   - <kbd>Drag and drop</kbd> to add files from elsewhere on your disk to the project or move files and folders to new locations in the project.
+   - <kbd>Right click</kbd> to open a _context menu_ from where you can create new files or folders, rename, delete, track file dependencies and more.
+
+The *Editor* view
+
+: The center view shows the currently open file in an editor for that file type. All visual editors allows you to change the camera view:
+
+- Pan: <kbd>Alt + left mouse button</kbd>.
+- Zoom: <kbd>Alt + Right button</kbd> (three button mouse) or <kbd>Ctrl + Mouse button</kbd> (one button). If your mouse has a scroll wheel, it can be used to zoom.
+- Rotate in 3D: <kbd>Ctrl + left mouse button</kbd>.
+
+There is a toolbar in the top right corner of the scene view where you find object manipulation tools: *Move*, *Rotate* and *Scale*.
+
+![toolbar](images/editor/toolbar.png){srcset="images/editor/[email protected] 2x"}
+
+The *Outline*
+: This view shows the content of the file currently being edited, but in a hierarchial tree structure. The outline reflects the editor view and allows you to perform operations on your items:
+   - <kbd>Click</kbd> to select an item. Hold <kbd>Shift</kbd> or <kbd>Option</kbd> to expand the selection.
+   - <kbd>Drag and drop</kbd> to move items. Drop a game object on another game object in a collection to child it.
+   - <kbd>Right click</kbd> to open a _context menu_ from where you can add items, delete selected items etc.
+
+The *Properties* view
+: This view shows properties associated with the currently selected item, like Position, Rotation, Animation etc, etc.
+
+The *Console*
+: This view shows any error output or purposeful printing that you do while your game is running. Alongside the console are tabs containing the *Curve Editor* which is used when editing curves in the particle editor, the *Build Errors* view that shows build errors, and the *Search Results* view that displays search results. The console is also used for interacting with the integrated debugger.
+
+The *Changed Files* view:
+: This view lists any files that has been changed, added or deleted in your project. By synchronizing the project regularly you can bring your local copy in sync with what is stored in the project Git repository, that way you can collaborate within a team, and you won’t lose your work if unfortune strikes. Some file oriented operations can be performed in this view:
+
+   - <kbd>Double click</kbd> a file to open a diff view of the file. Editor 2 opens the file in a suitable editor, just like in the assets view.
+   - <kbd>Right click</kbd> a file to open a pop up menu from where you can open a diff view, revert all changes done to the file, find the file on the filesystem and more (editor 2).
+
+## Side-by-side editing
+
+If you have multiple files open, a separate tab for each file is shown at the top of the editor view. It is possible to open 2 editor views side by side. <kbd>Right click</kbd> the tab for the editor you want to move and select <kbd>Move to Other Tab Pane</kbd>.
+
+![2 panes](images/editor/2-panes.png){srcset="images/editor/[email protected] 2x"}
+
+You can also use the tab menu to swap the position of the two panes and join them to a single pane.
+
+## The scene editor
+
+Double clicking a collection or game object file brings up the *Scene Editor*:
+
+![Select object](images/editor/select.jpg)
+
+Selecting objects
+: Click on objects in the main window to select them. The rectangle surrounding the object in the editor view will highlight green to indicate what item is selected. The selected object is also highlighted in the *Outline* view.
+
+  You can also select objects by:
+
+  - <kbd>Click and drag</kbd> to select all objects inside the selection region.
+  - <kbd>Click</kbd> objects in the Outline view.
+
+  Hold <kbd>Shift</kbd> or <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> (Win/Linux) while clicking to expand the selection.
+
+The move tool
+: ![Move tool](images/editor/icon_move.png){.left}
+  To move objects, use the *Move Tool*. You find it in the toolbar in the top right corner of the scene editor, or by pressing the <kbd>W</kbd> key.
+
+  ![Move object](images/editor/move.jpg)
+
+  The selected object shows a set of manipulators (squares and arrows). Click and drag the green center square handle to move the object freely in screen space, click and drag the arrows to move the object along the X, Y or Z-axis. There arn also square handles for moving the object in the X-Y plane and (visible if rotating the camera in 3D) for moving the object in the X-Z and Y-Z planes.
+
+The rotate tool
+: ![Rotate tool](images/editor/icon_rotate.png){.left}
+  To rotate objects, use the *Rotate Tool* by selecting it in the toolbar, or by pressing the <kbd>E</kbd> key.
+
+  ![Move object](images/editor/rotate.jpg)
+
+  This tool consists of four circular manipulators. An orange manipulator that rotates the object in screen space and one for rotation around each of the X, Y and Z axes. Since the view is peripendicular to the X- and Y-axis, the circles only appear as two lines crossing the object.
+
+The scale tool
+: ![Scale tool](images/editor/icon_scale.png){.left}
+  To scale objects, use the *Scale Tool* by selecting it in the toolbar, or by pressing the <kbd>R</kbd> key.
+
+  ![Scale object](images/editor/scale.jpg)
+
+  This tool consists of a set of square handles. The center one scales the object uniformly in all axes (including Z). There also one handle for scaling along each of the X, Y and Z axes and one handle for scaling in the X-Y plane, the X-Z plane and the Y-Z plane.
+
+## Creating new project files
+
+To create new resource files, either select <kbd>File ▸ New...</kbd> and then choose the file type from the menu, or use the context menu:
+
+<kbd>Right click</kbd> the target location in the *Assets* browser, then select <kbd>New... ▸ [file type]</kbd>:
+
+![create file](images/editor/create_file.png){srcset="images/editor/[email protected] 2x"}
+
+Type a suitable name for the new file. The full file name including the file type suffix is shown under *Path* in the dialog:
+
+![create file name](images/editor/create_file_name.png){srcset="images/editor/[email protected] 2x"}
+
+## Importing files to your project
+
+To add asset files (images, sounds, models etc) to your project, simply drag and drop them to the correct position in the *Assets* browser. This will make _copies_ of the files at the selected location in the project file structure.
+
+![Import files](images/editor/import.png){srcset="images/editor/[email protected] 2x"}

+ 124 - 0
docs/zh/manuals/extensions-best-practices.md

@@ -0,0 +1,124 @@
+---
+title: 原生扩展 - 最佳实践
+brief: 本教程介绍了开发原生扩展的最佳实践.
+---
+
+# 最佳实践
+
+编写跨平台代码可能很困难, 但是通过一些方法可以更易于开发与维护. 本教程列举了 Defold 与跨平台原生代码共同工作的 API 和方法.
+
+## Defold 代码
+
+在 Defold 引擎中我们很少使用 C++ 代码. 事实上, 大多数是 C-like 代码. 除了少数容器类外, 我们去掉了模板, 因为模板会增加编译时间和包体大小.
+
+### C++ 版本
+
+Defold 源码使用默认 C++ 版本编译.
+
+我们不用最新的 C++ 版本及特性. 主要因为默认版本对于游戏引擎足够用了. 追寻最新 C++ 版本特性相当耗费时间.
+
+这也有助于向扩展开发者提供稳定 ABI. 而且使用最新 C++ 特性的话很可能会在不同平台上造成编译问题.
+
+### 标准模板库 - STL
+
+Defold 引擎不支持 STL 代码, 除了某些算法和数学库 (std::sort, std::upper_bound 等), 但是你的扩展里可以使用 STL.
+
+再次注意 ABI 的不兼容性可能使你使用其他扩展或者第三方库造成困难.
+
+去掉 (重模板化的) STL 库, 还能减少编译时间, 更重要的是, 减小应用体积.
+
+#### 字符串
+
+在 Defold 引擎中, 我们使用 `const char*` 代替了 `std::string`.
+
+`std::string` 使得 C++ 不同版本混合编译造成困难: 原因是 ABI 不匹配.
+所以我们选择使用 `const char*` 及相关工具函数代替.
+
+### 函数隐藏
+
+本地函数尽量使用 `static` 关键字定义. 这样便于编译器优化, 提高性能减小应用体积.
+
+## 第三方库
+
+当我们选用第三方库时 (不管由什么语言编写), 至少需要考虑这些事情:
+
+* 功能 - 这个库满足你的功能要求了吗?
+* 性能 - 运行时是否需要消耗大量性能?
+* 体积 - 会给包体增大多少体积?是否在可接受范围内?
+* 依赖 - 是否依赖其他库?
+* 支持 - 这个库是个什么样的状态? 是否有许多bug? 是否还在维护?
+* 证书 - 是否可以合法使用?
+
+
+## 开源依赖
+
+确定你能访问你的依赖库. 比如说在 GitHub 上托管的库, 随时可能被移除, 突然改变开发方向或者改变拥有者维护者. 如果你fork了这个库就能减少这些变化带来的损失.
+
+库代码是直接注入你的游戏中的, 所以需要保证它在满足你的要求的前提下不会在后台做什么小动作!
+
+
+## 项目结构
+
+当你创建扩展, 开发和维护时是有些技巧的.
+
+### Lua api
+
+应该只有一个 Lua api, 只有一个实现方法. 这样有助于在所有平台上保持一致的表现.
+
+如果某平台不支持这个扩展, 建议不要注册 Lua 模块.
+这样就可以通过检查非 nil 来判断对扩展的支持性:
+
+    if myextension ~= nil then
+        myextension.do_something()
+    end
+
+### 文件夹结构
+
+这是我们开发扩展使用的常用结构.
+
+    /root
+        /input
+        /main                            -- 示例项目根目录
+            /...
+        /myextension                     -- 扩展根目录
+            ext.manifest
+            /include                     -- 其他扩展使用的外部包含
+            /libs
+                /<platform>              -- 各个平台使用的外部包含
+            /src
+                myextension.cpp          -- 扩展的 Lua api 及其生命周期函数
+                                            还包含 Lua api 功能的通用实现方法.
+                myextension_private.h    -- 每个平台需要实现的内部 api (也就是 `myextension_Init` 之类的功能)
+                myextension.mm           -- 如果需要调用 iOS/macOS 原生功能. 就要为 iOS/macOS 实现 `myextension_Init` 之类的功能 
+                myextension_android.cpp  -- 如果需要调用 Android 的JNI. 就要为 Android 实现 `myextension_Init` 之类的功能
+                /java
+                    /<platform>          -- Android 需要的java文件
+            /res                         -- 平台需要的资源文件
+            /external
+                README.md                -- 扩展相关编译打包的说明/脚本
+        /bundleres                       -- 需要打包的资源 (参见 game.project 以及 [bundle_resources 设置](/manuals/project-settings/#project))
+            /<platform>
+        game.project
+        game.appmanifest                 -- 其他应用设置
+
+
+注意 `myextension.mm` 和 `myextension_android.cpp` 只在调用平台特定原生功能时使用.
+
+#### 平台文件夹
+
+在某些地方, 需要针对架构平台命名文件夹, 以便应用编译/打包时使用正确的文件.
+结构是这样的:
+
+    <architecture>-<platform>
+
+目前支持的有:
+
+    arm64-ios, armv7-ios, x86_64-ios, arm64-android, armv7-android, x86_64-linux, x86_64-osx, x86_64-win32, x86-win32
+
+比如, 这么放置平台相关库:
+
+    /libs
+        /arm64-ios
+                            /libFoo.a
+        /arm64-android
+                            /libFoo.a

+ 155 - 0
docs/zh/manuals/extensions-build-variants.md

@@ -0,0 +1,155 @@
+---
+title: 原生扩展 - Build variants
+brief: 本教程介绍了 Defold 能创建的各种 Build variants 以及它们如何与原生扩展和引擎交互.
+---
+
+# 原生扩展 - Build variants
+
+## Build variants
+
+打包游戏时, 需要选择你想用的引擎类型.
+
+  * Debug
+  * Release
+  * Headless
+
+不同类型即是 `Build variants`
+
+注意: 使用 `Build and run` 时使用的是 debug 版引擎.
+
+### Debug
+
+此版本保留调试功能, 例如 profiling, logging 和 hot reload. 开发阶段使用此版本.
+
+### Release
+
+此版本移除调试功能. 准备发布到应用商店时使用此版本.
+
+### Headless
+
+此版本没有图像和声音. 也就是说它可以 CI 服务器上进行 unit/smoke 测试, 甚至可以在云端作为服务器程序使用.
+
+## App Manifest
+
+不但可以为引擎加入原生扩展功能, 还可以从引擎中剔除一些部分. 比如你不需要物理引擎, 就可以从应用中去除.
+
+我们通过 `App Manifest` (.appmanifest) 文件支持这个功能. 在这个文件里, 你可以配置哪些库或 symbols 需要去除, 或者增加编译选项
+
+此功能尚在开发中.
+
+### 上下文组合
+
+实际上 app manifest 有着与 extension manifest 相同的结构和语法. 这使我们能够在最终编译时为每个平台混合上下文配置.
+
+而且, Defold 自身, 有其基础 build manifest (`build.yml`). 编译每个扩展时, 这些文件做如下混合:
+
+	manifest = merge(game.appmanifest, ext.manifest, build.yml)
+
+用户可以覆盖引擎和每个扩展的默认行为. 而且, 对于最终链接阶段, 我们混合了 app manifest 与 defold manifest:
+
+	manifest = merge(game.appmanifest, build.yml)
+
+### 编辑
+
+目前, 这些文件可以手动编辑, 但是推荐使用 [Manifestation](https://britzl.github.io/manifestation/) 工具生成 app manifest. 最终, app manifest 文件的创建和修改功能会并入编辑器中.
+
+### 语法
+
+这是 [Manifestation](https://britzl.github.io/manifestation/) 工具生成的一个结构 (很有可能会改变. 不要直接从这里拷贝. 而要使用最新的在线工具):
+
+	platforms:
+	    x86_64-osx:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    x86_64-linux:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    js-web:
+	        context:
+	            excludeLibs: []
+	            excludeJsLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    wasm-web:
+	        context:
+	            excludeLibs: []
+	            excludeJsLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    x86-win32:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    x86_64-win32:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    armv7-android:
+	        context:
+	            excludeLibs: []
+	            excludeJars: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    armv7-ios:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+	    arm64-ios:
+	        context:
+	            excludeLibs: []
+	            excludeSymbols: []
+	            libs: []
+	            linkFlags: []
+
+
+#### 白名单
+
+对于所有关键字, 我们提供白名单过滤. 这样可以避免非法路径处理和访问编译上载文件夹之外的文件.
+
+#### linkFlags
+
+可以在这里添加指定平台的编译标志.
+
+#### libs
+
+此标志仅在需要添加平台或者 Defold SDK 里的库时使用. 应用的扩展库是自动添加的, 不应在这里添加. 下面是从引擎中剔除 3D 物理的例子:
+
+    x86_64-linux:
+        context:
+            excludeLibs: ["physics","LinearMath","BulletDynamics","BulletCollision"]
+            excludeSymbols: []
+            libs: ["physics_2d"]
+            linkFlags: []
+
+#### Exclude flags
+
+此标志用于剔除平台上下文已经预先定义的东西. 下面是从引擎中剔除 Facebook 扩展的例子 (注意 `(.*)` 是帮助去掉正确元素而使用的正则表达式).
+
+    armv7-android:
+        context:
+            excludeLibs: ["facebookext"]
+            excludeJars: ["(.*)/facebooksdk.jar","(.*)/facebook_android.jar"]
+            excludeSymbols: ["FacebookExt"]
+            libs: []
+            linkFlags: []
+
+#### 所有 flags, libraries, symbols 在哪?
+
+与其在这里列举我们不然努力把 manifest 的编辑功能加入编辑器, 让用户使用更方便.
+
+与此同时, [Manifestation](https://britzl.github.io/manifestation/) 工具也会持续更新.

+ 82 - 0
docs/zh/manuals/extensions-debugging-android.md

@@ -0,0 +1,82 @@
+---
+title: Android调试
+brief: 本教程介绍了如何调试运行在 Android 设备上的应用.
+---
+
+# Android调试
+
+这里列举了一些在 Android 设备上调试应用的方法.
+
+## Android Studio
+
+* 打包前在  `game.project` 打开 `android.debuggable` 选项
+
+	![android.debuggable](images/extensions/debugging/android/game_project_debuggable.png)
+
+* 编译时选择 debug 模式.
+
+	![bundle_android](images/extensions/debugging/android/bundle_android.png)
+
+* 启动 [Android Studio](https://developer.android.com/studio/)
+
+* 选择 `Profile or debug APK`
+
+	![debug_apk](images/extensions/debugging/android/android_profile_or_debug.png)
+
+* 选择刚打包好的apk文件
+
+	![select_apk](images/extensions/debugging/android/android_select_apk.png)
+
+* 选择主 `.so` 文件, 确保其包含调试信息
+
+	![select_so](images/extensions/debugging/android/android_missing_symbols.png)
+
+* 如果没有调试信息, 提交一个带调试信息的 `.so` 文件. (文件大概 20mb 左右)
+
+* 路径映射帮助你重新把应用的各个路径从编译的地方 (在云端) 映射到你的本地目录下.
+
+* 选择 .so 文件, 再添加一个到本地的映射
+
+	![path_mapping1](images/extensions/debugging/android/path_mappings_android.png)
+
+	![path_mapping2](images/extensions/debugging/android/path_mappings_android2.png)
+
+* 如果你访问了引擎代码, 同样要添加一个对引擎代码的路径映射
+
+		* 确定checkout的是你正在调试的版本
+
+			defold$ git checkout 1.2.148
+
+* 点击 `Apply changes`
+
+* 现在你应该可以看到你的项目的代码映射了
+
+	![source](images/extensions/debugging/android/source_mappings_android.png)
+
+* 加入断点
+
+	![breakpoint](images/extensions/debugging/android/breakpoint_android.png)
+
+* 点击 `Run` -> `Debug "Appname"` 然后调用加入断点代码
+
+	![breakpoint](images/extensions/debugging/android/callstack_variables_android.png)
+
+* 现在你就可以在调用栈中步进调试和查看变量状态了
+
+
+## 注意
+
+### 原生扩展 job 目录
+
+目前, 工作流对于项目开发有点麻烦. 这是因为job目录名是随机的, 没法进行路径映射.
+
+但是对于调试来说还是可行的.
+
+路径映射保存在 Android Studio 项目的 <project>.iml 文件中.
+
+这样就能获得当前应用的job目录名
+
+	$ arm-linux-androideabi-readelf --string-dump=.debug_str build/armv7-android/libdmengine.so | grep /job
+
+job目录命名类似 `job1298751322870374150`, 每次编译都随机命名.
+

+ 136 - 0
docs/zh/manuals/extensions-debugging-ios.md

@@ -0,0 +1,136 @@
+---
+title: 在 iOS/macOS 中调试
+brief: 本教程介绍了如何使用 XCode 进行调试.
+---
+
+# 在 iOS/macOS 中调试
+
+这里我们介绍如何使用 [XCode](https://developer.apple.com/xcode/), Apple的 macOS 和 iOS 首选开发环境来调试应用.
+
+## Xcode
+
+* 使用 bob, 加上 `--with-symbols` 选项打包应用
+
+		$ cd myproject
+		$ wget http://d.defold.com/archive/<sha1>/bob/bob.jar
+		$ java -jar bob.jar --platform armv7-darwin build --with-symbols debug --archive bundle -bo build/ios -mp <app>.mobileprovision --identity "iPhone Developer: Your Name (ID)"
+
+* 安装应用, 可以通过 `XCode`, `iTunes` 或者 [ios-deploy](https://github.com/ios-control/ios-deploy)
+
+		$ ios-deploy -b <AppName>.ipa
+
+* 得到 `.dSYM` 文件夹 (即调试 symbols)
+
+	* 如果没使用原生扩展, 可以从 [d.defold.com](http://d.defold.com) 下载 `.dSYM` 文件
+
+	* 如果使用了原生扩展, 可以使用 [bob.jar](https://www.defold.com/manuals/bob/) 生成 `.dSYM` 文件夹. 只需要 building (不需要 archive 和 bundling):
+
+			$ cd myproject
+			$ unzip .internal/cache/arm64-ios/build.zip
+			$ mv dmengine.dSYM <AppName>.dSYM
+			$ mv <AppName>.dSYM/Contents/Resources/DWARF/dmengine <AppName>.dSYM/Contents/Resources/DWARF/<AppName>
+
+
+### 创建项目
+
+要正确的调试, 我们需要一个项目, 以及一个代码映射(source map).
+这次项目不是用来编译的, 只是调试举例.
+
+*新建 XCode 项目, 选择 `Game` 模板
+
+	![project_template](images/extensions/debugging/ios/project_template.png)
+
+* 指定一个名字 (例如 `debug`) 并且使用默认设置
+
+* 选择一个存放项目的目录
+
+* 为应用加入代码文件
+
+	![add_files](images/extensions/debugging/ios/add_files.png)
+
+* 确保 "Copy items if needed" 未选中.
+
+	![add_source](images/extensions/debugging/ios/add_source.png)
+
+* 结果是这样
+
+	![added_source](images/extensions/debugging/ios/added_source.png)
+
+
+* 关闭 `Build` 步骤
+
+	![edit_scheme](images/extensions/debugging/ios/edit_scheme.png)
+
+	![disable_build](images/extensions/debugging/ios/disable_build.png)
+
+* 设置 `Deployment target` 版本
+
+	![deployment_version](images/extensions/debugging/ios/deployment_version.png)
+
+* 设置目标设备
+
+	![select_device](images/extensions/debugging/ios/select_device.png)
+
+
+### 启动调试器
+
+调试应用有如下方法
+
+* 可以使用 `Debug` -> `Attach to process...` 然后选择要调试应用
+
+* 也可以选择 `Attach to process by PID or Process name`
+
+	![select_device](images/extensions/debugging/ios/attach_to_process_name.png)
+
+	然后在设备上启动应用
+
+* 在 `Edit Scheme` 中加入 <AppName>.app 作为可运行文件夹
+
+### 调试 symbols
+
+**要使用 lldb, 运行必须先暂停**
+
+* 把 `.dSYM` 目录加入到 lldb 中
+
+		(lldb) add-dsym <PathTo.dSYM>
+
+	![add_dsym](images/extensions/debugging/ios/add_dsym.png)
+
+* 确认 `lldb` 成功读取 symbols
+
+		(lldb) image list <AppName>
+
+### 路径映射
+
+* 加入引擎路径 (根据你的安装目录自行调整)
+
+		(lldb) settings set target.source-map /Users/builder/ci/builds/engine-ios-64-master/build /Users/mathiaswesterdahl/work/defold
+		(lldb) settings append target.source-map /private/var/folders/m5/bcw7ykhd6vq9lwjzq1mkp8j00000gn/T/job4836347589046353012/upload/videoplayer/src /Users/mathiaswesterdahl/work/projects/extension-videoplayer-native/videoplayer/src
+
+	* 从可运行文件夹里可以得到 job 文件夹.
+	job 文件夹命名类似这样 `job1298751322870374150`, 每次都是随机数字.
+
+			$ dsymutil -dump-debug-map <executable> 2>&1 >/dev/null | grep /job
+
+* 验证路径映射
+
+		(lldb) settings show target.source-map
+
+可以使用如下命令确定 symbol 的源代码文件
+
+	(lldb) image lookup -va <SymbolName>
+
+
+### 断点
+
+* 从 project 视图打开一个文件, 然后设置断点
+
+	![breakpoint](images/extensions/debugging/ios/breakpoint.png)
+
+## 注意
+
+### 检查二进制文件 UUID
+
+为了让调试器接受 `.dSYM` 文件夹, UUID 需要与可运行文件的 UUID 相匹配. 你可以这样检查 UUID:
+
+	$ dwarfdump -u <PathToBinary>

+ 148 - 0
docs/zh/manuals/extensions-debugging.md

@@ -0,0 +1,148 @@
+---
+title: 调试原生代码
+brief: 本教程介绍了一些调试应用以及解析崩溃日志的方法.
+---
+
+# 调试原生代码
+
+这里我们介绍了一些调试应用以及读取崩溃日志的方法.
+
+## 调试器
+
+当你的代码出现问题时,
+有一些方法可以找到问题根源.
+
+最普通的就是使用 `调试器`.
+调试可以让你在代码中步进, 设置 `断点` 而且能在崩溃时冻结运行.
+
+各个平台都有一些调试器.
+
+* Visual studio - Windows
+* VSCode - Windows, macOS, Linux
+* Android Studio - Windows, macOS, Linux
+* XCode - macOS
+* WinDBG - Windows
+* lldb / gdb - macOS, Linux, (Windows)
+* ios-deploy - macOS
+
+各个工具可以用来调试特定平台应用:
+
+* Visual studio - Windows + platforms supporting gdbserver (E.g. Linux/Android)
+* VSCode - Windows, macOS (lldb), Linux (lldb/gdb) + platforms supporting gdbserver
+* XCode -  macOS, iOS
+* Android Studio - Android
+* WinDBG - Windows
+* lldb/gdb - macOS, Linux, (iOS)
+* ios-deploy - iOS (via lldb)
+
+
+## 打印调试信息
+
+有些时候, 需要在代码里加入 printf() 声明.
+之后, 你就可以从设备上获取日志文件来分析它.
+
+注意 Defold 的debug编译版本默认只输出 dmLog* 函数结果.
+
+### [Android](/manuals/extensions-debugging-android.md)
+
+在 Android 上, 获取日志最简单办法是通过终端的 `adb`.
+还可以在 Android Studio 里使用 `console`, 这俩是一样的.
+
+如果你从 Android 日志中获得了跟踪堆栈, 你可能要使用 [ndk-stack](https://developer.android.com/ndk/guides/ndk-stack.html) 来进行解析.
+
+### [iOS](/manuals/extensions-debugging-ios.md)
+
+在 iOS 中, 你要使用 iTunes 或者 XCode 来观察设备日志.
+
+## Defold 崩溃日志
+
+当 Defold 引擎硬崩溃时会保存一个 `_crash` 文件.
+它包含了关于系统和崩溃的信息.
+
+你可以使用 [crash module](https://www.defold.com/ref/crash/) 来读取这个文件.
+
+鼓励你读取文件, 收集信息然后放送到自己适用的服务器上来归集数据.
+
+### 获取设备上的崩溃日志
+
+#### Android
+
+adb 可以显示此文件在哪 (不同设备保存位置不同)
+
+如果应用是 [可调试的](https://www.defold.com/manuals/project-settings/#android), 可以这样获取崩溃日志:
+
+	$ adb shell "run-as com.defold.adtest sh -c 'cat /data/data/com.defold.adtest/files/_crash'" > ./_crash
+
+#### iOS
+
+在 iTunes 中, 你可以 view/download 应用容器.
+
+在 `XCode -> Devices` 窗口中, 也可以选择崩溃日志
+
+
+## Symbolication
+
+如果你从 `_crash` 文件或者日志文件获得了调用堆栈, 就可以开始解析它.
+也就是把各个调用堆栈的地址转化为文件名和代码行, 这样有助于找到出问题的原因.
+
+### 获取正确的引擎
+
+使调用堆栈匹配正确的引擎是很重要的.
+否则很容易让你调试到不正确的地方.
+
+而且, 如果编译时使用了原生扩展, 确保添加了 [--with-symbols](https://www.defold.com/manuals/bob/) 选项
+以便从编译服务器获取所需信息. 比如, 可以在 iOS/macOS 的编译文件 `build.zip` 里找到 `dmengine.dSYM` 文件夹.
+
+Android/Linux 可运行文件已经包含了调试信息.
+
+还有, 你要持有引擎的完整版.
+这样有助于分析调试文件的调用堆栈.
+
+
+### Android
+
+1. 从 build 文件夹获取
+
+	$ ls <project>/build/<platform>/[lib]dmengine[.exe|.so]
+
+1. 解压缩:
+
+	$ unzip dmengine.apk -d dmengine_1_2_105
+
+1. 找到调用堆栈地址
+
+	也就是分析前的调用堆栈, 类似这样
+
+	#00 pc 00257224 libmy_game_name.so
+
+	其中 *00257224* 就是地址
+
+1. 解析地址
+
+    $ arm-linux-androideabi-addr2line -C -f -e dmengine_1_2_105/lib/armeabi-v7a/libdmengine.so _address_
+
+### iOS
+
+1. 如果使用了原生扩展, 服务器会提供解析文件 (.dSYM) 给你 (使用 bob.jar 加 "--with-symbols" 选项)
+
+	$ unzip <project>/build/arm64-darwin/build.zip
+	# 可以解压出 Contents/Resources/DWARF/dmengine
+
+1. 如果未使用原生扩展, 下载解析文件:
+
+	$ wget http://d.defold.com/archive/<sha1>/engine/arm64-darwin/dmengine.dSYM
+
+1. 使用载入地址进行解析
+
+	如果, 简单的输入调用堆栈地址不管用 (即 载入地址 0x0)
+
+		$ atos -arch arm64 -o Contents/Resources/DWARF/dmengine 0x1492c4
+
+	# 直接输入载入地址也不管用
+
+		$ atos -arch arm64 -o MyApp.dSYM/Contents/Resources/DWARF/MyApp -l0x100000000 0x1492c4
+
+	把载入地址加到地址里就管用了:
+
+		$ atos -arch arm64 -o MyApp.dSYM/Contents/Resources/DWARF/MyApp 0x1001492c4
+		dmCrash::OnCrash(int) (in MyApp) (backtrace_execinfo.cpp:27)

+ 31 - 0
docs/zh/manuals/extensions-defold-sdk.md

@@ -0,0 +1,31 @@
+---
+title: 原生扩展 - Defold SDK
+brief: 本教程介绍了创建原生扩展时如何使用 Defold SDK.
+---
+
+# Defold SDK
+
+Defold SDK 包含了应用运行的原生平台底层接口与高层Lua逻辑接口来实现原生扩展的功能.
+
+## 用法
+
+你可以通过引用 `dmsdk/sdk.h` 头文件来使用 Defold SDK:
+
+    #include <dmsdk/sdk.h>
+
+这个头文件并不公开发布但是SDK的所有功能都在 [API](/ref/dmExtension/) 里写明了. SDK包含以下命名空间和功能:
+
+* [Align](/ref/dmAlign/) - 公共宏. 用来保证编译器兼容
+* [Array](/ref/dmArray/) - 具有边界检测的模板化数组.
+* [Buffer](/ref/dmBuffer/) - 数据缓存功能是不同平台互相交流的主要途径. [Lua API](/ref/buffer/) 同样具有缓存功能.
+* [Condition Variable](/ref/dmConditionVariable/) - 条件变量.
+* [ConfigFile](/ref/dmConfigFile/) - 配置文件的存取功能. 配置文件是 game.project 文件的编译后版本.
+* [Extension](/ref/dmExtension/) - 创建和控制引擎扩展的功能.
+* [Graphics](/ref/dmGraphics/) - 特定原生平台的图像功能.
+* [Hash](/ref/dmHash/) - 哈希功能.
+* [Json](/ref/dmJson/) - 平台与关的json解析器.
+* [Log](/ref/dmLog/) - 日志功能.
+* [Mutex](/ref/dmMutex/) - 平台无关的互斥同步基础功能
+* [Script](/ref/dmScript/) - 内建脚本运行环境.
+* [Shared Library](/ref/sharedlibrary/) - 共享库导入导出功能
+* [Sony vector Math Library](/manuals/assets/Vector_Math_Library-Overview.pdf) - Sony 矢量计算库 主要为了3D图像和3D, 4D矢量运算, 矩阵运算和四元运算.

+ 61 - 0
docs/zh/manuals/extensions-details.md

@@ -0,0 +1,61 @@
+---
+title: 原生扩展 - 详述
+brief: 本教程介绍了有关编译系统用来编译原生扩展的一些细节.
+---
+
+# Defold 编译器 (流程应该是 编译--构建--打包,  为了方便这里把编译和构建统称为了编译)
+
+为了让你的扩展整合更加方便, 我们这里列举了一些编译相关的细节.
+
+在创建 Defold 引擎扩展的时候, 要考虑一些事情.
+对于更全面的如何开发跨平台原生代码以及扩展/Lua API的使用, 请参考 [原生扩展 - 最佳实践](/manuals/extensions-best-practices)
+
+## C++ 版本
+
+在引擎里我们用的都是不会高于C++98的版本. 你在开发扩展时可能使用了更高的版本, 注意高版本可能会引入 ABI 的变化. 这可能导致你无法在引擎或者asset store里使用你的扩展.
+
+要记住创建代码库 (比如扩展)时, 最好选择最具兼容性的版本.
+
+## 工具链
+
+Clang - macOS, iOS, Win32, Android
+GCC - Linux
+
+*我们打算以后也给Linux使用 clang *
+
+### SDK 版本
+
+* Android: NDK 20r, Build Tools 23.0.2, Api Level 16 for armv7 and Api level 21 for arm64
+* iOS: iPhoneOS11.2.sdk
+* MacOS: MacOSX10.13.sdk
+* Windows: WindowsKits 8.1 + 10.0, Microsoft Visual Studio 14.0
+* Linux: Ubuntu 16.04, gcc 5.4.0, libssl-dev, uuid-dev, libxi-dev, libopenal-dev, libgl1-mesa-dev, libglw1-mesa-dev, freeglut3-dev
+* Html5: Emscripten 1.38.0,
+
+### C++ 版本 + ABI 兼容
+
+* Linux: `GCC 5.4.0`
+* Android:`GCC 4.9`
+* Html5: `Emscripten 1.35.0`
+* Win32: `Microsoft Visual Studio 14.0` 或 `clang-6.0`
+* iOS/MacOS: `apple-clang` 或 `clang-6.0`
+
+对于 iOS/MacOS, 我们分别使用了 `-miphoneos-version-min=8.0` 和 `-mmacosx-version-min=10.7`.
+
+由于我们不指定 C++ 版本, 所以各个编译器都使用了默认设置.
+
+## Win32 + Clang
+
+近来的版本能够在Windows上使用clang.
+这使得我们编译服务器运行更快速, 同时打包更精简.
+
+## 静态链接
+
+自定义引擎使用静态链接进行编译.
+主要原因时 iOS 版本 < 8 时, app store 不支持运行一个 .ipa 里的多个可执行程序.
+
+## 没有 C++ Exceptions
+
+在引擎里我们不使用任何C++ Exceptions.
+游戏引擎基本用不到, 因为 (大多数) 游戏数据在引擎开发时是未知的.
+移除 C++ exceptions 支持能够减小包体提升运行效率.

+ 270 - 0
docs/zh/manuals/extensions-manifest-merge-tool.md

@@ -0,0 +1,270 @@
+---
+title: 原生扩展 - Manifest 混合工具
+brief: 本教程介绍了应用的 manifests 混合是如何工作的
+---
+
+# Application manifests
+
+一些平台上需要提供 manifests 片段 (或称存根) 来为扩展提供支持.
+可以是部分 `AndroidManifest.xml`, `Info.plist` 或者 `engine_template.html`
+
+从应用基础 manifest 开始, 每个扩展 manifest 存根一个一个的被使用.
+基础 manifest 可以是默认的 (位于 `builtins\manifests\<platforms>\...`), 也可以是由用户自定义的.
+
+## 命名和结构
+
+扩展 manifests 必须被放置在适当的指定位置才能生效.
+
+    /myextension
+        ext.manifest
+        /manifests
+            /android
+                AndroidManifest.xml
+            /ios
+                Info.plist
+            /osx
+                Info.plist
+            /web
+                engine_template.html
+
+
+## Android
+
+Android 平台提供了 manifest 混合工具 (基于 `ManifestMerger2`), `bob.jar` 中使用此工具混合 Manifest.
+关于 Android manifests 的详细信息, 参见 [官方文档](https://developer.android.com/studio/build/manifest-merge)
+
+::: 注意
+如果扩展 manifest 中没有设置应用的 `android:targetSdkVersion` , 下列权限会被自动加入:  `WRITE_EXTERNAL_STORAGE`, `READ_PHONE_STATE`, `READ_EXTERNAL_STORAGE`. 详情请见 [此文档](https://developer.android.com/studio/build/manifest-merge#implicit_system_permissions).
+我们推荐这么设置: `<uses-sdk android:targetSdkVersion=“{{android.target_sdk_version}}” />`
+:::
+### 示例
+
+基础 manifest
+
+```xml
+    <?xml version='1.0' encoding='utf-8'?>
+    <manifest xmlns:android='http://schemas.android.com/apk/res/android'
+            package='com.defold.testmerge'
+            android:versionCode='14'
+            android:versionName='1.0'
+            android:installLocation='auto'>
+        <uses-feature android:required='true' android:glEsVersion='0x00020000' />
+        <uses-sdk android:minSdkVersion='9' android:targetSdkVersion='26' />
+        <application android:label='Test Project' android:hasCode='true'>
+        </application>
+        <uses-permission android:name='android.permission.VIBRATE' />
+    </manifest>
+```
+
+扩展 manifest:
+
+```xml
+    <?xml version='1.0' encoding='utf-8'?>
+    <manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.defold.testmerge'>
+         <uses-sdk android:targetSdkVersion=“{{android.target_sdk_version}}” />
+        <uses-feature android:required='true' android:glEsVersion='0x00030000' />
+        <application>
+            <meta-data android:name='com.facebook.sdk.ApplicationName'
+                android:value='Test Project' />
+            <activity android:name='com.facebook.FacebookActivity'
+              android:theme='@android:style/Theme.Translucent.NoTitleBar'
+              android:configChanges='keyboard|keyboardHidden|screenLayout|screenSize|orientation'
+              android:label='Test Project' />
+        </application>
+    </manifest>
+```
+
+混合结果
+
+```xml
+    <?xml version='1.0' encoding='utf-8'?>
+    <manifest xmlns:android='http://schemas.android.com/apk/res/android'
+        package='com.defold.testmerge'
+        android:installLocation='auto'
+        android:versionCode='14'
+        android:versionName='1.0' >
+        <uses-sdk
+            android:minSdkVersion='9'
+            android:targetSdkVersion='26' />
+        <uses-permission android:name='android.permission.VIBRATE' />
+        <uses-feature
+            android:glEsVersion='0x00030000'
+            android:required='true' />
+        <application
+            android:hasCode='true'
+            android:label='Test Project' >
+            <meta-data
+                android:name='com.facebook.sdk.ApplicationName'
+                android:value='Test Project' />
+            <activity
+                android:name='com.facebook.FacebookActivity'
+                android:configChanges='keyboard|keyboardHidden|screenLayout|screenSize|orientation'
+                android:label='Test Project'
+                android:theme='@android:style/Theme.Translucent.NoTitleBar' />
+        </application>
+    </manifest>
+```
+
+## iOS / macOS
+
+对于 `Info.plist` 我们实现了专用的混合工具.
+列表和字典都是支持的.
+
+### 示例
+
+基础 Manifest
+
+```xml
+    <?xml version='1.0' encoding='UTF-8'?>
+    <!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN' 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'>
+    <plist version='1.0'>
+    <dict>
+            <key>NSAppTransportSecurity</key>
+            <dict>
+                <key>NSExceptionDomains</key>
+                <dict>
+                    <key>foobar.net</key>
+                    <dict>
+                        <key>testproperty</key>
+                        <true/>
+                    </dict>
+                </dict>
+            </dict>
+            <key>INT</key>
+            <integer>8</integer>
+            <key>REAL</key>
+            <real>8.0</real>
+            <key>BASE64</key>
+            <data>SEVMTE8gV09STEQ=</data>
+    </dict>
+    </plist>
+```
+
+扩展 manifest:
+
+```xml
+    <?xml version='1.0' encoding='UTF-8'?>
+    <!DOCTYPE plist PUBLIC '-//Apple//DTD PLIST 1.0//EN' 'http://www.apple.com/DTDs/PropertyList-1.0.dtd'>
+    <plist version='1.0'>
+    <dict>
+        <key>NSAppTransportSecurity</key>
+        <dict>
+            <key>NSExceptionDomains</key>
+            <dict>
+                <key>facebook.com</key>
+                <dict>
+                    <key>NSIncludesSubdomains</key>
+                    <true/>
+                    <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
+                    <false/>
+                </dict>
+            </dict>
+        </dict>
+        <key>INT</key>
+        <integer>42</integer>
+    </dict>
+    </plist>
+```
+
+混合结果:
+
+```xml
+    <?xml version='1.0'?>
+    <!DOCTYPE plist SYSTEM 'file://localhost/System/Library/DTDs/PropertyList.dtd'>
+    <plist version='1.0'>
+        <dict>
+            <key>NSAppTransportSecurity</key>
+            <dict>
+                <key>NSExceptionDomains</key>
+                <dict>
+                    <key>foobar.net</key>
+                    <dict>
+                        <key>testproperty</key>
+                        <true/>
+                    </dict>
+                    <key>facebook.com</key>
+                    <dict>
+                        <key>NSIncludesSubdomains</key>
+                        <true/>
+                        <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
+                        <false/>
+                    </dict>
+                </dict>
+            </dict>
+            <key>INT</key>
+            <integer>8</integer>
+            <key>REAL</key>
+            <real>8.0</real>
+            <key>BASE64</key>
+            <data>SEVMTE8gV09STEQ=</data>
+            <key>INT</key>
+            <integer>42</integer>
+        </dict>
+    </plist>
+```
+
+
+## HTML5
+
+对于 html 模板, 我们给各部分命名, 以便混合时相匹配 (比如 "engine-start").
+标签属性可以是 `merge` 或者 `keep`. `merge` 是默认值.
+
+### 示例
+
+基础 manifest
+
+```html
+    <!DOCTYPE html>
+    <html>
+    <body>
+     <script id='engine-loader' type='text/javascript' src='dmloader.js'></script>
+     <script id='engine-setup' type='text/javascript'>
+     function load_engine() {
+         var engineJS = document.createElement('script');
+         engineJS.type = 'text/javascript';
+         engineJS.src = '{{exe-name}}_wasm.js';
+         document.head.appendChild(engineJS);
+     }
+     </script>
+     <script id='engine-start' type='text/javascript'>
+         load_engine();
+     </script>
+    </body>
+    </html>
+```
+
+扩展 manifest
+
+```html
+    <html>
+    <body>
+     <script id='engine-loader' type='text/javascript' src='mydmloader.js'></script>
+     <script id='engine-start' type='text/javascript' merge='keep'>
+         my_load_engine();
+     </script>
+    </body>
+    </html>
+```
+
+混合结果
+
+```html
+    <!doctype html>
+    <html>
+    <head></head>
+    <body>
+        <script id='engine-loader' type='text/javascript' src='mydmloader.js'></script>
+        <script id='engine-setup' type='text/javascript'>
+            function load_engine() {
+                var engineJSdocument.createElement('script');
+                engineJS.type = 'text/javascript';
+                engineJS.src = '{{exe-name}}_wasm.js';
+                document.head.appendChild(engineJS);
+            }
+        </script>
+        <script id='engine-start' type='text/javascript' merge='keep'>
+            my_load_engine();
+        </script>
+    </body>
+    </html>
+```

+ 54 - 0
docs/zh/manuals/extensions-script-api.md

@@ -0,0 +1,54 @@
+---
+title: 为原生扩展提供编辑器代码提示
+brief: 本教程介绍了如何创建脚本 API 定义, 以便 Defold 编辑器能为用户提供代码提示功能.
+---
+
+# 原生扩展的代码提示
+
+Defold 编辑器为所有 Defold API 功能以及用户引用的Lua模块提供代码提示. 但是编辑器无法为原生扩展暴露的功能. 原生扩展可以在单独一个文件里提供 API 定义来实现代码提示功能.
+
+
+## 创建脚本 API 定义文件
+
+脚本 API 定义文件使用扩展名 `.script_api`. 必须以 [YAML 格式](https://yaml.org/) 与扩展文件放在一起. 一般脚本 API 定义像这样:
+
+```yml
+- name: 扩展名
+  type: table
+  desc: 扩展描述
+  members:
+  - name: 成员名1
+    type: 成员类型
+    desc: 成员描述
+    # 如果成员是 "function"
+    parameters:
+    - name: 参数名1
+      type: 参数类型
+      desc: 参数描述
+    - name: 参数名2
+      type: 参数类型
+      desc: 参数描述
+    # 如果成员是 "function"
+    returns:
+    - name: 返回值名
+      type: 返回值类型
+      desc: 返回值描述
+    examples:
+    - desc: 成员使用示例1
+    - desc: 成员使用示例2
+
+  - name: 成员名2
+    ...
+```
+
+数据类型有 `table, string , boolean, number, function` 几种. 如果一个值有多个类型则这样写 `[type1, type2, type3]`.
+:::注意
+目前编辑器里不显示类型. 但是还是鼓励输入类型以便以后编辑器可以显示出来.
+:::
+
+## 例子
+
+实际使用实例参见下面的扩展:
+
+* [Facebook 扩展](https://github.com/defold/extension-facebook/tree/master/facebook/api)
+* [WebView 扩展](https://github.com/defold/extension-webview/blob/master/webview/api/webview.script_api)

+ 238 - 0
docs/zh/manuals/extensions.md

@@ -0,0 +1,238 @@
+---
+title: 为 Defold 编写原生扩展
+brief: This manual explains how to write a native extension for the Defold game engine and how to compile it through the zero setup cloud builders.
+---
+
+# Native extensions
+
+If you need custom interaction with external software or hardware on a low level where Lua won't suffice, the Defold SDK allows you to write extensions to the engine in C, C++, Objective C, Java or Javascript, depending on target platform. Typical use cases for native extensions are:
+
+- Interaction with specific hardware, for instance the camera on mobile phones.
+- Interaction with external low level APIs, for instance advertising network APIs that do not allow interaction through network APIs where Luasocket could be used.
+- High performance calculations and data processing.
+
+## The build platform
+
+Defold provides a zero setup entry point to native extensions with a cloud based build solution. Any native extension that is developed and added to a game project becomes part of the ordinary project content. There is no need to build special versions of the engine and distribute them to team members, that is handled automatically---any team member that builds and runs the project will get a project specific engine executable with all native extensions baked in.
+
+![Cloud build](images/extensions/cloud_build.png)
+
+## Project layout
+
+To create a new extension, create a folder in the project root. This folder will contain all settings, source code, libraries and resources associated with the extension. The extension builder recognizes the folder structure and collects any source files and libraries.
+
+![Project layout](images/extensions/layout.png)
+
+*ext.manifest*
+: The extension folder _must_ contain an *ext.manifest* file. This file is a YAML format file that is picked up by the extension builder. A minimal manifest file should contain the name of the extension.
+
+*src*
+: This folder should contain all source code files.
+
+*include*
+: This optional folder contains any include files.
+
+*lib*
+: This optional folder contains any compiled libraries that the extension depends on. Library files should be placed in subfolders named by `platform`, or `architecure-platform`, depending on what architectures are supported by your libraries.
+
+  :[platforms](../shared/platforms.md)
+
+*res*
+: This optional folder contains any extra resources that the extension depends on. Resource files should be placed in subfolders named by `platform`, or `architecure-platform` just as the "lib" subfolders. A subfolder `common` is also allowed, containing resource files common for all platforms.
+
+## Sharing an extension
+
+Extensions are treated just like any other assets in your project and they can be shared in the same way. If a native extension folder is added as a Library folder it can be shared and used by others as a project dependency. Refer to the [Library project manual](/manuals/libraries/) for more information.
+
+## A simple example extension
+
+Let's build a very simple extension. First, we create a new root folder *myextension* and add a file *ext.manifest* containing the name of the extension "MyExtension". Note that the name is a C++ symbol and must match the first argument to `DM_DECLARE_EXTENSION` (see below).
+
+![Manifest](images/extensions/manifest.png)
+
+```yaml
+# C++ symbol in your extension
+name: "MyExtension"
+```
+
+The extension consists of a single C++ file, *myextension.cpp* that is created in the "src" folder.
+
+![C++ file](images/extensions/cppfile.png)
+
+The extension source file contains the following code:
+
+```cpp
+// myextension.cpp
+// Extension lib defines
+#define LIB_NAME "MyExtension"
+#define MODULE_NAME "myextension"
+
+// include the Defold SDK
+#include <dmsdk/sdk.h>
+#include <stdlib.h>
+
+static int Rot13(lua_State* L)
+{
+    int top = lua_gettop(L);
+
+    // Check and get parameter string from stack
+    const char* str = luaL_checkstring(L, 1);
+
+    // Allocate new string
+    int len = strlen(str);
+    char *rot = (char *) malloc(len + 1);
+
+    // Iterate over the parameter string and create rot13 string
+    for(int i = 0; i <= len; i++) {
+        const char c = str[i];
+        if((c >= 'A' && c <= 'M') || (c >= 'a' && c <= 'm')) {
+            // Between A-M just add 13 to the char.
+            rot[i] = c + 13;
+        } else if((c >= 'N' && c <= 'Z') || (c >= 'n' && c <= 'z')) {
+            // If rolling past 'Z' which happens below 'M', wrap back (subtract 13)
+            rot[i] = c - 13;
+        } else {
+            // Leave character intact
+            rot[i] = c;
+        }
+    }
+
+    // Put the rotated string on the stack
+    lua_pushstring(L, rot);
+
+    // Free string memory. Lua has a copy by now.
+    free(rot);
+
+    // Assert that there is one item on the stack.
+    assert(top + 1 == lua_gettop(L));
+
+    // Return 1 item
+    return 1;
+}
+
+// Functions exposed to Lua
+static const luaL_reg Module_methods[] =
+{
+    {"rot13", Rot13},
+    {0, 0}
+};
+
+static void LuaInit(lua_State* L)
+{
+    int top = lua_gettop(L);
+
+    // Register lua names
+    luaL_register(L, MODULE_NAME, Module_methods);
+
+    lua_pop(L, 1);
+    assert(top == lua_gettop(L));
+}
+
+dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
+{
+    return dmExtension::RESULT_OK;
+}
+
+dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
+{
+    // Init Lua
+    LuaInit(params->m_L);
+    printf("Registered %s Extension\n", MODULE_NAME);
+    return dmExtension::RESULT_OK;
+}
+
+dmExtension::Result AppFinalizeMyExtension(dmExtension::AppParams* params)
+{
+    return dmExtension::RESULT_OK;
+}
+
+dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
+{
+    return dmExtension::RESULT_OK;
+}
+
+
+// Defold SDK uses a macro for setting up extension entry points:
+//
+// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
+
+// MyExtension is the C++ symbol that holds all relevant extension data.
+// It must match the name field in the `ext.manifest`
+DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, 0, 0, FinalizeMyExtension)
+```
+
+Note the macro `DM_DECLARE_EXTENSION` that is used to declare the various entry points into the extension code. The first argument `symbol` must match the name specified in *ext.manifest*. For this simple example, there is no need for any "update" or "on_event" entry points, so `0` is provided in those locations to the macro.
+
+Now it is just a matter of building the project (<kbd>Project ▸ Build and Launch</kbd>). This will upload the extension to the extension builder which will produce a custom engine with the new extension included. If the builder encounters any errors, a dialog with the build errors will show.
+
+To test the extension, create a game object and add a script component with some test code:
+
+```lua
+local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+local rot_s = myextension.rot13(s)
+print(rot_s) --> nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM
+```
+
+And that's it! We have created a fully working native extension.
+
+## Defined platform identifiers
+
+The following identifiers are defined by the builder on each respective platform:
+
+* DM_PLATFORM_WINDOWS
+* DM_PLATFORM_OSX
+* DM_PLATFORM_IOS
+* DM_PLATFORM_ANDROID
+* DM_PLATFORM_LINUX
+* DM_PLATFORM_HTML5
+
+## The ext.manifest file
+
+Apart from the name of the extension, the manifest file can contain platform specific compile flags, link flags, libs and frameworks. If the *ext.manifest* file does not contain a "platforms" segment, or a platform is missing from the list, the platform you bundle for will still build, but without any extra flags set.
+
+Here is an example:
+
+```yaml
+name: "AdExtension"
+
+platforms:
+    arm64-ios:
+        context:
+            frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
+            flags:      ["-stdlib=libc++"]
+            linkFlags:  ["-ObjC"]
+            libs:       ["z", "c++", "sqlite3"]
+            defines:    ["MY_DEFINE"]
+
+    armv7-ios:
+        context:
+            frameworks: ["CoreGraphics", "CFNetwork", "GLKit", "CoreMotion", "MessageUI", "MediaPlayer", "StoreKit", "MobileCoreServices", "AdSupport", "AudioToolbox", "AVFoundation", "CoreGraphics", "CoreMedia", "CoreMotion", "CoreTelephony", "CoreVideo", "Foundation", "GLKit", "JavaScriptCore", "MediaPlayer", "MessageUI", "MobileCoreServices", "OpenGLES", "SafariServices", "StoreKit", "SystemConfiguration", "UIKit", "WebKit"]
+            flags:      ["-stdlib=libc++"]
+            linkFlags:  ["-ObjC"]
+            libs:       ["z", "c++", "sqlite3"]
+            defines:    ["MY_DEFINE"]
+```
+
+### Allowed keys
+
+Allowed keys are for platform specific compile flags are:
+
+* `frameworks` - Apple frameworks to include when building (iOS and OSX)
+* `flags` - Flags that should be passed to the compiler
+* `linkFlags` - Flags that should be passed to the linker
+* `libs` - Libraries to include when linking
+* `defines` - Defines to set when building
+* `aaptExtraPackages` - Extra package name that should be generated (Android)
+* `aaptExcludePackages` - Regexp (or exact names) of packages to exclude (Android)
+* `aaptExcludeResourceDirs` - Regexp (or exact names) of resource dirs to exclude (Android)
+
+## Example extensions
+
+* [Basic extension example](https://github.com/defold/template-native-extension) (the extension from this manual)
+* [Android extension example](https://github.com/defold/extension-android)
+* [HTML5 extension example](https://github.com/defold/extension-html5)
+* [MacOS, iOS and Android videoplayer extension](https://github.com/defold/extension-videoplayer)
+* [MacOS and iOS camera extension](https://github.com/defold/extension-camera)
+* [iOS and Android Admob extension](https://github.com/defold/extension-admob)
+
+The [Defold asset portal](https://www.defold.com/assets/) also contain several native extensions.

+ 212 - 0
docs/zh/manuals/facebook.md

@@ -0,0 +1,212 @@
+---
+title: Defold Facebook 教程
+brief: 本教程介绍了如何在 Defold 游戏中设置和整合 Facebook 功能.
+---
+
+# Facebook
+
+Facebook API 作为 [原生扩展](/manuals/extensions/) 提供. 此扩展使得 iOS, Android 和 HTML5 游戏可以使用 Facebook 的在线交互功能. Defold Facebook 扩展对于 iOS, Android 和 HTML5 (基于 Facebook Canvas) 不同平台封装了同一的 Facebook API 函数库. 要在游戏中使用 Facebook 在线交互功能, 首先需要有一个 Facebook 账户.
+
+## 安装扩展
+
+要使用 Facebook 扩展, 需要在 `game.project` 文件中设置依赖. 最新稳定版的 URL 是:
+```
+https://github.com/defold/extension-facebook/archive/master.zip
+```
+
+推荐使用 [指定版本](https://github.com/defold/extension-facebook/releases) 的zip包链接作为依赖.
+
+从 Defold 1.2.162 开始, 此扩展需要其他依赖:
+```
+https://github.com/defold/extension-gps/archive/master.zip
+```
+
+API 文档位于 [这里](https://defold.github.io/extension-facebook/).
+
+## 注册成为 Facebook 开发者
+
+开发 Facebook 应用首先要注册成为 Facebook 开发者. 这样你的 Defold 游戏就能与 Facebook 应用交互了.
+
+* 访问 [Facebook 开发者网站](https://developers.facebook.com) 进行注册
+* 登入你的 Facebook 账户.
+* 注册激活你的开发者身份.
+
+![Register as a developer](images/facebook/register_dev.png)
+![ developer](images/facebook/register_verify.png)
+
+## 创建 Facebook 应用
+
+下一步要创建一个 Facebook 应用. 右上角 <kbd>My Apps</kbd> 菜单列出了你的应用, 以及 <kbd>Add a New App</kbd> 按钮.
+
+![Add new app](images/facebook/add_new_app_menu.png)
+
+然后是选择目标平台界面. 点击 *basic setup* 可以略过引导界面.
+
+::: 注意
+引导界面里绝大多数内容与开发 Defold 游戏无关. 而且, 一般不需要自己修改 *Info.plist* 或者 *AndroidManifest.xml* 文件. Defold 会自动完成.
+:::
+
+![Add new app platform](images/facebook/add_new_app_platform.png)
+
+在 dashboard 里可以随意添加, 删除应用或者更改平台设置. 接下来需要设置 *Display Name*, *Namespace* 和 *Category*. 这些也都可以在 dashboard 里设置. 设置完后, Facebook 会给你的应用创建唯一id. *App ID* 是不可修改的.
+
+![New app id](images/facebook/new_app_id.png)
+
+![App dashboard settings](images/facebook/add_platform.png)
+
+点击 *Settings* 面板. 这里显示了 *App ID*. 你要在 Defold 游戏的 [项目设置](/manuals/project-settings) 里输入这个id. 通过 *Project Explorer* 打开 *game.project* 文件, 滚动到 *Facebook* 部分, 在 `Appid` 这里填入 *App ID*.
+
+现在回到 Facebook 网站的 *Settings* 页面, 点击 *+ Add Platform* 来为应用设置目标平台. 针对每个平台都有不同的设置.
+
+![Select platform](images/facebook/select_platform.png)
+
+## iOS
+
+iOS 平台需要填写和 *game.project* 里一样的 `bundle_identifier`.
+
+![iOS settings](images/facebook/settings_ios.png)
+
+## Android
+
+Android 平台需要填写 *Google Play Package Name*, 也就是 *game.project* 里的 *package* id. 还要在 *Key Hashes* 里填入证书的 Hashes. 可以使用 openssl 从 *certificate.pem* 文件生成 Hashes:
+
+```sh
+$ cat certificate.pem | openssl x509 -outform der | openssl sha1 -binary | openssl base64
+```
+
+(关于签名文件详细信息参见 [创建证书和密匙](/manuals/android/#creating-certificates-and-keys).)
+
+![Android settings](images/facebook/settings_android.png)
+
+## Facebook Canvas
+
+对于 HTML5 游戏, 过程略有不同. Facebook 需要直接在线访问你的游戏内容. 两个办法:
+
+![Facebook Canvas settings](images/facebook/settings_canvas.png)
+
+1. 使用 Facebook 的 *Simple Application Hosting*. 点击 *Yes* 使用在线托管. 选择 *uploaded assets* 打开托管资源管理器.
+
+    ![Simple hosting](images/facebook/simple_hosting.png)
+
+    托管类型选择 "HTML5 Bundle":
+
+    ![HTML5 bundle](images/facebook/html5_bundle.png)
+
+    把你的 HTML5 游戏包压缩为一个 .7z 或者 .zip 包上传至 Facebook. 点击 *Push to production* 即可在线发布.
+
+2. 另一个办法就是把你的 HTML5 游戏包托管到你自己选择的服务器上通过 HTTPS 访问. *Secure Canvas URL* 这里填写你的游戏地址.
+
+至此 Facebook 就能通过 *Canvas Page* 发布你的游戏了.
+
+## 小测试
+
+可以通过创建一个小测试来看看扩展工作是否顺利.
+
+1. 新建游戏对象然后在上面添加一个脚本.
+2. 脚本里加入如下代码 (需要 Facebook 扩展 v.2 版及以上):
+
+```lua
+local function get_me_callback(self, id, response)
+    -- The response table includes all the response data
+    pprint(response)
+end
+
+local function fb_login(self, data)
+    if data.status == facebook.STATE_OPEN then
+        -- Logged in ok. Let's try reading some "me" data through the
+        -- HTTP graph API.
+        local token = facebook.access_token()
+        local url = "https://graph.facebook.com/me/?access_token=" .. token
+        http.request(url, "GET", get_me_callback)
+    elseif data.status == facebook.STATE_CLOSED_LOGIN_FAILED then
+        -- Do something to indicate that login failed
+    end
+    if data.error then
+        -- An error occurred
+    else
+        -- No error
+    end
+end
+
+function init(self)
+    -- Log in with read permissions.
+    local permissions = { "public_profile", "email" }
+    facebook.login_with_permissions(permissions, facebook.AUDIENCE_EVERYONE, fb_login)
+end
+```
+
+直接运行, 控制台输出大概这样:
+
+```txt
+DEBUG:SCRIPT:
+{
+  status = 200,
+  headers = {
+    connection = keep-alive,
+    date = Fri, 04 Nov 2016 13:54:33 GMT,
+    etag = "0725a4f703fe6af27da183cfec0bb22637e331e0",
+    access-control-allow-origin = *,
+    content-length = 53,
+    expires = Sat, 01 Jan 2000 00:00:00 GMT,
+    content-type = text/javascript; charset=UTF-8,
+    x-fb-debug = Pr1qUssb8Xa3x3r1t913hHMdefh69DSYYV5vcxeOB7O33mcfShIw+r7BoLpn147I2wzLF2CZRTpnR3/VYOtFpA==,
+    facebook-api-version = v2.5,
+    cache-control = private, no-cache, no-store, must-revalidate,
+    pragma = no-cache,
+    x-fb-trace-id = F03S5dtsdaS,
+    x-fb-rev = 2664414,
+  }
+  response = {"name":"Max de Fold ","id":"14159265358979323"},
+}
+```
+
+* 完整的 Defold Facebook API 文档在 [这里](https://defold.github.io/extension-facebook/).
+* Facebook Graph API 在这里: https://developers.facebook.com/docs/graph-api
+
+
+## Facebook Analytics
+
+Facebook Analytics 可以对游戏相关信息汇总统计并提供适当建议, 比如开启游戏人数, 付款频率和其他各种信息.
+
+### 配置
+
+使用 Facebook Analytics 之前你得创建好 Facebook 应用. 然后就是把分析功能整合进去:
+
+![Add Facebook Analytics](images/facebook/add_facebook_analytics.png)
+
+分析功能也有很多配置选项. 详情请见:
+
+![Add Facebook Analytics](images/facebook/facebook_analytics_settings.png)
+
+### 使用
+
+分析功能配置好之后就可以通过发布分析事件来进行信息统计了:
+
+```lua
+function init(self)
+    -- post a spent credits event
+    local params = { [facebook.PARAM_LEVEL] = 30, [facebook.PARAM_NUM_ITEMS] = 2 }
+    facebook.post_event(facebook.EVENT_SPENT_CREDITS, 25, params)
+
+    -- post a custom event
+    local level = 19
+    local params = { kills = 23, gold = 4, xp = 890 }
+    facebook.post_event("level_completed", level, params)
+end
+```
+
+各种事件和参数详情请见 [Facebook 扩展 API 文档](https://defold.github.io/extension-facebook/). 这些应该与 Facebook 的 [标准事件](https://developers.facebook.com/docs/analytics/send_data/events#standard) 和 [参数](https://developers.facebook.com/docs/analytics/send_data/events#parameter) 文档相一致.
+
+除了分析统计事件, Defold 使用 Facebook SDK 时也会自动产生一些事件, 比如装机次数启动次数之类的. 详情请见 Facebook 的 [自动日志事件](https://developers.facebook.com/docs/analytics/send_data/events#autologged) 文档.
+
+事件汇总后会在 Facebook Analytics dashboard 中显示出来, 点击 *View Analytics* 按钮查看分析信息:
+
+![Add Facebook Analytics](images/facebook/facebook_analytics_open_dashboard.png)
+
+通过页面里 *Events* 选项可以看到各种事件:
+
+![Add Facebook Analytics](images/facebook/facebook_analytics_show_events.png)
+
+### Facebook 的事件分享
+
+你可以选择是否向 Facebook 分享你的事件数据. 通过 [`enable_event_usage()`](https://defold.github.io/extension-facebook/#enable_event_usage) 和 [`disable_event_usage()`](https://defold.github.io/extension-facebook/#disable_event_usage) 函数控制. 默认不分享.

+ 217 - 0
docs/zh/manuals/factory.md

@@ -0,0 +1,217 @@
+---
+title: Factory 组件教程
+brief: 本教程介绍了如何使用工厂组件在游戏运行时创建游戏对象.
+---
+
+# Factory 组件
+
+工厂组件用于在游戏运行时从对象池动态创建游戏对象.
+
+工厂组件的 *Prototype* 属性就是动态创建游戏对象的蓝图.
+
+![Factory component](images/factory/factory_collection.png)
+
+![Factory component](images/factory/factory_component.png)
+
+要创建游戏对象, 调用 `factory.create()`:
+
+```lua
+-- factory.script
+local p = go.get_position()
+p.y = vmath.lerp(math.random(), min_y, max_y)
+local component = "#star_factory"
+factory.create(component, p)
+```
+
+![Spawned game object](images/factory/factory_spawned.png)
+
+`factory.create()` 有5个参数:
+
+`url`
+: 工厂组件的id.
+
+`[position]`
+: (可选) 新创建游戏对象的世界坐标位置. 以 `vector3` 表示. 如果不指定位置, 默认位置是工厂组件游戏对象的位置.
+
+`[rotation]`
+: (可选) 新创建游戏对象的世界坐标旋转. 以 `quat` 表示.
+
+`[properties]`
+: (可选) 新创建游戏对象的属性初始化 Lua 表. 详情请见 [脚本属性教程](/manuals/script-properties).
+
+`[scale]`
+: (可选) 新创建游戏对象的等比缩放. 以 `number` (大于 0) 表示. 或者以 `vector3` 表示每个坐标轴上的非等比缩放.
+
+例如:
+
+```lua
+-- factory.script
+local p = go.get_position()
+p.y = vmath.lerp(math.random(), min_y, max_y)
+local component = "#star_factory"
+-- Spawn with no rotation but double scale.
+-- Set the score of the star to 10.
+factory.create(component, p, nil, { score = 10 }, 2.0) -- <1>
+```
+1. 设置 star 游戏对象的 "score" 属性.
+
+```lua
+-- star.script
+go.property("score", 1) -- <1>
+
+local speed = -240
+
+function update(self, dt)
+    local p = go.get_position()
+    p.x = p.x + speed * dt
+    if p.x < -32 then
+        go.delete()
+    end
+    go.set_position(p)
+end
+
+function on_message(self, message_id, message, sender)
+    if message_id == hash("collision_response") then
+        msg.post("main#gui", "add_score", {amount = self.score}) -- <2>
+        go.delete()
+    end
+end
+```
+1. "score" 脚本属性初始化时要有默认值.
+2. "score" 脚本属性保存在 "self" 中.
+
+![Spawned game object with property and scaling](images/factory/factory_spawned2.png)
+
+::: 注意
+Defold 目前不支持碰撞形状的非等比缩放. 如果赋了非等比值, 比如 `vmath.vector3(1.0, 2.0, 1.0)` 则 sprite 会正确缩放但是碰撞形状不会正确缩放.
+:::
+
+## 新对象引用和对象父级
+
+调用 `factory.create()` 会返回新游戏对象的id, 以便保存其引用. 通常把 id:s 保存到一个表里以便需要时统一删除, 比如重启关卡时:
+
+```lua
+-- spawner.script
+self.spawned_coins = {}
+
+...
+
+-- 把新建对象存入 "spawned_coins" 表中.
+local id = factory.create("#coinfactory", coin_position)
+table.insert(self.spawned_coins, id)
+```
+
+需要的时候:
+
+```lua
+-- coin.script
+-- 删除所有 coins.
+for _, coin_id = ipairs(self.spawned_coins) do
+    go.delete(coin_id)
+end
+
+-- 或者直接
+go.delete_all(self.spawned_coins)
+```
+
+另一种常见用法是创建新对象时保存一个引用, 同时新对象也保存脚本的一个引用, 等以后需要时可以给创建脚本发送通知消息:
+
+```lua
+-- spawner.script
+-- 创建 drone 然后设置其引用者为此脚本
+self.spawned_drone = factory.create("#dronefactory", drone_position, nil, { parent = msg.url() })
+
+...
+
+function on_message(self, message_id, message, sender)
+    if message_id == hash("drone_dead") then
+        self.spawed_drone = nil
+    end
+end
+```
+
+drone 的脚本:
+
+```lua
+-- drone.script
+go.property("parent", msg.url())
+
+...
+
+function final(self)
+    -- 析构时.
+    msg.post(self.parent, "drone_dead")
+end
+```
+
+## 工厂资源的动态加载
+
+开启工厂属性的 *Load Dynamically*, 工厂资源将会被延迟加载.
+
+![Load dynamically](images/factory/load_dynamically.png)
+
+关闭动态加载, 则加载工厂组件时会同时加载其需要的资源以便工厂可以尽快创建新游戏对象.
+
+开启动态加载, 有两种用法:
+
+同步加载
+: 调用 [`factory.create()`](/ref/factory/#factory.create) 函数创建新对象时. 资源会同步加载, 这意味着游戏可能会卡一下, 加载完成后再创建新对象.
+
+  ```lua
+  function init(self)
+      -- 工厂父级集合加载时
+      -- 工厂资源不会被加载. 调用 create 函数
+      -- 会把资源进行同步加载.
+      self.go_id = factory.create("#factory")
+  end
+  
+  function final(self)  
+      -- 删掉游戏对象, 资源引用计数减少
+      -- 本例中工厂资源也会被卸载
+      -- 因为工厂组件不包含对资源的引用.
+      go.delete(self.go_id)
+
+      -- 因为工厂组件不包含对资源的引用, 所以对工厂调用 unload 没有意义
+      factory.unload("#factory")
+  end
+  ```
+
+异步加载
+: 调用 [`factory.load()`](/ref/factory/#factory.load) 函数进行资源的异步加载. 资源加载完毕后, 回调用回调函数.
+
+  ```lua
+  function load_complete(self, url, result)
+      -- 资源加载完成, 可以新建对象
+      self.go_id = factory.create(url)
+  end
+  
+  function init(self)
+      -- 工厂父级集合加载时
+      -- 工厂资源不被加载. 调用 load 函数进行资源异步加载.
+      factory.load("#factory", load_complete)
+  end
+  
+  function final(self)
+      -- 删掉游戏对象, 资源引用计数减少
+      -- 本例中工厂资源不会被卸载
+      -- 因为工厂组件包含对资源的引用.
+      go.delete(self.go_id)
+  
+      -- 调用 unload 函数, 工厂对资源引用被释放,
+      -- 这样资源才会被卸载.
+      factory.unload("#factory")
+  end
+  ```
+
+## 实例限制
+
+项目设置 *Collection related settings* 部分 *max_instances* 限制了游戏世界 (启动集合 main.collection 或者通过集合代理加载的集合) 中游戏对象的最大数目. 不论是子编辑器里创建的还是用脚本动态创建的游戏对象综合不得超过这个最大值.
+
+![Max instances](images/factory/factory_max_instances.png)
+
+比如如果把 *max_instances* 设置为 1024 然后手动拖放 24 游戏对象到主集合, 那么最多还能创建 1000 个游戏对象. 如果删除一个对象, 就能再创建一个对象.
+
+## 游戏对象池
+
+使用游戏对象池提高对象重用性是个好办法. 然而, 游戏引擎已经使用对象池进行游戏对象管理, 用户就不必多此一举了. 不论删除还是创建对象, 都能保证稳定高效.
+

+ 355 - 0
docs/zh/manuals/flash.md

@@ -0,0 +1,355 @@
+---
+title: Flash 开发者 Defold 过渡教程
+brief: 本教程针对 Flash 游戏开发者对比介绍了 Defold 相对应的概念和方法.
+---
+
+# Flash 开发者 Defold 过渡
+
+本教程针对 Flash 游戏开发者对比介绍了 Defold 相对应的概念和方法.
+
+## 介绍
+
+Flash 上手快门槛低. 新用户开发方便入门, 短时间内就可以开发出简单的游戏. Defold 针对游戏开发提供了类似的易用工具集, 此外还对高端开发者提供了更自由的发挥空间 (比如自己编写渲染脚本).
+
+Flash 用 ActionScript (最新 3.0 版) 写脚本, Defold 用 Lua 写脚本. 本教程不涉及 Lua 和 Actionscript 3.0 编程. [Defold Lua 教程](/manuals/lua) 介绍了 Defold 中的 lua 脚本, [Programming in Lua](https://www.lua.org/pil/) (第一版) 有在线免费版可供学习.
+
+Jesse Warden 写了一篇 [Actionscript 与 Lua 简要对比](http://jessewarden.com/2011/01/lua-for-actionscript-developers.html) 的文章, 可以先看看这个. 注意 Defold 和 Flash 架构上的不同比起脚本语言的区别更多. Actionscript 和 Flash 是标准的面向对象的架构. Defold 却没有类也没有集成的概念. 它有着叫做 *游戏对象* 的概念, 用来表达视听, 行为和数据. 脚本通过调用 Defold API *函数* 进行逻辑编写. 而且, Defold 推荐使用 *消息* 机制进行对象间的互相通信. 消息机制比函数调用更高级别. 这些概念需要一段时间掌握, 本教程不做讲解.
+
+本教程, 主要是寻找 Flash 开发中的关键技术, 然后在 Defold 中找到对应的解决方案. 我们将探讨相似处和区别以及一些注意事项, 让你快速从 Flash 过渡到 Defold.
+
+## 影片剪辑和游戏对象
+
+影片剪辑是 Flash 游戏开发的基础组成部分. 每个影片剪辑包含自己的时间轴. Defold 中类似的概念是游戏对象.
+
+![game object and movieclip](images/flash/go_movieclip.png)
+
+不同的是, Defold 游戏对象没有时间轴. 却能包含很多组件. 组件有 sprite, sound, 脚本---等等 (关于组件详情请见 [构成教程](/manuals/building-blocks)). 下图这个游戏对象包含一个 sprite 和一个脚本. 脚本用来控制游戏对象生命周期中的行为:
+
+![script component](images/flash/script_component.png)
+
+影片剪辑可以包含其他影片剪辑, 游戏对象不是 *包含* 其他游戏对象. 但是能够与其他游戏对象建立 *父子* 层级关系, 父子关系的游戏对象可以一起移动, 旋转和缩放.
+
+## Flash 手动创建影片剪辑
+
+Flash 里, 可以从库中往时间轴上拖放影片剪辑以创建实例. 下图中, 舞台上的每个图标都是logo影片剪辑的实例:
+
+![manual movie clips](images/flash/manual_movie_clips.png)
+
+## Defold 手动创建游戏对象
+
+上文说了, Defold 没有时间轴概念. 但是, 集合可以用来管理游戏对象. 集合是容纳游戏对象和其他集合的容器 (或称 prefabs). 最简单的情况, 一个游戏有一个集合. 通常, Defold 游戏包含许多集合, 或者手动指定启动 “main” 集合或者通过 [集合代理](/manuals/collection-proxy) 动态载入集合. 但是 Flash 的 "levels" 或者 "screens" 没有这个能力.
+
+下面的例子里, "main" 集合 (看右边, *Outline* 窗口里) 包含3个 "logo" 游戏对象 (看左边, *Assets* 浏览器窗口里):
+
+![manual game objects](images/flash/manual_game_objects.png)
+
+## Flash—手动引用影片剪辑
+
+Flash 需要定义影片剪辑实例名再手动引用:
+
+![flash instance name](images/flash/flash_instance_name.png)
+
+## Defold—游戏对象id
+
+Defold 通过地址引用所有对象. 多数情况下使用快捷地址或者短小的名字就好. 例如:
+
+- `"."` 定位当前游戏对象.
+- `"#"` 定位当前脚本组件.
+- `"logo"` 定位 id 叫 "logo" 的游戏对象.
+- `"#script"` 定位当前游戏对象里 id 叫 "script" 的脚本组件.
+- `"logo#script"` 定位游戏对象 "logo" 下的 "script" 脚本.
+
+手动拖放对象的地址由 *Id* 属性 (上图右下角) 决定. 每个集合里一个对象的id是唯一的. 编辑器可以自动生成默认id但是所有对象的id都可以随意更改.
+
+![game object id](images/flash/game_object_id.png)
+
+::: 注意
+对象的id可以使用脚本: `print(go.get_id())` 查看. 它会在控制台打印出当前游戏对象的id.
+:::
+
+地址定位和消息传递是 Defold 游戏开发的核心概念. [定位教程](/manuals/addressing) 和 [消息传递教程](/manuals/message-passing) 里有更详细的介绍.
+
+## Flash—动态创建影片剪辑
+
+Flash 里动态创建影片剪辑, 需要预先设置好 ActionScript Linkage:
+
+![actionscript linkage](images/flash/actionscript_linkage.png)
+
+它创建了一个类 (本例是 Logo 图标), 这个类可以用于创建对象. 如下代码使用Logo类在舞台上创建了logo对象:
+
+```as
+var logo:Logo = new Logo();
+addChild(logo);
+```
+
+## Defold—使用工厂创建游戏对象
+
+Defold 使用 *工厂* 动态创建游戏对象. 工厂是创建游戏对象拷贝的组件. 本例中, 以 "logo" 游戏对象为原型创建了一个工厂组件:
+
+![logo factory](images/flash/logo_factory.png)
+
+注意工厂组件, 需要像其他组件一样, 需要添加到游戏对象里才能用. 本例中, 我们创建了叫做 "factories" 的游戏对象, 来容纳工厂组件:
+
+![factory component](images/flash/factory_component.png)
+
+如下代码使用工厂创建了游戏对象实例:
+
+```lua
+local logo_id = factory.create("factories#logo_factory")
+```
+
+URL 是 `factory.create()` 函数的必要参数. 此外, 还有可选参数用以设置位置, 旋转, 缩放, 和其他属性. 工厂组件详情请见 [工厂教程](/manuals/factory). 注意调用 `factory.create()` 可返回被创建游戏对象的id. 可以把这个id放入表中留待以后引用 (Lua 的表相当于其他语言的数组).
+
+## Flash—物体
+
+Flash 里经常使用时间轴 (下图上半部分) 和舞台 (时间轴下方):
+
+![timeline and stage](images/flash/stage.png)
+
+就像上文提到的影片剪辑容器, 舞台是Flash游戏的顶级容器. 舞台默认有一个子集, 叫 *MainTimeline*. 项目中每个影片剪辑都有子集的时间轴, 可以作为容纳其他组件的容器 (包括可以嵌套影片剪辑).
+
+## Defold—集合
+
+Defold 的集合类似于舞台. 引擎启动时集合文件的内容组成了游戏世界. 默认启动集合叫 "main.collection" 但是可以在 *game.project* 项目配置文件里随意更改:
+
+![game.project](images/flash/game_project.png)
+
+集合作为容器管理着游戏对象和其他集合. 通过 [集合工厂](/manuals/collection-factory/#创建集合) 可以在运行时动态创建集合内容, 就像游戏对象工厂创建游戏对象一样. 集合可以包含多组敌人, 或者一堆钱币, 之类的. 下图中, 我们手动拖放了两组 "logos" 集合到 "main" 集合中.
+
+![collection](images/flash/collection.png)
+
+有时, 你需要载入完整的游戏世界. [集合代理](/manuals/collection-proxy/) 组件能让你基于集合文件内容创建一个新的游戏世界. 这在诸如需要加载关卡, 迷你游戏, 或者过场动画之类的功能时很有用.
+
+## Flash—时间轴
+
+Flash 时间轴主要用来制作动画, 可以是逐帧动画也可以是形状/运动补间动画. 项目设置定义了全局 FPS (帧每秒) 决定了每帧显示多长时间. 老鸟用户可以随时修改游戏 FPS, 或者为影片剪辑独立设置 FPS.
+
+形状补间可以在矢量图的两个状态间进行插值. 这主要针对简单的图形和应用, 比如下例中把方块补间成三角:
+
+![timeline](images/flash/timeline.png)
+
+运动补间可以应用于对象属性, 包括大小, 位置和旋转. 下例中这些属性都进行了补间.
+
+![motion tween](images/flash/tween.png)
+
+## Defold—属性动画
+
+Defold 不使用矢量图而是使用位图, 所以没有形状补间. 但是运动补间可以使用 [属性动画](/ref/go/#go.animate) 来实现. 通过脚本, 调用 `go.animate()` 函数即可. go.animate() 函数基于各种缓动函数 (可以自定义) , 对属性 (比如颜色, 缩放, 旋转或者位置) 进行从初始值到设定结束值的补间. Defold 引擎内置了许多要 Flash 用户自定义才能实现的 [缓动函数](/manuals/animation/#easing).
+
+Flash 在时间轴上用关键帧做动画, Defold 动画功能之一是用导入的序列图做逐帧动画. 动画基于图集管理. 下例中图集有一个叫做 "run" 的动画. 此动画由一组图片组成:
+
+![flipbook](images/flash/flipbook.png)
+
+## Flash—深度索引
+
+在 Flash 里, 显示列表决定显示次序. 每个容器 (比如舞台) 都有一个显示列表. 对象使用 `addChild()` 方法会自动被加入到显示列表顶端, 从 0 开始索引层层递增. 下图中, 有三个 "logo" 影片剪辑的对象:
+
+![depth index](images/flash/depth_index.png)
+
+图标上标注了其所在显示列表索引位置. 除去 x/y 位置设置, 如下代码会把图标加入到显示列表中:
+
+```as
+var logo1:Logo = new Logo();
+var logo2:Logo = new Logo();
+var logo3:Logo = new Logo();
+
+addChild(logo1);
+addChild(logo2);
+addChild(logo3);
+```
+
+显示列表索引位置决定了它们的显示层次. 如果交互两个图标的索引, 比如:
+
+```as
+swapChildren(logo2,logo3);
+```
+
+结果如下 (索引已更新):
+
+![depth index](images/flash/depth_index_2.png)
+
+## Defold— z 轴位置
+
+Defold 里游戏对象的位置向量包含三部分: x, y, 和 z. 其中 z 轴位置决定了其深度. 在默认 [渲染脚本](/manuals/render) 中, z 轴位置范围是 -1 到 1.
+
+::: 注意
+如果游戏对象的 z 轴位置不在 -1 到 1 的范围内就不会被渲染也就是不可见. Defold 新手经常会因为这个感到困惑, 所以如果发现该显示的东西不显示想想是不是这个原因.
+:::
+
+不同于 Flash 由编辑器决定显示索引 (然后可以使用 *Bring Forward* 和 *Send Backward* 之类的命令修改索引), Defold 可以在编辑器里直接设置游戏对象的 z 轴位置. 下图中, 你会看到 "logo3" 显示在最上层, 其 z 轴位置是 0.2. 其他两个的 z 轴位置是 0.0 和 0.1.
+
+![z-order](images/flash/z_order.png)
+
+注意游戏对象 z 轴位置是由其本身 z 轴位置, 连同其所有父级的 z 轴位置共同决定的. 比如, 假设上文图标位于 "logos" 集合中, 该集合又位于 "main" 集合中 (见下图). 如果 "logos" 集合 z 位置是 0.9, 那么这三个图标的 z 位置就会是 0.9, 1.0, 和 1.1. 所以, "logo3" 不会被渲染因为其 z 位置大于 1.
+
+![z-order](images/flash/z_order_outline.png)
+
+z 轴位置可由脚本更改. 如下代码设置了游戏对象的 z 轴位置:
+
+```lua
+local pos = go.get_position()
+pos.z  = 0.5
+go.set_position(pos)
+```
+
+## Flash—hitTestObject 和 hitTestPoint 碰撞检测
+
+Flash 中使用 `hitTestObject()` 方法进行基本碰撞检测. 举个例子, 有两个影片剪辑: "bullet" 和 "bullseye". 见下图. 在 Flash 编辑器选中对象时会显示一个蓝色边框, `hitTestObject()` 方法就是用这样的边框来进行碰撞检测的.
+
+![hit test](images/flash/hittest.png)
+
+如下使用 `hitTestObject()` 进行碰撞检测:
+
+```as
+bullet.hitTestObject(bullseye);
+```
+
+这样检测可能会不准确, 比如如下的情况:
+
+![hit test bounding box](images/flash/hitboundingbox.png)
+
+除了 `hitTestObject()` 还有 `hitTestPoint()` 方法. 此方法包含一个 `shapeFlag` 参数, 可以提供像素对目标有像素形状的碰撞检测. 如下使用 `hitTestPoint()` 进行碰撞检测:
+
+```as
+bullseye.hitTestPoint(bullet.x, bullet.y, true);
+```
+
+这样通过子弹 x 和 y 坐标 (子弹图片左上角) 对靶子形状进行碰撞检测. 因为 `hitTestPoint()` 是点对形状的碰撞检测, 哪个 (或哪些) 点需要检测是要考虑的关键.
+
+## Defold—碰撞对象
+
+Defold 内含物理引擎可以用于碰撞检测然后使用其上的脚本进行相应. 首先要在游戏对象上面添加碰撞对象组件. 如下图所示, 我们对 "bullet" 游戏对象添加了碰撞对象. 碰撞对象以红色半透明方块表示 (只在编辑器中可见):
+
+![collision object](images/flash/collision_object.png)
+
+Defold 包含一个 Box2D 物理引擎的修改版, 可以用来自动模拟真实的碰撞. 本教程使用运 Kinematic 碰撞对象, 因为它的碰撞检测和 Flash 的最接近. 关于动态碰撞详情请见 Defold [物理教程](/manuals/physics).
+
+此碰撞对象包含如下属性:
+
+![collision object properties](images/flash/collision_object_properties.png)
+
+用一个矩形代表上例中的子弹. 圆形代表靶子进行碰撞检测. 设置类型为 Kinematic 意味着使用脚本进行碰撞处理, 物理引擎默认不是这样 (关于其他类型, 请见 [物理手册](/manuals/physics)). 属性 group 和 mask 分别决定了碰撞对象属于哪个组以及和哪个组相碰撞. 当前设置是 "bullet" 只能与 "target" 碰撞. 要是如下这样:
+
+![collision group/mask](images/flash/collision_groupmask.png)
+
+子弹之间就能相互碰撞了. 我们为靶子设置了如下的碰撞对象:
+
+![collision object bullet](images/flash/collision_object_bullet.png)
+
+注意 *Group* 属性设置为了 "target" 然后 *Mask* 设置为了 "bullet".
+
+Flash 里, 需要脚本调用才会进行碰撞检测. Defold 里, 只要碰撞对象开启, 后台就会持续进行碰撞检测. 碰撞发生时, 消息会发送到游戏对象所有组件上 (更确切地说是脚本组件). 有 [碰撞处理和碰撞点处理](/manuals/physics/#collision-messages) 消息, 其中包含了处理碰撞所需的各种信息.
+
+Defold 的碰撞检测比 Flash 的要高级, 毫不费力就能检测复杂形状间的碰撞. 碰撞检测是自动的, 也就是说不需要手动遍历各个对象然后挨个进行碰撞检测. 但是没有 Flash 的 shapeFlag. 但是对于复杂图形可以使用简单图形组合达成. 更复杂的需求下, 还可以使用 [自定义图形](//forum.defold.com/t/does-defold-support-only-three-shapes-for-collision-solved/1985).
+
+## Flash—事件监听
+
+事件对象及其监听器用来检测各种事件 (比如说 鼠标点击, 按钮按下, 剪辑加载) 并在反馈里处理行为. 包括许许多多的事件.
+
+## Defold—回调函数和消息
+
+Defold 跟 Flash 比有几个地方差不多. 首先, 每个脚本组件都包含一组特定事件的回调函数. 具体有:
+
+init
+:   脚本组件初始化时调用. 相当于 Flash 的构造函数.
+
+final
+:   脚本组件析构时调用 (比如游戏对象被删除时).
+
+update
+:   在每一帧调用. 相当于 Flash 的 enterFrame.
+
+on_message
+:   当脚本组件收到消息时调用.
+
+on_input
+:   当用户输入 (比如鼠标或键盘) 发送到得到 [输入焦点](/ref/go/#acquire_input_focus) 的游戏对象上时调用, 得到输入焦点的游戏对象会接收并反馈所有输入.
+
+on_reload
+:   脚本组件重载时调用.
+
+这些都是可选回调函数如果不需要可以删除. 关于如何接收输入, 详情请见 [输入教程](/manuals/input). 有一个关于集合代理易用错的地方 - 详情请见输入教程的 [这一章](/manuals/input/#input-dispatch-and-on_input).
+
+就像碰撞检测部分说的那样, 碰撞事件被发送到相关游戏对象上进行处理. 各个脚本组件的 on_message 回调函数会被调用.
+
+## Flash—按钮剪辑
+
+Flash 为按钮使用了一种特殊剪辑. 按钮监听到用户交互时使用特殊的事件处理方法 (比如 `click` 和 `buttonDown`) 来运行指定行为. 按钮 "Hit" 部分的图形决定了按钮的可点击区域.
+
+![button](images/flash/button.png)
+
+## Defold—GUI场景和脚本
+
+Defold 没有内置按钮组件, 也不像 Flash 那样使用游戏对象的图形进行方便的点击检测. 使用 [GUI](/manuals/gui) 组件是一个通用方案, 部分因为 Defold GUI 组件的位置不受游戏中摄像机 (如果有使用). GUI API 还包含在 GUI 组件的范围内检测用户输入例如点击和触摸事件的功能.
+
+## 调试
+
+在 Flash 里, 用 `trace()` 命令帮助调试. 在 Defold 里相应的是 `print()`, 跟使用 `trace()` 方法一样:
+
+```lua
+print("Hello world!"")
+```
+
+可以调用一次 `print()` 函数输出多个变量:
+
+```lua
+print(score, health, ammo)
+```
+
+还有一个 `pprint()` 函数 (pretty print), 用于打印表. 此函数能输出表的内容, 包括嵌套表. 看下面的脚本:
+
+```lua
+factions = {"red", "green", "blue"}
+world = {name = "Terra", teams = factions}
+pprint(world)
+```
+
+这里把表 (`factions`) 嵌入到表 (`world`) 里. 使用普通 `print()` 命令只会输出表的id, 不含内容:
+
+```
+DEBUG:SCRIPT: table: 0x7ff95de63ce0
+```
+
+使用 `pprint()` 函数就能显示出更多内容:
+
+```
+DEBUG:SCRIPT:
+{
+  name = Terra,
+  teams = {
+    1 = red,
+    2 = green,
+    3 = blue,
+  }
+}
+```
+
+如果游戏使用了碰撞检测, 可以发送如下消息开关物理调试:
+
+```lua
+msg.post("@system:", "toggle_physics_debug")
+```
+
+也可以在项目设置里打开物理调试. 打开物理调试前我们的项目看起来像这样:
+
+![no debug](images/flash/no_debug.png)
+
+打开物理调试显示出项目中的碰撞对象:
+
+![with debug](images/flash/with_debug.png)
+
+当碰撞发生时, 相关碰撞对象会高光显示. 而且, 碰撞向量也会被显示出来:
+
+![collision](images/flash/collision.png)
+
+最后, 关于检测 CPU 和内存使用情况详情请见 [性能分析教程](/ref/profiler/). 更高级的调试技术, 详情请见 Defold 手册的 [调试部分](/manuals/debugging).
+
+## 更多参考
+
+- [Defold examples](/examples)
+- [Tutorials](/tutorials)
+- [Manuals](/manuals)
+- [Reference](/ref)
+- [FAQ](/faq)
+
+如果你有疑问, [Defold 论坛](//forum.defold.com) 是一个获取帮助的好地方.

+ 164 - 0
docs/zh/manuals/font.md

@@ -0,0 +1,164 @@
+---
+title: Defold 字体教程
+brief: 本教程介绍了 Defold 如何处理和在游戏中使用字体.
+---
+
+# 字体文件
+
+字体用于在 Label 组件和 GUI 文本节点上显示文字. Defold 支持下列字体类型:
+
+- TrueType
+- OpenType
+- BMFont
+
+字体加入到 Defold 后会被自动转换成可以渲染的纹理. 文字渲染有两种技术, 各自都有优缺点:
+
+- Bitmap
+- Distance field
+
+## 创建字体
+
+在 Defold 中, 可以通过菜单栏 <kbd>File ▸ New...</kbd> 然后旋转 <kbd>Font</kbd> 来新建字体. 或者在 *Assets* 浏览器中 <kbd>右键点击</kbd> , 选择 <kbd>New... ▸ Font</kbd>.
+
+![New font name](images/font/new_font_name.png){srcset="images/font/[email protected] 2x"}
+
+填写字体名并点击 <kbd>Ok</kbd>. 字体编辑器会自动打开.
+
+![New font](images/font/new_font.png){srcset="images/font/[email protected] 2x"}
+
+把字体文件拖放到 *Assets* 浏览器中.
+
+设置字体的 *Font* 属性为所需字体文件然后设置其他所需属性.
+
+## 属性
+
+*Font*
+: TTF, OTF 或者 *.fnt* 文件用以生成文字数据.
+
+*Material*
+: 渲染文字所用材质. distance field 和 BMFonts 不同格式所需材质不同 (详见下文).
+
+*Output Format*
+: 字体生成的纹理格式.
+
+  - `TYPE_BITMAP` 把 OTF 或 TTF 的文字转换成为可以渲染的位图图表. 颜色通道决定了文字, 描边和阴影的颜色. 对于 *.fnt* 文件, 直接使用里面的位图纹理.
+  - `TYPE_DISTANCE_FIELD` 也是把文字转换成纹理但是要记录每个像素到文字边缘的距离. 详情见下文.
+
+*Render Mode*
+: 文字渲染模式.
+
+  - `MODE_SINGLE_LAYER` 为每个字母渲染一个四边形.
+  - `MODE_MULTI_LAYER` 为文字, 描边和阴影分别渲染一个四边形. 从后往前渲染, 这样能够避免描边太大对前一个字母造成的遮挡. 这种渲染模式可以依照字体资源阴影 X/Y 属性, 准确渲染阴影位置.
+
+*Size*
+: 文字大小单位像素.
+
+*Antialias*
+: 生成位图时是否抗锯齿. 如果想要像素对齐效果则设置为0.
+
+*Alpha*
+: 文字透明度. 范围 0.0--1.0,  其中 0.0 表示透明 1.0 表示不透明.
+
+*Outline Alpha*
+: 描边透明度. 范围 0.0--1.0.
+
+*Outline Width*
+: 描边宽度单位像素. 0 代表无描边.
+
+*Shadow Alpha*
+: 阴影透明度. 范围 0.0--1.0.
+
+::: 注意
+内置文字材质着色器单层多层渲染模式下都支持文字阴影. 如果不需要分层渲染或者阴影渲染, 最好使用 builtins/font-singlelayer.fp 之类的简单版着色器.
+:::
+
+*Shadow Blur*
+: 对于位图字体, 此设置代表文字阴影叠加计算次数. 对于 distance field 字体, 此设置代表文字阴影宽度像素数.
+
+*Shadow X/Y*
+: 阴影水平和垂直偏移. 只在输出格式为 `MODE_MULTI_LAYER` 时有效.
+
+*Extra Characters*
+: 默认字体包含 ASCII 字母表字符 (字符码 32-126). 如果需要更多字符, 需要手动在这里输入.
+
+::: 注意
+ASCII 字母表字符包含:
+space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ \` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
+:::
+
+*All Chars*
+: 把字体可以显示的所有字符都打包进游戏中来.
+
+*Cache Width/Height*
+: 文字缓存大小限制. 渲染文字时, 先从缓存中查找字符. 如果没找到的话, 实际渲染前会先添加进缓存中. 如果缓存太小, 会造成溢出错误 (`ERROR:RENDER: Out of available cache cells! Consider increasing cache_width or cache_height for the font.`).
+
+  设置为0代表自动管理缓存大小.
+
+## Distance field 字体
+
+Distance field 字体不存储位图像素而是存储像素到纹理边缘的距离. 这样在渲染文字时, 专用的着色器会通过距离数据渲染文字. Distance field 字体往往比位图数据量大, 但是对于尺寸控制更为灵活.
+
+![Distance field font](images/font/df_font.png){srcset="images/font/[email protected] 2x"}
+
+这种字体要确保 *Material* 属性设置为 *builtins/fonts/font-df.material* (或其他 distance field 数据专用材质) --- 否则的话渲染会不正确.
+
+## 位图 BMFont
+
+Defold 还支持 "BMFont" 格式字体. 这种字体的字符都是由位图组成的. 而且, *.fnt* 文件保存了字符位置大小间距等信息. (注意 Defold 不支持 Phaser 等其他引擎用的 XML 格式的 *.fnt* 文件格式)
+
+相比其他格式字体 BMFont 并无性能优势, 但是因为基于图片, 颜色阴影效果可以随意添加.
+
+把 *.fnt* 和 *.png* 文件加入 Defold 项目中. 这些文件要保存在同一文件夹中. 新建字体然后设置 *font* 属性为 *.fnt* 文件. 确保 *output_format* 属性为 `TYPE_BITMAP`. Defold 会直接使用 PNG 文件而不用再生成位图.
+
+::: 注意
+要使用 BMFont, 需要使用工具软件来生成所需文件. 下面列举一些这样的工具:
+
+* [Bitmap Font Generator](http://www.angelcode.com/products/bmfont/), AngelCode 开发的 Windows 版软件.
+* [Shoebox](http://renderhjs.net/shoebox/), 免费的基于 Adobe Air 的可运行与 Windows 和 MacOS 上的工具.
+* [Hiero](https://github.com/libgdx/libgdx/wiki/Hiero), 基于 Java 的开源软件.
+* [Glyph Designer](https://71squared.com/glyphdesigner), 71 Squared 开发的付费 MacOS 应用.
+* [bmGlyph](https://www.bmglyph.com), Sovapps 开发的付费 MacOS 应用.
+:::
+
+![BMfont](images/font/bm_font.png){srcset="images/font/[email protected] 2x"}
+
+要使用位图字体, 别忘了将其材质设置为 *builtins/fonts/font-fnt.material*.
+
+## 举例与最佳实践
+
+一般来说, 不用缩放的话位图字体最好. 因为渲染速度快.
+
+Distance field 字体适用于需要放大文字的地方. 相对的位图字体放大需要填充更多像素会导致模糊的效果. 下例是字体尺寸 48 像素, 放大 4 倍.
+
+![Fonts scaled up](images/font/scale_up.png){srcset="images/font/[email protected] 2x"}
+
+位图字体缩小的时候没有什么问题,  GPU 还会帮助抗锯齿. 位图字体颜色保持得比 distance field 字体好. 下例是字体尺寸 48 像素, 缩小到 1/5:
+
+![Fonts scaled down](images/font/scale_down.png){srcset="images/font/[email protected] 2x"}
+
+Distance field 需要足够多的数据信息才能较好地显示出文字边角部位. 下例是字体尺寸 18  像素, 放大 10 倍. 可以看到边角信息严重不足:
+
+![Distance field artifacts](images/font/df_artifacts.png){srcset="images/font/[email protected] 2x"}
+
+如果不需要文字阴影和描边, 要将这两种属性设置为0. 否则, 阴影和描边仍然会生成, 造成不必要的内存浪费.
+
+## 文字缓存
+Defold 中字体在运行时包含两部分内容, 纹理和字体数据.
+
+* 字体数据是一个字符表, 包含了字符对应的纹理及其字间距信息.
+* 纹理在引擎内部称为 "glyph cache texture" 用以渲染显示文字.
+
+运行时渲染文字的时候, 引擎会首先在文字缓存里查找需要的字符. 找不到的话再往缓存里添加这个字符.
+
+每个字符纹理基于字体基准线排列在缓存中, 以便着色器计算字符纹理本地坐标. 这意味着可以动态实现渐变或者或者纹理混合之类的效果. 引擎通过一个叫做 `texture_size_recip` 的常量将缓存信息暴露给着色器, 这个四元数包含如下信息:
+
+* `texture_size_recip.x` 是缓存宽度倒数
+* `texture_size_recip.y` 是缓存高度倒数
+* `texture_size_recip.z` 是单位宽度与缓存宽度的比
+* `texture_size_recip.w` 是单位高度与缓存高度的比
+
+例如 - 实现一个渐变渲染的片元着色器, 可以这么写:
+
+`float horizontal_gradient = fract(var_texcoord0.y / texture_size_recip.w);`
+
+更多详情请见 [着色器教程](/manuals/shader).

+ 69 - 0
docs/zh/manuals/getting-help.md

@@ -0,0 +1,69 @@
+---
+title: 如何获得帮助
+brief: 本教程介绍了使用 Defold 遇到麻烦时该如何寻求帮助.
+---
+
+# 获得帮助
+
+如果你使用 Defold 时遇到了麻烦请联系我们以便解决或绕过问题! 有许多途径可以讨论和汇报问题. 依个人喜好选择:
+
+## 在论坛里提交问题
+
+在我们的 [论坛](https://www.defold.com/forum) 上提交问题是一个好方法. 依据你的问题的类型可以在 [Questions](https://forum.defold.com/c/questions) 或者 [Bugs](https://forum.defold.com/c/bugs) 类目下发帖. 提交问题的时候请尽附加可能多的信息. 记得发问之前在论坛 [搜索](https://forum.defold.com/search) 一下相关内容, 也许论坛上已经存在你的问题的解决方案了. 提问时请填写以下信息:
+
+* **问题的描述 (必须)** - 问题的简短描述.
+
+* **问题的复现 (必须)** - 复现问题的步骤:
+  1. 进入 '...'
+  2. 点击 '....'
+  3. 滑动到 '....'
+  4. 错误出现
+
+* **期望行为 (必须)** - 期望实现的行为的简短描述.
+
+* **Defold 版本 (必须)** - 版本 [例如 1.2.155]. 最好再加上引擎和编辑器的 SHA1, 可以从 <kbd>Help->About</kbd> 菜单项里看到.
+
+* **操作平台 (必须)** - 在哪个操作平台上出现的问题?
+  - 平台: [比如 iOS, Android, Windows, macOS, Linux, HTML5]
+  - 系统: [比如 iOS8.1, Windows 10, High Sierra]
+  - 设备: [比如 iPhone6]
+
+* **日志 (可选)** - 请附加相关日志 (引擎或者编辑器的). 编辑器日志位于:
+  - Windows: `C:\Users\ **Your Username** \AppData\Local\Defold`
+  - macOS: `/Users/ **Your Username** /Library/Application Support/` 或者 `~/Library/Application Support/Defold`
+  - Linux: `~/.Defold`
+
+  Android 的引擎日志可以通过使用 `adb` (Android Debug Bridge) 命令行工具获取. 关于 `adb` 命令行工具详情请见 [Android 教程](/manuals/android/#android-debug-bridge).
+
+  iOS 的引擎日志可以通过使用 XCode 和设备模拟器菜单项获取.
+
+  HTML5 的引擎日志可以通过使用浏览器开发者控制台获取:
+  - Chrome: 菜单 > 更多工具 > 开发者工具
+  - Firefox: 工具 > web 开发者 > Web 控制台
+  - Safari: 开发 > 显示 JavaScript 控制台
+
+  桌面应用的引擎日志通过使用终端运行Defold应用获取.
+
+  你还可以把引擎日志写入一个文件便于存取. 详情请见 [调试教程](/manuals/debugging/#提取日志文件).
+
+* **问题复现小项目 (可选)** - 请附加一个可以再现问题的最小项目包. 这可以对别人研究修复问题提供极大帮助. 如果你把项目打成zip包请去掉其中的 `.git`, `.internal` 和 `build` 文件夹.
+
+* **绕过方法 (可选)** - 如果你找到了可以绕过问题的方案, 也请附加上.
+
+* **屏幕截图 (可选)** - 如果可以, 附加屏幕截图有助于描述出现的问题.
+
+* **其他 (可选)** - 还可以加入其他问题相关上下文信息.
+
+
+## 从编辑器里汇报问题
+
+编辑器提供了一个汇报错误的方便的方法. 选择 <kbd>Help->Report Issue</kbd> 菜单项来汇报错误.
+
+![](images/getting_help/report_issue.png)
+
+选择此菜单项会在 GitHub 上提交一个 issue tracker. 请把尽量多的信息填入报表. 注意此种方法需要你有 GitHub 账号.
+
+
+## 在 Slack 上讨论问题
+
+如果在使用 Defold 时遇到困难你可以尝试在 [Slack](https://www.defold.com/slack/) 上提出问题. 虽然我们推荐复杂问题应该在论坛上深入讨论. 而且注意 Slack 上不支持错误报告.

+ 180 - 0
docs/zh/manuals/glossary.md

@@ -0,0 +1,180 @@
+---
+title: Defold 术语
+brief: 本教程列举了使用 Defold 工作中会遇到的各种专用词汇及其简短的解释.
+---
+
+# Defold glossary
+
+该名词表简要介绍了您在 Defold 中遇到的所有东西。在大多数情况下,您会找到更多相关详细文档的链接。
+
+## Animation set
+
+![Animation set](images/icons/animationset.png){.left} An animation set resource contains a list of .dae files or other .animationset files from where to read animations. Adding one .animationset files to another is handy if you share partial sets of animations between several models. See the [3D graphics manual](/manuals/graphics/) for details.
+
+## Atlas
+
+![Atlas](images/icons/atlas.png){.left} An atlas is a set of separate images that are compiled into a larger sheet for performance and memory reasons. They can contain still images or flip-book animated series of images. Atlases are used by GUI, Sprite, Spine model and ParticleFX components to share graphics resources. See the [Atlas documentation](/manuals/atlas) for more information.
+
+## Builtins
+
+![Builtins](images/icons/builtins.png){.left} The builtins project folder is a read-only folder containing useful default resources. Here you find the default renderer, render script, materials and more. If you need custom modifications on any of these resources, simply copy them into your project and edit as you see fit.
+
+## Camera
+
+![Camera](images/icons/camera.png){.left} The camera component helps to decide what part of the game world should be visible and how it should be projected. A common use case is to attach a camera to the player game object, or to have a separate game object with a camera that follows the player around with some smoothing algorithm. See the [Camera documentation](/manuals/camera) for more information.
+
+## Collision object
+
+![Collision object](images/icons/collision-object.png){.left} Collision objects are components that extend game objects with physical properties (like spatial shape, weight, friction and restitution). These properties govern how the collision object should collide with other collision objects. The most common types of collision objects are kinematic objects, dynamic objects and triggers. A kinematic object gives detailed collision information that you have to manually respond to, a dynamic object is automatically simulated by the physics engine to obey Newtonian laws of physics. Triggers are simple shapes that detect if other shapes have entered or exited the trigger. See the [Physics documentation](/manuals/physics) for details on how this works.
+
+## Component
+
+Components are used to give specific expression and/or functionality to game objects, like graphics, animation, coded behavior and sound. They don’t live a life of their own but have to be contained inside game objects. There are many kinds of components available in Defold. See [the Building blocks manual](/manuals/building-blocks) for a description of components.
+
+## Collection
+
+![Collection](images/icons/collection.png){.left} Collections are Defold’s mechanism for creating templates, or what in other engines are called "prefabs" in where hierarchies of game objects can be reused. Collections are tree structures that hold game objects and other collections. A collection is always stored on file and brought into the game either statically by placing it manually in the editor, or dynamically by spawning. See [the Building blocks manual](/manuals/building-blocks) for a description of collections.
+
+## Collection factory
+
+![Collection factory](images/icons/collection-factory.png){.left} A Collection factory component is used to spawn hierarchies of game objects dynamically into a running game. See the [Collection factory manual](/manuals/collection-factory) manual for details.
+
+## Collection proxy
+
+![Collection](images/icons/collection.png){.left} A Collection proxy is used to load and enable collections on the fly while an app or game is running. The most common use case for Collection proxies is to load levels as they are to be played. See the [Collection proxy documentation](/manuals/collection-proxy) for details.
+
+## Cubemap
+
+![Cubemap](images/icons/cubemap.png){.left} A cubemap is a special type of texture that consists of 6 different textures that are mapped on the sides of a cube. This is useful for rendering skyboxes and different kinds of reflection and illumination maps.
+
+## Debugging
+
+At some point your game will behave in an unexpected way and you need to figure out what is wrong. Learning how to debug is an art and fortunately Defold ships with a built in debugger to help you out. See the [Debugging manual](/manuals/debugging) for more information.
+
+## Display profiles
+
+![Display profiles](images/icons/display-profiles.png){.left} The display profiles resource file is used for specifying GUI layouts depends on the orientation, aspect ratio or device model. It helps to adapt your UI for any kind of devices. Read more in the [Layouts manual](/manuals/gui-layouts).
+
+## Factory
+
+![Factory](images/icons/factory.png){.left} In some situations you cannot manually place all needed game objects in a collection, you have to create the game objects dynamically, on the fly. For instance, a player might fire bullets and each shot should be dynamically spawned and sent off whenever the player presses the trigger. To create game objects dynamically (from a pre-allocated pool of objects), you use a factory component. See the [Factory manual](/manuals/factory) for details.
+
+## Font
+
+![Font file](images/icons/font.png){.left} A Font resource is built from a TrueType or OpenType font file. The Font specifies which size to render the font in and what type of decoration (outline and shadow) the rendered font should have. Fonts are used by GUI and Label components. See the [Font manual](/manuals/font/) for details.
+
+## Fragment shader
+
+![Fragment shader](images/icons/fragment-shader.png){.left} This is a program that is run on the graphics processor for each pixel (fragment) in a polygon when it is drawn to the screen. The purpose of the fragment shader is to decide the color of each resulting fragment. This is done by calculation, texture lookups (one or several) or a combination of lookups and computations. See the [Shader manual](/manuals/shader) for more information.
+
+## Gamepads
+
+![Gamepads](images/icons/gamepad.png){.left} A gamepads resource file defines how specific gamepad device input is mapped to gamepad input triggers on a certain platform. See the [Input manual](/manuals/input) for details.
+
+## Game object
+
+![Game object](images/icons/game-object.png){.left} Game objects are simple objects that have a separate lifespan during the execution of your game. Game objects are containers and are usually equipped with visual or audible components, like a sound or a sprite. They can also be equipped with behavior through script components. You create game objects and place them in collections in the editor, or spawn them dynamically at run-time with factories. See [the Building blocks manual](/manuals/building-blocks) for a description of game objects.
+
+## GUI
+
+![GUI component](images/icons/gui.png){.left} A GUI component contains elements used to construct user interfaces: text and colored and/or textured blocks. Elements can be organized into hierarchical structures, scripted and animated. GUI components are typically used to create heads-up displays, menu systems and on-screen notifications. GUI components are controlled with GUI scripts that define the behavior of the GUI and control the user interaction with it. Read more in the [GUI documentation](/manuals/gui).
+
+## GUI script
+
+![GUI script](images/icons/script.png){.left} GUI scripts are used to control the behaviour of GUI components. They control GUI animations and how the user interacts with the GUI. See the [Lua in Defold manual](/manuals/lua) for details on how Lua scripts are used in Defold.
+
+## Hot reload
+
+The Defold editor allows you to update content in an already running game, on desktop and device. This feature is extremely powerful and can improve the development workflow a lot. See the [Hot reload manual](/manuals/hot-reload) for more information.
+
+## Input binding
+
+![Input binding](images/icons/input-binding.png){.left} Input binding files define how the game should interpret hardware input (mouse, keyboard, touchscreen and gamepad). The file binds hardware input to high level input _actions_ like "jump" and "move_forward". In script components that listen to input you are able to script the actions the game or app should take given certain input. See the [Input documentation](/manuals/input) for details.
+
+## Label
+
+![Label](images/icons/label.png){.left} The label component allows you to attach text content to any game object. It renders a piece of text with a particular font, on screen, in game space. See the [Label manual](/manuals/label) for more information.
+
+## Library
+
+![Game object](images/icons/builtins.png){.left} Defold allows you to share data between projects through a powerful library mechanism. You can use it to set up shared libraries that are accessible from all your projects, either for yourself or across the whole team. Read more about the library mechanism in the [Libraries documentation](/manuals/libraries).
+
+## Lua language
+
+The Lua programming language is used in Defold to create game logic. Lua is a powerful, efficient, very small scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description. You can read more about the language on the official Lua homepage at https://www.lua.org/ and in the [Lua in Defold manual](/manuals/lua).
+
+## Lua module
+
+![Lua module](images/icons/lua-module.png){.left} Lua modules allow you to structure your project and create reusable library code. Read more about it in the [Lua modules manual](/manuals/modules/)
+
+## Material
+
+![Material](images/icons/material.png){.left} Materials define how different objects should be rendered by specifying shaders and their properties. See the [Material manual](/manuals/material) for more information.
+
+## Message
+
+Components communicate with each other and other systems through message passing. Components also respond to a set of predefined messages that alter them or trigger specific actions. You send messages to hide graphics or nudge physics objects. The engine also uses messages to notify components of events, for instance when physics shapes collide. The message passing mechanism needs a recipient for each sent message. Therefore, everything in the game is uniquely addressed. To allow communication between objects, Defold extends Lua with message passing. Defold also provides a library of useful functions.
+
+For instance, the Lua-code required to hide a sprite component on a game object looks like this:
+
+```lua
+msg.post("#weapon", "disable")
+```
+
+Here, `"#weapon"` is the address of the current object's sprite component. `"disable"` is a message that sprite components respond to. See the [Message passing documentation](/manuals/message-passing) for an in depth explanation of how message passing works.
+
+## Model
+
+![Model](images/icons/model.png){.left} With the 3D model component can import Collada mesh, skeleton and animation assets into your game. See the [Model manual](/manuals/model/) for more information.
+
+## ParticleFX
+
+![ParticleFX](images/icons/particlefx.png){.left} Particles are very useful for creating nice visual effects, particularly in games. you can use them to create fog, smoke, fire, rain or falling leaves. Defold contains a powerful particle effects editor that allows you to build and tweak effects while you run them real time in your game. The [ParticleFX documentation](/manuals/particlefx) gives you the details on how that works.
+
+## Profiling
+
+Good performance is key in games and it is vital that you are able to do performance and memory profiling to measure your game and identify performance bottlenecks and memory problems that needs to be fixed. See the [Profiling manual](/manuals/profiling) for more information on the profiling tools available for Defold.
+
+## Render
+
+![Render](images/icons/render.png){.left} Render files contain settings used when rendering the game to the screen. Render files define which Render script to use for rendering and which materials to use. See the [Render manual](/manuals/render/) for more details.
+
+## Render script
+
+![Render script](images/icons/script.png){.left} A Render script is a Lua script that controls how the game or app should be rendered to the screen. There is a default Render script that covers most common cases, but you can write your own if you need custom lighting models and other effects. See the [Render manual](/manuals/render/) for more details on how the render pipeline works, and the [Lua in Defold manual](/manuals/lua) for details on how Lua scripts are used in Defold.
+
+## Script
+
+![Script](images/icons/script.png){.left}  A script is a component that contains a program that defines game object behaviors. With scripts you can specify the rules of your game, how objects should respond to various interactions (with the player as well as other objects). All scripts are written in the Lua programming language. To be able to work with Defold, you or someone on your team needs to learn how to program in Lua. See the [Lua in Defold manual](/manuals/lua) for an overview on Lua and details on how Lua scripts are used in Defold.
+
+## Sound
+
+![Sound](images/icons/sound.png){.left} The sound component is responsible for playing a specific sound. Currently, Defold supports sound files in the WAV and Ogg Vorbis formats. See the [Sound manual](/manuals/sound) for more information.
+
+## Spine model
+
+![Spine model](images/icons/spine-model.png){.left} The Spine model component is used to bring Spine skeletal animations to life in Defold. Read more about how to use it in the [Spine model manual](/manuals/spinemodel).
+
+## Spine scene
+
+![Spine scene](images/icons/spine-scene.png){.left} The Spine scene resource ties together the Spine JSON data file and the Defold image atlas file that is used to fill bone slots with graphics. The [Spine animation manual](/manuals/spine) contains more information.
+
+## Sprite
+
+![Sprite](images/icons/sprite.png){.left} A sprite is a component that extends game objects with graphics. It displays an image either from a Tile source or from an Atlas. Sprites have built-in support for flip-book and bone animation. Sprites are usually used for characters and items.
+
+## Texture profiles
+
+![Texture profiles](images/icons/texture-profiles.png){.left} The texture profiles resource file is used in the bundling process to automatically process and compress image data (in Atlas, Tile sources, Cubemaps and stand-alone textures used for models, GUI etc). Read more in the [Texture profiles manual](/manuals/texture-profiles).
+
+## Tile map
+
+![Tile map](images/icons/tilemap.png){.left} Tile map components display images from a tile source in one or more overlaid grids. They are most commonly used to build game environments: ground, walls, buildings and obstacles. A tile map can display several layers aligned on top of each other with a specified blend mode. This is useful to, for example, put foliage on top of grass background tiles. It is also possible to dynamically change the displayed image in a tile. That allows you to, for instance, destroy a bridge and make it impassable by simply replacing the tiles with ones depicting the broken down bridge and containing the corresponding physics shape. See the [Tile map documentation](/manuals/tilemap) for more information.
+
+## Tile source
+
+![Tile source](images/icons/tilesource.png){.left} A tile source describes a texture that is composed of multiple smaller images, each with the same size. You can define flip-book animations from a sequence of images in a tile source. Tile sources can also automatically calculate collision shapes from image data. This is very useful for creating tiled levels that object can collide and interact with. Tile sources are used by Tile map components (and Sprite and ParticleFX) to share graphics resources. Note that Atlases are often a better fit than tile sources. See the [Tile map documentation](/manuals/tilemap) for more information.
+
+## Vertex shader
+
+![Vertex shader](images/icons/vertex-shader.png){.left} The vertex shader computes the screen geometry of a component's primitive polygon shapes. For any type of visual component, be it a sprite, spine model or model, the shape is represented by a set of polygon vertex positions. The vertex shader program processes each vertex (in world space) and computes the resulting coordinate that each vertex of a primitive should have. See the [Shader manual](/manuals/shader) for more information.

+ 191 - 0
docs/zh/manuals/graphics.md

@@ -0,0 +1,191 @@
+---
+title: Defold 图像教程
+brief: 本教程简述了 Defold 支持的图像组件.
+---
+
+# 图像
+
+Defold是一个全3D引擎, 但是设计上还是为2D提供强大支持的. 目前该引擎比较适用于开发2D游戏.
+
+## 导入图片文件
+
+Defold使用的资源全部保存在项目目录下. 需要显示什么样的图像, 就要先导入图像资源. 要导入一个资源只要简单的把文件从电脑上拖拽到Defold编辑器的 _资源目录_.
+
+![Importing image files](images/graphics/import.png){srcset="images/graphics/[email protected] 2x"}
+
+Defold支持PNG和JPEG图片格式. 如果需要模型, Defold支持Collada DAE格式.
+
+## 图片资源
+
+Defold中, 可视组件使用两种图片资源:
+
+![atlas](images/icons/atlas.png){.icon} 图集
+: 图集由一组图片组成, 它们自动组成一张大图片. 图集中保存有图片和 *动画组*, 也就是逐帧动画的一组图片.
+
+  ![atlas](images/graphics/atlas.png){srcset="images/graphics/[email protected] 2x"}
+
+更多详情参见 [图集教程](/manuals/atlas).
+
+![tile source](images/icons/tilesource.png){.icon} Tile Source
+: 瓷砖图源是由一系列小图块按顺序拼贴而成的图片. 就像 _Sprite动画表_ 一样. 瓷砖图源可以包含逐帧动画, 只需指定动画的首尾帧. 瓷砖图块也可以自动生成其碰撞图形.
+
+  ![tile source](images/graphics/tilesource.png){srcset="images/graphics/[email protected] 2x"}
+
+更多详情参见 [Tile source manual](/manuals/tilesource).
+
+## 可视组件
+
+从图集或者瓷砖图源资源获得的数据可以用于几种可视组件:
+
+![sprite](images/icons/sprite.png){.icon}
+: Sprite是可以在屏幕上显示的图片或者逐帧动画.
+
+  ![sprite](images/graphics/sprite.png){srcset="images/graphics/[email protected] 2x"}
+
+Sprite更多详情请见 [Sprite manual](/manuals/sprite).
+
+![tile map](images/icons/tilemap.png){.icon} Tile Map
+: 瓷砖地图组件是由瓷砖图源中的瓷砖 (包括瓷砖图及其碰撞图形) 组成的地图. 瓷砖地图不能使用普通图集资源.
+
+  ![tilemap](images/graphics/tilemap.png){srcset="images/graphics/[email protected] 2x"}
+
+瓷砖地图更多详情请见 [Tilemap manual](/manuals/tilemap).
+
+![particle effect](images/icons/particlefx.png){.icon} Particle FX
+: 粒子是粒子发射器所发射出来的, 来自于图集或者瓷砖图源的一个个静态图片或者逐帧动画.
+
+  ![particles](images/graphics/particles.png){srcset="images/graphics/[email protected] 2x"}
+
+粒子特效更多详情请见 [Particle fx manual](/manuals/particlefx).
+
+![gui](images/icons/gui.png){.icon} GUI(图形用户界面)
+: GUI box 节点和 pie 节点同样使用来自图集和瓷砖图源的静态图片或者逐帧动画.
+
+  ![gui](images/graphics/gui.png){srcset="images/graphics/[email protected] 2x"}
+
+GUI更多详情请见 [GUI manual](/manuals/gui).
+
+![spine](images/icons/spine-model.png){.icon} Spine 模型
+: Spine 模型从 Spine 场景资源 中获取数据. 分为两部分:
+
+  1. 一个记录骨骼动画的Spine Json文件.
+  2. 一个由附加在骨骼上的图片组成的图集. Spine模型不能使用来自瓷砖地图的数据.
+
+  ![spine](images/graphics/spine.png){srcset="images/graphics/[email protected] 2x"}
+
+Spine模型更多详情请见 [Spine model manual](/manuals/spine-model).
+
+
+## 3D 图像
+
+模型直接从图片文件获取数据, 然后根据模型的UV映射到模型上:
+
+![model](images/icons/model.png){.icon} Model
+: 3D模型
+
+  ![model](images/graphics/model.png){srcset="images/graphics/[email protected] 2x"}
+
+模型更多详情请见 [Model manual](/manuals/model).
+
+Collada 支持
+: Defold's 3D 需要你保存或者导出模型, 骨骼和动画数据为 _Collada_ 格式. 这是绝大多数3D建模软件所支持的格式. 包括 _Maya_, _3D Max_, _Blender_, _Sketchup_ 等等, 都可以导入作品到 Defold.
+
+  Defold 目前只支持烘焙动画. 动画需要每帧每个骨骼的数据矩阵, 而不是仅仅是关键帧上的移动旋转缩放数据.
+
+  动画是线性插值的. 如果你想要曲线插值的动画, 记得先烘焙再导出.
+
+  不支持Collada中的动画剪辑. 要想一个模型多个动画, 就得分成多个 *.dae* 文件然后在Defold里合成一个 *.animationset* 文件.
+
+材质, 着色器和纹理
+: 3D软件一般可以在模型上设置属性, 比如颜色和纹理. 这些信息会保存在导出的 Collada *.dae* 文件中. 根据游戏需要你要选择创建合适的 _高效的_ 模型材质. 材质由 _着色器程序_ 和渲染时使用的一组参数组成.
+
+  你还需设计和实现一个合适的游戏摄像机.
+
+  built-in materials 文件夹下有一个简单的3D材质. 如果你需要为模型设计自定义材质, 详情请参考 [Material documentation](/manuals/material). [Shader manual](/manuals/shader)介绍了着色器程序是如何工作的.
+
+渲染模型
+: 默认的渲染器是为2D游戏而不是3D模型打造的. 但是参考它然后加入简单的几行代码就能实现3D渲染. 比如:
+
+  ```lua
+
+  function init(self)
+    self.model_pred = render.predicate({"model"})
+    ...
+  end
+
+  function update()
+    ...
+    render.set_depth_mask(true)
+    render.enable_state(render.STATE_DEPTH_TEST)
+    render.set_projection(stretch_projection(-1000, 1000))  -- orthographic
+    render.draw(self.model_pred)
+    render.set_depth_mask(false)
+    ...
+  end
+  ```
+
+  渲染脚本如何工作详情请见 [Render documentation](/manuals/render).
+
+
+## Z 排序
+
+所有游戏对象和组件在 3D 空间中的位置由 vector3 对象来决定. 在2D图像中, X 和 Y 值决定了物体在"横" , "竖" 轴的位置, Z 值决定了其在"深度"上的位置. Z轴位置可以让你控制可见物体的遮挡情况: Z 值为 1 的sprite会出现在 Z 值为 0 的sprite前面. 默认情况下, Defold 允许的 Z 值范围是 -1 到 1:
+
+![model](images/graphics/z-order.png){srcset="images/graphics/[email protected] 2x"}
+
+-1 到 1 的远近限制使得Z轴的数值精度很高. 在制作3D游戏时, 你可能需要在自定义渲染脚本里调整这个限制. 更多详情请见 [Render manual](/manuals/render/).
+
+## 混合模式
+
+*Blend Mode* 属性定义了 sprite 如何和其后面的图像混合. 以下列举了支持的混合模式及其混合算法:
+
+Alpha
+: 普通混合: a~0~ * rgb~0~ + (1 - a~0~) * rgb~1~
+
+Add
+: 使用相应的 sprite 像素颜色值提亮背景: rgb~0~ + rgb~1~
+
+Add Alpha (废弃!)
+: 使用相应的可见 sprite 像素颜色值提亮背景: a~0~ * rgb~0~ + rgb~1~
+
+Multiply
+: 使用相应的 sprite 像素颜色值调暗背景: rgb~0~ * rgb~1~
+
+
+## 纹理过滤和采样
+
+你可以控制在纹理采样时完成的过滤方法. 比如当一个 _纹素_ (纹理上的一个像素) 不是和屏幕完美的像素对齐时, 可以由过滤器决定显示结果 . 当你移动一个带纹理的图像元素少于一个像素时它就会发生. 下面的过滤方法是可选的:
+
+Nearest
+: 选取距离屏幕像素颜色最近的纹素. 如果你想要从纹理到屏幕显示完美的一对一像素映射就应该使用这种采样方法. 使用最近过滤方法所有物体移动的时候都是像素对齐的. 当 Sprite 慢慢移动时看起来可能会是一抽一抽的.
+
+Linear
+: 屏幕着色前纹素会和旁边的均值化. 当 Sprite 着色前会渗入像素, 呈现出一个慢慢的, 持续的动作 --从而使Sprite移动小于1个像素成为可能.
+
+采样的设置保存在 [Project Settings](/manuals/project-settings) 文件中. 有两个设置:
+
+default_texture_min_filter
+: 纹素比屏幕像素小时的缩小过滤方法.
+
+default_texture_mag_filter
+: 纹素比屏幕像素大时的放大过滤方法.
+
+两种设置都可接受 `linear` 或者 `nearest` 的设置. 比如:
+
+```ini
+[graphics]
+default_texture_min_filter = nearest
+default_texture_mag_filter = nearest
+```
+
+如果不设置, 两项默认都是 `linear`.
+
+注意默认采样器使用 "game.project" 里的设置. 如果你为自定义材质指定了采样器, 你可以为每个采样器单独指定过滤方法. 详情请见 [Materials manual](/manuals/material/).
+
+## 材质和着色器
+
+默认材质和着色器文件位于项目的 "/builtins/materials/" 下. Sprite, 瓷砖, spine 模型 和 3D模型的默认材质从 "game.project" 中设置的采样和过滤中查找纹理. 片元着色器还使用与纹理颜色相乘的叫做 `tint` 的常量.
+
+当游戏运行时, 你可以使用 [`sprite.set_constant()`](/ref/sprite#sprite.set_constant) 和 [`sprite.reset_constant()`](/ref/sprite#sprite.reset_constant) 函数设置 `tint` 和其他着色常量设置 `tint` 和其他着色常量. sprite 以外的组件也有相应的函数.
+
+[Materials manual](/manuals/material/) 解释了如何创建自定义材质.

+ 48 - 0
docs/zh/manuals/gui-box.md

@@ -0,0 +1,48 @@
+---
+title: Defold 中的 GUI 方块节点
+brief: 本教程介绍了如何使用 GUI 方块节点.
+---
+
+# GUI 方块节点
+
+方块节点是一个可以填充颜色, 纹理或者动画的矩形.
+
+## 添加方块节点
+
+添加方块节点可以在 *Outline* 中 <kbd>右键点击</kbd> 然后选择 <kbd>Add ▸ Box</kbd>, 或者按 <kbd>A</kbd> 然后选择 <kbd>Box</kbd>.
+
+你可以使用图集或者瓷砖图源里的图片或者动画添加到GUI上去. 要添加纹理 <kbd>右键点击</kbd>  *Outline* 中的 *Textures* 文件夹图标, 选择 <kbd>Add ▸ Textures...</kbd>. 然后设置方块节点的 *Texture* 属性:
+
+![纹理](images/gui-box/create.png){srcset="images/gui-box/[email protected] 2x"}
+
+注意方块节点的图像可以染色. 使用 color 加成到图片上面, 也就是说如果设置 color 为白色 (默认值) 则没有染色.
+
+![染色纹理](images/gui-box/tinted.png){srcset="images/gui-box/[email protected] 2x"}
+
+即使没有纹理设置, 方块节点也会被渲染, 或者不论把 alpha 设置成 `0`, 还是把 sized 设置成 `0, 0, 0`. 方块节点应该设置纹理以便渲染器合批而减少 draw call.
+
+## 九宫格纹理
+
+GUIs 对于其元素的大小改变是积极的: 面板和对话框总是应该填满其容纳的区域. 但是在缩放节点时纹理可能会产生问题.
+
+通常, 引擎把纹理整个填充到方块节点的边界, 但是九宫格纹理可以指定纹理里的那些内容需要缩放:
+
+![GUI 缩放](images/gui-box/scaling.png){srcset="images/gui-box/[email protected] 2x"}
+
+九宫格方块节点包含4个像素数值分别代表左, 上, 右, 下有多少边缘不参与缩放:
+
+![九宫格属性](images/gui-box/slice9_properties.png){srcset="images/gui-box/[email protected] 2x"}
+
+从左边开始, 顺时针设置:
+
+![九宫格设置](images/gui-box/slice9.png){srcset="images/gui-box/[email protected] 2x"}
+
+- 角落部分不会被缩放.
+- 边缘部分延单轴缩放. 左右边缘竖直缩放. 上下边缘水平缩放.
+- 中央部分正常延两个轴缩放.
+
+因为渲染器里 mipmapping 的工作方式, 部分缩放纹理可能会造成小问题. 当你把纹理一部分 _缩小_ 到比本身小的时候. 渲染器会自动选择一个低分辨率的 mipmap 来渲染这部分, 导致了这个小问题.
+
+![九宫格 mipmapping](images/gui-box/mipmap.png){srcset="images/gui-box/[email protected] 2x"}
+
+为避免这类问题, 使用小图导进来之后只放大别缩小就行了.

+ 73 - 0
docs/zh/manuals/gui-clipping.md

@@ -0,0 +1,73 @@
+---
+title: GUI 蒙版教程
+brief: 本教程介绍了创建使用蒙版剪裁遮蔽其他 GUI 节点的方法.
+---
+
+# 蒙版
+
+GUI 节点可以作为 *蒙版* 节点---遮蔽影响其他节点的显示方式. 本教程介绍了其用法.
+
+## 创建蒙版节点
+
+方块, 文本 和 饼状图节点可以被裁剪. 要创建裁剪节点, 在 GUI 里添加一个节点, 然后设置相关属性:
+
+Clipping Mode
+: 裁剪模式.
+  - `None` 不施加裁剪.
+  - `Stencil` 施加裁剪.
+
+Clipping Visible
+: 选中则蒙版内容可见.
+
+Clipping Inverted
+: 选中则遮蔽内容反转.
+
+然后把被裁剪节点作为蒙版子节点加入进来.
+
+![Create clipping](images/gui-clipping/create.png){srcset="images/gui-clipping/[email protected] 2x"}
+
+## 裁剪蒙版
+
+原理上裁剪是把节点写入 *裁剪缓冲区*. 此缓冲区包含蒙版: 就是告诉显卡哪些像素该渲染, 哪些不该渲染.
+
+- 一个没有父蒙版的节点, 如果设置了 clipping mode 为 `Stencil` 的话相当于把它的形状 (或者其反转形状) 写入裁剪蒙版保存在裁剪缓冲区当中.
+- 如果一个蒙版节点有父蒙版那么它会继续裁剪父蒙版. 子蒙版不会 _继承_ 当前蒙版, 只会继续剪裁当前蒙版.
+- 非蒙版节点作为蒙版的子节点的话, 会被父蒙版层级裁剪渲染.
+
+![Clipping hierarchy](images/gui-clipping/setup.png){srcset="images/gui-clipping/[email protected] 2x"}
+
+这里, 我们建立了节点的三层结构:
+
+- 六边形和矩形都是蒙版节点.
+- 六边形是第一个蒙版, 矩形进一步裁剪.
+- 园是最下层被裁剪的普通节点.
+
+这种结构下可以有四种裁剪方式. 绿色标志出园被裁剪以后的样子. 结果如下所示:
+
+![Stencil masks](images/gui-clipping/modes.png){srcset="images/gui-clipping/[email protected] 2x"}
+
+## 蒙版局限性
+
+- 蒙版数最大不超过 256 个.
+- _蒙版_ 节点最大嵌套8层. (只计算设置了蒙版的节点)
+- 同层次蒙版不超过 127 个. 每深一层, 数目减半.
+- 反转蒙版很耗性能. 最多8个反转蒙版并且每个反转蒙版会使非反转蒙版的最大数目减半.
+- 裁剪渲染基于蒙版节点的 _几何形状_  (而非纹理). 设置 *Inverted clipper* 可以反转蒙版渲染.
+
+
+## 层
+
+层可以控制节点的渲染顺序 (以及渲染合批) . 当使用层与蒙版节点共同使用时, 层的功能会被影响.
+
+- 蒙版裁剪顺序优先与层顺序---不管节点属于那一层, 都会被父蒙版所裁剪.
+- 层只负责图像显示顺序---进一步说, 蒙版节点的层设置只影响 _该蒙版层级_ 的显示顺序.
+
+::: 注意
+蒙版节点及其层级有层设置的话会优先显示, 没有设置的话按照普通顺序显示.
+:::
+
+![Layers and clipping](images/gui-clipping/layers.png){srcset="images/gui-clipping/[email protected] 2x"}
+
+这里蒙版节点 "ocular" 层设置为 "layer3" 然后 "bean" 节点设置成 "layer1". 所以被 ocular 剪裁的纹理显示在了 bean 的上层.
+
+节点 "shield" 设置为 "layer2", 但是在显示顺序上与 "ocular" 和 "bean" 并不冲突. 要更改 "shield" 的显示顺序, 设置层级顺序即可.

+ 102 - 0
docs/zh/manuals/gui-layouts.md

@@ -0,0 +1,102 @@
+---
+title: Defold 里的 GUI 布局
+brief: Defold 支持让 GUIs 自动适配手机屏幕方向的改变. 本教程介绍这部分功能.
+---
+
+# Layouts
+
+Defold支持可自动适应移动设备上屏幕方向变化的GUI。通过使用此功能,您可以设计适合各种屏幕尺寸的方向和纵横比的GUI。也可以创建与特定设备型号匹配的布局。
+
+## Creating display profiles
+
+By default, the "game.project" settings specify that a built in display profiles settings file ("builtins/render/default.display_profiles") is used. The default profiles are "Landscape" (1280 pixels wide and 720 pixels high) and "Portrait" (720 pixels wide and 1280 pixels high). No device models are set on the profiles so they will match on any device.
+
+To create a new profiles settings file, either copy the one from the "builtins" folder or <kbd>right click</kbd> a suitable location in the *Assets* view and select <kbd>New... ▸ Display Profiles</kbd>. Give the new file a suitable name and click <kbd>Ok</kbd>.
+
+The editor now opens the new file for editing. Add new profiles by clicking the <kbd>+</kbd> in the *Profiles* list. For each profile, add a set of *qualifiers* for the profile:
+
+Width
+: The pixel width of the qualifier.
+
+Height
+: The pixel height of the qualifier.
+
+Device Models
+: A comma separated list of device models. The device model matches the start of the device model name, e.g. `iPhone10` will match "iPhone10,\*" models. Model names with commas should be enclosed in quotes, i.e. `"iPhone10,3", "iPhone10,6"` matches iPhone X models (see https://www.theiphonewiki.com/wiki/Models). Note that the only platforms reporting a device model when calling `sys.get_sys_info()` is Android and iOS. Other platforms return an empty string and will therefore never pick a display profile that has a device model qualifier.
+
+![New display profiles](images/gui-layouts/new_profiles.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+You also need to specify that the engine should use your new profiles. Open "game.project" and select the display profiles file in the *Display Profiles* setting under *display*:
+
+![Settings](images/gui-layouts/settings.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+::: sidenote
+The current development app for iOS does not respect the *Dynamic Orientation* setting but will always change orientation dynamically.
+:::
+
+If you want the engine to automatically switch between portrait and landscape layouts on device rotation, check the *Dynamic Orientation* box. The engine will dynamically select a matching layout and also change the selection if the device changes orientation.
+
+## GUI layouts
+
+The current set of display profiled can be used to create layout variants of your GUI node setup. To add a new layout to a GUI scene, right-click the *Layouts* icon in the *Outline* view and select <kbd>Add ▸ Layout ▸ ...</kbd>:
+
+![Add layout to scene](images/gui-layouts/add_layout.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+When editing a GUI scene, all nodes are edited on a particular layout. The currently selected layout is indicated in the GUI scene layout dropdown in the toolbar. If no layout is chosen, the nodes are edited in the *Default* layout.
+
+![Layouts toolbar](images/gui-layouts/toolbar.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+![portrait edit](images/gui-layouts/portrait.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+Each change to a node property that you do with a layout selected _overrides_ the property in respect to the *Default* layout. Properties that are overridden are marked in blue. Nodes with overridden properties are also marked in blue. You can click on the reset button next to any overridden property to reset it to the original value.
+
+![landscape edit](images/gui-layouts/landscape.png){srcset="images/gui-layouts/[email protected] 2x"}
+
+A layout cannot delete or create new nodes, only override properties. If you need to remove a node from a layout you can either move the node off-screen or delete it with script logic. You should also pay attention to the currently selected layout. If you add a layout to your project, the new layout will be set up according to the currently selected layout. Also, copying and pasting nodes considers the currently selected layout, when copying *and* when pasting.
+
+## Dynamic profile selection
+
+The dynamic layout matcher scores each display profile qualifier according to the following rules:
+
+1. If there is no device model set, or the device model matches, a score $S$ is calculated for the qualifier.
+
+2. The score ($S$) is calculated with the area of the display ($A$), the area from the qualifier ($A_Q$), the aspect ratio of the display ($R$) and the aspect ratio of the qualifier ($R_Q$):
+
+   $$
+   S=\left|1 - \frac{A}{A_Q}\right| + \left|1 - \frac{R}{R_Q}\right|
+   $$
+
+3. The profile with the lowest scoring qualifier is selected, if the orientation (landscape or portrait) of the qualifier matches the display.
+
+4. If no profile with a qualifier of the same orientation is found, the profile with the best scoring qualifier of the other orientation is selected.
+
+5. If no profile can be selected, the *Default* fallback profile is used.
+
+Since the *Default* layout is used as fallback in runtime if there are no better matching layout it means that if you add a "Landscape" layout, it will be the best match for *all* orientations until you also add a "Portrait" layout.
+
+## Layout change messages
+
+When the engine switches layout as a result of device rotation, a `layout_changed` message is posted to the GUI components' scripts that are affected by the change. The message contains the hashed id of the layout so the script can perform logic depending on which layout is selected:
+
+```lua
+function on_message(self, message_id, message, sender)
+  if message_id == hash("layout_changed") and message.id == hash("My Landscape") then
+    -- switching layout to landscape
+  elseif message_id == hash("layout_changed") and message.id == hash("My Portrait") then
+    -- switching layout to portrait
+  end
+end
+```
+
+In addition, the current render script receives a message whenever the window (game view) changes and this includes orientation changes.
+
+```lua
+function on_message(self, message_id, message)
+  if message_id == hash("window_resized") then
+    -- The window was resized. message.width and message.height contain the
+    -- new dimensions of the window.
+  end
+end
+```
+
+When orientation is switched, the GUI layout manager will automatically rescale and reposition GUI nodes according to your layout and node properties. In-game content, however, is rendered in a separate pass (by default) with a stretch-fit projection into the current window. To change this behavior, either supply your own modified render script, or use a camera [library](/assets/).

+ 34 - 0
docs/zh/manuals/gui-particlefx.md

@@ -0,0 +1,34 @@
+---
+title: Defold里的GUI粒子特效
+brief: 本教程解释了 Defold GUI 的粒子特效如何工作.
+---
+
+# GUI ParticleFX 节点
+
+粒子特效节点用来在 GUI 屏幕空间中实现粒子特效.
+
+## 添加 Particle FX 节点
+
+在 *outline 视图* 中点击 <kbd>鼠标右键</kbd> 选择 <kbd>Add ▸ ParticleFX</kbd>, 或者按 <kbd>A</kbd> 选择 <kbd>ParticleFX</kbd> 来添加新粒子节点.
+
+也可以使用 GUI 里已经存在的资源创建粒子特效. 在 *outline 视图* 的 *Particle FX* 文件夹上点击 <kbd>鼠标右键</kbd> 选择 <kbd>Add ▸ Particle FX...</kbd>. 然后设置节点的 *Particlefx* 属性:
+
+![Particle fx](images/gui-particlefx/create.png){srcset="images/gui-particlefx/[email protected] 2x"}
+
+## 控制特效
+
+可以使用脚本控制节点上的特效:
+
+```lua
+-- start the particle effect
+local particles_node = gui.get_node("particlefx")
+gui.play_particlefx(particles_node)
+```
+
+```lua
+-- stop the particle effect
+local particles_node = gui.get_node("particlefx")
+gui.stop_particlefx(particles_node)
+```
+
+详情请见 [粒子特效教程](/manuals/particlefx).

+ 56 - 0
docs/zh/manuals/gui-pie.md

@@ -0,0 +1,56 @@
+---
+title: Defold GUI 饼状图节点
+brief: 本教程介绍了在 Defold GUI 场景中如何使用饼状图节点.
+---
+
+# GUI 饼状图节点
+
+饼状图节点用以创建圆的或者椭圆的从实心到环状的可视对象.
+
+## 创建饼状图节点
+
+<kbd>右键点击</kbd>  *Outline* 中的 *Nodes* 部分, 选择 <kbd>Add ▸ Pie</kbd>. 饼状图就创建好了.
+
+![创建饼状图节点](images/gui-pie/create.png){srcset="images/gui-pie/[email protected] 2x"}
+
+以下属性是饼状图节点的特有属性:
+
+Inner Radius
+: 节点的内半径, 延X轴.
+
+Outer Bounds
+: 节点外轮廓.
+
+  - `Ellipse` 可以把节点扩展到外半径处.
+  - `Rectangle` 可以把节点扩展到边界方框处.
+
+Perimeter Vertices
+: 图形的分段数, 就是360度一圈需要的顶点数.
+
+Pie Fill Angle
+: 饼状图的填充. 从右侧开始按逆时针方向.
+
+![属性](images/gui-pie/properties.png){srcset="images/gui-pie/[email protected] 2x"}
+
+如果为节点设置了纹理, 那么纹理图会和边界框的角对应起来平铺.
+
+## 运行时修改饼状图
+
+饼状图节点同样可以控制 size, pivot, color 之类的属性. 此外还有饼状图特定属性:
+
+```lua
+local pienode = gui.get_node("my_pie_node")
+
+-- get the outer bounds
+local fill_angle = gui.get_fill_angle(pienode)
+
+-- increase perimeter vertices
+local vertices = gui.get_perimeter_vertices(pienode)
+gui.set_perimeter_vertices(pienode, vertices + 1)
+
+-- change outer bounds
+gui.set_outer_bounds(pienode, gui.PIEBOUNDS_RECTANGLE)
+
+-- animate the inner radius
+gui.animate(pienode, "inner_radius", 100, gui.EASING_INOUTSINE, 2, 0, nil, gui.PLAYBACK_LOOP_PINGPONG)
+```

+ 149 - 0
docs/zh/manuals/gui-script.md

@@ -0,0 +1,149 @@
+---
+title: Defold 中的 GUI 脚本 
+brief: 本教程介绍了 GUI 脚本.
+---
+
+# GUI 脚本
+
+为了控制 GUI 逻辑和动画节点要使用 Lua 脚本. GUI 脚本和游戏对象脚本一样, 但是扩展名不一样而且使用的函数集不一样: 使用 `gui` 模块函数.
+
+## 在 GUI 上添加脚本
+
+要在 GUI 上添加脚本, 首先在 *Assets* 浏览器里<kbd>右键点击</kbd> 再在弹出菜单选择 <kbd>New ▸ Gui Script</kbd> 来创建 GUI 脚本.
+
+编辑器会自动打开脚本文件. 它基于一个模板, 各种空白生命周期函数齐全, 跟游戏对象脚本一样:
+
+```lua
+function init(self)
+   -- Add initialization code here
+   -- Remove this function if not needed
+end
+
+function final(self)
+   -- Add finalization code here
+   -- Remove this function if not needed
+end
+
+function update(self, dt)
+   -- Add update code here
+   -- Remove this function if not needed
+end
+
+function on_message(self, message_id, message, sender)
+   -- Add message-handling code here
+   -- Remove this function if not needed
+end
+
+function on_input(self, action_id, action)
+   -- Add input-handling code here
+   -- Remove this function if not needed
+end
+
+function on_reload(self)
+   -- Add input-handling code here
+   -- Remove this function if not needed
+end
+```
+
+要把脚本添加到 GUI 组件, 打开 GUI 蓝图文件, 在 *Outline* 里选择根节点显示出 GUI *Properties*. 把 *Script* 属性设置为脚本文件即可.
+
+![Script](images/gui-script/set_script.png){srcset="images/gui-script/[email protected] 2x"}
+
+如果这个 GUI 组件被添加到游戏中的游戏对象里, 它上面的脚本就可以运行了.
+
+## "gui" 命名空间
+
+GUI 脚本访问 `gui` 命名空间及其 [所有gui函数](/ref/gui). `go` 命名空间不可用, 所以要注意区分游戏对象的脚本组件以及二者间的消息传递. 尝试使用 `go` 函数会报错:
+
+```lua
+function init(self)
+   local id = go.get_id()
+end
+```
+
+```txt
+ERROR:SCRIPT: /main/my_gui.gui_script:2: You can only access go.* functions and values from a script instance (.script file)
+stack traceback:
+   [C]: in function 'get_id'
+   /main/my_gui.gui_script:2: in function </main/my_gui.gui_script:1>
+```
+
+## 消息传递
+
+游戏运行时 GUI 脚本可与其他对象互相传递消息, 同其他脚本组件相同.
+
+定位 GUI 组件也与其他脚本组件中定位方法相同:
+
+```lua
+local stats = { score = 4711, stars = 3, health = 6 }
+msg.post("hud#gui", "set_stats", stats)
+```
+
+![message passing](images/gui-script/message_passing.png){srcset="images/gui-script/[email protected] 2x"}
+
+## 定位节点
+
+GUI 中的节点可由脚本控制. 在编辑器中每个节点都有唯一 *Id*:
+
+![message passing](images/gui-script/node_id.png){srcset="images/gui-script/[email protected] 2x"}
+
+*Id* 使得脚本引用节点并对其使用 [gui 命名空间函数](/ref/gui) 进行控制:
+
+```lua
+-- 扩展 10 单位血条
+local healthbar_node = gui.get_node("healthbar")
+local size = gui.get_size(healthbar_node)
+size.x = size.x + 10
+gui.set_size(healthbar_node, size)
+```
+
+## 动态创建节点
+
+在运行时使用脚本创建新节点有两种方法. 一种是通过调用 `gui.new_[type]_node()` 函数. 该函数返回新节点引用以便对其进行控制:
+
+```lua
+-- 新建节点
+local new_position = vmath.vector3(400, 300, 0)
+local new_size = vmath.vector3(450, 400, 0)
+local new_boxnode = gui.new_box_node(new_position, new_size)
+gui.set_color(new_boxnode, vmath.vector4(0.2, 0.26, 0.32, 1))
+
+-- 新建文本节点
+local new_textnode = gui.new_text_node(new_position, "Hello!")
+gui.set_font(new_textnode, "sourcesans")
+gui.set_color(new_textnode, vmath.vector4(0.69, 0.6, 0.8, 1.0))
+```
+
+![dynamic node](images/gui-script/dynamic_nodes.png){srcset="images/gui-script/[email protected] 2x"}
+
+第二种方法是通过调用 `gui.clone()` 函数克隆一个已存在的节点或者通过调用 `gui.clone_tree()` 函数克隆一个已存在的节点树:
+
+```lua
+-- 克隆血条
+local healthbar_node = gui.get_node("healthbar")
+local healthbar_node_2 = gui.clone(healthbar_node)
+
+-- 克隆按钮节点树
+local button = gui.get_node("my_button")
+local new_button_nodes = gui.clone_tree(button)
+
+-- 获得节点树根节点
+local new_root = new_button_nodes["my_button"]
+
+-- 向右移动根节点 (及其子节点) 300 像素
+local root_position = gui.get_position(new_root)
+root_position.x = root_position.x + 300
+gui.set_position(new_root, root_position)
+```
+
+## 动态节点id
+
+动态创建的节点没有id. 设计上就是这样. 引用由 `gui.new_[type]_node()`, `gui.clone()` 和 `gui.clone_tree()` 函数返回, 这是访问动态节点的唯一途径, 记得保留好这个引用.
+
+```lua
+-- 添加文本节点
+local new_textnode = gui.new_text_node(vmath.vector3(100, 100, 0), "Hello!")
+-- "new_textnode" 保存新节点的引用.
+-- 新节点没有 id, 但是没关系. 得到节点的引用
+-- 就没有必要使用 gui.get_node() 函数了.
+```

+ 68 - 0
docs/zh/manuals/gui-spine.md

@@ -0,0 +1,68 @@
+---
+title: Defold GUI Spine 节点
+brief: 本教程介绍了 Defold GUI 场景中骨骼动画 Spine 节点的使用.
+---
+
+# GUI Spine 节点
+
+Spine 动画模型可以作为 GUI 节点也可以作为游戏对象加入场景. 本教程介绍了导入的 Spine 动画数据在 GUI 场景下的使用.
+
+## 创建 spine 节点
+
+首先你应该导入动画数据并建立 Spine Scene 资源. [Spine 动画](/manuals/spine) 文档介绍了其方法.
+
+接着, Spine Scene 资源的内容要加入到 GUI 场景中去. 加入方法 <kbd>右键点击</kbd>  *Outline* 中的 *Spine Scenes* 部分, 选择 <kbd>Add ▸ Spine Scenes...</kbd>. 选择要加入的 Spine Scenes (可加多个).
+
+![添加 Spine Scene](images/gui-spine/add.png){srcset="images/gui-spine/[email protected] 2x"}
+
+最后, <kbd>右键点击</kbd> *Outline* 中的 *Nodes* 部分, 选择 <kbd>Add ▸ Spine</kbd> 来创建 Spine 节点.
+
+![New spine node](images/gui-spine/new_node.png){srcset="images/gui-spine/[email protected] 2x"}
+
+新节点自动被选中. 注意设置其属性:
+
+Spine Scene
+: 此节点使用的 Spine Scene 数据源.
+
+Spine Default Animation
+: 场景初始化时节点默认的动画.
+
+Skin
+: 场景初始化时节点用于动画的皮肤.
+
+## 运行时动画控制
+
+使用脚本可以在运行时控制Spine节点. 要在一个节点上开始播放动画, 只要调用 [`gui.play_spine_anim()`](/ref/gui/#gui.play_spine_anim:node-animation_id-playback-[play_properties]-[complete_function]) 函数:
+
+```lua
+local catnode = gui.get_node("cat_note")
+local play_properties = { blend_time = 0.3, offset = 0, playback_rate = 1 }
+gui.play_spine_anim(catnode, hash("run"), gui.PLAYBACK_ONCE_FORWARD, play_properties, function(self, node)
+    print("Animation done!")
+end)
+```
+
+## 骨骼层级
+
+Spine 骨架中的各个骨骼都可以像 GUI 节点一样使用. 节点名就是 Spine 里设置的骨骼名.
+
+![Spine 骨骼名](images/gui-spine/bone.png){srcset="images/gui-spine/[email protected] 2x"}
+
+比如, 要做一个骨骼节点下增添一个节点, 使用 [`gui.get_spine_bone()`](/ref/gui#gui.get_spine_bone) 函数加节点名来获取此节点, 然后再在上面加入一个节点:
+
+```lua
+-- Attach a text node to the tail of the cat
+local cat = gui.get_node("cat_node")
+local textnode = gui.new_text_node(vmath.vector3(400, 0, 0), "Hello tail!")
+local tail = gui.get_spine_bone(cat, "tail")
+gui.set_parent(textnode, tail)
+```
+
+同样可以用 [`gui.get_node()`](/ref/gui#gui.get_node) 函数获取骨骼节点, 此时引用名要用 Spine 节点名加正斜杠斜杠 (`/`) 加子节点名:
+
+```lua
+-- Attach a text node to the tail of the cat
+local textnode = gui.new_text_node(vmath.vector3(400, 0, 0), "Hello tail!")
+local tail = gui.get_node("cat_node/tail")
+gui.set_parent(textnode, tail)
+```

+ 62 - 0
docs/zh/manuals/gui-template.md

@@ -0,0 +1,62 @@
+---
+title: GUI 模板教程
+brief: 本教程介绍了用以创建基于模板(或称作'prefabs')的可重用可视 GUI 组件的 Defold GUI 模板系统.
+---
+
+# GUI 模板节点
+
+GUI 模板节点提供了基于模板或者叫 "prefabs"基于模板或者叫 "prefabs" 创建可重用 GUI 组件的有效机制. 本教程介绍了如何使用这一特性.
+
+GUI 模板是 GUI 某个场景的实例化版本. GUI 模板里节点的设置可以覆盖GUI场景的设定.
+
+## 创建模板
+
+GUI 模板也是一种场景, 创建和普通场景一样. 在 *Assets* 面板里某位置上 <kbd>右键点击</kbd> 然后选择 <kbd>New... ▸ Gui</kbd>.
+
+![Create template](images/gui-templates/create.png){srcset="images/gui-templates/[email protected] 2x"}
+
+输入名称并保存. 注意节点都是参照模板原点设置位置的, 所以模板位置也最好设置成 0, 0, 0.
+
+## 创建模板节点
+
+一个模板可以创建许多实例. 先创建或者打开 GUI 场景, 然后 <kbd>右键点击</kbd> *Outline* 视图里的 *Nodes* 部分, 然后选择 <kbd>Add ▸ Template</kbd>.
+
+![Create instance](images/gui-templates/create_instance.png){srcset="images/gui-templates/[email protected] 2x"}
+
+然后便可以在GUI场景里设置 *Template* 的属性.
+
+一个模板可以创建多个实例节点, 实例里的每个节点都可以修改自身属性, 比如位置,  颜色, 大小, 纹理之类的.
+
+![Instances](images/gui-templates/instances.png){srcset="images/gui-templates/[email protected] 2x"}
+
+更改了的属性会以蓝色显示. 点击重置按钮可以退回成原始的模板属性:
+
+![Properties](images/gui-templates/properties.png){srcset="images/gui-templates/[email protected] 2x"}
+
+被修改了属性的节点也会在 *Outline* 视图中以蓝色显示:
+
+![Outline](images/gui-templates/outline.png){srcset="images/gui-templates/[email protected] 2x"}
+
+这些模板实例以折叠方式在 *Outline* 视图中显示. 然而, 你要明确它 *不是一个普通节点*. 同样, 运行时也没有模板的概念, 只是其所有节点存在着.
+
+有些模板实例会自动以 模板名加正斜杠 (`"/"`) 加 *Id* 的形式命名.
+
+::: 注意
+修改模板实例中 *Layouts* 属性在目前2代编辑器中无效. 必须使用的话请使用1代编辑器.
+
+参见 https://github.com/defold/editor2-issues/issues/1124
+:::
+
+## 运行时修改模板
+
+代码访问节点只需使用模板 *Id* 作为前缀加上实例节点名即可:
+
+```lua
+if gui.pick_node(gui.get_node("button_1/button"), x, y) then
+    -- Do something...
+end
+```
+
+模板本身没有实例. 如果需要根节点, 请在模板里面添加.
+
+如果脚本被添加到 GUI 场景里, 那么此脚本不存在于节点树状结构中. 每个 GUI 场景可以添加一个脚本, 实例化的时候脚本执行与 GUI 场景之上.

+ 58 - 0
docs/zh/manuals/gui-text.md

@@ -0,0 +1,58 @@
+---
+title: Defold GUI 文本节点
+brief: 本教程介绍了如何在 GUI 场景中添加文本.
+---
+
+# GUI 文本节点
+
+Defold 支持专门用于GUI场景中显示文本的GUI节点. 各种字体资源都可以被文本节点用以渲染文字.
+
+## 添加文本节点
+
+需要在文本节点使用的字体首先要应用到 GUI 组件之中. 或者使用右键点击 *Fonts* 文件夹, 使用 <kbd>GUI</kbd> 顶级菜单或者快捷键.
+
+![Fonts](images/gui-text/fonts.png){srcset="images/gui-text/[email protected] 2x"}
+
+文本节点有一些特有属性:
+
+*Font*
+: 每个文本节点都要有 *字体* 属性设置.
+
+*Text*
+: 此属性设置节点显示的文字.
+
+*Line Break*
+: 文本对齐与锚点相关, 此属性可以让文本流动几行. 节点宽度决定文本在哪里换行.
+
+## 锚点和对齐
+
+你可以通过设置锚点来改变文本的对齐方式.
+
+*Center*
+: 如果锚点设置成 `Center`, `North` 或者 `South`, 则文本居中对齐.
+
+*Left*
+: 如果锚点设置成任何 `West` 模式, 则文本左对齐.
+
+*Right*
+: 如果锚点设置成任何 `East` 模式, 则文本右对齐.
+
+![文本对齐](images/gui-text/align.png){srcset="images/gui-text/[email protected] 2x"}
+
+## 运行时控制操作
+
+文本节点同样可以控制 size, pivot, color 之类的属性. 此外还有一些文本节点特有属性:
+
+* 要改变文本字体, 使用 [`gui.set_font()`](/ref/gui/#gui.set_font) 函数.
+* 要改变文本换行行为, 使用 [`gui.set_line_break()`](/ref/gui/#gui.set_line_break) 函数.
+* 要改变文本文字, 使用 [`gui.set_text()`](/ref/gui/#gui.set_text) 函数.
+
+```lua
+function on_message(self, message_id, message, sender)
+    if message_id == hash("set_score") then
+        local s = gui.get_node("score")
+        gui.set_text(s, message.score)
+    end
+end
+```
+

+ 351 - 0
docs/zh/manuals/gui.md

@@ -0,0 +1,351 @@
+---
+title: Defold 里的 GUI 场景
+brief: 本教程介绍了 Defold GUI 编辑器, 各种各样的 GUI 节点以及 GUI 脚本.
+---
+
+# GUI
+
+Defold provides you with a custom GUI editor and powerful scripting possibilities that are tailor made for the construction and implementation of user interfaces.
+
+A graphical user interface in Defold is a component that you build and attach to a game object and place in a collection. This component has the following properties:
+
+* It has simple, but powerful, layout features that allow resolution and aspect ratio independent rendering of your user interface.
+* It can have logic behavior attached to it through a *GUI script*.
+* It is (by default) rendered on top of other content, independent of camera view so even if you have a moving camera, your GUI elements will stay put on the screen. The rendering behavior can be changed.
+
+GUI components are rendered independently of the game view. Because of this it is not placed in a particular location in the collection editor, nor does it have a visual representation in the collection editor. However, GUI components have to reside in a game object that has a location in a collection. Changing that location has no effect on the GUI.
+
+## Creating a GUI component
+
+GUI components are created from a GUI scene blueprint file. To to create a new GUI component, <kbd>right click</kbd> a location in the *Assets* browser and select <kbd>New ▸ Gui</kbd>. Type a name for the new GUI file and press <kbd>Ok</kbd>.
+
+![New gui file](images/gui/new_gui_file.png){srcset="images/gui/[email protected] 2x"}
+
+Defold now automatically opens the file in the GUI scene editor.
+
+![New gui](images/gui/new_gui.png){srcset="images/gui/[email protected] 2x"}
+
+The *Outline* lists all the GUI:s content: it's list of nodes and any dependencies (see below).
+
+The central editing area shows the GUI. The toolbar in the top right corner of the editing area contains *Move*, *Rotate* and *Scale* tools, as well as a [layout](/manuals/gui-layouts) selector.
+
+![toolbar](images/gui/toolbar.png){srcset="images/gui/[email protected] 2x"}
+
+A white rectangle shows the bounds of the currently selected layout, of the default display width and height as set in the project settings.
+
+Selecting the root "Gui" node in the *Outline* shows the *Properties* for the GUI component:
+
+Script
+: The GUI script bound to this GUI component.
+
+Material
+: The material used when rendering this GUI.
+
+Adjust Reference
+: Controls how each node's *Adjust Mode* should be calculated:
+
+  - `Per Node` adjusts each node against the adjusted size of the parent node, or the resized screen.
+  - `Disable` turns off node adjust mode. This forces all nodes to keep their set size.
+
+Max Nodes
+: The maximum number of nodes for this GUI.
+
+## Dependencies
+
+The resource tree in a Defold game is static so any dependences that you need for your GUI nodes need to be added to the component. The *Outline* groups all dependencies by type under "folders":
+
+![dependencies](images/gui/dependencies.png){srcset="images/gui/[email protected] 2x"}
+
+To add a new dependency, <kbd>right click</kbd> the "Gui" root in the *Outline*, then select <kbd>Add ▸ [type]</kbd> from the popup context menu.
+
+You can also <kbd>right click</kbd> on the folder icon for the type you want to add and select <kbd>Add ▸ [type]</kbd>.
+
+## Node types
+
+A GUI component is built from a set of nodes. Nodes are simple elements. They can be translated (moved, scaled and rotated) and ordered in parent-child hierarchies either in the editor or at runtime through scripting. The following node types exist:
+
+Box node
+: ![box node](images/icons/gui-box-node.png){.left}
+  Rectangular node with either a single color, texture or flip-book animation. See the [Box node documentation](/manuals/gui-box) for details.
+
+<div style="clear: both;"></div>
+
+Text node
+: ![text node](images/icons/gui-text-node.png){.left}
+  Displays text. See the [Text node documentation](/manuals/gui-text) for details.
+
+<div style="clear: both;"></div>
+
+Pie node
+: ![pie node](images/icons/gui-pie-node.png){.left}
+  A circular or ellipsoid node that can be partially filled or inverted. A See the [Pie node documentation](/manuals/gui-pie) for details.
+
+<div style="clear: both;"></div>
+
+Template node
+: ![template node](images/icons/gui.png){.left}
+  Templates are used to create instances based on other GUI scene files. See the [Template node documentation](/manuals/gui-template) for details.
+
+<div style="clear: both;"></div>
+
+Spine node
+: ![spine node](images/icons/spine-model.png){.left}
+  Displays and animates a spine model. See the [Spine node documentation](/manuals/gui-spine) for details.
+
+<div style="clear: both;"></div>
+
+ParticleFX node
+: ![particlefx node](images/icons/particlefx.png){.left}
+  Plays a particle effect. See the [ParticleFX node documentation](/manuals/gui-particlefx) for details.
+
+<div style="clear: both;"></div>
+
+Add nodes by right-clicking on the *Nodes* folder and selecting <kbd>Add ▸</kbd> and then <kbd>Box</kbd>, <kbd>Text</kbd>, <kbd>Pie</kbd>, <kbd>Template</kbd>, <kbd>Spine</kbd> or <kbd>ParticleFx</kbd>.
+
+![Add nodes](images/gui/add_node.png){srcset="images/gui/[email protected] 2x"}
+
+You can also press <kbd>A</kbd> and select the type you want to add to the GUI.
+
+## Node properties
+
+Each node has an extensive set of properties that control its appearance:
+
+Id
+: The identity of the node. This name has to be unique within the GUI scene.
+
+Position, Rotation and Scale
+: Governs the location, orientation and stretching of the node. You can use the *Move*, *Rotate* and *Scale* tools to change these values. The values can be animated from script.
+
+Size (box, text and pie nodes)
+: The size of the node is automatic by default but by setting the *Size Mode* to `Manual` you can alter the value. The size defines the bounds of the node and is used when doing input picking. This value can be animated from script.
+
+Size Mode (box and pie nodes)
+: If set to `Automatic` the editor will set a size for the node. If set to `Manual` you can set the size yourself.
+
+Text (text nodes)
+: The text to display on the node.
+
+Line Break (text nodes)
+: Set for text to wrap according to the width of the node.
+
+Font (text nodes)
+: The font to use when rendering the text.
+
+Texture (box and pie nodes)
+: The texture to draw on the node. This is a reference to an image or animation in an atlas or tile source.
+
+Slice 9 (box nodes)
+: Set to preserve the pixel size of the node's texture around the edges when the node is resized. See the [Box node documentation](/manuals/gui-box) for details.
+
+Inner Radius (pie nodes)
+: The inner radius of the node, expressed along the X axis. See the [Pie node documentation](/manuals/gui-pie) for details.
+
+Outer Bounds (pie nodes)
+: Controls the behavior of the outer bounds. See the [Pie node documentation](/manuals/gui-pie) for details.
+
+Perimeter Vertices (pie nodes)
+: The number of segments that will be used to build the shape. See the [Pie node documentation](/manuals/gui-pie) for details.
+
+Pie Fill Angle (pie nodes)
+: How much of the pie should be filled. See the [Pie node documentation](/manuals/gui-pie) for details.
+
+Template (template nodes)
+: The GUI scene file to use as template for the node. See the [Template node documentation](/manuals/gui-template) for details.
+
+Spine Scene (spine nodes)
+: The Spine Scene to use for this node. See the [Spine node documentation](/manuals/gui-spine) for details.
+
+Default Animation (spine nodes)
+: The animation to automatically play on this node. See the [Spine node documentation](/manuals/gui-spine) for details.
+
+Skin (spine nodes)
+: The skin to use for the node. See the [Spine node documentation](/manuals/gui-spine) for details.
+
+ParticleFX (particlefx nodes)
+: The particle effect to use on this node. See the [ParticleFX node documentation](/manuals/gui-particlefx) for details.
+
+Color
+: The color of the node. It the node is textured, the color tints the texture. The color can be animated from script.
+
+Alpha
+: The translucency of the node. The alpha value can be animated from script.
+
+Inherit Alpha
+: Setting this checkbox makes a node inherit the alpha value of the parent node. The node's alpha value is then multiplied with the parent's alpha value.
+
+Leading (text nodes)
+: A scaling number for the line spacing. A value of `0` gives no line spacing. `1` (the default) is normal line spacing.
+
+Tracking (text nodes)
+: A scaling number for the letter spacing. Defaults to 0.
+
+Layer
+: Assigning a layer to the node overrides the normal draw order and instead follows the layer order. See below for details.
+
+Blend mode
+: Controls how the graphics of the node is blended with background graphics:
+  - `Alpha` alpha blends the pixel values of the node with the background. This corresponds to "Normal" blend mode in graphics software.
+  - `Add` adds the pixel values of the node with the background. This corresponds to "Linear dodge" in some graphics software.
+  - `Multiply` multiplies the pixel values of the node with the background.
+
+Pivot
+: Sets the pivot point for the node. This can be seen as the "center point" of the node. Any rotation, scaling or size change will happen around this point.
+
+  Possible values are `Center`, `North`, `South`, `East`, `West`, `North West`, `North East`, `South West` or `South East`.
+
+  ![pivot point](images/gui/pivot.png){srcset="images/gui/[email protected] 2x"}
+
+  If you change the pivot of a node, the node will be moved so that the new pivot will be at the node's position. Text nodes are aligned so that `Center` sets the text center-aligned, `West` sets the text left-aligned and `East` sets the text right-aligned.
+
+X Anchor, Y Anchor
+: Anchoring controls how the node's vertical and horizontal position is altered when the scene boundaries, or the parent node's boundaries are stretched to fit the physical screen size.
+
+  ![Anchor unadjusted](images/gui/anchoring_unadjusted.png){srcset="images/gui/[email protected] 2x"}
+
+  The following anchoring modes are available:
+
+  - `None` (for both *X Anchor* and *Y Anchor*) keeps the node's position from the center of the parent node or scene, relative it's *adjusted* size.
+  - `Left` or `Right` (*X Anchor*) scales the horizontal position of the node so it keeps the position from the left and right edges of the parent node or scene at the same percentage.
+  - `Top` or `Bottom` (*Y Anchor*) scales the vertical position of the node so it keeps the position from the top and bottom edges of the parent node or scene at the same percentage.
+
+  ![Anchoring](images/gui/anchoring.png){srcset="images/gui/[email protected] 2x"}
+
+Adjust Mode
+: Sets the adjust mode for the node. The adjust mode setting controls what happens to a node when the scene boundaries, or the parent node's boundaries, are adjusted to fit the physical screen size.
+
+  A node created in a scene where the logical resolution is a typical landscape resolution:
+
+  ![Unadjusted](images/gui/unadjusted.png){srcset="images/gui/[email protected] 2x"}
+
+  Fitting the scene to a portrait screen cause the scene to be stretched. Each node's bounding box is similarly stretched. However, by setting the adjust mode, the aspect ratio of the node's content can be kept intact. The following modes are available:
+
+  - `Fit` scales the node content so that it is equal to the stretched bounding box width or height, whichever is smallest. In other words, the content will fit inside the stretched node bounding box.
+  - `Zoom` scales the node content so that it is equal to the stretched bounding box width or height, whichever is largest. In other words, the content will fully cover the stretched node bounding box.
+  - `Stretch` stretches the node content so it fills the stretched node bounding box.
+
+  ![Adjust modes](images/gui/adjusted.png){srcset="images/gui/[email protected] 2x"}
+
+  If the GUI scene property *Adjust Reference* is set to `Disabled`, this setting will be ignored.
+
+Clipping Mode (box, pie and spine nodes)
+: Sets the clipping mode on the node:
+
+  - `None` renders the node as usual.
+  - `Stencil` makes the node boundaries define a stencil mask that is used to clip the node's child nodes.
+
+  See the [GUI clipping manual](/manuals/gui-clipping) for details.
+
+Clipping Visible (box, pie and spine nodes)
+: Set to render the node's content in the stencil area. See the [GUI clipping manual](/manuals/gui-clipping) for details.
+
+Clipping Inverted (box, pie and spine nodes)
+: Invert the stencil mask. See the [GUI clipping manual](/manuals/gui-clipping) for details.
+
+
+## Pivot, Anchors and Adjust Mode
+
+The combination of Pivot, Anchors and Adjust Mode properties allows for a very flexible design of GUIs but it can be somewhat hard to understand how it all works without looking at a concrete example. Let's take this GUI mockup created for a 640x1136 screen as an example:
+
+![](images/gui/adjustmode_example_original.png)
+
+The UI is created with X and Y Anchors set to None and the Adjust Mode for each node is left at the default value of Fit. The Pivot point for the top panel is North, the pivot for the bottom panel is South and the pivot point for the bars in the top panel are set to West. The rest of the nodes have pivot points set to Center. If we resize the window to make it wider this is what happens:
+
+![](images/gui/adjustmode_example_resized.png)
+
+Now, what if we want the top and bottom bars to always be as wide as the screen? We can change the Adjust Mode for the grey background panels at the top and bottom to Stretch:
+
+![](images/gui/adjustmode_example_resized_stretch.png)
+
+This is better. The grey background panels will now always stretch to the width of the window, but the bars in the top panel as well as the two boxes at the bottom aren't positioned properly. If we want to keep the bars at the top positioned to the left we need to change the X Anchor from None to Left:
+
+![](images/gui/adjustmode_example_top_anchor_left.png)
+
+That is exactly as we want it for the top panel. The bars in the top panel already had their Pivot points set to West which means that they will position themselves nicely with the left/west edge of the bars (Pivot) anchored to the left edge of the parent panel (X Anchor).
+
+Now, if we set the X Anchor to Left for the box on the left and the X Anchor to Right for the box on the right we get the following result:
+
+![](images/gui/adjustmode_example_bottom_anchor_left_right.png)
+
+This is not quite the expected result. The two boxes should stay as close to the left and right edges as the two bars did in the top panel. The reason for this is that the Pivot point is wrong:
+
+![](images/gui/adjustmode_example_bottom_pivot_center.png)
+
+Both boxes have a Pivot point set to Center. What this means is that when the screen becomes wider the center point (the pivot point) of the boxes will stay at the same relative distance from the edges. In the case of the left box it was 17% from the left edge with the original 640x1136 window:
+
+![](images/gui/adjustmode_example_original_ratio.png)
+
+When the screen is resized the center point of the left box remains at the same distance of 17% from the left edge:
+
+![](images/gui/adjustmode_example_resized_stretch_ratio.png)
+
+If we change the Pivot point from Center to West for the box on the left and to East for the box on the right and reposition the boxes we get the result we're after even when the screen is resized:
+
+![](images/gui/adjustmode_example_bottom_pivot_west_east.png)
+
+
+## Draw order
+
+All nodes are rendered in the order they are listed under the "Nodes" folder. The node at the top of the list is drawn first and will thus appear behind every other node. The last node in the list is drawn last, meaning it will appear in front of all other nodes. Altering the Z-value on a node does not control its draw order; however, if you set the Z-value outside of your render script's render range the node will no longer be rendered to screen. You can override the index ordering of nodes with layers (see below).
+
+![Draw order](images/gui/draw_order.png){srcset="images/gui/[email protected] 2x"}
+
+Select a node and press <kbd>Alt + Up/Down</kbd> to move a node up or down and change its index order.
+
+The draw order can be changed in script:
+
+```lua
+local bean_node = gui.get_node("bean")
+local shield_node = gui.get_node("shield")
+
+if gui.get_index(shield_node) < gui.get_index(bean_node) then
+  gui.move_above(shield_node, bean_node)
+end
+```
+
+## Parent-child hierarchies
+
+A node is made the child of another node by dragging it onto the node that you wish to be the child's parent. A node with a parent inherits the transform (position, rotation and scale) applied to the parent and relative to the parent pivot.
+
+![Parent child](images/gui/parent_child.png){srcset="images/gui/[email protected] 2x"}
+
+Parents are drawn before their children. Use layers to change the draw order of parent and child nodes and to optimize the rendering of nodes (see below).
+
+
+## Layers and draw calls
+
+Layers give fine grained control over how nodes are drawn and can be used to reduce the number of draw calls the engine must create to draw a GUI scene. When the engine is about to draw the nodes of a GUI scene, it groups the nodes into draw call batches based on the following conditions:
+
+- The nodes must use the same type.
+- The nodes must use the same atlas or tile source.
+- The nodes must be rendered with the same blend mode.
+- They must use same font.
+
+If a node differs from the previous one on any of these points, it will break the batch and create another draw call. Clipping nodes always break the batch and each stencil scope also breaks the batch.
+
+The ability to arrange nodes in hierarchies makes it easy to group nodes into manageable units. But hierarchies can effectively break batch rendering if you mix different node types:
+
+![Breaking batch hierarchy](images/gui/break_batch.png){srcset="images/gui/[email protected] 2x"}
+
+When the rendering pipeline walks through the list of nodes, it is forced to set up a separate batch for each separate node because the types are different. All in all these three buttons will require six draw calls.
+
+By assigning layers to the nodes, they can be ordered differently, allowing the render pipeline to group the nodes together in fewer draw calls. Start by adding the layers you need to the scene. <kbd>Right click</kbd> the "Layers" folder icon in the *Outline* and select <kbd>Add ▸ Layer</kbd>. Mark the new layer and assign it a *Name* property in the *Properties* view.
+
+![Layers](images/gui/layers.png){srcset="images/gui/[email protected] 2x"}
+
+Then set the *Layer* property on each node to the corresponding layer. The layer drawing order takes precedence over the regular indexed node order, so setting the button graphics box-nodes to "graphics" and the button text nodes to "text" will result in the following draw order:
+
+* First all nodes in the "graphics" layer, from the top:
+
+  1. "button-1"
+  2. "button-2"
+  3. "button-3"
+
+* Then all nodes in the "text" layer, from the top:
+
+  4. "button-text-1"
+  5. "button-text-2"
+  6. "button-text-3"
+
+The nodes can now be batched into two draw calls, instead of six. A major performance win!
+
+Note that a child node with unset layer will implicitly inherit the layer setting of its parent node. Not setting a layer on a node implicitly adds it to the "null" layer, which is drawn before any other layer.

+ 122 - 0
docs/zh/manuals/hot-reload.md

@@ -0,0 +1,122 @@
+---
+title: 热重载
+brief: 本教程介绍了 Defold 中的热重载特性.
+---
+
+# 热重载资源
+
+Defold 允许资源的热重载. 开发游戏时此功能可以大大节省时间. 它可以让你在游戏运行时修改代码和内容. 经常用于:
+
+- 使用 Lua 脚本调整游戏.
+- 编辑调整可视元素 (比如粒子特效或 GUI 元素) 即时观察效果.
+- 编辑调整 shader 代码即时观察效果.
+- 测试时重启关卡, 设定状态之类---而不用关闭游戏.
+
+## 如何热重载
+
+从编辑器启动游戏 (<kbd>Project ▸ Build</kbd>).
+
+选择菜单项 <kbd>File ▸ Hot Reload</kbd> 或者通过键盘快捷键实现热重载:
+
+![Reloading resources](images/hot-reload/menu.png){srcset="images/hot-reload/[email protected] 2x"}
+
+## 设备上的热重载
+
+除了桌面设备, 热重载也可以其他设备上使用. 要在设备上使用热重载, 在移动设备上运行游戏的调试(debug)版本, 或者运行 [开发应用](/manuals/dev-app) , 然后在编辑器中选择目标设备:
+
+![target device](images/hot-reload/target.png){srcset="images/hot-reload/[email protected] 2x"}
+
+当编译运行时, 编辑器会把所有资源上传到设备上运行着的游戏里. 也就是说, 热重载的所有文件都会在设备上进行更新.
+
+比如, 想在手机上运行着的游戏 GUI 上添加几个按钮, 仅需要打开 GUI 文件:
+
+![reload gui](images/hot-reload/gui.png){srcset="images/hot-reload/[email protected] 2x"}
+
+加入按钮, 保存并热重载 GUI 文件. 然后在手机上就能看见新建的按钮了:
+
+![reloaded gui](images/hot-reload/gui-reloaded.png){srcset="images/hot-reload/[email protected] 2x"}
+
+当你将某个文件进行热重载, 游戏引擎会在控制台列出每个被热重载了的资源文件.
+
+## 重载脚本
+
+任何被重载的 Lua 脚本文件都会在 Lua 运行环境里重新执行.
+
+```lua
+local my_value = 10
+
+function update(self, dt)
+    print(my_value)
+end
+```
+
+修改 `my_value` 为 11 然后进行热重载就可以看到改动立刻生效了:
+
+```text
+...
+DEBUG:SCRIPT: 10
+DEBUG:SCRIPT: 10
+DEBUG:SCRIPT: 10
+INFO:RESOURCE: /main/hunter.scriptc was successfully reloaded.
+DEBUG:SCRIPT: 11
+DEBUG:SCRIPT: 11
+DEBUG:SCRIPT: 11
+...
+```
+
+注意热重载不影响生命周期函数的执行. 比如热更新不会自动调用 `init()` 函数. 当然在这些函数上所做的修改, 还是会被更新的.
+
+## 重载 Lua 模块
+
+只要在模块文件中加入了全局变量, 重载此模块文件后变量也会随之更新:
+
+```lua
+--- my_module.lua
+my_module = {}
+my_module.val = 10
+```
+
+```lua
+-- user.script
+require "my_module"
+
+function update(self, dt)
+    print(my_module.val) -- hot reload "my_module.lua" and the new value will print
+end
+```
+
+Lua 模块的一个常用方法是构造一个局部数据表, 输出并返回它:
+
+```lua
+--- my_module.lua
+local M = {} -- a new table object is created here
+M.val = 10
+return M
+```
+
+```lua
+-- user.script
+local mm = require "my_module"
+
+function update(self, dt)
+    print(mm.val) -- will print 10 even if you change and hot reload "my_module.lua"
+end
+```
+
+更改并重载 "my_module.lua" 并 _不会_ 更新 "user.script" 的输出值. 关于这种情况的成因以及如何避免, 详见 [模块教程](/manuals/modules).
+
+## on_reload() 函数
+
+所有脚本组件都能定义 `on_reload()` 函数. 如果此函数存在, 则在重载时会自动被调用. 对于检查和修改数据, 发送消息之类的很有用:
+
+```lua
+function on_reload(self)
+    print(self.velocity)
+
+    msg.post("/level#controller", "setup")
+end
+```
+
+## 重载shader数据
+
+当重载顶点与片元着色器时, GLSL 代码会被显卡驱动程序重新编译并上传至 GPU. 因为 GLSL 很底层的所以很有可能出现着色器代码崩溃的情况, 这种情况下游戏引擎也会崩溃.

+ 214 - 0
docs/zh/manuals/html5.md

@@ -0,0 +1,214 @@
+---
+title: Defold HTML5 平台开发
+brief: 本教程介绍了 HTML5 游戏开发, 及其已知问题和局限性.
+---
+
+# HTML5 开发
+
+通过编辑器编译菜单可以看到, Defold 支持导出 HTML5 游戏. 进一步说, 游戏会通过一个模板系统嵌入到一个 HTML 页面之中.
+
+*game.project* 文件包含了 HTML5 相关设置:
+
+![Project settings](images/html5/html5_project_settings.png)
+
+## Heap size
+
+Defold 通过 Emscripten (详见 http://en.wikipedia.org/wiki/Emscripten) 支持 HTML5 导出. 简单地说, 它为应用的运行建立了一个虚拟内存堆. 默认情况下, 引擎分配了一块内存 (256MB). 这对一般游戏足够了. 通过游戏优化, 可以做到申请内存最小化. 要调整内存分配, 步骤如下:
+
+1. 设置 *heap_size* 为需要的值. 以兆字节表示.
+2. 打包 HTML5 游戏 (见下文)
+
+## 测试 HTML5 游戏
+
+要测试 HTML5 游戏, 需要先启动一个 HTTP 服务程序. Defold 可以通过 <kbd>Project ▸ Build HTML5</kbd> 启动内建 HTTP 服务.
+
+![Build HTML5](images/html5/html5_build_launch.png)
+
+要测试 HTML5 游戏, 把游戏上传到远程 HTTP 服务器或者使用本地服务程序, 比如, 使用 python 自带的 HTTP 服务.
+Python 2:
+> python -m SimpleHTTPServer
+
+Python 3:
+> python -m http.server
+
+或者
+> python3 -m http.server
+
+::: 注意
+不能直接用浏览器打开 HTML5 游戏的 `index.html` 文件. 要通过服务器访问打开.
+:::
+
+## 打包 HTML5 游戏
+
+Defold 打包 HTML5 游戏很简单, 跟其他平台一样: 从菜单栏选择 <kbd>Project ▸ Bundle...​ ▸ HTML5 Application...</kbd>:
+
+![Application files](images/html5/html5_bundle.png)
+
+会弹出提示框让你选择游戏存放位置. 打包结束后, 就可以看到输出的所有文件.
+
+## 已知问题和局限性
+
+* Live update - Defold 应用必须通过服务器加载运行才能接收热更新. 纯浏览器网页无法获得热更新.
+* Internet Explorer 11
+  * Audio - Defold 使用 HTML5 _WebAudio_ (详见 http://www.w3.org/TR/webaudio) 来处理声音, 目前 Internet Explorer 11 还不支持. 所以这种情况下没有声音.
+  * WebGL - Microsoft 没有完全实现 _WebGL_ API (详见 https://www.khronos.org/registry/webgl/specs/latest/). 所以, 较其他浏览器而言对WebGL支持不好.
+  * Full screen - 全屏模式在浏览器中不可靠.
+* Chrome
+  * Slow debug builds - 为了在 HTML5 平台更好地调试我们开启了校验所有 WebGL 图像调用来检测错误. 但是这样做在 Chrome 上会运行缓慢. 可以把 *game.project* 里的 *Engine Arguments* 部分设置为 `–verify-graphics-calls=false` 来关闭图像调用校验.
+
+## 自定义 HTML5 打包
+
+针对 HTML5 版本的游戏, Defold 提供了一个默认模板网页. 其中包含的样式和脚本代码决定了游戏的显示方式.
+
+游戏输出时, 这个页面也会重新生成. 如果想要自定义网页模板需要在项目设置里手动配置. 要配置的话, 打开 Defold 编辑器的 *game.project* 文件然后找到 *html5* 部分:
+
+![HTML5 Section](images/html5/html5_section.png)
+
+关于每个选项详情请见 [形目设置教程](/manuals/project-settings/#html5).
+
+::: 注意
+`builtins` 文件夹下的默认 html/css 模板文件是不能直接修改的. 要先从 `builtins` 里把文件拷贝出来然后再在 `game.project` 文件里指明要使用的文件的位置.
+:::
+
+::: 注意
+网页 canvas 不能有 border 或者 padding. 否则的话, 鼠标输入坐标会产生偏差.
+:::
+
+可以在 `game.project` 文件里禁用 `Fullscreen` 按钮以及 `Made with Defold` 链接.
+Defold 提供了 index.html 文件的亮暗两种风格. 默认亮风格但是可以在 `Custom CSS` 修改成暗风格. 在 `Scale Mode` 部分还预定义了四种缩放模式可供选择.
+
+::: 注意
+各种缩放模式计算时考虑了当前屏幕 DPI 以支持 `game.project` 里的 `High Dpi` 选项 (在 `Display` 部分)
+:::
+
+### Fit 和 Downscale Fit
+
+使用 `Fit` 模式 canvas 会以原始比例缩放来适配当前屏幕. `Downscale Fit` 的区别在于, 如果内嵌网页比游戏 canvas 小, 则游戏缩小;反之则以原始大小显示而并不放大=.
+
+![HTML5 Section](images/html5/html5_fit.png)
+
+### Stretch
+
+使用 `Stretch` 模式 canvas 会充满整个内嵌网页.
+
+![HTML5 Section](images/html5/html5_stretch.png)
+
+### No Scale
+使用 `No Scale` 模式游戏 canvas 大小保持在 `game.project` 文件里 `[display]` 部分设置的值.
+
+![HTML5 Section](images/html5/html5_no_scale.png)
+
+## Tokens
+
+使用 [Mustache 模板语言](https://mustache.github.io/mustache.5.html) 创建 `index.html` 文件. 编译或打包时, HTML 和 CSS 文件会基于项目设置填充模板里面对应的 Tokens. 这些 Tokens 通常使用双大括号或者三层大括号标注 (`{{TOKEN}}` 或者 `{{{TOKEN}}}`), 用哪种取决于标注里面有没有转义字符. 这种方法便于频繁修改以及代码重用.
+
+::: 注意
+关于 Mustache 模板语言详情请见 [官方手册](https://mustache.github.io/mustache.5.html).
+:::
+
+`game.project` 里的设置都可以使用标注来引用. 比如说, 引用 `Display` 里 `Width` 的值:
+
+![Display section](images/html5/html5_display.png)
+
+用普通文本编辑器打开 `game.project` 找到想引用的 `[section_name]` 部分. 像这样引用设置的值: `{{section_name.field}}` 或者 `{{{section_name.field}}}`.
+
+![Display section](images/html5/html5_game_project.png)
+
+比如, 在 HTML 模板的 JavaScript 里:
+
+```javascript
+function doSomething() {
+    var x = {{display.width}};
+    // ...
+}
+```
+
+而且, 我们还可以自定义标注:
+
+DEFOLD_SPLASH_IMAGE
+: 溅射屏幕图片文件名, 如果 `game.project` 里的 `html5.splash_image` 为空, 则设置为 `false`.
+
+
+```css
+{{#DEFOLD_SPLASH_IMAGE}}
+		background-image: url("{{DEFOLD_SPLASH_IMAGE}}");
+{{/DEFOLD_SPLASH_IMAGE}}
+```
+
+exe-name
+: 不包含任何非法符号的项目名
+
+
+DEFOLD_CUSTOM_CSS_INLINE
+: 这里就是在 `game.project` 里设置的内联 CSS 文件的地方.
+
+
+```html
+<style>
+{{{DEFOLD_CUSTOM_CSS_INLINE}}}
+</style>
+```
+
+::: 注意
+内联块要出现在主程序脚本加载之前. 因为里面有 HTML 标签, 所以要用三层大括号 `{{{TOKEN}}}` 来引用它.
+:::
+
+DEFOLD_SCALE_MODE_IS_DOWNSCALE_FIT
+: 如果 `html5.scale_mode` 是 `Downscale Fit` 的话则值为 `true`.
+
+DEFOLD_SCALE_MODE_IS_FIT
+: 如果 `html5.scale_mode` 是 `Fit` 的话则值为 `true`.
+
+DEFOLD_SCALE_MODE_IS_NO_SCALE
+: 如果 `html5.scale_mode` 是 `No Scale` 的话则值为 `true`.
+
+DEFOLD_SCALE_MODE_IS_STRETCH
+: 如果 `html5.scale_mode` 是 `Stretch` 的话则值为 `true`.
+
+DEFOLD_HEAP_SIZE
+: 在 `game.project` 里设置的内存大小, `html5.heap_size` 的值以字节为单位.
+
+DEFOLD_ENGINE_ARGUMENTS
+: 在 `game.project` 里设置的引擎参数, `html5.engine_arguments` 以逗号 `,` 分隔.
+
+
+## 额外参数
+
+要创建自定义模板, 可以为引擎加载提供额外参数:
+```
+`Module.runApp("canvas", extra_params) - 通过指定canvas启动游戏
+
+'extra_params' 可选的额外参数, 如下:
+
+'archive_location_filter':
+    包地址过滤.
+
+'unsupported_webgl_callback':
+    如果不支持 WebGL 则需调用的回调函数.
+
+'engine_arguments':
+    传入引擎的参数列表 (字符串).
+
+'persistent_storage':
+    是否使用持久化存储的布尔值.
+
+'custom_heap_size':
+    自定义内存使用的大小.
+
+'disable_context_menu':
+    为 true 的话则在canvas上关闭右键上下文弹出菜单.
+
+'retry_time':
+    文件下载失败重试时间间隔.
+
+'retry_count':
+    文件下载失败充实次数.
+
+'can_not_download_file_callback':
+    如果重试次数已满但是仍没有得到文件则需调用的回调函数.
+*/
+```
+
+## HTML5 的文件操作
+
+HTML5 支持 `sys.save()`, `sys.load()` 和 `io.open()` 之类的文件操作, 但是与其他平台实现方法不同. 基于安全考虑浏览器里运行的 Javascript 无权直接读写本地文件. Emscripten (即 Defold) 使用 [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB) 代替, 它是基于浏览器的持久化存储方案, 基于浏览器的虚拟文件系统. 与其他平台的区别主要是比直接读写文件要慢而且实质上读写的是一个数据库. 浏览器开发者工具通常都提供了 IndexedDB 的读写功能.

+ 44 - 0
docs/zh/manuals/iac.md

@@ -0,0 +1,44 @@
+---
+title: Defold 的应用内通信
+brief: 应用内通信可以让你获得应用启动时的启动参数信息. 本教程解释了Defold中此功能的API.
+---
+
+# 应用内通信
+
+大多数操作系统中应用可以由以下方式启动:
+
+* 从已安装应用表中启动
+* 从应用链接启动
+* 从推送消息中启动
+* 在安装程序最后一步启动.
+
+从链接, 通知, 安装程序启动应用时可以获得引用, 比如安装时的快捷方式或者超级链接, 通知里的长链接. Defold 使用一个native extension提供一个统一的方法来获得应用是如何启动的相关信息.
+
+## 安装扩展
+
+要使用应用内通信扩展程序你需要在你的 `game.project` 里添加一个依赖. 此依赖的URL是:
+```
+https://github.com/defold/extension-iac/archive/master.zip
+```
+
+推荐使用 [指定版本](https://github.com/defold/extension-iac/releases) 的zip包链接作为依赖.
+
+## 使用扩展
+
+API很简单. 提供给扩展程序一个回调用的监听器函数.
+
+```
+local function iac_listener(self, payload, type)
+     if type == iac.TYPE_INVOCATION then
+         -- This was an invocation
+         print(payload.origin) -- origin may be empty string if it could not be resolved
+         print(payload.url)
+     end
+end
+
+function init(self)
+     iac.set_listener(iac_listener)
+end
+```
+
+API完整文档在[此页面](https://defold.github.io/extension-iac/).

+ 202 - 0
docs/zh/manuals/iap.md

@@ -0,0 +1,202 @@
+---
+title: Defold 中的内支付
+brief: In-app purchases (or in-app billing) allows you to charge your players or app users for extra content or functionality. This manual explains Defold's API available for this functionality.
+---
+
+# In-app purchases
+
+Defold provides a unified, simple to use interface to Apple's iOS Appstore "in-app purchases" and Google Play's or Amazon's "in-app billing" on Android devices. Facebook Canvas "game payments" are supported for Facebook Canvas. These services gives you the opportunity to sell products as:
+
+* Standard in-app products (one time billing) of consumables or non-consumables and
+* Subscriptions (recurring, automated billing)
+
+::: important
+The current Defold interface allows full interaction with Apple's Storekit functionality. For Google Play and Facebook Canvas, the interface is identical, meaning that you can run the same code on either platform. However, some process flow might differ from platform to platform. Also note that there is currently no support for OS X purchases through the Mac Appstore.
+:::
+
+Detailed documentation from Apple, Google, Amazon and Facebook can be found here:
+
+* [In-App Purchase Programming Guide](https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html).
+* [Google Play In-app Billing documentation](http://developer.android.com/google/play/billing/index.html).
+* [Amazon In-app Purchase documentation](https://developer.amazon.com/public/apis/earn/in-app-purchasing).
+* [Facebook game payments documentation](https://developers.facebook.com/docs/payments).
+
+## Installing the extension
+
+To start using the In-app purchases extension you need to add it as a dependency to your `game.project` file. The latest stable version is available with the dependency URL:
+```
+https://github.com/defold/extension-iap/archive/master.zip
+```
+
+We recommend using a link to a zip file of a [specific release](https://github.com/defold/extension-iap/releases).
+
+Documentation of the API is available on the [extension GitHub page](https://defold.github.io/extension-iap/).
+
+
+## Testing Google Play Billing with static responses
+
+On Android it is recommended that you start implementing IAP in your app by using static responses from Google Play. This enables you to verify that everything in your app works correctly before you publish the app. Four reserved product IDs exist for testing static In-app Billing responses:
+
+`android.test.purchased`
+: Google Play responds as though you successfully purchased an item. The response includes a JSON string, which contains fake purchase information (for example, a fake order ID).
+
+`android.test.canceled`
+: Google Play responds as though the purchase was canceled. This can occur when an error is encountered in the order process, such as an invalid credit card, or when you cancel a user's order before it is charged.
+
+`android.test.refunded`
+: Google Play responds as though the purchase was refunded.
+
+`android.test.item_unavailable`
+: Google Play responds as though the item being purchased was not listed in your application's product list.
+
+## Setting up your app for purchases/billing
+
+The procedure on iOS and Android is similar:
+
+1. Make sure you are a registered Apple or Google Play developer.
+2. Set up your project so it works on your target device. See the [iOS development](/manuals/ios) and [Android development](/manuals/android) guides.
+3. Set up the app for testing:
+
+    - For Android, this is done on the [Google Play Developer Console](https://play.google.com/apps/publish/).
+    - For iOS, this is done on [iTunes Connect](https://itunesconnect.apple.com/). Make sure that your App ID (created in the "Member Center" on https://developer.apple.com) has "In-App Purchase" enabled.
+
+    ![iTunes Connect and Google Play Dev Console](images/iap/itunes_connect_google_play.png)
+
+4. For Google Play, you need to _upload and publish_ an alpha *.apk* file. For iTunes Connect, you should _not upload_ the development binary to iTunes Connect until the application is ready for App Review approval. If you upload a binary to iTunes Connect and it is not fully functional, Apple will likely reject it.
+
+5. Create products for your app.
+
+    ![iTunes Products](images/iap/itunes_products.png)
+
+    ![Google Play Products](images/iap/google_play_products.png)
+
+6. Add test users.
+    - The iTunes Connect page *Users and Roles* allow you to add users that can do test purchases in the _sandbox environment_. You should sign your app with a Developer certificate and use the sandbox account in Appstore on the test device.
+    - From the Google Play Developer Console, choose *Settings > Account Details* where you can add user emails to the License Testing section. Separate the emails by commas. This allows your testers to use test purchases that don’t actually cost real money.
+    - On Google Play, you also need to set up a Google Group for your testers. Google uses Groups to manage testers that can download your app from the Alpha and Beta stores. Click on the *Alpha Testing* tab and then *Manage list of testers* to add your Google Group as Alpha testers. The app must have passed through alpha publishing before you can see the opt-in link.
+
+![Alpha testers](images/iap/alpha_testers.png)
+
+The procedure on Facebook:
+
+1. Make sure you are a registered Facebook developer. Go to [Facebook for developers](https://developers.facebook.com/), "My Apps" and "Register as a developer", follow the steps.
+2. Facebook has extensive payment functionality and requires support of both synchronous and asynchronous payments. More info here [Payment overview](https://developers.facebook.com/docs/payments/overview)
+3. Set up app hosting and callback server:
+    * You will need to set up a secure canvas URL hosting your project. How this works is explained here [Games on Facebook](https://developers.facebook.com/docs/games/gamesonfacebook/hosting).
+    * The next step is to set up your callback server. Follow the steps here [Setting up your callback server](https://developers.facebook.com/docs/payments/realtimeupdates#yourcallbackserver).
+4. Set up you canvas app. Follow the steps on [Facebook Developer Dashboard](https://developers.facebook.com/quickstarts/?platform=canvas).
+5. Add test users. This is done in the "Canvas Payments" section of the app dashboard.
+6. Create products for your app [Defining products](https://developers.facebook.com/docs/payments/implementation-guide/defining-products/).
+
+## Asynchronous transactions
+
+The IAP API is asynchronous, meaning that after each request that your program sends to the server, the program will not halt and wait for a response. Instead, the program continues as ordinary and when the response arrives, a _callback_ function is invoked where you can react to the response data.
+
+To fetch all product information available:
+
+```lua
+local COINS_ID = "com.defold.examples.coins"
+local LOGO_ID = "com.defold.examples.logo"
+
+local function product_list(self, products, error)
+    if error == nil then
+        for i,p in pairs(products) do
+            print(p.ident)
+            print(p.title)
+            print(p.description)
+            print(p.currency_code)
+            print(p.price_string)
+        end
+    else
+        print(error.error)
+    end
+end
+
+function init(self)
+    -- Initiate a fetch of products (max 20 at a time for Google Play)
+    iap.list({ COINS_ID, LOGO_ID }, product_list)
+end
+```
+
+To perform actual transactions, first register a function that will listen to transaction results, then call the store function at the appropriate time:
+
+```lua
+local function iap_listener(self, transaction, error)
+    if error == nil then
+        if transaction.state == iap.TRANS_STATE_PURCHASING then
+            print("Purchasing...")
+        elseif transaction.state == iap.TRANS_STATE_PURCHASED then
+            print("Purchased!")
+        elseif transaction.state == iap.TRANS_STATE_UNVERIFIED then
+            print("Unverified!")
+        elseif transaction.state == iap.TRANS_STATE_FAILED then
+            print("Failed!")
+        elseif transaction.state == iap.TRANS_STATE_RESTORED then
+            print("Restored")
+        end
+    else
+        print(error.error)
+    end
+end
+
+function on_message(self, message_id, message, sender)
+    ...
+    -- Register the function that will listen to IAP transactions.
+    iap.set_listener(iap_listener)
+    -- Initiate a purchase of a coin...
+    iap.buy(COINS_ID)
+    ...
+end
+```
+
+The device operating system will automatically show a pop-up window allowing the user to go through with the purchase. The interface clearly indicates when you are running in the test/sandbox environment.
+
+![Confirm purchase](images/iap/ios_confirm_purchase.png)
+
+![Android purchase](images/iap/android_purchase.png)
+
+![Confirm purchase](images/iap/ios_purchase_done.png)
+
+## Synchronous payments
+
+Most payment providers only supports synchronous payments. This means that the client (your application) will receive a notification when the payment is complete, TRANS_STATE_PURCHASED. This is the final state of the payment, meaning no more callbacks will be done on this transaction.
+
+## Asynchronous payments
+
+Some payment providers require supporting asynchronous payments. This means that the client (your application) will only receive a notification when the payment is initiated. In order to verify completion of payment, further communication needs to be done between the developer server (or client) and the payment provider in order to verify.
+In the case of an initiated asynchronous payment the IAP listener will receive the state TRANS_STATE_UNVERIFIED to indicate this (as opposed to TRANS_STATE_PURCHASED). This is the final state of the payment, meaning no more callbacks will be done on this transaction.
+
+## Purchase fulfillment
+
+In order to complete a purchase from a payment provider, the application needs to signal a purchase fulfillment to the provider telling the provider the purchase has gone through (for example by developer server-side verification).
+IAP supports auto-completion, where fulfillment is automatically signaled to the provider when a purchase is complete (this is the default behavior). You can also disable auto-completion in the game project settings. You are then required to call `iap.finish()` when the transaction is complete, which will signal purchase fulfillment to the provider.
+
+### Consumable vs non-consumable products
+The Google Play store does only support consumable products. If you need non-consumable products it is recommended to use manual fulfillment of purchases and never finish purchases for products that should be non-consumable. As long as a purchase isn't finished it will be returned as an active purchase when `iap.set_listener()` is called.
+
+The Apple App Store supports non-consumable products which means that you need to finish all purchases when you provide products to your users. You can do it automatically by keeping the default behavior in the game project settings or manually (if you want to do that after server validation, for example) using `iap.finish()`.
+
+## Transaction receipt
+
+The receipt is a signed chunk of data that can be sent to the App Store to verify that the payment was successfully processed. This is most useful when designing a store that uses a separate server to verify that payment was processed.
+
+## Troubleshooting
+
+Android `iap.list()` returns "failed to fetch product"
+: You need to upload and publish an *.apk* on the alpha or beta channels on the Google Play Developer Console. Also make sure that the _time and date_ on your device is correct.
+
+Android (Google Play) `iap.list()` never returns more than 20 products
+: Google has an [limit of 20 products per request](https://github.com/googlesamples/android-play-billing/blob/master/TrivialDrive/app/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl#L62). The solution is to make multiple calls to `iap.list()` and combine the results if the number of products exceeds 20.
+
+iOS `iap.list()` returns nothing
+: Make sure that you’ve requested an iOS Paid Applications account, and all proper documentation has been filed. Without proper authorization, your iOS app purchasing (even test purchases) will not work.
+
+  Check that the AppId you have on the "Member Center" has in-app purchases activated and that you are signing your app (or the dev-app) with a provisioning profile that is up to date with the AppId (check the "Enabled Services:" field in the provisioning profile details in the "Certificates, Identifiers & Profiles" area of "Member Center")
+
+  Wait. It can take a few hours for the In-App product IDs to propagate to the Sandbox environment.
+
+iOS `iap.list()` fails logging error "Unexpected callback set"
+: `iap.list()` does not support nested calls. Calling `iap.list()` from an `iap.list()` callback function will be ignored, with the engine logging this error.
+
+On iOS, the "price_string" field contains '~' characters
+: The '~' characters are placeholders where no matching character could be found in the font file. The "price_string" field returned in the product list when using `iap.list()` is formatted with a _non breaking space_ (`\u00a0`) between the value and the currency denominator. If you render this string in the GUI, you need to add the character to the font's *extra_characters* field. On Mac OS X you can type non breaking spaces by pressing <kbd>Option + SPACE</kbd>. See http://en.wikipedia.org/wiki/Non-breaking_space for more information.

BIN
docs/zh/manuals/images/3dgraphics/add_animation.png


BIN
docs/zh/manuals/images/3dgraphics/animationset.png


BIN
docs/zh/manuals/images/addressing/absolute.png


BIN
docs/zh/manuals/images/addressing/bean.png


BIN
docs/zh/manuals/images/addressing/bean_buddy.png


BIN
docs/zh/manuals/images/addressing/bean_editor.png


BIN
docs/zh/manuals/images/addressing/bean_shield.png


BIN
docs/zh/manuals/images/addressing/bean_shield_editor.png


BIN
docs/zh/manuals/images/addressing/collection_team.png


BIN
docs/zh/manuals/images/addressing/manager_editor.png


BIN
docs/zh/manuals/images/addressing/name_collision.png


BIN
docs/zh/manuals/images/addressing/relative_same.png


BIN
docs/zh/manuals/images/addressing/team_editor.png


BIN
docs/zh/manuals/images/addressing/teams_editor.png


BIN
docs/zh/manuals/images/addressing/teams_manager.png


BIN
docs/zh/manuals/images/android/apk_file.png


BIN
docs/zh/manuals/images/android/sign_bundle.png


BIN
docs/zh/manuals/images/android/sign_bundle2.png


BIN
docs/zh/manuals/images/android/usb_debugging.png


BIN
docs/zh/manuals/images/animation/animsheet.png


BIN
docs/zh/manuals/images/animation/blender_animation.png


BIN
docs/zh/manuals/images/animation/[email protected]


BIN
docs/zh/manuals/images/animation/bounce.gif


BIN
docs/zh/manuals/images/animation/custom_curve.png


BIN
docs/zh/manuals/images/animation/frog_runloop.gif


BIN
docs/zh/manuals/images/animation/model_hierarchy.png


BIN
docs/zh/manuals/images/animation/property_animation.png


BIN
docs/zh/manuals/images/animation/[email protected]


BIN
docs/zh/manuals/images/animation/runloop.gif


BIN
docs/zh/manuals/images/animation/spine_animation.png


BIN
docs/zh/manuals/images/animation/spine_bones.png


BIN
docs/zh/manuals/images/animation/[email protected]


BIN
docs/zh/manuals/images/animation/spine_events.png


BIN
docs/zh/manuals/images/animation/spine_ingame.png


BIN
docs/zh/manuals/images/animation/[email protected]


BIN
docs/zh/manuals/images/animation/square_curve.png


BIN
docs/zh/manuals/images/animation/suzanne.gif


BIN
docs/zh/manuals/images/animation/wiggle.gif


BIN
docs/zh/manuals/images/application_lifecycle/application_lifecycle_final.png


BIN
docs/zh/manuals/images/application_lifecycle/application_lifecycle_init.png


BIN
docs/zh/manuals/images/application_lifecycle/application_lifecycle_overview.png


BIN
docs/zh/manuals/images/application_lifecycle/application_lifecycle_update.png


BIN
docs/zh/manuals/images/atlas/add.png


BIN
docs/zh/manuals/images/atlas/[email protected]


BIN
docs/zh/manuals/images/atlas/add_animation.png


BIN
docs/zh/manuals/images/atlas/[email protected]


BIN
docs/zh/manuals/images/atlas/animation_group.png


Some files were not shown because too many files changed in this diff