Open David1Socha opened 1 year ago
For portrait-to-landscape rotation (or vice versa), you should be able to detect whether the root's viewport size has changed, since it will change from width × height
to height × width
:
func _ready():
get_viewport().connect("size_changed", self, "_root_viewport_size_changed")
func _root_viewport_size_changed():
print("Size changed")
I don't know of a workaround for 180-degree rotations though (maybe using the accelerometer, but this will ignore user-defined rotation locks).
Not sure if it is broken in 4.3.beta1.mono, but on my device (Android, Poco F5, MIUI 14.0.6) "size_changed" signal is not being triggered when I rotate my phone from landscape to portrait and vice versa, though the viewport is rotating and scale is applied.
@Calinou which version of engine you were using when you wrote a comment?
Here the code that I was using, I've tried string literal and cached SignalName, no success.
public partial class Core : Node {
private Vector2I _targetViewportSize = new(1280, 704);
private Window? _window;
public override void _Ready() {
_window = GetWindow();
GetViewport().Connect("size_changed", Callable.From(CheckAndUpdateScreenViewport));
// next code also don't work
// GetViewport().Connect(
// Viewport.SignalName.SizeChanged,
// Callable.From(CheckAndUpdateScreenRotation)
// );
CheckAndUpdateScreenViewport();
}
private void CheckAndUpdateScreenViewport() {
_window.ContentScaleSize = _window.Size.X > _window.Size.Y
? _targetViewportSize // Landscape
: new Vector2I(_targetViewportSize.Y, _targetViewportSize.X); // Portrait
}
}
@Calinou which version of engine you were using when you wrote a comment?
I didn't test the particular code sample for the use case of changing device orientation, but it did work on desktop at least (I think this was 4.0.beta). Which stretch mode and stretch aspect do you use in the Project Settings? If using the viewport
stretch mode and keep
stretch aspect, the viewport's size won't change when the window is resized or the device orientation changes.
Yep, I'm using viewport
and keep
values, like as you said.
As a workaround now I'm checking GetWindow().Size
in _PhysicsProcess, this is unoptimized but I haven't found any signals on Window and WindowWrapper classes that could be used for this.
If someone want to repeat this, here is the code that I'm using:
public partial class Core : Node {
private Window? _window;
private Vector2I _previousResolution = Vector2I.Zero;
private Vector2I _targetViewportSize = new(1280, 704);
[Signal]
public delegate void OrientationChangedEventHandler(DisplayServer.ScreenOrientation screenOrientation, Vector2I resolution);
public override void _Ready() {
_window = GetWindow();
CheckAndUpdateScreenRotation();
}
public override void _PhysicsProcess(double delta) {
base._PhysicsProcess(delta);
CheckAndUpdateScreenRotation();
}
private void CheckAndUpdateScreenRotation() {
if (_window is null) {
return;
}
Vector2I currentResolution = _window.Size;
if (_previousResolution.Equals(currentResolution)) {
return;
}
_previousResolution = currentResolution;
Vector2I newViewportSize = currentResolution.X > currentResolution.Y
? _targetViewportSize // Landscape
: new Vector2I(_targetViewportSize.Y, _targetViewportSize.X); // Portrait
if (_window.ContentScaleSize.Equals(newViewportSize)) {
return;
}
_window.ContentScaleSize = newViewportSize;
EmitSignal(
SignalName.OrientationChanged,
(long) (currentResolution.X > currentResolution.Y
? DisplayServer.ScreenOrientation.Landscape
: DisplayServer.ScreenOrientation.Portrait),
currentResolution
);
}
}
Describe the project you are working on
A 2D game that plays in landscape mode on several platforms including Android and iOS
Describe the problem or limitation you are having in your project
As far as I can tell, there is currently no way for a Godot game to handle changes in device orientation. One use-case where this can be problematic: in my game, I want to ensure that UI controls are not inside the bezel/notch of an Android/iPhone's screen.
OS.get_window_safe_area()
works well for this purpose; however, if the game is insensor_landscape
mode, upon rotating the device 180 degrees to the opposite landscape mode,OS.get_window_safe_area()
needs to be called again so the UI safe area can be recalculated. Without a notification/callback/signal on orientation change, I don't see a good way to accomplish this. To avoid this issue, I'm currently keeping orientation mode aslandscape
(device can only turn one way), but I would prefer to support both possible landscape orientations.Describe the feature / enhancement and how it helps to overcome the problem or limitation
Add a new Notification code called something like
NOTIFICATION_OS_ORIENTATION_CHANGED
that is similar to many of the OS-level notifications listed here. This notification would be triggered whenever an Android or iOS device changes its orientation.Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Not 100% sure on what implementation would look like, but Android and iOS both expose callbacks for device orientation change, so I think Godot could essentially listen to the appropriate device-specific callbacks for orientation change, then fire a notification whenever the callbacks are hit.
If this enhancement will not be used often, can it be worked around with a few lines of script?
From searching Godot documentation, Godot source code/issues, and searching online, I haven't been able to find any existing callback or notification that would allow a user to respond to changes in device screen orientation.
Is there a reason why this should be core and not an add-on in the asset library?
I think this would require updates in the Android/iOS-specific Godot wrappers, so I don't think an add-on could really achieve this.