godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 96 forks source link

Add a Camera2D aspect ratio scaling mode that behaves like Camera3D's Keep Width (Vert-) #120

Open The5-1 opened 5 years ago

The5-1 commented 5 years ago

Describe the project you are working on: 2D side scrolling fighting game in pixel-art style. Support multiple resolutions via up-scaling where, for a side scrolling game, the vertical field of view is to remain fixed.

Describe the problem or limitation you are having in your project: Window stretch mode 2d results in black borders as in letterbox filming. With "borderless" I refer to removing those black borders by up-scaling the visible view port rather than expanding it. To me up-scaling appears to be the more common solution. Similar to how 3D games adjust to aspect ratios by modifying horizontal/vertical field of view rather than letterboxing. keep height, to me, should behave like keeping the vertical field of view rather than keeping the height in pixels. Of course this may well be an option for those with the requirement to remain pixel-perfect without up-scaling.

See the following example: Godot_keep_height2 This is stretch mode 2Dwith keep_height enabled. (Same happens for viewport mode.)

My expected behavior would be that keep_height forces the vertical field of view to remain constant and up-scale to fill the height, while the horizontal field of view adapts into the other dimension. To me the black border is un-intuitive and the less aesthetic solution when compared with up-scaling. In fact up-scaling does already occur when resizing the display "diagonally" maintaining a somewhat similar aspect ratio. No combination of settings seems to yield a border less scaling. To me it appears like a bug but I could not find any relevant reports in the engine´s issue board.

Describe how this feature / enhancement will help you overcome this problem or limitation: Remove any black borders by setting an option in the expected settings category.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work: Refer to the image above. Add option to enable borderless scaling in Project Settings/Display/Window/Stretch.

Describe implementation detail for your proposal (in code), if possible: As of now I do not understand the reasoning behind the current logic involving the black border. So I can not estimate what is necessary to not conflict with it. To me it appears like there currently is a more complex logic happening that checks for more conditions than a scaling based on a fixed dimension would require.

vec2 viewportRes = ...;
vec2 deviceRes = ...;
//...
if(fixedDimension == Dim::X) {
    Viewport.height *= deviceRes.y/viewportRes.y;
}
else if(fixedDimension == Dim::Y) {
    Viewport.width *= deviceRes.x/viewportRes.x;
}

If this enhancement will not be used often, can it be worked around with a few lines of script?: Implementing the view port scaling in GDScript should be possible, though I have not yet attempted it, so I am not certain if the API provides everything needed. But it defies the purpose of the already existent options as you most likely have to disable them as to not interfere.

Is there a reason why this should be core and not an add-on in the asset library?: The current stretch options are core, this is an (possibly simple) addition to them.

Calinou commented 4 years ago

Isn't this achieved by setting the stretch mode to expand? See Multiple resolutions in the Godot documentation.

The5-1 commented 4 years ago

expand allows the vertical "field of view" to change. With keep height I would expect the vertical FOV to remain, and height to be scaled (rather than expanded ) to fill the screen, while the horizontal FOV expands or narrows to compensate for the new aspect ratio.

Currently no scaling occurs, the knight stays the same size in pixels. Godot_keep_height_2020_01

Imagine this as a side scrolling game. I have a lower and upper fixed bound for the world, there wont be any content beyond these borders, I can not use expand for the height as it would reveal the empty world. However due to the nature of it being side-scrolling I have more environment to show to the left and right, so widening the horizontal field of view is possible. In the example above where I increase the viewports height, it would of course narrow the horizontal field of view, taking away visible parts of the world at the left and right edges, which also OK and the expected behavior.

Calinou commented 4 years ago

I can not use expand for the height as it would reveal the empty world.

You could write a script that adjusts the camera zoom when the window is resized to an aspect ratio that's narrower than the default. To do this, you can connect the viewport's size_changed signal to a method:

get_viewport().connect("size_changed", self, "_root_viewport_size_changed")

The method would then handle the camera's zoom level so that areas going beyond the playable area are never visible. You can get the viewport size using get_viewport().size.

BarelyAliveMau5 commented 4 years ago

This might be relevant, it limits the displayed boundaries, but requires a Camera2D node. The title says it all: Screen content resizing without black-bars, nor distortions, nor content reveal https://gist.github.com/BarelyAliveMau5/2ff2d83566e6db63b4f6f782ef46e2bc

Here an example of how it looks https://i.imgur.com/PK6M8Sr.mp4

I agree that this proposal by the way, i wish this was built-in the engine as its not very straight-forward to come up with this solution every time this is desired