親戚のゲーム作ってるおじさんブログ

「そういえば、そんな人いるとか聞いたなあ」って思ったでしょ? 私です。

uGUIで線を引く~その2:線の描画編~

はじめに

前回、三角メッシュを描画しました uGUIで線を引く~その1:三角メッシュの描画 今回は、それを応用して、四角を作成します

作ってみる

前回は頂点3つでしたが、4つ用意して、メッシュを2つ描画するだけです

using UnityEngine;
using UnityEngine.UI;
public class UIOneLine : Graphic
{
    /// <summary>
    /// uGUIでメッシュ生成する際のコールバック
    /// </summary>
    /// <param name="vh">この引数にメッシュを設定していく</param>
    protected override void OnPopulateMesh(VertexHelper vh)
    {
        //(1)座標の準備
        var v1 = new Vector2(0.0f, 0.0f);
        var v2 = new Vector2(100.0f, 0.0f);
        var v3 = new Vector2(0.0f, 100.0f);
        var v4 = new Vector2(100.0f, 100.0f);
        // (2)(1)の座標に頂点を追加
        AddVert(vh, v1);
        AddVert(vh, v2);
        AddVert(vh, v3);
        AddVert(vh, v4);
        // (3)(2)で追加した頂点に三角形メッシュを2つ設定
        vh.AddTriangle(0, 1, 2);
        vh.AddTriangle(1, 2, 3);
    }

    private void AddVert(VertexHelper vh, Vector2 pos)
    {
        var vert = UIVertex.simpleVert;
        vert.position = pos;
        vert.color = color;
        vh.AddVert(vert);
    }
}

image.png (1)のv3,v4のy座標100.0fを、5.0fにすれば image.png 線になりました!

実用性をあげる

インスペクターで設定できるようにします。 ただ、線を引くのにいちいち4点を指定するのは面倒なので、2点と太さをもらって、描画するようにしてみます。

using UnityEngine;
using UnityEngine.UI;
public class UIOneLine : Graphic
{
    [SerializeField]
    private Vector2 _position1;
    [SerializeField]
    private Vector2 _position2;
    [SerializeField]
    private float _weight; // ←太さ

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        // (1)頂点を頂点リストに追加
        AddVert(vh, new Vector2(_position1.x, _position1.y - _weight / 2));
        AddVert(vh, new Vector2(_position1.x, _position1.y + _weight / 2));
        AddVert(vh, new Vector2(_position2.x, _position2.y - _weight / 2));
        AddVert(vh, new Vector2(_position2.x, _position2.y + _weight / 2));

        // (2)頂点リストを元にメッシュを貼る
        vh.AddTriangle(0, 1, 2);
        vh.AddTriangle(1, 2, 3);

    }
    private void AddVert(VertexHelper vh, Vector2 pos)
    {
        var vert = UIVertex.simpleVert;
        vert.position = pos;
        vert.color = color;
        vh.AddVert(vert);
    }
}

image.png できました! …が、ここで問題が。。

線を動的に動かしたい

上記の例だと、プレイ前に設定した位置に線が引かれますが、プレイ中にインスペクターでPosition1とPosition2を変更しても、線が変わりません。 なぜかというと、確かに、変更したタイミングで再度OnPopulateMeshが呼ばれて、変更後の座標に頂点が増えますが、メッシュは、変更前の座標のインデックス(0,1,2,3)に描画しているため、変更後の座標にメッシュが描画していないためです。 じゃあどうすればいいかというと、行頭でClearメソッドを呼んで、同インデックスの頂点の座標を更新するようにします

using UnityEngine;
using UnityEngine.UI;
public class UIOneLine : Graphic
{
    [SerializeField]
    private Vector2 _position1;
    [SerializeField]
    private Vector2 _position2;
    [SerializeField]
    private float _weight;

    protected override void OnPopulateMesh(VertexHelper vh)
    {
        // (1)☆この行を追加!!過去にAddした頂点を全部削除!
        vh.Clear();
        // (2)あとは同じ。頂点を頂点リストに追加
        AddVert(vh, new Vector2(_position1.x, _position1.y - _weight / 2));
        AddVert(vh, new Vector2(_position1.x, _position1.y + _weight / 2));
        AddVert(vh, new Vector2(_position2.x, _position2.y - _weight / 2));
        AddVert(vh, new Vector2(_position2.x, _position2.y + _weight / 2));
        // (3)頂点リストを元にメッシュを貼る
        vh.AddTriangle(0, 1, 2);
        vh.AddTriangle(1, 2, 3);
    }
    private void AddVert(VertexHelper vh, Vector2 pos)
    {
        var vert = UIVertex.simpleVert;
        vert.position = pos;
        vert.color = color;
        vh.AddVert(vert);
    }
}

MoveOneLine.gif

ちなみに再生してなくても動かせます。便利! MoveOneLineInEditor.gif

次回予告

このままだと、太さが縦への長さにしているため、縦に線が引けません。 次は、線の角度によって、4頂点の位置を調整するようにします uGUIで線を引く~その3:線の端を垂線にする~