Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Viewport 和画布变换

前言

本文简要介绍了从本地绘制节点内容开始到这些内容绘制到屏幕上为止的 2D 变换过程,对引擎非常底层的细节进行了讨论。

The goal of this tutorial is to teach a way for feeding input events to the Input with a position in the correct coordinate system.

A more extensive description of all coordinate systems and 2d transforms is available in 2D coordinate systems and 2D transforms.

画布变换

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

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

全局画布变换

Viewports also have a Global Canvas transform (also a Transform2D). This is the master transform and affects all individual Canvas Layer transforms. Generally, this is primarily used in Godot's CanvasItem Editor.

拉伸变换

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

Input events are multiplied by this transform but lack the ones above. To convert InputEvent coordinates to local CanvasItem coordinates, the CanvasItem.make_input_local() function was added for convenience.

Window transform

The root viewport is a Window. In order to scale and position the Window's content as described in 多分辨率, each Window contains a window transform. It is for example responsible for the black bars at the Window's sides so that the Viewport is displayed with a fixed aspect ratio.

变换顺序

To convert a CanvasItem local coordinate to an actual screen coordinate, the following chain of transforms must be applied:

../../_images/viewport_transforms3.webp

变换函数

The above graphic shows some available transform functions. All transforms are directed from right to left, this means multiplying a transform with a coordinate results in a coordinate system further to the left, multiplying the affine inverse of a transform results in a coordinate system further to the right:

# Called from a CanvasItem.
canvas_pos = get_global_transform() * local_pos
local_pos = get_global_transform().affine_inverse() * canvas_pos

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

var screen_coord = get_viewport().get_screen_transform() * get_global_transform_with_canvas() * local_pos

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

提供自定义输入事件

It is often desired to feed custom input events to the game. With the above knowledge, to correctly do this in the focused window, it must be done the following way:

var local_pos = Vector2(10, 20) # Local to Control/Node2D.
var ie = InputEventMouseButton.new()
ie.button_index = MOUSE_BUTTON_LEFT
ie.position = get_viewport().get_screen_transform() * get_global_transform_with_canvas() * local_pos
Input.parse_input_event(ie)