うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】ジグソーパズルの自動生成 ~1~

ふと Unity でジグソーパズルを作成したくなったので、Unity でのジグソーパズルの自動生成について考える

ピース Mesh の生成

まずピースの生成について考える

自前で頂点を作成するのは容易ですが、頂点からメッシュを作成するのは容易では無いため
頂点とメッシュの両方ができるツールがあればそれを利用したほうが早い

探したところ、まだ Preview 版ではあるが Vector-graphics が見つかった

VectorUtils.TessellateScene

を使えば線情報からメッシュの生成ができる

vector-graphics-samples/vectorgraphics.md at master · Unity-Technologies/vector-graphics-samples · GitHub

Vector-graphics に関しては「テラシュールブログ」さんに詳しく書かれてます

【Unity】Unityでベクターグラフィック(SVG)を利用する - テラシュールブログ
【Unity】Unityでベジェ曲線(パス)を描く方法 - テラシュールブログ

ピース境界

https://3.bp.blogspot.com/-BDdu8TVY-pY/VHPgCghVdNI/AAAAAAAApOA/UtnEohNhOag/s800/jigsaw_puzzle.png

次にピースの境界部分をベジェ曲線を使って作成していきます

ベジェ曲線を利用した場合下図のような境界が作成できます
※凸ってますが凹るにはy座標を下げればいいだけです

f:id:hacchi_man:20200108231953p:plain

こちらで利用したコードは以下になります。

using System.Collections.Generic;
using Unity.VectorGraphics;
using UnityEngine;

[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class PieceBoundary : MonoBehaviour
{
    private void Awake()
    {
        var segments = new List<BezierPathSegment>
        {
            new BezierPathSegment {P0 = Vector2.zero, P1 = new Vector2(0.1f, 0f), P2 = new Vector2(0.3f, 0f),},
            new BezierPathSegment
            {
                P0 = new Vector2(0.4f, 0f), P1 = new Vector2(0.4f, 0.1f), P2 = new Vector2(0.3f, 0.1f),
            },
            new BezierPathSegment
            {
                P0 = new Vector2(0.3f, 0.2f), P1 = new Vector2(0.3f, 0.3f), P2 = new Vector2(0.7f, 0.3f),
            },
            new BezierPathSegment
            {
                P0 = new Vector2(0.7f, 0.2f), P1 = new Vector2(0.7f, 0.1f), P2 = new Vector2(0.6f, 0.1f),
            },
            new BezierPathSegment
            {
                P0 = new Vector2(0.6f, 0f), P1 = new Vector2(0.7f, 0f), P2 = new Vector2(0.9f, 0f),
            },
            new BezierPathSegment {P0 = Vector2.right,}
        };
        var shape = new Shape
        {
            Contours = new[]
            {
                new BezierContour
                {
                    Segments = segments.ToArray(),
                    Closed = false,
                }
            },
            PathProps = new PathProperties
            {
                Stroke = new Stroke
                {
                    Color = Color.white,
                    HalfThickness = 0.01f,
                }
            }
        };

        var scene = new Scene {Root = new SceneNode {Shapes = new List<Shape> {shape}}};
        
        var options = new VectorUtils.TessellationOptions
        {
            StepDistance = 100,
            MaxCordDeviation = 0.05f,
            MaxTanAngleDeviation = 0.05f,
            SamplingStepSize = 0.01f
        };

        var mesh = new Mesh();
        var geometries = VectorUtils.TessellateScene(scene, options);
        VectorUtils.FillMesh(mesh, geometries, 1f);
        GetComponent<MeshFilter>().mesh = mesh;
    }
}

ピースのメッシュ生成は次の記事に記述します