Forum rules - please read before posting.

Fixed aspect ratio with texture replacing black bars

edited July 2020 in Technical Q&A

Hi there,

I am making a 2D game. In order to avoid stretched artwork (and because the nature of the artwork doesn't allow for any of it to be cropped) I need my game to use a fixed aspect ratio. Happy for it to scale up and down, so long as the ratio doesn't change.

This is very trivial to do using the 'force aspect ratio' setting. However, this results in any unused space being filled in with solid black.

What I would instead like is for the background pattern that already surrounds the play area (and on which the UI elements sit) to be extended into the unused parts of the screen, so that the entire game window is part of the game. Imagine my background is some nice flock wallpaper and the game is in a picture frame; I would like the entire screen to be filled with the patterned wallpaper, with no obvious joins, rather than ending in black bars.

I have done a fair amount of research, but have not yet found anything that leads me to a good solution, though possibly that's because I'm not quite sure what I'm looking for. I found the AspectRatioEnforcer plugin, but this looks like it doesn't solve this bit of the problem (and, perhaps, isn't needed at all).

My feeling is that what I need to do is to not enforce aspect ratio on the game, but instead set up a second camera that fills the whole screen space with pattern, with a hole punched out for the game area which is dynamically sized to a best-fit 16:9 for the system it is running on. However, I'm kind of pulling that idea out of thin air, and I don't really know where to start in terms of implementing it.

Does anyone have any ideas about how to do this?

If this is more of a Unity question than an AC question, please let me know and I'll try an alternative forum. Any recommendations about where to ask or what kind of terminology I should use when phrasing the question would be helpful!

Kind regards,

-- HappyDog

Comments

  • edited July 2020

    Would the pattern scroll as the camera moves, or could it be a fixed image that's always displayed the same way?

    AC achieves the border effect by drawing the MainCamera's fade texture in an OnGUI call after everything else - to make sure that they're always displayed on top of everything else.

    You'll want to uncheck this option if you want anything else to be visible in that space. I'd suggest starting out with Unity UI to create left/right/top/down borders that resize to always make a 16:9 hole in the middle. If you want the borders to have a scrolling pattern, you'll probably have to look into some UI shader trickery as mentioned in this thread on the Unity forums. This would be a Unity UI issue, though, not so much AC.

  • Hi Chris,

    It would be the latter. Actually, the camera doesn't move, but if it did it would be the inside of the frame that changes, only. The outside (walllpaper) is fixed at all times, throughout the entire game.

    I'll investigate the method you suggest, using four UI borders. My worry about this approach is that the pattern won't match up at the joins. That's why I was wondering whether a big square object with a hole punched in it would work out better.

    One alternative might be to put the wallpaper behind the play area, but the artwork requires that the player can walk 'off' the play area, i.e. out of the bounding rectangle, but we should not see any part of them appearing outside the box. Perhaps this could be achieved by applying a mask to the game area?

    If all of this makes no sense, I can do a quick graphical mock-up to demonstrate.

  • If you had the wallpaper be part of the scene, you could position it in between the play area and the camera - so that when characters move off-screen they're drawn underneath.

  • That's what I meant by 'punching a hole'. Do you think that might be the way forward - a textured plane representing a large rectangle with a smaller rectangle punched out of it, to let the play area show through?

    If I went down this route, would I need to write code to handle scaling the scene to the window size, or is there a way of setting this up via camera properties? The play area should always be as large as it can without changing the 16:9 ratio, and the rest of the scene is just filler for the remaining screen space (if there is any).

  • If it's always 16:9, then a large graphic with a hole in the middle wouldn't change shape - you should just need to make the edges extend far enough to cover all screen aspect ratios. The graphic itself wouldn't need scaling.

  • Sorry - perhaps I wasn't clear.

    I meant that the main play area should occupy either the full height (minus a bit of padding) OR the full width (minus a bit of padding), depending on the window's aspect ratio. If the screen's aspect ration is > 16:9 then the play area will be full height, with filler to the sides (pillarbox) or if it is < 16:9 then the play area will be full width, with filler above and below (lettarbox).

    So, you're right, the play area and the hole wouldn't change shape, but the zoom on the camera presumably needs to change in order to ensure the best fit.

    Is that something that I would need to do in code, or is it a matter of setting appropriate properties in Unity and/or AC?

  • I think sharing some screens or mockups of the actual situation would be the best way of conveying the problem.

    AC's "Force aspect ratio" option won't affect the camera's FOV, so unless you're just looking to change the appearance of the provided letterboxing / pillarboxing effect then you're going to need to extend your camera with an additional script that changes the FOV based on the aspect ratio.

    A script that does something similar - change a camera's movement limits based on the aspect ratio - can be found on the wiki.

    A variant that isntead controls the camera's "Orthographic Size" value (better for 2D to use Orthographic projection):

    using UnityEngine;
    using AC;
    
    [RequireComponent (typeof (GameCamera2D))]
    public class DynamicOrthographicSize : MonoBehaviour
    {
    
        #region Variables
    
        [SerializeField] private CameraLimits fourByThree = new CameraLimits (1.333f);
        [SerializeField] private CameraLimits sixteenByNine = new CameraLimits (1.778f);
    
        private GameCamera2D gameCamera2D;
    
        #endregion
    
    
        #region UnityStandards
    
        private void OnEnable ()
        {
            gameCamera2D = GetComponent <GameCamera2D>();
        }
    
    
        private void Update ()
        {
            float aspectRatio = GetAspectRatio ();
    
            float size = GetSize (aspectRatio);
            gameCamera2D.Camera.orthographicSize = size;
        }
    
        #endregion
    
    
        #region PrivateFunctions
    
        private float GetAspectRatio ()
        {
            Vector2 windowSize = ACScreen.safeArea.size;
            return windowSize.x / windowSize.y;
        }
    
    
        private float GetSize (float aspectRatio)
        {
            float fourByThreeFOV = fourByThree.orthographicSize;
            float sixteenByNineFOV = sixteenByNine.orthographicSize;
    
            float gradient = (sixteenByNineFOV - fourByThreeFOV) / (sixteenByNine.AspectRatio - fourByThree.AspectRatio);
            float intercept = fourByThreeFOV - (gradient * fourByThree.AspectRatio);
    
            return (aspectRatio * gradient) + intercept;
        }
    
        #endregion
    
    
        #region PrivateClasses
    
        [System.Serializable]
        private class CameraLimits
        {
    
            public float orthographicSize;
            private float aspectRatio;
    
    
            public CameraLimits (float aspectRatio)
            {
                this.aspectRatio = aspectRatio;
                orthographicSize = 4f;
            }
    
    
            public float AspectRatio
            {
                get
                {
                    return aspectRatio;
                }
            }
    
        }
    
        #endregion
    
    }
    
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.