Generic background screen matcher

Posted: 19 Nov 2020 13:15
by Elringus

In version v1.15 we're removing automatic camera ortho size correction in favor of per-background corrections with more options. This resolves an issue when characters were also affected by the ortho size correction appearing cropped and also adds a way to tailor the matching mode for each individual background (crop, fit, custom with controllable ratio).

Image

This, however, leaves generic backgrounds (and potentially custom implementations, in case you didn't use transitional sprite renderer) without the matching support. While this is by design (generic implementations just route the events form scenario scripts, but otherwise it's up to user to implement other features), this still can be considered a breaking change.

To alleviate the issue, below is an example component, that will scale an arbitrary game object to match the screen aspect ratio. This component can be attached to the root of a generic background prefab, or any other game object, that should be matched against the screen.

Note: It'll only work with Naninovel v1.17 or later.

Create a new C# script and paste the code below:

Code: Select all

using Naninovel;
using UnityEngine;

[RequireComponent(typeof(RenderCanvas))]
public class ScaleToScreen : MonoBehaviour
{
    private class Matcher : CameraMatcher
    {
        private readonly Transform transform;
        private readonly Vector2 referenceSize;
        private readonly Vector3 initialScale;

        public Matcher (ICameraManager cameraManager, Vector2 referenceSize, Transform transform)
            : base(cameraManager, transform.gameObject)
        {
            this.transform = transform;
            this.referenceSize = referenceSize;
            initialScale = transform.localScale;
        }

        protected override void ApplyScale (float scaleFactor)
        {
            transform.localScale = initialScale * scaleFactor;
        }

        protected override bool TryGetReferenceSize (out Vector2 referenceSize)
        {
            referenceSize = this.referenceSize;
            return true;
        }
    }

    [SerializeField] private CameraMatchMode matchMode = default;
    [SerializeField] private float customMatchRatio = default;

    private Matcher matcher;

    private void Awake ()
    {
        var renderCanvas = GetComponent<RenderCanvas>();
        var cameraManager = Engine.GetService<ICameraManager>();
        matcher = new Matcher(cameraManager, renderCanvas.Size, transform);
        matcher.MatchMode = matchMode;
        matcher.CustomMatchRatio = customMatchRatio;
    }

    private void OnEnable () => matcher.Start();

    private void OnDisable () => matcher.Stop();
}

Attach Scale To Screen component to the root game object of your generic background prefab; setup the size by changing Size property of Render Canvas component, which is added automatically. Enable gizmos in the Scene window to see a white frame, which represent the size; make sure the frame is positioned exactly over the background borders. The process is similar to setting the render canvas size for layered and Live2D characters. Usually, the size will equal to the sprite resolution divided by pixels per unit set in the sprite import settings; so, for a 1920x1080 sprite with the default PPU value of 100 it'll be 19.2 to 10.8.

Image

Now, select the desired match mode (it's similar to the match mode set in the background actors configuration) and save the prefab. The generic background will now match the screen aspect ratio in a similar way to the other background implementations.


Re: Generic background screen matcher

Posted: 07 Jan 2023 10:05
by Elringus

Updated version for 1.18:

Code: Select all

using Naninovel;
using UnityEngine;

[RequireComponent(typeof(RenderCanvas))]
public class ScaleToScreen : MonoBehaviour
{
    private class Matcher : CameraMatcher
    {
        private readonly Transform transform;
        private readonly Vector2 referenceSize;
        private readonly Vector3 initialScale;

        public Matcher (ICameraManager cameraManager, Vector2 referenceSize, Transform transform)
            : base(cameraManager, transform.gameObject)
        {
            this.transform = transform;
            this.referenceSize = referenceSize;
            initialScale = transform.localScale;
        }

        protected override void ApplyScale (float scaleFactor)
        {
            transform.localScale = initialScale * scaleFactor;
        }

        protected override bool TryGetReferenceSize (out Vector2 referenceSize)
        {
            referenceSize = this.referenceSize;
            return true;
        }
    }

    [SerializeField] private AspectMatchMode matchMode;
    [SerializeField] private float customMatchRatio;

    private Matcher matcher;

    private void Awake ()
    {
        var renderCanvas = GetComponent<RenderCanvas>();
        var cameraManager = Engine.GetService<ICameraManager>();
        matcher = new Matcher(cameraManager, renderCanvas.Size, transform);
        matcher.MatchMode = matchMode;
        matcher.CustomMatchRatio = customMatchRatio;
    }

    private void OnEnable () => matcher.Start();

    private void OnDisable () => matcher.Stop();
}