LoginSignup
0
0

More than 1 year has passed since last update.

RectTransformのRectに沿ったラインを引く

Last updated at Posted at 2021-10-11

UGUIを組んでいると、RectTransformに対して線を引きたい場合が有ります。
例えばガイドラインだったり、例えばカーソルだったり。
そんな時に利用できるRectLineコンポーネントを作りました。
スクリーンショット 2021-10-11 173113.png

RectLine.cs
using System;
using UnityEngine;
using UnityEngine.UI;

namespace ScreenPocket.UI
{
    /// <summary>
    /// RectLineのブレンドモード
    /// </summary>
    public enum RectLineBlendMode
    {
        /// <summary>
        /// 乗算
        /// </summary>
        Multiply,
        /// <summary>
        /// 加算
        /// </summary>
        Additive,
        /// <summary>
        /// 減算
        /// </summary>
        Subtract,
    }

    /// <summary>
    /// ライン位置
    /// 内側か、中間か、外側か
    /// </summary>
    public enum RectLinePositionType
    {
        /// <summary>
        /// 矩形の内側
        /// </summary>
        Inside,
        /// <summary>
        /// 矩形の中間
        /// </summary>
        Middle,
        /// <summary>
        /// 矩形の外側
        /// </summary>
        Outside
    }

    /// <summary>
    /// Rectに合わせた線を引く
    /// </summary>
    [RequireComponent(typeof(RectTransform))]
    [RequireComponent(typeof(CanvasRenderer))]
    public sealed class RectLine : MaskableGraphic
    {
        /// <summary>
        /// テクスチャ(一応)
        /// </summary>
        [SerializeField]
        private Texture2D _texture;

        /// <summary>
        /// アウトラインの太さ
        /// </summary>
        [SerializeField]
        private float _size;

        [SerializeField]
        private Color _inColor = Color.white;
        [SerializeField]
        private Color _outColor = Color.white;

        [SerializeField]
        private RectLineBlendMode _blendMode = RectLineBlendMode.Multiply;

        [SerializeField]
        private RectLinePositionType _positionType = RectLinePositionType.Middle;

        public override Texture mainTexture => _texture != null ? _texture : Texture2D.whiteTexture;

        protected override void OnPopulateMesh(VertexHelper vh)
        {
            var r = GetPixelAdjustedRect();
            var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);

            var inLength = _positionType switch
            {
                RectLinePositionType.Inside => _size * Mathf.Sqrt(2f),
                RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f,
                RectLinePositionType.Outside => 0f,
                _ => throw new ArgumentOutOfRangeException()
            };
            var outLength = _positionType switch
            {
                RectLinePositionType.Inside => 0f,
                RectLinePositionType.Middle => _size * Mathf.Sqrt(2f) * 0.5f,
                RectLinePositionType.Outside => _size * Mathf.Sqrt(2f),
                _ => throw new ArgumentOutOfRangeException()
            };

            //ローカル関数
            //合成した色を返す
            Color32 GetColor(Color target)
            {
                var ret = _blendMode switch
                {
                    RectLineBlendMode.Multiply => target * color,
                    RectLineBlendMode.Additive => target + color,
                    RectLineBlendMode.Subtract => target - color,
                    _ => throw new ArgumentOutOfRangeException()
                };

                //アルファはcolorの物を使う(扱いやすいので)
                ret.a = color.a;
                return ret;
            }

            var inColor = GetColor(_inColor);
            var outColor = GetColor(_outColor);

            vh.Clear();
            var lb = new Vector3(v.x, v.y);
            var lt = new Vector3(v.x, v.w);
            var rt = new Vector3(v.z, v.w);
            var rb = new Vector3(v.z, v.y);

            var lbIn = lb + new Vector3(inLength, inLength);
            var lbOut = lb + new Vector3(-outLength, -outLength);
            vh.AddVert(lbIn, inColor, new Vector2(0f, 0f));
            vh.AddVert(lbOut, outColor, new Vector2(0f, 1f));
            vh.AddVert(lt + new Vector3(inLength,-inLength), inColor, new Vector2(1f, 0f));
            vh.AddVert(lt + new Vector3(-outLength,outLength), outColor, new Vector2(1f, 1f));
            vh.AddVert(rt + new Vector3(-inLength,-inLength), inColor, new Vector2(2f, 0f));
            vh.AddVert(rt + new Vector3(outLength,outLength), outColor, new Vector2(2f, 1f));
            vh.AddVert(rb + new Vector3(-inLength,inLength), inColor, new Vector2(3f, 0f));
            vh.AddVert(rb + new Vector3(outLength,-outLength), outColor, new Vector2(3f, 1f));
            vh.AddVert(lbIn, inColor, new Vector2(4f, 0f));
            vh.AddVert(lbOut, outColor, new Vector2(4f, 1f));

            vh.AddTriangle(0, 1, 2);
            vh.AddTriangle(2, 1, 3);
            vh.AddTriangle(2, 3, 4);
            vh.AddTriangle(4, 3, 5);
            vh.AddTriangle(4, 5, 6);
            vh.AddTriangle(6, 5, 7);
            vh.AddTriangle(6, 7, 8);
            vh.AddTriangle(8, 7, 9);
        }
    }
}

  • 太さの調整
  • テクスチャを指定可能(内側がv0、外側がv1各辺がu0~1、u1~2、u2~3、u3~4とタイリング)
  • 矩形の内側、中間、外側で位置を調整可能
  • 内周色、外周色を指定可能
  • 内周/外周色とGraphicのColorのブレンド方法を選択可能

となっているのでソコソコ多機能かな?と。
MaskableGraphic派生なので、当然マスク対象にもできるし、Maskコンポーネントと組み合わせれば、ライン部分のみマスクをかける事も可能です。

次作るゲームのカーソルはコレで作ろうかな。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0