Viewport 和画布变换

前言

本小节概述了节点从绘制本地内容开始到显示到屏幕上结束的过程中的2D变换. 本概述讨论了一些比较低级的的引擎的细节.

画布变换

正如前面教程 画布层 中提到的那样, 每个CanvasItem节点(要记得Node2D和基于Control的节点使用CanvasItem作为它们的公共根)将驻留在 Canvas Layer 中. 每个Canvas Layer都有一个变换(平移, 旋转, 缩放等), 可以作为 Transform2D 进行访问.

在前面的教程中也有介绍, 节点默认是在0层, 在内置的画布中绘制的. 如果要把节点放在不同的层中, 可以使用一个 CanvasLayer 节点.

全局画布变换

Viewport还具有全局画布变换(也是 Transform2D ). 这是一个影响所有单独的 画布层 的主变换. 通常这种变换用得不多. 它被用在了Godot的编辑器中的画布项编辑器中.

拉伸变换

最后,Viewport有 拉伸变换 , 用于调整大小或拉伸屏幕. 此变换在内部使用(见 多分辨率 ), 但也可以在每个Viewport上手动设置.

MainLoop._input_event() 回调中接收的输入事件上应用了拉伸变换, 但没有应用上面那些变换. 为了方便将InputEvent坐标转换为本地画布项坐标, 引擎添加了 CanvasItem.make_input_local() 函数.

变换顺序

要使CanvasItem的本地属性中的坐标成为实际屏幕坐标, 必须应用以下一系列变换:

../../_images/viewport_transforms2.png

变换函数

通过以下函数可以获取各个转换:

类型

变换

CanvasItem(画布项)

CanvasItem.get_global_transform()

CanvasLayer(画布层)

CanvasItem.get_canvas_transform()

CanvasLayer(画布层)+GlobalCanvas(全局画布)+Stretch(拉伸)

CanvasItem.get_viewport_transform()

那么最后, 要将CanvasItem的本地坐标转换为屏幕坐标, 只需按以下顺序相乘:

GDScript

C#

  1. var screen_coord = get_viewport_transform() * (get_global_transform() * local_pos)
  1. var screenCord = (GetViewportTransform() * GetGlobalTransform()).Xform(localPos);

但请记住, 通常情况最好不要使用屏幕坐标. 推荐的方法是, 仅仅使用画布坐标( CanvasItem.get_global_transform() ), 以保证自动分辨率调整能正常工作.

提供自定义输入事件

通常需要将自定义输入事件提供给场景树. 有了上述知识, 要正确地做到这一点, 必须通过以下方式完成:

GDScript

C#

  1. var local_pos = Vector2(10, 20) # local to Control/Node2D
  2. var ie = InputEventMouseButton.new()
  3. ie.button_index = BUTTON_LEFT
  4. ie.position = get_viewport_transform() * (get_global_transform() * local_pos)
  5. get_tree().input_event(ie)
  1. var localPos = new Vector2(10,20); // local to Control/Node2D
  2. var ie = new InputEventMouseButton();
  3. ie.ButtonIndex = (int)ButtonList.Left;
  4. ie.Position = (GetViewportTransform() * GetGlobalTransform()).Xform(localPos);
  5. GetTree().InputEvent(ie);