最終確認日

Godotでモバイル向けの画面サイズ取得

要点

Screen座標系

DisplayServer から取得した値は端末に依存するScreen座標系(物理ピクセル)である。

  • DisplayServer.screen_get_size() で実際のスクリーンの解像度を取得できる
  • DisplayServer.screen_get_scale() で端末の画面スケールを取得できる

Viewport座標系

viewport から取得した値は Project SettingsViewport WidthViewport HeightStretch > Aspect の設定に依存するViewport座標系(論理ピクセル)である。

  • get_viewport_rect().size では、Stretch > Aspect に基づいて引き伸ばし等を行った後の描画可能なサイズを返す。
  • get_viewport().content_scale_size では Viewport WidthViewport 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().sizeget_viewport_rect().size と同様
    • 違いを探す

get_viewport().get_visible_rect().sizeget_viewport_rect().size の違い

違いがわからんけど、SubViewport を使うと異なる Viewport を作ることができることがわかった。このとき、Subviewport を (300, 300) に設定すると、これらの関数も (300, 300) を返すようになる。

わかりません!!!!

調査まとめ

モバイルのような全画面で端末のセーフエリアなどを気にする場合は DisplayServer.screen_get_size()DisplayServer.screen_get_scale() を用いて計算するのが良さそう。

反対にWebなどでゲームを埋め込んだ場合には DisplayServer.screen_get_size() は使うと危ないかもしれない。

ドキュメント

関連ノート

サイトアイコン
公開日
更新日