UGUIを組んでいると、RectTransformに対して線を引きたい場合が有ります。
例えばガイドラインだったり、例えばカーソルだったり。
そんな時に利用できるRectLineコンポーネントを作りました。
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コンポーネントと組み合わせれば、ライン部分のみマスクをかける事も可能です。
次作るゲームのカーソルはコレで作ろうかな。