Godotでモバイル向けの画面サイズ取得
要点
Screen座標系
DisplayServer
から取得した値は端末に依存するScreen座標系(物理ピクセル)である。
DisplayServer.screen_get_size()
で実際のスクリーンの解像度を取得できるDisplayServer.screen_get_scale()
で端末の画面スケールを取得できる
Viewport座標系
viewport
から取得した値は Project Settings
の Viewport Width
と Viewport Height
や Stretch
> Aspect
の設定に依存するViewport座標系(論理ピクセル)である。
get_viewport_rect().size
では、Stretch
>Aspect
に基づいて引き伸ばし等を行った後の描画可能なサイズを返す。get_viewport().content_scale_size
ではViewport Width
とViewport Height
に設定した値をそのまま返す。get_viewport().get_visible_rect().size
では、Stretch
>Aspect
に基づいて引き伸ばし等を行った後の描画可能なサイズを返す。get_viewport_rect().size
との違いは調査したがわからず。Control
から使える。
各座標系
画面タップ時
Viewport座標系 (論理ピクセル)
func _input(event):
# 入力がタッチかどうかを確認
if event is InputEventScreenTouch:
print("タップ!:", event.position)
出力
# iPhone 13 mini
# 左上ギリギリを狙う
タップ!:(13.44, 38.87069)
# 右上ギリギリを狙う
タップ!:(516.96, 30.23276)
# 右下ギリギリを狙う
タップ!:(504.0, 1140.207)
# 左下ギリギリを狙う
タップ!:(36.48, 1138.767)
- 角がまるいので (0,0) も (540, 1169) も狙えないが、 取得できる
position
にはscreen_scale
は関係がない。 get_viewport().content_scale_size
で取得できる範囲である。event.position.x * get_viewport().get_screen_transform().x.x
という書き方をGodotでモバイル向けにジョイスティックを実装するで見かけたが、CanvasLayer の物に対しては必要がなさそう。(単にevent_position.x
を使えばおk)
画面タップできる範囲は get_viewport().content_scale_size
である。
セーフエリア
スクリーン座標系 (物理ピクセル)
var screen_size := DisplayServer.screen_get_size()
var safe_area := DisplayServer.get_display_safe_area()
var screen_scale := DisplayServer.screen_get_scale()
var viewport_size := get_viewport().get_visible_rect().size
var scale_x := screen_size.x / viewport_size.x
var scale_y := screen_size.y / viewport_size.y
# スクリーン座標系 -> Viewport座標系へ
var safe_area_in_ui := Rect2(
Vector2(safe_area.position.x / scale_x, safe_area.position.y / scale_y),
Vector2(safe_area.size.x / scale_x, safe_area.size.y / scale_y)
)
詳しくは Godotでモバイル向けのセーフエリア対応 にて。
キーボードサイズ
スクリーン座標系 (物理ピクセル)
var screen_scale = DisplayServer.screen_get_scale()
var keyboard_height = DisplayServer.virtual_keyboard_get_height()
# iOSネイティブで取得できる値
var keyboard_height_in_ui = keyboard_height / screen_scale
# Godot で実際に使う値
# Viewport座標系とスクリーン座標系のスケールを計算
var screen_size: Vector2 = DisplayServer.screen_get_size()
var viewport_size: Vector2 = get_viewport().get_visible_rect().size
var scale_y: float = screen_size.y / viewport_size.y
var keyboard_height_in_viewport: float = keyboard_height / scale_y
print("screen_scale: ", screen_scale)
print("keyboard_height: ", keyboard_height)
print("keyboard_height_in_ui: ", keyboard_height_in_ui)
print("keyboard_height_in_viewport:", )
出力
# iPhone 13 mini
screen_scale: 3.0
keyboard_height: 1008
keyboard_height_in_ui: 336.0 // この値は iOS と一致する
keyboard_height_in_viewport: 483
keyboard_height
にはセーフエリアのbottom_insets も含まれているため、キーボードの上端のy座標を取得したい場合には、単にviewport.size.y - keyboard_height
で取得できる。
詳しくはGodotでモバイル端末のキーボードの高さの取得する にて。
キーボード関連ノート
調査
画面サイズ取得の各関数
print("DisplayServer.screen_get_size(): ", DisplayServer.screen_get_size())
print("get_viewport_rect().size: ", get_viewport_rect().size)
print("get_viewport().content_scale_size: ", get_viewport().content_scale_size)
print("get_viewport().get_visible_rect().size: ", get_viewport().get_visible_rect().size)
print("DisplayServer.screen_get_scale(): ", DisplayServer.screen_get_scale())
var mode = ProjectSettings.get_setting("display/window/stretch/mode")
var aspect = ProjectSettings.get_setting("display/window/stretch/aspect")
print("Stretch mode: ", mode)
print("Aspect mode: ", aspect)
調査1
Stretch: canvas_items
(viewport
でも同様な結果)Aspect: keep_width
Viewport Width: 10
Viewport Height: 960
# Mac上
DisplayServer.screen_get_size(): (3024, 1964)
get_viewport_rect().size: (10.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (10.0, 960.0)
DisplayServer.screen_get_scale(): 2.0
Stretch mode: canvas_items
Aspect mode: keep_width
# iPhone 13 mini 実機
DisplayServer.screen_get_size(): (1125, 2436)
get_viewport_rect().size: (10.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (10.0, 960.0)
DisplayServer.screen_get_scale(): 3.0
Stretch mode: canvas_items
Aspect mode: keep_width
調査2
Stretch: canvas_items
(viewport
でも同様な結果)Aspect: expand
Viewport Width: 10
Viewport Height: 960
# Mac
DisplayServer.screen_get_size(): (3024, 1964)
get_viewport_rect().size: (64.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (64.0, 960.0)
DisplayServer.screen_get_scale(): 2.0
Stretch mode: canvas_items
Aspect mode: expand
# iPhone 13 mini 実機
DisplayServer.screen_get_size(): (1125, 2436)
get_viewport_rect().size: (443.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (443.0, 960.0)
DisplayServer.screen_get_scale(): 3.0
Stretch mode: canvas_items
Aspect mode: expand
調査3
Stretch: canvas_items
(viewport
でも同様な結果)Aspect: keep_height
Viewport Width: 10
Viewport Height: 960
# Mac
DisplayServer.screen_get_size(): (3024, 1964)
get_viewport_rect().size: (64.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (64.0, 960.0)
DisplayServer.screen_get_scale(): 2.0
Stretch mode: canvas_items
Aspect mode: keep_height
# iPhone 13 mini 実機
DisplayServer.screen_get_size(): (1125, 2436)
get_viewport_rect().size: (443.0, 960.0)
get_viewport().content_scale_size: (10, 960)
get_viewport().get_visible_rect().size: (443.0, 960.0)
DisplayServer.screen_get_scale(): 3.0
Stretch mode: canvas_items
Aspect mode: keep_height
DisplayServer.screen_get_size()
はゲームを表示しているスクリーンの解像度get_viewport().content_scale_size
は Project Settings で設定した値get_viewport_rect().size
は、Project Settings でStretch
>Aspect
に基づいて計算された描画可能なサイズget_viewport().get_visible_rect().size
はget_viewport_rect().size
と同様- 違いを探す
get_viewport().get_visible_rect().size
と get_viewport_rect().size
の違い
-
- Returns the viewport's boundaries as a Rect2.
get_viewport().get_visible_rect().size
- Returns the visible rectangle in global screen coordinates.
SubViewport
などを使って実験してみたけれど、異なる値を返すパターンに遭遇しない...
違いがわからんけど、SubViewport
を使うと異なる Viewport
を作ることができることがわかった。このとき、Subviewport
を (300, 300) に設定すると、これらの関数も (300, 300) を返すようになる。
わかりません!!!!
調査まとめ
モバイルのような全画面で端末のセーフエリアなどを気にする場合は DisplayServer.screen_get_size()
と DisplayServer.screen_get_scale()
を用いて計算するのが良さそう。
反対にWebなどでゲームを埋め込んだ場合には DisplayServer.screen_get_size()
は使うと危ないかもしれない。
ドキュメント
関連ノート
- Godotでモバイルゲームを作るメモ(Udemy)セクション2
- Godotでモバイル向けの環境設定をする
- Godotでモバイル向けのセーフエリア対応
- GodotでiOSのキーボードに追従するツールバーを実装する
- 物理ピクセル(physical pixel)
- 論理ピクセル(logical pixel)
